[gtk/wip/otte/float-textures: 19/30] texture: Add gdk_texture_download_texture()




commit 4f17f3ac240117ae38cd83e3c8140a4b2a8dccff
Author: Benjamin Otte <otte redhat com>
Date:   Sun Sep 12 04:42:24 2021 +0200

    texture: Add gdk_texture_download_texture()
    
    A private vfunc that downloads a texture as a GdkMemoryTexture in
    whatever format the texture deems best.
    
    There are multiple reasons for this:
    
     * GLES cannot download the Cairo format. But it can download some
       format and then just delegate to the GdkMemoryTexture implementation.
    
     * All the other download vfuncs (including the ones still coming) can
       be implemented via download_texture() and delegation, making the
       interface easier.
    
     * We want to implement image loading and saving support. By using
       download_texture(), we can save in the actual format of the texture.
    
     * A potential GdkCompressedTexture could be implemented by just
       providing this one vfunc as a compress() step.

 gdk/gdkgltexture.c      | 72 ++++++++++++++++++++++++++++++++++++++++++++++++-
 gdk/gdkmemorytexture.c  |  7 +++++
 gdk/gdktexture.c        | 36 ++++++++++++++++++++++---
 gdk/gdktextureprivate.h |  5 ++++
 4 files changed, 115 insertions(+), 5 deletions(-)
---
diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c
index adf075ea91..9b5aa86866 100644
--- a/gdk/gdkgltexture.c
+++ b/gdk/gdkgltexture.c
@@ -21,7 +21,7 @@
 #include "gdkgltextureprivate.h"
 
 #include "gdkcairo.h"
-#include "gdkmemorytexture.h"
+#include "gdkmemorytextureprivate.h"
 #include "gdktextureprivate.h"
 
 #include <epoxy/gl.h>
@@ -70,6 +70,75 @@ gdk_gl_texture_dispose (GObject *object)
   G_OBJECT_CLASS (gdk_gl_texture_parent_class)->dispose (object);
 }
 
+static GdkTexture *
+gdk_gl_texture_download_texture (GdkTexture *texture)
+{
+  GdkGLTexture *self = GDK_GL_TEXTURE (texture);
+  GdkTexture *result;
+  int active_texture;
+  GdkMemoryFormat format;
+  GLint internal_format, gl_format, gl_type;
+  guchar *data;
+  gsize stride;
+  GBytes *bytes;
+
+  if (self->saved)
+    return g_object_ref (self->saved);
+
+  gdk_gl_context_make_current (self->context);
+
+  glGetIntegerv (GL_TEXTURE_BINDING_2D, &active_texture);
+  glBindTexture (GL_TEXTURE_2D, self->id);
+
+  glGetTexLevelParameteriv (GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
+
+  switch (internal_format)
+  {
+    case GL_RGB8:
+      format = GDK_MEMORY_R8G8B8;
+      gl_format = GL_RGB;
+      gl_type = GL_UNSIGNED_BYTE;
+      break;
+
+    case GL_RGBA8:
+      format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
+      gl_format = GL_RGBA;
+      gl_type = GL_UNSIGNED_BYTE;
+      break;
+
+    default:
+      g_warning ("Texture in unexpected format 0x%X (%d). File a bug about adding it to GTK", 
internal_format, internal_format);
+      /* fallback to the dumbest possible format
+       * so that even age old GLES can do it */
+      format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
+      gl_format = GL_RGBA;
+      gl_type = GL_UNSIGNED_BYTE;
+      break;
+  }
+
+  stride = gdk_memory_format_bytes_per_pixel (format) * texture->width;
+  data = g_malloc (stride * texture->height);
+
+  glGetTexImage (GL_TEXTURE_2D,
+                 0,
+                 gl_format,
+                 gl_type,
+                 data);
+
+  bytes = g_bytes_new_take (data, stride * texture->height);
+  result = gdk_memory_texture_new (texture->width,
+                                   texture->height,
+                                   format,
+                                   bytes,
+                                   stride);
+
+  g_bytes_unref (bytes);
+
+  glBindTexture (GL_TEXTURE_2D, active_texture);
+
+  return result;
+}
+
 static void
 gdk_gl_texture_download (GdkTexture *texture,
                          guchar     *data,
@@ -112,6 +181,7 @@ gdk_gl_texture_class_init (GdkGLTextureClass *klass)
   GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  texture_class->download_texture = gdk_gl_texture_download_texture;
   texture_class->download = gdk_gl_texture_download;
   gobject_class->dispose = gdk_gl_texture_dispose;
 }
diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c
index ab117a01ff..edb4d741c6 100644
--- a/gdk/gdkmemorytexture.c
+++ b/gdk/gdkmemorytexture.c
@@ -79,6 +79,12 @@ gdk_memory_texture_dispose (GObject *object)
   G_OBJECT_CLASS (gdk_memory_texture_parent_class)->dispose (object);
 }
 
