[gtk/wip/otte/float-textures: 10/10] gltexture whatever HELP: CLEAN THIS UP!
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/float-textures: 10/10] gltexture whatever HELP: CLEAN THIS UP!
- Date: Sat, 11 Sep 2021 23:58:02 +0000 (UTC)
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]