[gtk/wip/otte/float-textures: 5/12] texture: Add gdk_texture_download_float()




commit 5db349b17b97ff3c40895f9aa12f0d79be754a3b
Author: Benjamin Otte <otte redhat com>
Date:   Fri Sep 10 02:40:21 2021 +0200

    texture: Add gdk_texture_download_float()

 gdk/gdkgltexture.c            | 55 +++++++++++++++++++++++++
 gdk/gdkmemorytexture.c        | 95 +++++++++++++++++++++++++++++++++++++++++++
 gdk/gdkmemorytextureprivate.h |  8 ++++
 gdk/gdktexture.c              | 52 +++++++++++++++++++++++
 gdk/gdktexture.h              |  4 ++
 gdk/gdktextureprivate.h       |  3 ++
 6 files changed, 217 insertions(+)
---
diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c
index bd69809061..365a3a6ac2 100644
--- a/gdk/gdkgltexture.c
+++ b/gdk/gdkgltexture.c
@@ -179,6 +179,60 @@ gdk_gl_texture_download (GdkTexture *texture,
   glBindTexture (GL_TEXTURE_2D, active_texture);
 }
 
+static void
+gdk_gl_texture_do_download_float (GdkTexture *texture,
+                                  float      *data)
+{
+  GdkGLTexture *self = GDK_GL_TEXTURE (texture);
+  int active_texture;
+
+  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_RGBA,
+                 GL_FLOAT,
+                 data);
+
+  glBindTexture (GL_TEXTURE_2D, active_texture);
+}
+
+static void
+gdk_gl_texture_download_float (GdkTexture *texture,
+                               float      *data,
+                               gsize       stride)
+{
+  GdkGLTexture *self = GDK_GL_TEXTURE (texture);
+  int width, height, y;
+  float *copy;
+
+  if (self->saved)
+    {
+      gdk_texture_download_float (self->saved, data, stride);
+      return;
+    }
+
+  width = gdk_texture_get_width (texture);
+  height = gdk_texture_get_height (texture);
+
+  if (stride == width * 4)
+    {
+      gdk_gl_texture_do_download_float (texture, data);
+      return;
+    }
+
+  copy = g_new (float, width * height * 4);
+
+  gdk_gl_texture_do_download_float (texture, copy);
+  for (y = 0; y < height; y++)
+    memcpy (data + y * stride, copy + y * 4 * width, 4 * width);
+
+  g_free (copy);
+}
+
 static void
 gdk_gl_texture_class_init (GdkGLTextureClass *klass)
 {
@@ -187,6 +241,7 @@ gdk_gl_texture_class_init (GdkGLTextureClass *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 edb4d741c6..6d0c861eec 100644
--- a/gdk/gdkmemorytexture.c
+++ b/gdk/gdkmemorytexture.c
@@ -101,6 +101,21 @@ gdk_memory_texture_download (GdkTexture *texture,
                       gdk_texture_get_height (texture));
 }
 
+static void
+gdk_memory_texture_download_float (GdkTexture *texture,
+                                   float      *data,
+                                   gsize       stride)
+{
+  GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture);
+
+  gdk_memory_convert_to_float (data, stride,
+                               (guchar *) g_bytes_get_data (self->bytes, NULL),
+                               self->stride,
+                               self->format,
+                               gdk_texture_get_width (texture),
+                               gdk_texture_get_height (texture));
+}
+
 static void
 gdk_memory_texture_class_init (GdkMemoryTextureClass *klass)
 {
@@ -109,6 +124,7 @@ gdk_memory_texture_class_init (GdkMemoryTextureClass *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;
 }
 
@@ -323,3 +339,82 @@ gdk_memory_convert (guchar              *dest_data,
 
   converters[src_format][dest_format] (dest_data, dest_stride, src_data, src_stride, width, height);
 }
+
+#define CONVERT_FLOAT(R,G,B,A,premultiply) G_STMT_START {\
+  for (y = 0; y < height; y++) \
+    { \
+      for (x = 0; x < width; x++) \
+        { \
+          if (A >= 0) \
+            { \
+              dest_data[4 * x + 0] = src_data[4 * x + R] / 255.0f; \
+              dest_data[4 * x + 1] = src_data[4 * x + G] / 255.0f; \
+              dest_data[4 * x + 2] = src_data[4 * x + B] / 255.0f; \
+              dest_data[4 * x + 3] = src_data[4 * x + A] / 255.0f; \
+              if (premultiply) \
+                { \
+                  dest_data[4 * x + 0] *= dest_data[4 * x + 3]; \
+                  dest_data[4 * x + 1] *= dest_data[4 * x + 3]; \
+                  dest_data[4 * x + 2] *= dest_data[4 * x + 3]; \
+                } \
+            } \
+          else \
+            { \
+              dest_data[4 * x + 0] = src_data[3 * x + R] / 255.0f; \
+              dest_data[4 * x + 1] = src_data[3 * x + G] / 255.0f; \
+              dest_data[4 * x + 2] = src_data[3 * x + B] / 255.0f; \
+              dest_data[4 * x + 3] = 1.0; \
+            } \
+        } \
+\
+      dest_data += dest_stride; \
+      src_data += src_stride; \
+    } \
+}G_STMT_END
+
+void
+gdk_memory_convert_to_float (float           *dest_data,
+                             gsize            dest_stride,
+                             const guchar    *src_data,
+                             gsize            src_stride,
+                             GdkMemoryFormat  src_format,
+                             gsize            width,
+                             gsize            height)
+{
+  gsize x, y;
+
+  switch (src_format)
+  {
+    case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED:
+      CONVERT_FLOAT (2, 1, 0, 3, FALSE);
+      break;
+    case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED:
+      CONVERT_FLOAT (1, 2, 3, 0, FALSE);
+      break;
+    case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED:
+      CONVERT_FLOAT (0, 1, 2, 3, FALSE);
+      break;
+    case GDK_MEMORY_B8G8R8A8:
+      CONVERT_FLOAT (2, 1, 0, 3, TRUE);
+      break;
+    case GDK_MEMORY_A8R8G8B8:
+      CONVERT_FLOAT (1, 2, 3, 0, TRUE);
+      break;
+    case GDK_MEMORY_R8G8B8A8:
+      CONVERT_FLOAT (0, 1, 2, 3, TRUE);
+      break;
+    case GDK_MEMORY_A8B8G8R8:
+      CONVERT_FLOAT (3, 2, 1, 0, TRUE);
+      break;
+    case GDK_MEMORY_R8G8B8:
+      CONVERT_FLOAT (0, 1, 2, -1, FALSE);
+      break;
+    case GDK_MEMORY_B8G8R8:
+      CONVERT_FLOAT (2, 1, 0, -1, FALSE);
+      break;
+
+    case GDK_MEMORY_N_FORMATS:
+    default:
+      g_assert_not_reached();
+  }
+}
diff --git a/gdk/gdkmemorytextureprivate.h b/gdk/gdkmemorytextureprivate.h
index a450a9a139..ddd9fd1c37 100644
--- a/gdk/gdkmemorytextureprivate.h
+++ b/gdk/gdkmemorytextureprivate.h
@@ -60,6 +60,14 @@ void                    gdk_memory_convert                  (guchar
                                                              gsize                       width,
                                                              gsize                       height);
 
