[gtk/wip/otte/float-textures: 2/9] texture: Add gdk_texture_download_float()
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/float-textures: 2/9] texture: Add gdk_texture_download_float()
- Date: Sun, 12 Sep 2021 03:54:45 +0000 (UTC)
commit 53275481a56c0f92a26e4fffb34db8fd98f6d4a0
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]