summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2021-09-12 04:42:24 +0200
committerBenjamin Otte <otte@redhat.com>2021-09-12 05:22:21 +0200
commit4f17f3ac240117ae38cd83e3c8140a4b2a8dccff (patch)
tree669601e7ecdcd02945ed7cd8ad0cafa39f59271b
parent9c8e464b04768c45f9043711a06a2d6eb9ab6076 (diff)
downloadgtk+-4f17f3ac240117ae38cd83e3c8140a4b2a8dccff.tar.gz
texture: Add gdk_texture_download_texture()
A private vfunc that downloads a texture as a GdkMemoryTexture in whatever format the texture deems best. There are multiple reasons for this: * GLES cannot download the Cairo format. But it can download some format and then just delegate to the GdkMemoryTexture implementation. * All the other download vfuncs (including the ones still coming) can be implemented via download_texture() and delegation, making the interface easier. * We want to implement image loading and saving support. By using download_texture(), we can save in the actual format of the texture. * A potential GdkCompressedTexture could be implemented by just providing this one vfunc as a compress() step.
-rw-r--r--gdk/gdkgltexture.c72
-rw-r--r--gdk/gdkmemorytexture.c7
-rw-r--r--gdk/gdktexture.c36
-rw-r--r--gdk/gdktextureprivate.h5
4 files changed, 115 insertions, 5 deletions
diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c
index adf075ea91..9b5aa86866 100644
--- a/gdk/gdkgltexture.c
+++ b/gdk/gdkgltexture.c
@@ -21,7 +21,7 @@
#include "gdkgltextureprivate.h"
#include "gdkcairo.h"
-#include "gdkmemorytexture.h"
+#include "gdkmemorytextureprivate.h"
#include "gdktextureprivate.h"
#include <epoxy/gl.h>
@@ -70,6 +70,75 @@ 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;
+
+ 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,
@@ -112,6 +181,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;
gobject_class->dispose = gdk_gl_texture_dispose;
}
diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c
index ab117a01ff..edb4d741c6 100644
--- a/gdk/gdkmemorytexture.c
+++ b/gdk/gdkmemorytexture.c
@@ -79,6 +79,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,
@@ -101,6 +107,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;
gobject_class->dispose = gdk_memory_texture_dispose;
}
diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c
index 9ae9f80944..4afd6ebfdd 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
@@ -186,6 +197,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;
gobject_class->set_property = gdk_texture_set_property;
@@ -473,6 +485,22 @@ gdk_texture_download (GdkTexture *texture,
GDK_TEXTURE_GET_CLASS (texture)->download (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 e2e7dc2bae..1133bf6acc 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);
@@ -34,6 +37,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,