+void                    gdk_memory_convert_to_float         (float                      *dest_data,
+                                                             gsize                       dest_stride,
+                                                             const guchar               *src_data,
+                                                             gsize                       src_stride,
+                                                             GdkMemoryFormat             src_format,
+                                                             gsize                       width,
+                                                             gsize                       height);
+
 
 G_END_DECLS
 
diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c
index 4afd6ebfdd..7b055238fd 100644
--- a/gdk/gdktexture.c
+++ b/gdk/gdktexture.c
@@ -134,6 +134,18 @@ gdk_texture_real_download (GdkTexture *texture,
   g_object_unref (memory_texture);
 }
 
+static void
+gdk_texture_real_download_float (GdkTexture *self,
+                                 float      *data,
+                                 gsize       stride)
+{
+  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
 gdk_texture_set_property (GObject      *gobject,
                           guint         prop_id,
@@ -199,6 +211,7 @@ gdk_texture_class_init (GdkTextureClass *klass)
 
   klass->download_texture = gdk_texture_real_download_texture;
   klass->download = gdk_texture_real_download;
+  klass->download_float = gdk_texture_real_download_float;
 
   gobject_class->set_property = gdk_texture_set_property;
   gobject_class->get_property = gdk_texture_get_property;
@@ -485,6 +498,45 @@ gdk_texture_download (GdkTexture *texture,
   GDK_TEXTURE_GET_CLASS (texture)->download (texture, data, stride);
 }
 
+/**
+ * gdk_texture_download_float:
+ * @texture: a `GdkTexture`
+ * @data: (array): pointer to enough memory to be filled with the
+ *   downloaded data of @texture
+ * @stride: rowstride in elements, will usually be equal to
+ *   gdk_texture_get_width() * 4
+ *
+ * Downloads the @texture into local memory in a high dynamic range format.
+ *
+ * This may be an expensive operation, as the actual texture data
+ * may reside on a GPU or on a remote display server and because the data
+ * may need to be upsampled if it was not already available in this
+ * format.
+ *
+ * You may want to use [method@Gdk.Texture.download] instead if you don't
+ * need high dynamic range support.
+ *
+ * The data format of the downloaded data is equivalent to
+ * GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, so every downloaded
+ * pixel requires 16 bytes of memory.
+ *
+ * Note that the caller is responsible to provide sufficiently
+ * aligned memory to access the resulting data directly as floats.
+ *
+ * Since: 4.6
+ */
+void
+gdk_texture_download_float (GdkTexture *texture,
+                            float      *data,
+                            gsize       stride)
+{
+  g_return_if_fail (GDK_IS_TEXTURE (texture));
+  g_return_if_fail (data != NULL);
+  g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4);
+
+  GDK_TEXTURE_GET_CLASS (texture)->download_float (texture, data, stride);
+}
+
 GdkTexture *
 gdk_texture_download_texture (GdkTexture *texture)
 {
diff --git a/gdk/gdktexture.h b/gdk/gdktexture.h
index f3d0bc9765..9e3b7a93fa 100644
--- a/gdk/gdktexture.h
+++ b/gdk/gdktexture.h
@@ -59,6 +59,10 @@ GDK_AVAILABLE_IN_ALL
 void                    gdk_texture_download                   (GdkTexture      *texture,
                                                                 guchar          *data,
                                                                 gsize            stride);
+GDK_AVAILABLE_IN_4_6
+void                    gdk_texture_download_float             (GdkTexture      *texture,
+                                                                float           *data,
+                                                                gsize            stride);
 GDK_AVAILABLE_IN_ALL
 gboolean                gdk_texture_save_to_png                (GdkTexture      *texture,
                                                                 const char      *filename);
diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h
index 1133bf6acc..29fca0a9ba 100644
--- a/gdk/gdktextureprivate.h
+++ b/gdk/gdktextureprivate.h
@@ -30,6 +30,9 @@ struct _GdkTextureClass {
   void                  (* download)                    (GdkTexture             *texture,
                                                          guchar                 *data,
                                                          gsize                   stride);
+  void                  (* download_float)              (GdkTexture             *texture,
+                                                         float                  *data,
+                                                         gsize                   stride);
 };
 
 gpointer                gdk_texture_new                 (const GdkTextureClass  *klass,


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