[gtk/wip/otte/float-textures: 10/10] gltexture whatever HELP: CLEAN THIS UP!




commit a4daa770e1baf74d3b505249a13bb6dc6ceed3db
Author: Benjamin Otte <otte redhat com>
Date:   Sun Sep 12 00:14:19 2021 +0200

    gltexture whatever HELP: CLEAN THIS UP!

 gdk/gdkglcontext.c      | 125 ++++++++++++++++++++++----------------
 gdk/gdkgltexture.c      | 156 +++++++++++++++++++++++++++++++++++++++++-------
 gdk/gdkmemorytexture.c  |   7 +++
 gdk/gdktexture.c        |  42 +++++++++++--
 gdk/gdktextureprivate.h |   5 ++
 5 files changed, 254 insertions(+), 81 deletions(-)
---
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index f957d9c1c5..76be3c7ef9 100644
--- a/gdk/gdkglcontext.c
+++ b/gdk/gdkglcontext.c
@@ -229,64 +229,83 @@ gdk_gl_context_upload_texture (GdkGLContext    *context,
 {
   GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context);
   guchar *copy = NULL;
-  guint gl_format;
-  guint gl_type;
-  guint bpp;
+  GLint gl_internalformat;
+  GLint gl_format;
+  GLint gl_type;
+  gsize bpp;
 
   g_return_if_fail (GDK_IS_GL_CONTEXT (context));
 
-  if (priv->use_es)
+  if (!priv->use_es && data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
     {
-      /* GLES only supports rgba, so convert if necessary */
-      if (data_format != GDK_MEMORY_R8G8B8A8_PREMULTIPLIED)
-        {
-          copy = g_malloc (width * height * 4);
-          gdk_memory_convert (copy, width * 4,
-                              GDK_MEMORY_CONVERT_GLES_RGBA,
-                              data, stride, data_format,
-                              width, height);
-          stride = width * 4;
-          data = copy;
-        }
-
-      bpp = 4;
-      gl_format = GL_RGBA;
+      gl_internalformat = GL_RGBA8;
+      gl_format = GL_BGRA;
+      gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
+    }
+  else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */
+    {
+      gl_internalformat = GL_RGBA8;
+      gl_format = GL_RGB;
       gl_type = GL_UNSIGNED_BYTE;
     }
-  else
+  else if (priv->use_es && data_format == GDK_MEMORY_B8G8R8)
     {
-      if (data_format == GDK_MEMORY_DEFAULT) /* Cairo surface format */
-        {
-          gl_format = GL_BGRA;
-          gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
-          bpp = 4;
-        }
-      else if (data_format == GDK_MEMORY_R8G8B8) /* Pixmap non-alpha data */
-        {
-          gl_format = GL_RGB;
-          gl_type = GL_UNSIGNED_BYTE;
-          bpp = 3;
-        }
-      else if (data_format == GDK_MEMORY_B8G8R8)
-        {
-          gl_format = GL_BGR;
-          gl_type = GL_UNSIGNED_BYTE;
-          bpp = 3;
-        }
-      else /* Fall-back, convert to cairo-surface-format */
-        {
-          copy = g_malloc (width * height * 4);
-          gdk_memory_convert (copy, width * 4,
-                              GDK_MEMORY_CONVERT_DOWNLOAD,
-                              data, stride, data_format,
-                              width, height);
-          stride = width * 4;
-          bpp = 4;
-          data = copy;
-          gl_format = GL_BGRA;
-          gl_type = GL_UNSIGNED_INT_8_8_8_8_REV;
-        }
+      gl_internalformat = GL_RGBA8;
+      gl_format = GL_BGR;
+      gl_type = GL_UNSIGNED_BYTE;
+    }
+  else if (data_format == GDK_MEMORY_R16G16B16)
+    {
+      gl_internalformat = GL_RGBA16;
+      gl_format = GL_RGB;
+      gl_type = GL_UNSIGNED_SHORT;
     }
+  else if (data_format == GDK_MEMORY_R16G16B16A16_PREMULTIPLIED)
+    {
+      gl_internalformat = GL_RGBA16;
+      gl_format = GL_RGBA;
+      gl_type = GL_UNSIGNED_SHORT;
+    }
+  else if (data_format == GDK_MEMORY_R16G16B16_FLOAT)
+    {
+      gl_internalformat = GL_RGB16F;
+      gl_format = GL_RGB;
+      gl_type = GL_HALF_FLOAT;
+    }
+  else if (data_format == GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED)
+    {
+      gl_internalformat = GL_RGBA16F;
+      gl_format = GL_RGBA;
+      gl_type = GL_HALF_FLOAT;
+    }
+  else if (data_format == GDK_MEMORY_R32G32B32_FLOAT)
+    {
+      gl_internalformat = GL_RGB32F;
+      gl_format = GL_RGB;
+      gl_type = GL_FLOAT;
+    }
+  else if (data_format == GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED)
+    {
+      gl_internalformat = GL_RGBA32F;
+      gl_format = GL_RGBA;
+      gl_type = GL_FLOAT;
+    }
+  else /* Fall-back, convert to GLES format */
+    {
+      copy = g_malloc (width * height * 4);
+      gdk_memory_convert (copy, width * 4,
+                          GDK_MEMORY_CONVERT_GLES_RGBA,
+                          data, stride, data_format,
+                          width, height);
+      data_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED;
+      stride = width * 4;
+      data = copy;
+      gl_internalformat = GL_RGBA8;
+      gl_format = GL_RGBA;
+      gl_type = GL_UNSIGNED_BYTE;
+    }
+
+  bpp = gdk_memory_format_bytes_per_pixel (data_format);
 
   /* GL_UNPACK_ROW_LENGTH is available on desktop GL, OpenGL ES >= 3.0, or if
    * the GL_EXT_unpack_subimage extension for OpenGL ES 2.0 is available
@@ -295,7 +314,7 @@ gdk_gl_context_upload_texture (GdkGLContext    *context,
     {
       glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
 
-      glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
+      glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
       glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
     }
   else if ((!priv->use_es ||
@@ -303,14 +322,14 @@ gdk_gl_context_upload_texture (GdkGLContext    *context,
     {
       glPixelStorei (GL_UNPACK_ROW_LENGTH, stride / bpp);
 
-      glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, data);
+      glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, data);
 
       glPixelStorei (GL_UNPACK_ROW_LENGTH, 0);
     }
   else
     {
       int i;
-      glTexImage2D (texture_target, 0, GL_RGBA, width, height, 0, gl_format, gl_type, NULL);
+      glTexImage2D (texture_target, 0, gl_internalformat, width, height, 0, gl_format, gl_type, NULL);
       for (i = 0; i < height; i++)
         glTexSubImage2D (texture_target, 0, 0, i, width, 1, gl_format, gl_type, data + (i * stride));
     }
diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c
index c35376583f..53a949257e 100644
--- a/gdk/gdkgltexture.c
+++ b/gdk/gdkgltexture.c
@@ -20,8 +20,7 @@
 
 #include "gdkgltextureprivate.h"
 
-#include "gdkcairo.h"
-#include "gdkmemorytexture.h"
+#include "gdkmemorytextureprivate.h"
 #include "gdktextureprivate.h"
 
 #include <epoxy/gl.h>
@@ -70,16 +69,118 @@ 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;
+
+    case GL_RGB16:
+      format = GDK_MEMORY_R16G16B16;
+      gl_format = GL_RGB;
+      gl_type = GL_UNSIGNED_SHORT;
+      break;
+
+    case GL_RGBA16:
+      format = GDK_MEMORY_R16G16B16A16_PREMULTIPLIED;
+      gl_format = GL_RGBA;
+      gl_type = GL_UNSIGNED_SHORT;
+      break;
+
+    case GL_RGB16F:
+      format = GDK_MEMORY_R16G16B16_FLOAT;
+      gl_format = GL_RGB;
+      gl_type = GL_HALF_FLOAT;
+      break;
+
+    case GL_RGBA16F:
+      format = GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED;
+      gl_format = GL_RGBA;
+      gl_type = GL_HALF_FLOAT;
+      break;
+
+    case GL_RGB32F:
+      format = GDK_MEMORY_R32G32B32_FLOAT;
+      gl_format = GL_RGB;
+      gl_type = GL_FLOAT;
+      break;
+
+    case GL_RGBA32F:
+      format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED;
+      gl_format = GL_RGBA;
+      gl_type = GL_FLOAT;
+      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,
                          gsize       stride)
 {
   GdkGLTexture *self = GDK_GL_TEXTURE (texture);
-  GdkSurface *gl_surface;
-  cairo_surface_t *surface;
-  cairo_t *cr;
-  int width, height;
+  GLint active_texture;
 
   if (self->saved)
     {
@@ -87,23 +188,31 @@ gdk_gl_texture_download (GdkTexture *texture,
       return;
     }
 
-  width = gdk_texture_get_width (texture);
-  height = gdk_texture_get_width (texture);
-  surface = cairo_image_surface_create_for_data (data,
-                                                 CAIRO_FORMAT_ARGB32,
-                                                 width, height,
-                                                 stride);
-
-  cr = cairo_create (surface);
-
-  gl_surface = gdk_gl_context_get_surface (self->context);
-  gdk_cairo_draw_from_gl (cr, gl_surface, self->id, GL_TEXTURE, 1, 
-                          0, 0,
-                          width, height);
-
-  cairo_destroy (cr);
-  cairo_surface_finish (surface);
-  cairo_surface_destroy (surface);
+  if (gdk_gl_context_get_use_es (self->context) ||
+      stride != texture->width * 4)
+    {
+      GDK_TEXTURE_CLASS (gdk_gl_texture_parent_class)->download (texture, data, stride);
+      return;
+    }
+
+  gdk_gl_context_make_current (self->context);
+
+  glGetIntegerv (GL_TEXTURE_BINDING_2D, &active_texture);
+  glBindTexture (GL_TEXTURE_2D, self->id);
+
+  glGetTexImage (GL_TEXTURE_2D,
+                 0,
+                 GL_BGRA,
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+                 GL_UNSIGNED_INT_8_8_8_8_REV,
+#elif G_BYTE_ORDER == G_BIG_ENDIAN
+                 GL_UNSIGNED_BYTE,
+#else
+#error "Unknown byte order for gdk_gl_texture_download()"
+#endif
+                 data);
+
+  glBindTexture (GL_TEXTURE_2D, active_texture);
 }
 
 static void
@@ -166,6 +275,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;
   texture_class->download_float = gdk_gl_texture_download_float;
   gobject_class->dispose = gdk_gl_texture_dispose;
diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c
index 5a5051efab..631357bcc8 100644
--- a/gdk/gdkmemorytexture.c
+++ b/gdk/gdkmemorytexture.c
@@ -129,6 +129,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,
@@ -166,6 +172,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;
   texture_class->download_float = gdk_memory_texture_download_float;
   gobject_class->dispose = gdk_memory_texture_dispose;
diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c
index 73c9d1cae5..7b055238fd 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
@@ -128,7 +139,11 @@ gdk_texture_real_download_float (GdkTexture *self,
                                  float      *data,
                                  gsize       stride)
 {
-  GDK_TEXTURE_WARN_NOT_IMPLEMENTED_METHOD (self, download_float);
+  GdkTexture *memory_texture;
+
+  memory_texture = gdk_texture_download_texture (self);
+  gdk_texture_download_float (memory_texture, data, stride);
+  g_object_unref (memory_texture);
 }
 
 static void
@@ -194,6 +209,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;
   klass->download_float = gdk_texture_real_download_float;
 
@@ -521,6 +537,22 @@ gdk_texture_download_float (GdkTexture *texture,
   GDK_TEXTURE_GET_CLASS (texture)->download_float (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 ca85824ac2..29fca0a9ba 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);
@@ -37,6 +40,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]