+static GdkTexture *
+gdk_memory_texture_download_texture (GdkTexture *texture)
+{
+  return g_object_ref (texture);
+}
+
 static void
 gdk_memory_texture_download (GdkTexture *texture,
                              guchar     *data,
@@ -101,6 +107,7 @@ gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
   GdkTextureClass *texture_class = GDK_TEXTURE_CLASS (klass);
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  texture_class->download_texture = gdk_memory_texture_download_texture;
   texture_class->download = gdk_memory_texture_download;
   gobject_class->dispose = gdk_memory_texture_dispose;
 }
diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c
index 9ae9f80944..4afd6ebfdd 100644
--- a/gdk/gdktexture.c
+++ b/gdk/gdktexture.c
@@ -115,12 +115,23 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkTexture, gdk_texture, G_TYPE_OBJECT,
 #define GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD(obj,method) \
   g_critical ("Texture of type '%s' does not implement GdkTexture::" # method, G_OBJECT_TYPE_NAME (obj))
 
+static GdkTexture *
+gdk_texture_real_download_texture (GdkTexture *self)
+{
+  GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download_texture);
+  return NULL;
+}
+
 static void
-gdk_texture_real_download (GdkTexture         *self,
-                           guchar             *data,
-                           gsize               stride)
+gdk_texture_real_download (GdkTexture *texture,
+                           guchar     *data,
+                           gsize      stride)
 {
-  GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download);
+  GdkTexture *memory_texture;
+
+  memory_texture = gdk_texture_download_texture (texture);
+  gdk_texture_download (memory_texture, data, stride);
+  g_object_unref (memory_texture);
 }
 
 static void
@@ -186,6 +197,7 @@ gdk_texture_class_init (GdkTextureClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 
+  klass->download_texture = gdk_texture_real_download_texture;
   klass->download = gdk_texture_real_download;
 
   gobject_class->set_property = gdk_texture_set_property;
@@ -473,6 +485,22 @@ gdk_texture_download (GdkTexture *texture,
   GDK_TEXTURE_GET_CLASS (texture)->download (texture, data, stride);
 }
 
+GdkTexture *
+gdk_texture_download_texture (GdkTexture *texture)
+{
+  g_return_val_if_fail (GDK_IS_TEXTURE (texture), NULL);
+
+  g_object_ref (texture);
+  while (!GDK_IS_MEMORY_TEXTURE (texture))
+    {
+      GdkTexture *downloaded = GDK_TEXTURE_GET_CLASS (texture)->download_texture (texture);
+      g_object_unref (texture);
+      texture = downloaded;
+    }
+
+  return texture;
+}
+
 gboolean
 gdk_texture_set_render_data (GdkTexture     *self,
                              gpointer        key,
diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h
index e2e7dc2bae..1133bf6acc 100644
--- a/gdk/gdktextureprivate.h
+++ b/gdk/gdktextureprivate.h
@@ -24,6 +24,9 @@ struct _GdkTexture
 struct _GdkTextureClass {
   GObjectClass parent_class;
 
+  /* mandatory: Download into a GdkMemoryTexture */
+  GdkTexture *          (* download_texture)            (GdkTexture             *texture);
+  /* optional */
   void                  (* download)                    (GdkTexture             *texture,
                                                          guchar                 *data,
                                                          gsize                   stride);
@@ -34,6 +37,8 @@ gpointer                gdk_texture_new                 (const GdkTextureClass
                                                          int                     height);
 GdkTexture *            gdk_texture_new_for_surface     (cairo_surface_t        *surface);
 cairo_surface_t *       gdk_texture_download_surface    (GdkTexture             *texture);
+/* NB: GdkMemoryTexture */
+GdkTexture *            gdk_texture_download_texture    (GdkTexture             *texture);
 
 gboolean                gdk_texture_set_render_data     (GdkTexture             *self,
                                                          gpointer                key,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]