[gtk/wip/otte/memoryformat] gl: Fix downloading textures *again*




commit 7827a0a90c13363b7da1c41b74dc4d0abd2af9f6
Author: Benjamin Otte <otte redhat com>
Date:   Mon Oct 11 03:29:11 2021 +0200

    gl: Fix downloading textures *again*
    
    It turns out glReadPixels() cannot convert pixels and you are only
    allowed to pass a single value into the function arguments. You need to
    know which ones or things will explode.
    
    GL is great.

 gdk/gdkgltexture.c   | 113 +++++++++++++++++++++++++++++++++++----------------
 gsk/gl/gskgldriver.c |   2 +-
 2 files changed, 80 insertions(+), 35 deletions(-)
---
diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c
index a6d6d6e9b3..d734dbc4b9 100644
--- a/gdk/gdkgltexture.c
+++ b/gdk/gdkgltexture.c
@@ -113,44 +113,105 @@ typedef struct _Download Download;
 
 struct _Download
 {
-  guint gl_internalformat;
-  guint gl_format;
-  guint gl_type;
+  GdkMemoryFormat format;
   guchar *data;
   gsize stride;
 };
 
+static gboolean
+gdk_gl_texture_find_format (gboolean         use_es,
+                            GLint            gl_format,
+                            GLint            gl_type,
+                            GdkMemoryFormat *out_format)
+{
+  GdkMemoryFormat format;
+
+  for (format = 0; format < GDK_MEMORY_N_FORMATS; format++)
+    {
+      GLenum q_internal_format, q_format, q_type;
+
+      if (!gdk_memory_format_gl_format (format, use_es, &q_internal_format, &q_format, &q_type))
+        continue;
+
+      if (q_format != gl_format || q_type != gl_type)
+        continue;
+
+      *out_format = format;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 static inline void
 gdk_gl_texture_do_download (gpointer texture_,
                             gpointer download_)
 {
+  gsize expected_stride;
   GdkGLTexture *self = texture_;
   GdkTexture *texture = texture_;
   Download *download = download_;
+  GLenum gl_internal_format, gl_format, gl_type;
 
-  if (gdk_gl_context_get_use_es (self->context))
+  expected_stride = texture->width * gdk_memory_format_bytes_per_pixel (download->format);
+
+  if (download->stride != expected_stride &&
+      !gdk_memory_format_gl_format (download->format, gdk_gl_context_get_use_es (self->context), 
&gl_internal_format, &gl_format, &gl_type))
+    {
+      glGetTexImage (GL_TEXTURE_2D,
+                     0,
+                     gl_format,
+                     gl_type,
+                     download->data);
+    }
+  else
     {
+      GdkMemoryFormat actual_format;
+      GLint gl_read_format, gl_read_type;
       GLuint fbo;
 
       glGenFramebuffers (1, &fbo);
       glBindFramebuffer (GL_FRAMEBUFFER, fbo);
       glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, self->id, 0);
-      glReadPixels (0, 0,
-                    texture->width, texture->height, 
-                    download->gl_format,
-                    download->gl_type,
-                    download->data);
+      glGetFramebufferParameteriv (GL_FRAMEBUFFER, GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_read_format);
+      glGetFramebufferParameteriv (GL_FRAMEBUFFER, GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_read_type);
+      if (!gdk_gl_texture_find_format (gdk_gl_context_get_use_es (self->context), gl_read_format, 
gl_read_type, &actual_format))
+        actual_format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; /* pray */
+
+      if (download->format == actual_format &&
+          (download->stride == expected_stride))
+        {
+          glReadPixels (0, 0,
+                        texture->width, texture->height, 
+                        gl_read_format,
+                        gl_read_type,
+                        download->data);
+        }
+      else
+        {
+          gsize actual_bpp = gdk_memory_format_bytes_per_pixel (actual_format);
+          guchar *pixels = g_malloc_n (texture->width * actual_bpp, texture->height);
+
+          glReadPixels (0, 0,
+                        texture->width, texture->height, 
+                        gl_read_format,
+                        gl_read_type,
+                        pixels);
+
+          gdk_memory_convert (download->data,
+                              download->stride,
+                              download->format,
+                              pixels,
+                              texture->width * actual_bpp,
+                              actual_format,
+                              texture->width,
+                              texture->height);
+
+          g_free (pixels);
+        }
       glBindFramebuffer (GL_FRAMEBUFFER, 0);
       glDeleteFramebuffers (1, &fbo);
     }
-  else
-    {
-      glGetTexImage (GL_TEXTURE_2D,
-                     0,
-                     download->gl_format,
-                     download->gl_type,
-                     download->data);
-    }
 }
 
 static void
@@ -168,26 +229,10 @@ gdk_gl_texture_download (GdkTexture      *texture,
       return;
     }
 
+  download.format = format;
   download.data = data;
   download.stride = stride;
 
-  if (stride != texture->width * gdk_memory_format_bytes_per_pixel (format) ||
-      !gdk_memory_format_gl_format (format,
-                                    gdk_gl_context_get_use_es (self->context),
-                                    &download.gl_internalformat,
-                                    &download.gl_format,
-                                    &download.gl_type))
-    {
-      GdkMemoryTexture *memtex;
-
-      memtex = gdk_memory_texture_from_texture (texture,
-                                                format == texture->format ? GDK_MEMORY_R8G8B8A8_PREMULTIPLIED
-                                                                          : texture->format);
-      gdk_texture_do_download (GDK_TEXTURE (memtex), format, data, stride);
-      g_object_unref (memtex);
-      return;
-    }
-
   gdk_gl_texture_run (self, gdk_gl_texture_do_download, &download);
 }
 
diff --git a/gsk/gl/gskgldriver.c b/gsk/gl/gskgldriver.c
index 61b8469d52..33fcf380b3 100644
--- a/gsk/gl/gskgldriver.c
+++ b/gsk/gl/gskgldriver.c
@@ -23,7 +23,7 @@
 
 #include "config.h"
 
-#include "gskngldriverprivate.h"
+#include "gskgldriverprivate.h"
 
 #include <gsk/gskdebugprivate.h>
 #include <gsk/gskglshaderprivate.h>


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