From 0ee3b1c8618f5e21070a4756f9009fe0918ba019 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Wed, 8 Sep 2021 20:46:25 +0200 Subject: texture: Remove unused argument from vfunc --- gdk/gdkgltexture.c | 16 +++++++++------- gdk/gdkmemorytexture.c | 14 ++++++-------- gdk/gdktexture.c | 20 +------------------- gdk/gdktextureprivate.h | 5 ----- 4 files changed, 16 insertions(+), 39 deletions(-) diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index caf3e7ab6b..214ed9eb03 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -74,18 +74,20 @@ gdk_gl_texture_dispose (GObject *object) } static void -gdk_gl_texture_download (GdkTexture *texture, - const GdkRectangle *area, - guchar *data, - gsize stride) +gdk_gl_texture_download (GdkTexture *texture, + guchar *data, + gsize stride) { GdkGLTexture *self = GDK_GL_TEXTURE (texture); cairo_surface_t *surface; cairo_t *cr; + int width, height; + width = gdk_texture_get_width (texture); + height = gdk_texture_get_width (texture); surface = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, - area->width, area->height, + width, height, stride); cr = cairo_create (surface); @@ -101,8 +103,8 @@ gdk_gl_texture_download (GdkTexture *texture, gl_surface = gdk_gl_context_get_surface (self->context); gdk_cairo_draw_from_gl (cr, gl_surface, self->id, GL_TEXTURE, 1, - area->x, area->y, - area->width, area->height); + 0, 0, + width, height); } cairo_destroy (cr); diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index 06fa3d6619..a8d8bbd834 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -80,21 +80,19 @@ gdk_memory_texture_dispose (GObject *object) } static void -gdk_memory_texture_download (GdkTexture *texture, - const GdkRectangle *area, - guchar *data, - gsize stride) +gdk_memory_texture_download (GdkTexture *texture, + guchar *data, + gsize stride) { GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture); gdk_memory_convert (data, stride, GDK_MEMORY_CAIRO_FORMAT_ARGB32, - (guchar *) g_bytes_get_data (self->bytes, NULL) - + area->x * gdk_memory_format_bytes_per_pixel (self->format) - + area->y * self->stride, + (guchar *) g_bytes_get_data (self->bytes, NULL), self->stride, self->format, - area->width, area->height); + gdk_texture_get_width (texture), + gdk_texture_get_height (texture)); } static void diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c index 7ac4f1bb53..1f262909e0 100644 --- a/gdk/gdktexture.c +++ b/gdk/gdktexture.c @@ -117,7 +117,6 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkTexture, gdk_texture, G_TYPE_OBJECT, static void gdk_texture_real_download (GdkTexture *self, - const GdkRectangle *area, guchar *data, gsize stride) { @@ -435,20 +434,6 @@ gdk_texture_download_surface (GdkTexture *texture) return surface; } -void -gdk_texture_download_area (GdkTexture *texture, - const GdkRectangle *area, - guchar *data, - gsize stride) -{ - g_assert (area->x >= 0); - g_assert (area->y >= 0); - g_assert (area->x + area->width <= texture->width); - g_assert (area->y + area->height <= texture->height); - - GDK_TEXTURE_GET_CLASS (texture)->download (texture, area, data, stride); -} - /** * gdk_texture_download: * @texture: a `GdkTexture` @@ -485,10 +470,7 @@ gdk_texture_download (GdkTexture *texture, g_return_if_fail (data != NULL); g_return_if_fail (stride >= gdk_texture_get_width (texture) * 4); - gdk_texture_download_area (texture, - &(GdkRectangle) { 0, 0, texture->width, texture->height }, - data, - stride); + GDK_TEXTURE_GET_CLASS (texture)->download (texture, data, stride); } gboolean diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h index 3e2e9f3a49..e2e7dc2bae 100644 --- a/gdk/gdktextureprivate.h +++ b/gdk/gdktextureprivate.h @@ -25,7 +25,6 @@ struct _GdkTextureClass { GObjectClass parent_class; void (* download) (GdkTexture *texture, - const GdkRectangle *area, guchar *data, gsize stride); }; @@ -35,10 +34,6 @@ 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); -void gdk_texture_download_area (GdkTexture *texture, - const GdkRectangle *area, - guchar *data, - gsize stride); gboolean gdk_texture_set_render_data (GdkTexture *self, gpointer key, -- cgit v1.2.1 From 51d0d13a9e403d5edf461e5f7cf76a84336135c2 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 12 Sep 2021 00:09:11 +0200 Subject: gltexture: release() to a texture, not a cairo_surface This makes forwarding vfuncs a lot easier, because we can just call them on the texture. --- gdk/gdkgltexture.c | 62 ++++++++++++++++++++++++------------------------------ 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index 214ed9eb03..adf075ea91 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -21,6 +21,7 @@ #include "gdkgltextureprivate.h" #include "gdkcairo.h" +#include "gdkmemorytexture.h" #include "gdktextureprivate.h" #include @@ -37,7 +38,7 @@ struct _GdkGLTexture { GdkGLContext *context; guint id; - cairo_surface_t *saved; + GdkTexture *saved; GDestroyNotify destroy; gpointer data; @@ -64,11 +65,7 @@ gdk_gl_texture_dispose (GObject *object) g_clear_object (&self->context); self->id = 0; - if (self->saved) - { - cairo_surface_destroy (self->saved); - self->saved = NULL; - } + g_clear_object (&self->saved); G_OBJECT_CLASS (gdk_gl_texture_parent_class)->dispose (object); } @@ -79,10 +76,17 @@ gdk_gl_texture_download (GdkTexture *texture, gsize stride) { GdkGLTexture *self = GDK_GL_TEXTURE (texture); + GdkSurface *gl_surface; cairo_surface_t *surface; cairo_t *cr; int width, height; + if (self->saved) + { + gdk_texture_download (self->saved, data, stride); + return; + } + width = gdk_texture_get_width (texture); height = gdk_texture_get_width (texture); surface = cairo_image_surface_create_for_data (data, @@ -92,20 +96,10 @@ gdk_gl_texture_download (GdkTexture *texture, cr = cairo_create (surface); - if (self->saved) - { - cairo_set_source_surface (cr, self->saved, 0, 0); - cairo_paint (cr); - } - else - { - GdkSurface *gl_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); - } + 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); @@ -152,24 +146,24 @@ gdk_gl_texture_get_id (GdkGLTexture *self) void gdk_gl_texture_release (GdkGLTexture *self) { - GdkSurface *surface; - GdkTexture *texture; - cairo_t *cr; + GdkTexture *texture = GDK_TEXTURE (self); + GBytes *bytes; + guchar *data; + gsize stride; g_return_if_fail (GDK_IS_GL_TEXTURE (self)); g_return_if_fail (self->saved == NULL); - texture = GDK_TEXTURE (self); - self->saved = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - texture->width, texture->height); - - cr = cairo_create (self->saved); - - surface = gdk_gl_context_get_surface (self->context); - gdk_cairo_draw_from_gl (cr, surface, self->id, GL_TEXTURE, 1, 0, 0, - texture->width, texture->height); - - cairo_destroy (cr); + stride = texture->width * 4; + data = malloc (stride * texture->height); + gdk_texture_download (texture, data, stride); + bytes = g_bytes_new_take (data, stride * texture->height); + self->saved = gdk_memory_texture_new (texture->width, + texture->height, + GDK_MEMORY_DEFAULT, + bytes, + stride); + g_bytes_unref (bytes); if (self->destroy) { -- cgit v1.2.1 From 9c8e464b04768c45f9043711a06a2d6eb9ab6076 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 9 Sep 2021 02:05:08 +0200 Subject: texture: Add GdkMemoryConversion private enum Now gdk_memory_convert() converts to one of these conversions instead of re(ab)using parts of the GdkMemoryFormat enum. --- gdk/gdkglcontext.c | 4 ++-- gdk/gdkmemorytexture.c | 20 ++++++++++---------- gdk/gdkmemorytextureprivate.h | 32 +++++++++++++++++++++++--------- gdk/gdktexture.c | 2 +- gsk/ngl/gsknglglyphlibrary.c | 2 +- gsk/ngl/gskngliconlibrary.c | 2 +- 6 files changed, 38 insertions(+), 24 deletions(-) diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 522cbcecf6..3357562add 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -243,7 +243,7 @@ gdk_gl_context_upload_texture (GdkGLContext *context, { copy = g_malloc (width * height * 4); gdk_memory_convert (copy, width * 4, - GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + GDK_MEMORY_CONVERT_GLES_RGBA, data, stride, data_format, width, height); stride = width * 4; @@ -282,7 +282,7 @@ gdk_gl_context_upload_texture (GdkGLContext *context, { copy = g_malloc (width * height * 4); gdk_memory_convert (copy, width * 4, - GDK_MEMORY_DEFAULT, + GDK_MEMORY_CONVERT_DOWNLOAD, data, stride, data_format, width, height); stride = width * 4; diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index a8d8bbd834..ab117a01ff 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -87,7 +87,7 @@ gdk_memory_texture_download (GdkTexture *texture, GdkMemoryTexture *self = GDK_MEMORY_TEXTURE (texture); gdk_memory_convert (data, stride, - GDK_MEMORY_CAIRO_FORMAT_ARGB32, + GDK_MEMORY_CONVERT_DOWNLOAD, (guchar *) g_bytes_get_data (self->bytes, NULL), self->stride, self->format, @@ -288,7 +288,7 @@ typedef void (* ConversionFunc) (guchar *dest_data, gsize width, gsize height); -static ConversionFunc converters[GDK_MEMORY_N_FORMATS][3] = +static ConversionFunc converters[GDK_MEMORY_N_FORMATS][GDK_MEMORY_N_CONVERSIONS] = { { convert_memcpy, convert_swizzle3210, convert_swizzle2103 }, { convert_swizzle3210, convert_memcpy, convert_swizzle3012 }, @@ -302,14 +302,14 @@ static ConversionFunc converters[GDK_MEMORY_N_FORMATS][3] = }; void -gdk_memory_convert (guchar *dest_data, - gsize dest_stride, - GdkMemoryFormat dest_format, - const guchar *src_data, - gsize src_stride, - GdkMemoryFormat src_format, - gsize width, - gsize height) +gdk_memory_convert (guchar *dest_data, + gsize dest_stride, + GdkMemoryConversion dest_format, + const guchar *src_data, + gsize src_stride, + GdkMemoryFormat src_format, + gsize width, + gsize height) { g_assert (dest_format < 3); g_assert (src_format < GDK_MEMORY_N_FORMATS); diff --git a/gdk/gdkmemorytextureprivate.h b/gdk/gdkmemorytextureprivate.h index 740a59da6e..a450a9a139 100644 --- a/gdk/gdkmemorytextureprivate.h +++ b/gdk/gdkmemorytextureprivate.h @@ -29,7 +29,21 @@ G_BEGIN_DECLS #define GDK_MEMORY_GDK_PIXBUF_OPAQUE GDK_MEMORY_R8G8B8 #define GDK_MEMORY_GDK_PIXBUF_ALPHA GDK_MEMORY_R8G8B8A8 -#define GDK_MEMORY_CAIRO_FORMAT_ARGB32 GDK_MEMORY_DEFAULT +typedef enum { + GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN, + GDK_MEMORY_CONVERT_DOWNLOAD_BIT_ENDIAN, + GDK_MEMORY_CONVERT_GLES_RGBA, + + GDK_MEMORY_N_CONVERSIONS +} GdkMemoryConversion; + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_LITTLE_ENDIAN +#elif G_BYTE_ORDER == G_BIG_ENDIAN +#define GDK_MEMORY_CONVERT_DOWNLOAD GDK_MEMORY_CONVERT_DOWNLOAD_BIG_ENDIAN +#else +#error "Unknown byte order for GDK_MEMORY_CONVERT_DOWNLOAD" +#endif gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format); @@ -37,14 +51,14 @@ GdkMemoryFormat gdk_memory_texture_get_format (GdkMemoryTexture * const guchar * gdk_memory_texture_get_data (GdkMemoryTexture *self); gsize gdk_memory_texture_get_stride (GdkMemoryTexture *self); -void gdk_memory_convert (guchar *dest_data, - gsize dest_stride, - GdkMemoryFormat dest_format, - const guchar *src_data, - gsize src_stride, - GdkMemoryFormat src_format, - gsize width, - gsize height); +void gdk_memory_convert (guchar *dest_data, + gsize dest_stride, + GdkMemoryConversion dest_format, + 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 1f262909e0..9ae9f80944 100644 --- a/gdk/gdktexture.c +++ b/gdk/gdktexture.c @@ -262,7 +262,7 @@ gdk_texture_new_for_surface (cairo_surface_t *surface) texture = gdk_memory_texture_new (cairo_image_surface_get_width (surface), cairo_image_surface_get_height (surface), - GDK_MEMORY_CAIRO_FORMAT_ARGB32, + GDK_MEMORY_DEFAULT, bytes, cairo_image_surface_get_stride (surface)); diff --git a/gsk/ngl/gsknglglyphlibrary.c b/gsk/ngl/gsknglglyphlibrary.c index 9f269d8643..8ddf1ab265 100644 --- a/gsk/ngl/gsknglglyphlibrary.c +++ b/gsk/ngl/gsknglglyphlibrary.c @@ -235,7 +235,7 @@ gsk_ngl_glyph_library_upload_glyph (GskNglGlyphLibrary *self, pixel_data = free_data = g_malloc (width * height * 4); gdk_memory_convert (pixel_data, width * 4, - GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + GDK_MEMORY_CONVERT_GLES_RGBA, cairo_image_surface_get_data (surface), width * 4, GDK_MEMORY_DEFAULT, diff --git a/gsk/ngl/gskngliconlibrary.c b/gsk/ngl/gskngliconlibrary.c index 977c201051..ab4d1b4d6f 100644 --- a/gsk/ngl/gskngliconlibrary.c +++ b/gsk/ngl/gskngliconlibrary.c @@ -115,7 +115,7 @@ gsk_ngl_icon_library_add (GskNglIconLibrary *self, { pixel_data = free_data = g_malloc (width * height * 4); gdk_memory_convert (pixel_data, width * 4, - GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + GDK_MEMORY_CONVERT_GLES_RGBA, surface_data, cairo_image_surface_get_stride (surface), GDK_MEMORY_DEFAULT, width, height); gl_format = GL_RGBA; -- cgit v1.2.1 From 4f17f3ac240117ae38cd83e3c8140a4b2a8dccff Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 12 Sep 2021 04:42:24 +0200 Subject: 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. --- gdk/gdkgltexture.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++- gdk/gdkmemorytexture.c | 7 +++++ gdk/gdktexture.c | 36 ++++++++++++++++++++++--- gdk/gdktextureprivate.h | 5 ++++ 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 @@ -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, -- cgit v1.2.1 From 74ce69a8a1187c9f4b65a0f8d38363f0d83b7574 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 12 Sep 2021 05:11:58 +0200 Subject: gltexture: Make release() use download_texture() 1. It avoids Cairo, and in particular conversion to Cairo. 2. Keeping a texture allows easy chaining in the vfuncs. 3. Using a texture means releasing will work for HDR formats too, once we add them. --- gdk/gdkgltexture.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index 9b5aa86866..ef95c4604b 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -216,24 +216,10 @@ gdk_gl_texture_get_id (GdkGLTexture *self) void gdk_gl_texture_release (GdkGLTexture *self) { - GdkTexture *texture = GDK_TEXTURE (self); - GBytes *bytes; - guchar *data; - gsize stride; - g_return_if_fail (GDK_IS_GL_TEXTURE (self)); g_return_if_fail (self->saved == NULL); - stride = texture->width * 4; - data = malloc (stride * texture->height); - gdk_texture_download (texture, data, stride); - bytes = g_bytes_new_take (data, stride * texture->height); - self->saved = gdk_memory_texture_new (texture->width, - texture->height, - GDK_MEMORY_DEFAULT, - bytes, - stride); - g_bytes_unref (bytes); + self->saved = gdk_texture_download_texture (GDK_TEXTURE (self)); if (self->destroy) { -- cgit v1.2.1 From c349ed956269129841a881343cd1d5841d4daa2c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 12 Sep 2021 00:14:19 +0200 Subject: gltexture: Implement download() via glGetTexImage() 1. The download via gdk_cairo_draw_from_gl() was broken sometimes 2. We get easy conversion on fallback by chaining up and using download_texture(). 3. One more place where Cairo is no longer necessary. --- gdk/gdkgltexture.c | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index ef95c4604b..bd69809061 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -20,7 +20,6 @@ #include "gdkgltextureprivate.h" -#include "gdkcairo.h" #include "gdkmemorytextureprivate.h" #include "gdktextureprivate.h" @@ -145,10 +144,7 @@ gdk_gl_texture_download (GdkTexture *texture, 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) { @@ -156,23 +152,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); + 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; + } - cr = cairo_create (surface); + gdk_gl_context_make_current (self->context); - 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); + glGetIntegerv (GL_TEXTURE_BINDING_2D, &active_texture); + glBindTexture (GL_TEXTURE_2D, self->id); - cairo_destroy (cr); - cairo_surface_finish (surface); - cairo_surface_destroy (surface); + 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 -- cgit v1.2.1 From cbe6d0da766b22445ff08aafbb3c21066ab3a60e Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 12 Sep 2021 00:10:10 +0200 Subject: gdk: Deprecate gdk_cairo_draw_from_gl() It's broken with various pixel formats and OpenGL ES, it's hard to understand what everything does, and gdk_texture_download() can be used instead. --- gdk/gdkcairo.h | 2 +- gdk/gdkgl.c | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/gdk/gdkcairo.h b/gdk/gdkcairo.h index 40ab46baf6..f2dfa3177e 100644 --- a/gdk/gdkcairo.h +++ b/gdk/gdkcairo.h @@ -50,7 +50,7 @@ cairo_region_t * gdk_cairo_region_create_from_surface (cairo_surface_t *surface); -GDK_AVAILABLE_IN_ALL +GDK_DEPRECATED_IN_4_6_FOR(gdk_gl_texture_new) void gdk_cairo_draw_from_gl (cairo_t *cr, GdkSurface *surface, int source, diff --git a/gdk/gdkgl.c b/gdk/gdkgl.c index 4e57853afb..417c29d15b 100644 --- a/gdk/gdkgl.c +++ b/gdk/gdkgl.c @@ -301,7 +301,7 @@ gdk_gl_texture_quads (GdkGLContext *paint_context, * @width: The width of the region to draw * @height: The height of the region to draw * - * The main way to draw GL content in GTK. + * The main way to not draw GL content in GTK. * * It takes a render buffer ID (@source_type == GL_RENDERBUFFER) or a texture * id (@source_type == GL_TEXTURE) and draws it onto @cr with an OVER operation, @@ -319,6 +319,12 @@ gdk_gl_texture_quads (GdkGLContext *paint_context, * with alpha components, so make sure you use GL_TEXTURE if using alpha. * * Calling this may change the current GL context. + * + * Deprecated: 4.6: The function is overly complex and produces broken output + * in various combinations of arguments. If you want to draw with GL textures + * in GTK, use [ctor@Gdk.GLTexture.new]; if you want to use that texture in + * Cairo, use [method@Gdk.Texture.download] to download the data into a Cairo + * image surface. */ void gdk_cairo_draw_from_gl (cairo_t *cr, -- cgit v1.2.1 From 53275481a56c0f92a26e4fffb34db8fd98f6d4a0 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 10 Sep 2021 02:40:21 +0200 Subject: 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, -- cgit v1.2.1 From 1759d27da9a17d0130df7078bfa9355618047b6c Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 11 Sep 2021 21:18:56 +0200 Subject: memorytexture: Add support for HDR formats Also sanitize the input bytes so the strides match alignment requirements of the data types. --- gdk/gdkmemorytexture.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++++- gdk/gdkmemorytexture.h | 20 ++++ 2 files changed, 311 insertions(+), 4 deletions(-) diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index 6d0c861eec..631357bcc8 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -20,6 +20,7 @@ #include "config.h" #include "gdkmemorytextureprivate.h" +#include "gsk/ngl/fp16private.h" /** * GdkMemoryTexture: @@ -49,6 +50,10 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) { switch (format) { + case GDK_MEMORY_R8G8B8: + case GDK_MEMORY_B8G8R8: + return 3; + case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: @@ -58,14 +63,59 @@ gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) case GDK_MEMORY_A8B8G8R8: return 4; + case GDK_MEMORY_R16G16B16: + case GDK_MEMORY_R16G16B16_FLOAT: + return 6; + + case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + return 8; + + case GDK_MEMORY_R32G32B32_FLOAT: + return 12; + + case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + return 16; + + case GDK_MEMORY_N_FORMATS: + default: + g_assert_not_reached (); + return 4; + } +} + +static gsize +gdk_memory_format_alignment (GdkMemoryFormat format) +{ + switch (format) + { case GDK_MEMORY_R8G8B8: case GDK_MEMORY_B8G8R8: - return 3; + case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: + case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: + case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: + case GDK_MEMORY_B8G8R8A8: + case GDK_MEMORY_A8R8G8B8: + case GDK_MEMORY_R8G8B8A8: + case GDK_MEMORY_A8B8G8R8: + return G_ALIGNOF (guchar); + + case GDK_MEMORY_R16G16B16: + case GDK_MEMORY_R16G16B16_FLOAT: + return G_ALIGNOF (guint16); + + case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + return G_ALIGNOF (guint16); + + case GDK_MEMORY_R32G32B32_FLOAT: + case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + return G_ALIGNOF (float); case GDK_MEMORY_N_FORMATS: default: g_assert_not_reached (); - return 4; + return G_ALIGNOF (double); } } @@ -133,6 +183,41 @@ gdk_memory_texture_init (GdkMemoryTexture *self) { } +static GBytes * +gdk_memory_sanitize (GBytes *bytes, + int width, + int height, + GdkMemoryFormat format, + gsize stride, + gsize *out_stride) +{ + gsize align, size, copy_stride, bpp; + const guchar *data; + guchar *copy; + int y; + + data = g_bytes_get_data (bytes, &size); + align = gdk_memory_format_alignment (format); + + if (GPOINTER_TO_SIZE (data) % align == 0 && + stride % align == 0) + { + *out_stride = stride; + return g_bytes_ref (bytes); + } + + bpp = gdk_memory_format_bytes_per_pixel (format); + copy_stride = bpp * width; + /* align to multiples of 4, just to be sure */ + copy_stride = (copy_stride + 3) & ~3; + copy = g_malloc (copy_stride * height); + for (y = 0; y < height; y++) + memcpy (copy + y * copy_stride, data + y * stride, bpp * width); + + *out_stride = copy_stride; + return g_bytes_new_take (copy, copy_stride * height); +} + /** * gdk_memory_texture_new: * @width: the width of the texture @@ -157,13 +242,20 @@ gdk_memory_texture_new (int width, { GdkMemoryTexture *self; + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + g_return_val_if_fail (bytes != NULL, NULL); + g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL); + + bytes = gdk_memory_sanitize (bytes, width, height, format, stride, &stride); + self = g_object_new (GDK_TYPE_MEMORY_TEXTURE, "width", width, "height", height, NULL); self->format = format; - self->bytes = g_bytes_ref (bytes); + self->bytes = bytes; self->stride = stride; return GDK_TEXTURE (self); @@ -304,6 +396,109 @@ SWIZZLE_PREMULTIPLY (3,0,1,2, 0,1,2,3) SWIZZLE_PREMULTIPLY (3,0,1,2, 3,0,1,2) SWIZZLE_PREMULTIPLY (3,0,1,2, 0,3,2,1) +#define CONVERT_FUNC(name,suffix,R,G,B,A,step) \ +static void \ +convert_ ## name ## _to_ ## suffix (guchar *dest_data, \ + gsize dest_stride, \ + const guchar *src_data, \ + gsize src_stride, \ + gsize width, \ + gsize height) \ +{ \ + gsize x, y; \ +\ + for (y = 0; y < height; y++) \ + { \ + for (x = 0; x < width; x++) \ + { \ + guchar conv[4]; \ + convert_pixel_ ## name (conv, src_data + step * x); \ + dest_data[4 * x + R] = conv[0]; \ + dest_data[4 * x + G] = conv[1]; \ + dest_data[4 * x + B] = conv[2]; \ + dest_data[4 * x + A] = conv[3]; \ + } \ +\ + dest_data += dest_stride; \ + src_data += src_stride; \ + } \ +} + +#define CONVERT_FUNCS(name,step) \ +CONVERT_FUNC(name, download_le, 2, 1, 0, 3, step) \ +CONVERT_FUNC(name, download_be, 1, 2, 3, 0, step) \ +CONVERT_FUNC(name, gles_rgba, 0, 1, 2, 3, step) \ + +static inline void +convert_pixel_rgb16 (guchar *dest_data, const guchar *src_data) +{ + const guint16 *src = (const guint16 *) src_data; + dest_data[0] = (guchar)(src[0] >> 8); + dest_data[1] = (guchar)(src[1] >> 8); + dest_data[2] = (guchar)(src[2] >> 8); + dest_data[3] = 0xFF; +} +CONVERT_FUNCS(rgb16, 3 * sizeof (guint16)) + +static inline void +convert_pixel_rgba16 (guchar *dest_data, const guchar *src_data) +{ + const guint16 *src = (const guint16 *) src_data; + dest_data[0] = (guchar)(src[0] >> 8); + dest_data[1] = (guchar)(src[1] >> 8); + dest_data[2] = (guchar)(src[2] >> 8); + dest_data[3] = (guchar)(src[3] >> 8); +} +CONVERT_FUNCS(rgba16, 4 * sizeof (guint16)) + +static inline void +convert_pixel_rgb16f (guchar *dest_data, const guchar *src_data) +{ + float src[4]; + guint16 tmp[4]; + memcpy(tmp, src_data, sizeof(guint16) * 3); + half_to_float4(tmp, src); + dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f); + dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f); + dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f); + dest_data[3] = 0xFF; +} +CONVERT_FUNCS(rgb16f, 3 * sizeof (guint16)) + +static inline void +convert_pixel_rgba16f (guchar *dest_data, const guchar *src_data) +{ + float src[4]; + half_to_float4((const guint16 *) src_data, src); + dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f); + dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f); + dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f); + dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f); +} +CONVERT_FUNCS(rgba16f, 4 * sizeof (guint16)) + +static inline void +convert_pixel_rgb32f (guchar *dest_data, const guchar *src_data) +{ + float *src = (float *) src_data; + dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f); + dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f); + dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f); + dest_data[3] = 0xFF; +} +CONVERT_FUNCS(rgb32f, 3 * sizeof (float)) + +static inline void +convert_pixel_rgba32f (guchar *dest_data, const guchar *src_data) +{ + float *src = (float *) src_data; + dest_data[0] = CLAMP (src[0] * 256.f, 0.f, 255.f); + dest_data[1] = CLAMP (src[1] * 256.f, 0.f, 255.f); + dest_data[2] = CLAMP (src[2] * 256.f, 0.f, 255.f); + dest_data[3] = CLAMP (src[3] * 256.f, 0.f, 255.f); +} +CONVERT_FUNCS(rgba32f, 4 * sizeof (float)) + typedef void (* ConversionFunc) (guchar *dest_data, gsize dest_stride, const guchar *src_data, @@ -321,7 +516,13 @@ static ConversionFunc converters[GDK_MEMORY_N_FORMATS][GDK_MEMORY_N_CONVERSIONS] { convert_swizzle_premultiply_3210_3012, convert_swizzle_premultiply_0123_3012, convert_swizzle_premultiply_3012_3012 }, { convert_swizzle_premultiply_3210_0321, convert_swizzle_premultiply_0123_0321, convert_swizzle_premultiply_3012_0321 }, { convert_swizzle_opaque_3210, convert_swizzle_opaque_0123, convert_swizzle_opaque_3012 }, - { convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 } + { convert_swizzle_opaque_3012, convert_swizzle_opaque_0321, convert_swizzle_opaque_3210 }, + { convert_rgb16_to_download_le, convert_rgb16_to_download_be, convert_rgb16_to_gles_rgba }, + { convert_rgba16_to_download_le, convert_rgba16_to_download_be, convert_rgba16_to_gles_rgba }, + { convert_rgb16f_to_download_le, convert_rgb16f_to_download_be, convert_rgb16f_to_gles_rgba }, + { convert_rgba16f_to_download_le, convert_rgba16f_to_download_be, convert_rgba16f_to_gles_rgba }, + { convert_rgb32f_to_download_le, convert_rgb32f_to_download_be, convert_rgb32f_to_gles_rgba }, + { convert_rgba32f_to_download_le, convert_rgba32f_to_download_be, convert_rgba32f_to_gles_rgba } }; void @@ -372,6 +573,74 @@ gdk_memory_convert (guchar *dest_data, } \ }G_STMT_END +#define CONVERT_FLOAT_PIXEL(func,step) G_STMT_START{\ + for (y = 0; y < height; y++) \ + { \ + for (x = 0; x < width; x++) \ + { \ + func (dest_data + 4 * x, src_data + step * x); \ + } \ +\ + dest_data += dest_stride; \ + src_data += src_stride; \ + } \ +}G_STMT_END + +static inline void +convert_rgb16_to_float (float *dest, const guchar *src_data) +{ + const guint16 *src = (const guint16 *) src_data; + dest[0] = src[0] / 65535.f; + dest[1] = src[1] / 65535.f; + dest[2] = src[2] / 65535.f; + dest[3] = 1.0; +} + +static inline void +convert_rgba16_to_float (float *dest, const guchar *src_data) +{ + const guint16 *src = (const guint16 *) src_data; + dest[0] = src[0] / 65535.f; + dest[1] = src[1] / 65535.f; + dest[2] = src[2] / 65535.f; + dest[3] = 1.0; +} + +static inline void +convert_rgb16f_to_float (float *dest, const guchar *src_data) +{ + guint16 tmp[4]; + memcpy(tmp, src_data, sizeof(guint16) * 3); + tmp[3] = FP16_ONE; + half_to_float4 (tmp, dest); +} + +static inline void +convert_rgba16f_to_float (float *dest, const guchar *src_data) +{ + half_to_float4 ((const guint16 *) src_data, dest); +} + +static inline void +convert_rgb32f_to_float (float *dest, const guchar *src_data) +{ + const float *src = (const float *) src_data; + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = 1.0; +} + +static inline void +convert_rgba32f_to_float (float *dest, const guchar *src_data) +{ + const float *src = (const float *) src_data; + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; +} + void gdk_memory_convert_to_float (float *dest_data, gsize dest_stride, @@ -412,6 +681,24 @@ gdk_memory_convert_to_float (float *dest_data, case GDK_MEMORY_B8G8R8: CONVERT_FLOAT (2, 1, 0, -1, FALSE); break; + case GDK_MEMORY_R16G16B16: + CONVERT_FLOAT_PIXEL (convert_rgb16_to_float, 3 * sizeof (guint16)); + break; + case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + CONVERT_FLOAT_PIXEL (convert_rgba16_to_float, 4 * sizeof (guint16)); + break; + case GDK_MEMORY_R16G16B16_FLOAT: + CONVERT_FLOAT_PIXEL (convert_rgb16f_to_float, 3 * sizeof (guint16)); + break; + case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + CONVERT_FLOAT_PIXEL (convert_rgba16f_to_float, 4 * sizeof (guint16)); + break; + case GDK_MEMORY_R32G32B32_FLOAT: + CONVERT_FLOAT_PIXEL (convert_rgb32f_to_float, 3 * sizeof (float)); + break; + case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + CONVERT_FLOAT_PIXEL (convert_rgba32f_to_float, 4 * sizeof (float)); + break; case GDK_MEMORY_N_FORMATS: default: diff --git a/gdk/gdkmemorytexture.h b/gdk/gdkmemorytexture.h index b9f1f21282..114922153e 100644 --- a/gdk/gdkmemorytexture.h +++ b/gdk/gdkmemorytexture.h @@ -42,6 +42,20 @@ G_BEGIN_DECLS * @GDK_MEMORY_A8B8G8R8: 4 bytes; for alpha, blue, green, red. * @GDK_MEMORY_R8G8B8: 3 bytes; for red, green, blue. The data is opaque. * @GDK_MEMORY_B8G8R8: 3 bytes; for blue, green, red. The data is opaque. + * @GDK_MEMORY_R16G16B16: 3 guint16 values; for red, green, blue. Since 4.6 + * @GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: 4 guint16 values; for red, green, + * blue, alpha. The color values are premultiplied with the alpha value. + * Since 4.6 + * @GDK_MEMORY_R16G16B16_FLOAT: 3 half-float values; for red, green, blue. + * The data is opaque. Since 4.6 + * @GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: 4 half-float values; for + * red, green, blue and alpha. The color values are premultiplied with + * the alpha value. Since 4.6 + * @GDK_MEMORY_B32G32R32_FLOAT: 3 float values; for blue, green, red. + * The data is opaque. Since 4.6 + * @GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: 4 float values; for + * red, green, blue and alpha. The color values are premultiplied with + * the alpha value. Since 4.6 * @GDK_MEMORY_N_FORMATS: The number of formats. This value will change as * more formats get added, so do not rely on its concrete integer. * @@ -67,6 +81,12 @@ typedef enum { GDK_MEMORY_A8B8G8R8, GDK_MEMORY_R8G8B8, GDK_MEMORY_B8G8R8, + GDK_MEMORY_R16G16B16, + GDK_MEMORY_R16G16B16A16_PREMULTIPLIED, + GDK_MEMORY_R16G16B16_FLOAT, + GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED, + GDK_MEMORY_R32G32B32_FLOAT, + GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, GDK_MEMORY_N_FORMATS } GdkMemoryFormat; -- cgit v1.2.1 From 719eafa60c54d5e6512289d0e44fb6e47c023feb Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 12 Sep 2021 05:04:32 +0200 Subject: gl: Implement uploading and downloading HDR formats Also refactor the GL uploading so it does the fallback in a GLES-compatible way, which means we only need one fallback. --- gdk/gdkglcontext.c | 123 +++++++++++++++++++++++++++++------------------------ gdk/gdkgltexture.c | 36 ++++++++++++++++ 2 files changed, 104 insertions(+), 55 deletions(-) diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c index 3357562add..76be3c7ef9 100644 --- a/gdk/gdkglcontext.c +++ b/gdk/gdkglcontext.c @@ -229,71 +229,84 @@ gdk_gl_context_upload_texture (GdkGLContext *context, { GdkGLContextPrivate *priv = gdk_gl_context_get_instance_private (context); guchar *copy = NULL; - guint gl_internalformat; - 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_internalformat = GL_RGBA8; - gl_format = GL_RGBA; + 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_internalformat = GL_RGBA8; - 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_internalformat = GL_RGBA8; - gl_format = GL_RGB; - gl_type = GL_UNSIGNED_BYTE; - bpp = 3; - } - else if (data_format == GDK_MEMORY_B8G8R8) - { - gl_internalformat = GL_RGBA8; - 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_internalformat = GL_RGBA8; - 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 */ diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index 365a3a6ac2..6c91c70f70 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -105,6 +105,42 @@ gdk_gl_texture_download_texture (GdkTexture *texture) 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 -- cgit v1.2.1 From c9d748fc51e79759c93d2a5231e53fe25f75375b Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 11 Sep 2021 21:19:48 +0200 Subject: testsuite: Overhaul memorytexture test Instead of hardcoding pixel values, allow construction of textures by filling them with GdkRGBA values. --- testsuite/gdk/memorytexture.c | 449 ++++++++++++++++++++++++++++++------------ 1 file changed, 327 insertions(+), 122 deletions(-) diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c index ea24c827e3..49f7159965 100644 --- a/testsuite/gdk/memorytexture.c +++ b/testsuite/gdk/memorytexture.c @@ -1,9 +1,6 @@ #include #include -/* maximum bytes per pixel */ -#define MAX_BPP 4 - typedef enum { BLUE, GREEN, @@ -13,7 +10,7 @@ typedef enum { N_COLORS } Color; -const char * color_names[N_COLORS] = { +static const char * color_names[N_COLORS] = { "blue", "green", "red", @@ -21,37 +18,310 @@ const char * color_names[N_COLORS] = { "almost_opaque_rebeccapurple" }; -typedef struct _MemoryData { - gsize bytes_per_pixel; - guint opaque : 1; - guchar data[N_COLORS][MAX_BPP]; -} MemoryData; +static const GdkRGBA colors[N_COLORS] = { + { 0.0, 0.0, 1.0, 1.0 }, + { 0.0, 1.0, 0.0, 1.0 }, + { 1.0, 0.0, 0.0, 1.0 }, + { 0.0, 0.0, 0.0, 0.0 }, + { 0.4, 0.2, 0.6, 2.f/3.f }, +}; + +typedef struct _TextureBuilder TextureBuilder; +typedef struct _TestData TestData; + +struct _TextureBuilder +{ + GdkMemoryFormat format; + int width; + int height; + + guchar *pixels; + gsize stride; + gsize offset; +}; -typedef struct _TestData { +struct _TestData +{ GdkMemoryFormat format; Color color; -} TestData; - -#define RGBA(a, b, c, d) { 0x ## a, 0x ## b, 0x ## c, 0x ## d } - -static MemoryData tests[GDK_MEMORY_N_FORMATS] = { - { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(00,FF,00,FF), RGBA(00,00,FF,FF), RGBA(00,00,00,00), RGBA(66,22,44,AA) } }, - { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(FF,00,FF,00), RGBA(FF,FF,00,00), RGBA(00,00,00,00), RGBA(AA,44,22,66) } }, - { 4, FALSE, { RGBA(00,00,FF,FF), RGBA(00,FF,00,FF), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(44,22,66,AA) } }, - { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(00,FF,00,FF), RGBA(00,00,FF,FF), RGBA(00,00,00,00), RGBA(99,33,66,AA) } }, - { 4, FALSE, { RGBA(FF,00,00,FF), RGBA(FF,00,FF,00), RGBA(FF,FF,00,00), RGBA(00,00,00,00), RGBA(AA,66,33,99) } }, - { 4, FALSE, { RGBA(00,00,FF,FF), RGBA(00,FF,00,FF), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(66,33,99,AA) } }, - { 4, FALSE, { RGBA(FF,FF,00,00), RGBA(FF,00,FF,00), RGBA(FF,00,00,FF), RGBA(00,00,00,00), RGBA(AA,99,33,66) } }, - { 3, TRUE, { RGBA(00,00,FF,00), RGBA(00,FF,00,00), RGBA(FF,00,00,00), RGBA(00,00,00,00), RGBA(44,22,66,00) } }, - { 3, TRUE, { RGBA(FF,00,00,00), RGBA(00,FF,00,00), RGBA(00,00,FF,00), RGBA(00,00,00,00), RGBA(66,22,44,00) } }, }; +static gsize +gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) +{ + switch (format) + { + case GDK_MEMORY_R8G8B8: + case GDK_MEMORY_B8G8R8: + return 3; + + case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: + case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: + case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: + case GDK_MEMORY_B8G8R8A8: + case GDK_MEMORY_A8R8G8B8: + case GDK_MEMORY_R8G8B8A8: + case GDK_MEMORY_A8B8G8R8: + return 4; + + case GDK_MEMORY_R16G16B16: + case GDK_MEMORY_R16G16B16_FLOAT: + return 6; + + case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + return 8; + + case GDK_MEMORY_R32G32B32_FLOAT: + return 12; + + case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + return 16; + + case GDK_MEMORY_N_FORMATS: + default: + g_assert_not_reached (); + return 4; + } +} + +static gboolean +gdk_memory_format_has_alpha (GdkMemoryFormat format) +{ + switch (format) + { + case GDK_MEMORY_R8G8B8: + case GDK_MEMORY_B8G8R8: + case GDK_MEMORY_R16G16B16: + case GDK_MEMORY_R16G16B16_FLOAT: + case GDK_MEMORY_R32G32B32_FLOAT: + return FALSE; + + case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: + case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: + case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: + case GDK_MEMORY_B8G8R8A8: + case GDK_MEMORY_A8R8G8B8: + case GDK_MEMORY_R8G8B8A8: + case GDK_MEMORY_A8B8G8R8: + case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + return TRUE; + + case GDK_MEMORY_N_FORMATS: + default: + g_assert_not_reached (); + return TRUE; + } +} + +static void +texture_builder_init (TextureBuilder *builder, + GdkMemoryFormat format, + int width, + int height) +{ + gsize extra_stride; + + builder->format = format; + builder->width = width; + builder->height = height; + + extra_stride = g_test_rand_bit() ? g_test_rand_int_range (0, 16) : 0; + builder->offset = g_test_rand_bit() ? g_test_rand_int_range (0, 128) : 0; + builder->stride = width * gdk_memory_format_bytes_per_pixel (format) + extra_stride; + builder->pixels = g_malloc0 (builder->offset + builder->stride * height); +} + +static GdkTexture * +texture_builder_finish (TextureBuilder *builder) +{ + GBytes *bytes; + GdkTexture *texture; + + bytes = g_bytes_new_with_free_func (builder->pixels + builder->offset, + builder->height * builder->stride, + g_free, + builder->pixels); + texture = gdk_memory_texture_new (builder->width, + builder->height, + builder->format, + bytes, + builder->stride); + g_bytes_unref (bytes); + + return texture; +} + +static inline void +set_pixel_u8 (guchar *data, + int r, + int g, + int b, + int a, + gboolean premultiply, + const GdkRGBA *color) +{ + if (a >= 0) + data[a] = CLAMP (color->alpha * 256.f, 0.f, 255.f); + if (premultiply) + { + data[r] = CLAMP (color->red * color->alpha * 256.f, 0.f, 255.f); + data[g] = CLAMP (color->green * color->alpha * 256.f, 0.f, 255.f); + data[b] = CLAMP (color->blue * color->alpha * 256.f, 0.f, 255.f); + } + else + { + data[r] = CLAMP (color->red * 256.f, 0.f, 255.f); + data[g] = CLAMP (color->green * 256.f, 0.f, 255.f); + data[b] = CLAMP (color->blue * 256.f, 0.f, 255.f); + } +} + +static inline guint16 +float_to_half (const float x) +{ + const guint b = *(guint*)&x+0x00001000; // round-to-nearest-even + const guint e = (b&0x7F800000)>>23; // exponent + const guint m = b&0x007FFFFF; // mantissa + return (b&0x80000000)>>16 | (e>112)*((((e-112)<<10)&0x7C00)|m>>13) | ((e<113)&(e>101))*((((0x007FF000+m)>>(125-e))+1)>>1) | (e>143)*0x7FFF; // sign : normalized : denormalized : saturate +} + +static void +texture_builder_set_pixel (TextureBuilder *builder, + int x, + int y, + const GdkRGBA *color) +{ + guchar *data; + + g_assert_cmpint (x, >=, 0); + g_assert_cmpint (x, <, builder->width); + g_assert_cmpint (y, >=, 0); + g_assert_cmpint (y, <, builder->height); + + data = builder->pixels + + builder->offset + + y * builder->stride + + x * gdk_memory_format_bytes_per_pixel (builder->format); + + switch (builder->format) + { + case GDK_MEMORY_B8G8R8A8_PREMULTIPLIED: + set_pixel_u8 (data, 2, 1, 0, 3, TRUE, color); + break; + case GDK_MEMORY_A8R8G8B8_PREMULTIPLIED: + set_pixel_u8 (data, 1, 2, 3, 0, TRUE, color); + break; + case GDK_MEMORY_R8G8B8A8_PREMULTIPLIED: + set_pixel_u8 (data, 0, 1, 2, 3, TRUE, color); + break; + case GDK_MEMORY_B8G8R8A8: + set_pixel_u8 (data, 2, 1, 0, 3, FALSE, color); + break; + case GDK_MEMORY_A8R8G8B8: + set_pixel_u8 (data, 1, 2, 3, 0, FALSE, color); + break; + case GDK_MEMORY_R8G8B8A8: + set_pixel_u8 (data, 0, 1, 2, 3, FALSE, color); + break; + case GDK_MEMORY_A8B8G8R8: + set_pixel_u8 (data, 3, 2, 1, 0, FALSE, color); + break; + case GDK_MEMORY_R8G8B8: + set_pixel_u8 (data, 0, 1, 2, -1, TRUE, color); + break; + case GDK_MEMORY_B8G8R8: + set_pixel_u8 (data, 2, 1, 0, -1, TRUE, color); + break; + case GDK_MEMORY_R16G16B16: + { + guint16 pixels[3] = { + CLAMP (color->red * color->alpha * 65536.f, 0, 65535.f), + CLAMP (color->green * color->alpha * 65536.f, 0, 65535.f), + CLAMP (color->blue * color->alpha * 65536.f, 0, 65535.f), + }; + memcpy (data, pixels, 3 * sizeof (guint16)); + } + break; + case GDK_MEMORY_R16G16B16A16_PREMULTIPLIED: + { + guint16 pixels[4] = { + CLAMP (color->red * color->alpha * 65536.f, 0, 65535.f), + CLAMP (color->green * color->alpha * 65536.f, 0, 65535.f), + CLAMP (color->blue * color->alpha * 65536.f, 0, 65535.f), + CLAMP (color->alpha * 65536.f, 0, 65535.f), + }; + memcpy (data, pixels, 4 * sizeof (guint16)); + } + break; + case GDK_MEMORY_R16G16B16_FLOAT: + { + guint16 pixels[3] = { + float_to_half (color->red * color->alpha), + float_to_half (color->green * color->alpha), + float_to_half (color->blue * color->alpha) + }; + memcpy (data, pixels, 3 * sizeof (guint16)); + } + break; + case GDK_MEMORY_R16G16B16A16_FLOAT_PREMULTIPLIED: + { + guint16 pixels[4] = { + float_to_half (color->red * color->alpha), + float_to_half (color->green * color->alpha), + float_to_half (color->blue * color->alpha), + float_to_half (color->alpha) + }; + memcpy (data, pixels, 4 * sizeof (guint16)); + } + break; + case GDK_MEMORY_R32G32B32_FLOAT: + { + float pixels[3] = { + color->red * color->alpha, + color->green * color->alpha, + color->blue * color->alpha + }; + memcpy (data, pixels, 3 * sizeof (float)); + } + break; + case GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED: + { + float pixels[4] = { + color->red * color->alpha, + color->green * color->alpha, + color->blue * color->alpha, + color->alpha + }; + memcpy (data, pixels, 4 * sizeof (float)); + } + break; + case GDK_MEMORY_N_FORMATS: + default: + g_assert_not_reached (); + break; + } +} + +static void +texture_builder_fill (TextureBuilder *builder, + const GdkRGBA *color) +{ + int x, y; + + for (y = 0; y < builder->height; y++) + for (x = 0; x < builder->width; x++) + texture_builder_set_pixel (builder, x, y, color); +} + static void compare_textures (GdkTexture *expected, GdkTexture *test, - gboolean ignore_alpha) + gboolean has_alpha) { - guchar *expected_data, *test_data; + guint32 *expected_data, *test_data; int width, height; int x, y; @@ -61,20 +331,20 @@ compare_textures (GdkTexture *expected, width = gdk_texture_get_width (expected); height = gdk_texture_get_height (expected); - expected_data = g_malloc (width * height * 4); - gdk_texture_download (expected, expected_data, width * 4); + expected_data = g_new (guint32, width * height); + gdk_texture_download (expected, (guchar *) expected_data, width * 4); - test_data = g_malloc (width * height * 4); - gdk_texture_download (test, test_data, width * 4); + test_data = g_new (guint32, width * height); + gdk_texture_download (test, (guchar *) test_data, width * 4); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { - if (ignore_alpha) - g_assert_cmphex (*(guint32 *) &expected_data[y * width + x * 4] & 0xFFFFFF, ==, *(guint32 *) &test_data[y * width + x * 4] & 0xFFFFFF); + if (has_alpha) + g_assert_cmphex (expected_data[y * width + x], ==, test_data[y * width + x]); else - g_assert_cmphex (*(guint32 *) &expected_data[y * width + x * 4], ==, *(guint32 *) &test_data[y * width + x * 4]); + g_assert_cmphex (expected_data[y * width + x] | 0xFF000000, ==, test_data[y * width + x]); } } @@ -84,33 +354,16 @@ compare_textures (GdkTexture *expected, static GdkTexture * create_texture (GdkMemoryFormat format, - Color color, int width, int height, - gsize stride) + const GdkRGBA *color) { - GdkTexture *texture; - GBytes *bytes; - guchar *data; - int x, y; + TextureBuilder builder; - data = g_malloc (height * MAX (stride, tests[format].bytes_per_pixel)); - for (y = 0; y < height; y++) - for (x = 0; x < width; x++) - { - memcpy (&data[y * stride + x * tests[format].bytes_per_pixel], - &tests[format].data[color], - tests[format].bytes_per_pixel); - } + texture_builder_init (&builder, format, width, height); + texture_builder_fill (&builder, color); - bytes = g_bytes_new_take (data, height * MAX (stride, tests[format].bytes_per_pixel)); - texture = gdk_memory_texture_new (width, height, - format, - bytes, - stride); - g_bytes_unref (bytes); - - return texture; + return texture_builder_finish (&builder); } static void @@ -119,25 +372,10 @@ test_download_1x1 (gconstpointer data) const TestData *test_data = data; GdkTexture *expected, *test; - expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 1, 1, tests[test_data->format].bytes_per_pixel); - test = create_texture (test_data->format, test_data->color, 1, 1, tests[test_data->format].bytes_per_pixel); + expected = create_texture (GDK_MEMORY_DEFAULT, 1, 1, &colors[test_data->color]); + test = create_texture (test_data->format, 1, 1, &colors[test_data->color]); - compare_textures (expected, test, tests[test_data->format].opaque); - - g_object_unref (expected); - g_object_unref (test); -} - -static void -test_download_1x1_with_stride (gconstpointer data) -{ - const TestData *test_data = data; - GdkTexture *expected, *test; - - expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 1, 1, 4); - test = create_texture (test_data->format, test_data->color, 1, 1, 2 * MAX_BPP); - - compare_textures (expected, test, tests[test_data->format].opaque); + compare_textures (expected, test, gdk_memory_format_has_alpha (test_data->format)); g_object_unref (expected); g_object_unref (test); @@ -149,39 +387,23 @@ test_download_4x4 (gconstpointer data) const TestData *test_data = data; GdkTexture *expected, *test; - expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 4, 4, 16); - test = create_texture (test_data->format, test_data->color, 4, 4, 4 * tests[test_data->format].bytes_per_pixel); + expected = create_texture (GDK_MEMORY_DEFAULT, 4, 4, &colors[test_data->color]); + test = create_texture (test_data->format, 4, 4, &colors[test_data->color]); - compare_textures (expected, test, tests[test_data->format].opaque); + compare_textures (expected, test, gdk_memory_format_has_alpha (test_data->format)); g_object_unref (expected); g_object_unref (test); } static void -test_download_4x4_with_stride (gconstpointer data) -{ - const TestData *test_data = data; - GdkTexture *expected, *test; - - expected = create_texture (GDK_MEMORY_DEFAULT, test_data->color, 4, 4, 16); - test = create_texture (test_data->format, test_data->color, 4, 4, 4 * MAX_BPP); - - compare_textures (expected, test, tests[test_data->format].opaque); - - g_object_unref (expected); - g_object_unref (test); -} - -int -main (int argc, char *argv[]) +add_test (const char *name, + GTestDataFunc func) { GdkMemoryFormat format; Color color; GEnumClass *enum_class; - (g_test_init) (&argc, &argv, NULL); - enum_class = g_type_class_ref (GDK_TYPE_MEMORY_FORMAT); for (format = 0; format < GDK_MEMORY_N_FORMATS; format++) @@ -189,42 +411,25 @@ main (int argc, char *argv[]) for (color = 0; color < N_COLORS; color++) { TestData *test_data = g_new (TestData, 1); - char *test_name = g_strdup_printf ("/memorytexture/download_1x1/%s/%s", + char *test_name = g_strdup_printf ("%s/%s/%s", + name, g_enum_get_value (enum_class, format)->value_nick, color_names[color]); test_data->format = format; test_data->color = color; g_test_add_data_func_full (test_name, test_data, test_download_1x1, g_free); g_free (test_name); - - test_data = g_new (TestData, 1); - test_name = g_strdup_printf ("/memorytexture/download_1x1_with_stride/%s/%s", - g_enum_get_value (enum_class, format)->value_nick, - color_names[color]); - test_data->format = format; - test_data->color = color; - g_test_add_data_func_full (test_name, test_data, test_download_1x1_with_stride, g_free); - g_free (test_name); - - test_data = g_new (TestData, 1); - test_name = g_strdup_printf ("/memorytexture/download_4x4/%s/%s", - g_enum_get_value (enum_class, format)->value_nick, - color_names[color]); - test_data->format = format; - test_data->color = color; - g_test_add_data_func_full (test_name, test_data, test_download_4x4, g_free); - g_free (test_name); - - test_data = g_new (TestData, 1); - test_name = g_strdup_printf ("/memorytexture/download_4x4_with_stride/%s/%s", - g_enum_get_value (enum_class, format)->value_nick, - color_names[color]); - test_data->format = format; - test_data->color = color; - g_test_add_data_func_full (test_name, test_data, test_download_4x4_with_stride, g_free); - g_free (test_name); } } +} + +int +main (int argc, char *argv[]) +{ + (g_test_init) (&argc, &argv, NULL); + + add_test ("/memorytexture/download_1x1", test_download_1x1); + add_test ("/memorytexture/download_4x4", test_download_4x4); return g_test_run (); } -- cgit v1.2.1 From 00439f9e5ca97e46747c9abfa68fc1ae078fe633 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 11 Sep 2021 22:26:37 +0200 Subject: testsuite: Rework memorytexture test some more Instead of predefined colors, generate them randomly. --- testsuite/gdk/memorytexture.c | 102 ++++++++++++++++++------------------------ 1 file changed, 44 insertions(+), 58 deletions(-) diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c index 49f7159965..c3cbc71e2b 100644 --- a/testsuite/gdk/memorytexture.c +++ b/testsuite/gdk/memorytexture.c @@ -1,33 +1,9 @@ #include #include -typedef enum { - BLUE, - GREEN, - RED, - TRANSPARENT, - ALMOST_OPAQUE_REBECCAPURPLE, - N_COLORS -} Color; - -static const char * color_names[N_COLORS] = { - "blue", - "green", - "red", - "transparent", - "almost_opaque_rebeccapurple" -}; - -static const GdkRGBA colors[N_COLORS] = { - { 0.0, 0.0, 1.0, 1.0 }, - { 0.0, 1.0, 0.0, 1.0 }, - { 1.0, 0.0, 0.0, 1.0 }, - { 0.0, 0.0, 0.0, 0.0 }, - { 0.4, 0.2, 0.6, 2.f/3.f }, -}; +#define N 50 typedef struct _TextureBuilder TextureBuilder; -typedef struct _TestData TestData; struct _TextureBuilder { @@ -40,12 +16,6 @@ struct _TextureBuilder gsize offset; }; -struct _TestData -{ - GdkMemoryFormat format; - Color color; -}; - static gsize gdk_memory_format_bytes_per_pixel (GdkMemoryFormat format) { @@ -367,33 +337,57 @@ create_texture (GdkMemoryFormat format, } static void -test_download_1x1 (gconstpointer data) +create_random_color (GdkRGBA *color) { - const TestData *test_data = data; + /* Generate colors so that premultiplying will result in values in steps of 1/15th */ + color->red = g_test_rand_int_range (0, 6) / 5.f; + color->green = g_test_rand_int_range (0, 6) / 5.f; + color->blue = g_test_rand_int_range (0, 6) / 5.f; + color->alpha = g_test_rand_int_range (0, 4) / 3.f; +} + +static void +test_download_1x1 (gconstpointer format_) +{ + GdkMemoryFormat format = GPOINTER_TO_SIZE (format_); GdkTexture *expected, *test; + gsize i; - expected = create_texture (GDK_MEMORY_DEFAULT, 1, 1, &colors[test_data->color]); - test = create_texture (test_data->format, 1, 1, &colors[test_data->color]); + for (i = 0; i < N; i++) + { + GdkRGBA color; - compare_textures (expected, test, gdk_memory_format_has_alpha (test_data->format)); + create_random_color (&color); + expected = create_texture (GDK_MEMORY_DEFAULT, 1, 1, &color); + test = create_texture (format, 1, 1, &color); + + compare_textures (expected, test, gdk_memory_format_has_alpha (format)); - g_object_unref (expected); - g_object_unref (test); + g_object_unref (expected); + g_object_unref (test); + } } static void -test_download_4x4 (gconstpointer data) +test_download_4x4 (gconstpointer format_) { - const TestData *test_data = data; + GdkMemoryFormat format = GPOINTER_TO_SIZE (format_); GdkTexture *expected, *test; + gsize i; - expected = create_texture (GDK_MEMORY_DEFAULT, 4, 4, &colors[test_data->color]); - test = create_texture (test_data->format, 4, 4, &colors[test_data->color]); + for (i = 0; i < N; i++) + { + GdkRGBA color; - compare_textures (expected, test, gdk_memory_format_has_alpha (test_data->format)); + create_random_color (&color); + expected = create_texture (GDK_MEMORY_DEFAULT, 4, 4, &color); + test = create_texture (format, 4, 4, &color); + + compare_textures (expected, test, gdk_memory_format_has_alpha (format)); - g_object_unref (expected); - g_object_unref (test); + g_object_unref (expected); + g_object_unref (test); + } } static void @@ -401,25 +395,17 @@ add_test (const char *name, GTestDataFunc func) { GdkMemoryFormat format; - Color color; GEnumClass *enum_class; enum_class = g_type_class_ref (GDK_TYPE_MEMORY_FORMAT); for (format = 0; format < GDK_MEMORY_N_FORMATS; format++) { - for (color = 0; color < N_COLORS; color++) - { - TestData *test_data = g_new (TestData, 1); - char *test_name = g_strdup_printf ("%s/%s/%s", - name, - g_enum_get_value (enum_class, format)->value_nick, - color_names[color]); - test_data->format = format; - test_data->color = color; - g_test_add_data_func_full (test_name, test_data, test_download_1x1, g_free); - g_free (test_name); - } + char *test_name = g_strdup_printf ("%s/%s", + name, + g_enum_get_value (enum_class, format)->value_nick); + g_test_add_data_func_full (test_name, GSIZE_TO_POINTER (format), test_download_1x1, NULL); + g_free (test_name); } } -- cgit v1.2.1 From bcc17b30339091f0e81b443c05d3f04bbb5725df Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 11 Sep 2021 22:50:09 +0200 Subject: testsuite: Add tests uploading the memorytextures Use a GL renderer and render_texture() them. --- testsuite/gdk/memorytexture.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c index c3cbc71e2b..bb379da18c 100644 --- a/testsuite/gdk/memorytexture.c +++ b/testsuite/gdk/memorytexture.c @@ -1,8 +1,11 @@ -#include -#include +#include + +#include "gsk/ngl/gsknglrenderer.h" #define N 50 +static GskRenderer *gl_renderer = NULL; + typedef struct _TextureBuilder TextureBuilder; struct _TextureBuilder @@ -412,10 +415,26 @@ add_test (const char *name, int main (int argc, char *argv[]) { - (g_test_init) (&argc, &argv, NULL); + GdkSurface *surface; + int result; + + gtk_test_init (&argc, &argv, NULL); add_test ("/memorytexture/download_1x1", test_download_1x1); add_test ("/memorytexture/download_4x4", test_download_4x4); - return g_test_run (); + surface = gdk_surface_new_toplevel (gdk_display_get_default()); + gl_renderer = gsk_ngl_renderer_new (); + if (!gsk_renderer_realize (gl_renderer, surface, NULL)) + { + g_clear_object (&gl_renderer); + g_clear_object (&surface); + } + + result = g_test_run (); + + g_clear_object (&gl_renderer); + g_clear_object (&surface); + + return result; } -- cgit v1.2.1 From 9179ebb28e8140c91282b6df482934e70746e98b Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 12 Sep 2021 00:11:44 +0200 Subject: testsuite: Add memory test support for OpenGL up/downloads Use a GL renderer to upload textures (and then optionally download them via release() again). This way, we can test that the GL renderer properly uploads textures to the right formats (not losing information for HDR for example) and downloads them again. --- testsuite/gdk/memorytexture.c | 122 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 106 insertions(+), 16 deletions(-) diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c index bb379da18c..4146d476ee 100644 --- a/testsuite/gdk/memorytexture.c +++ b/testsuite/gdk/memorytexture.c @@ -2,12 +2,20 @@ #include "gsk/ngl/gsknglrenderer.h" -#define N 50 +#define N 20 static GskRenderer *gl_renderer = NULL; typedef struct _TextureBuilder TextureBuilder; +typedef enum { + TEXTURE_METHOD_LOCAL, + TEXTURE_METHOD_GL, + TEXTURE_METHOD_GL_RELEASED, + + N_TEXTURE_METHODS +} TextureMethod; + struct _TextureBuilder { GdkMemoryFormat format; @@ -89,6 +97,26 @@ gdk_memory_format_has_alpha (GdkMemoryFormat format) } } +static gpointer +encode (GdkMemoryFormat format, + TextureMethod method) +{ + return GSIZE_TO_POINTER (method * GDK_MEMORY_N_FORMATS + format); +} + +static void +decode (gconstpointer data, + GdkMemoryFormat *format, + TextureMethod *method) +{ + gsize value = GPOINTER_TO_SIZE (data); + + *format = value % GDK_MEMORY_N_FORMATS; + value /= GDK_MEMORY_N_FORMATS; + + *method = value; +} + static void texture_builder_init (TextureBuilder *builder, GdkMemoryFormat format, @@ -325,18 +353,64 @@ compare_textures (GdkTexture *expected, g_free (test_data); } +static GdkTexture * +upload_to_gl (GdkTexture *texture) +{ + GskRenderNode *node; + GdkTexture *result; + + if (gl_renderer == NULL) + return texture; + + node = gsk_texture_node_new (texture, + &GRAPHENE_RECT_INIT( + 0, 0, + gdk_texture_get_width (texture), + gdk_texture_get_height (texture) + )); + result = gsk_renderer_render_texture (gl_renderer, node, NULL); + gsk_render_node_unref (node); + g_object_unref (texture); + + return result; +} + static GdkTexture * create_texture (GdkMemoryFormat format, + TextureMethod method, int width, int height, const GdkRGBA *color) { TextureBuilder builder; + GdkTexture *texture; texture_builder_init (&builder, format, width, height); texture_builder_fill (&builder, color); - return texture_builder_finish (&builder); + texture = texture_builder_finish (&builder); + + switch (method) + { + case TEXTURE_METHOD_LOCAL: + break; + + case TEXTURE_METHOD_GL: + texture = upload_to_gl (texture); + break; + + case TEXTURE_METHOD_GL_RELEASED: + texture = upload_to_gl (texture); + gdk_gl_texture_release (GDK_GL_TEXTURE (texture)); + break; + + case N_TEXTURE_METHODS: + default: + g_assert_not_reached (); + break; + } + + return texture; } static void @@ -350,19 +424,22 @@ create_random_color (GdkRGBA *color) } static void -test_download_1x1 (gconstpointer format_) +test_download_1x1 (gconstpointer data) { - GdkMemoryFormat format = GPOINTER_TO_SIZE (format_); + GdkMemoryFormat format; + TextureMethod method; GdkTexture *expected, *test; gsize i; + decode (data, &format, &method); + for (i = 0; i < N; i++) { GdkRGBA color; create_random_color (&color); - expected = create_texture (GDK_MEMORY_DEFAULT, 1, 1, &color); - test = create_texture (format, 1, 1, &color); + expected = create_texture (GDK_MEMORY_DEFAULT, TEXTURE_METHOD_LOCAL, 1, 1, &color); + test = create_texture (format, method, 1, 1, &color); compare_textures (expected, test, gdk_memory_format_has_alpha (format)); @@ -372,19 +449,22 @@ test_download_1x1 (gconstpointer format_) } static void -test_download_4x4 (gconstpointer format_) +test_download_4x4 (gconstpointer data) { - GdkMemoryFormat format = GPOINTER_TO_SIZE (format_); + GdkMemoryFormat format; + TextureMethod method; GdkTexture *expected, *test; gsize i; + decode (data, &format, &method); + for (i = 0; i < N; i++) { GdkRGBA color; create_random_color (&color); - expected = create_texture (GDK_MEMORY_DEFAULT, 4, 4, &color); - test = create_texture (format, 4, 4, &color); + expected = create_texture (GDK_MEMORY_DEFAULT, TEXTURE_METHOD_LOCAL, 4, 4, &color); + test = create_texture (format, method, 4, 4, &color); compare_textures (expected, test, gdk_memory_format_has_alpha (format)); @@ -398,17 +478,23 @@ add_test (const char *name, GTestDataFunc func) { GdkMemoryFormat format; + TextureMethod method; GEnumClass *enum_class; enum_class = g_type_class_ref (GDK_TYPE_MEMORY_FORMAT); for (format = 0; format < GDK_MEMORY_N_FORMATS; format++) { - char *test_name = g_strdup_printf ("%s/%s", - name, - g_enum_get_value (enum_class, format)->value_nick); - g_test_add_data_func_full (test_name, GSIZE_TO_POINTER (format), test_download_1x1, NULL); - g_free (test_name); + for (method = 0; method < N_TEXTURE_METHODS; method++) + { + const char *method_names[N_TEXTURE_METHODS] = { "local", "gl", "gl-released" }; + char *test_name = g_strdup_printf ("%s/%s/%s", + name, + g_enum_get_value (enum_class, format)->value_nick, + method_names[method]); + g_test_add_data_func_full (test_name, encode (format, method), test_download_1x1, NULL); + g_free (test_name); + } } } @@ -433,7 +519,11 @@ main (int argc, char *argv[]) result = g_test_run (); - g_clear_object (&gl_renderer); + if (gl_renderer) + { + gsk_renderer_unrealize (gl_renderer); + g_clear_object (&gl_renderer); + } g_clear_object (&surface); return result; -- cgit v1.2.1 From 416763bf2d31edc21608dd20cc6cf125ea3d6563 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 12 Sep 2021 04:34:42 +0200 Subject: testsuite: Add tests for gdk_texture_download_float() --- testsuite/gdk/memorytexture.c | 99 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/testsuite/gdk/memorytexture.c b/testsuite/gdk/memorytexture.c index 4146d476ee..021a7ad11b 100644 --- a/testsuite/gdk/memorytexture.c +++ b/testsuite/gdk/memorytexture.c @@ -353,6 +353,50 @@ compare_textures (GdkTexture *expected, g_free (test_data); } +static void +compare_textures_float (GdkTexture *expected, + GdkTexture *test, + float eps, + gboolean has_alpha) +{ + static int R = 0; + static int G = 1; + static int B = 2; + static int A = 3; + float *expected_data, *test_data; + int width, height; + int x, y; + + g_assert_cmpint (gdk_texture_get_width (expected), ==, gdk_texture_get_width (test)); + g_assert_cmpint (gdk_texture_get_height (expected), ==, gdk_texture_get_height (test)); + + width = gdk_texture_get_width (expected); + height = gdk_texture_get_height (expected); + + expected_data = g_new (float, width * height * 4); + gdk_texture_download_float (expected, expected_data, width * 4); + + test_data = g_new (float, width * height * 4); + gdk_texture_download_float (test, test_data, width * 4); + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + R], test_data[y * width + 4 * x + R], eps); + g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + G], test_data[y * width + 4 * x + G], eps); + g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + B], test_data[y * width + 4 * x + B], eps); + if (has_alpha) + g_assert_cmpfloat_with_epsilon (expected_data[y * width + 4 * x + A], test_data[y * width + 4 * x + A], eps); + else + g_assert_cmpfloat (1.0, ==, test_data[y * width + 4 * x + A]); + } + } + + g_free (expected_data); + g_free (test_data); +} + static GdkTexture * upload_to_gl (GdkTexture *texture) { @@ -473,6 +517,59 @@ test_download_4x4 (gconstpointer data) } } +static void +test_download_float_1x1 (gconstpointer data) +{ + GdkMemoryFormat format; + TextureMethod method; + GdkTexture *expected, *test; + gsize i; + + decode (data, &format, &method); + + for (i = 0; i < N; i++) + { + GdkRGBA color; + + create_random_color (&color); + expected = create_texture (GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, TEXTURE_METHOD_LOCAL, 1, 1, &color); + test = create_texture (format, method, 1, 1, &color); + + compare_textures_float (expected, test, + G_MINFLOAT, + gdk_memory_format_has_alpha (format)); + + g_object_unref (expected); + g_object_unref (test); + } +} + +static void +test_download_float_4x4 (gconstpointer data) +{ + GdkMemoryFormat format; + TextureMethod method; + GdkTexture *expected, *test; + gsize i; + + decode (data, &format, &method); + + for (i = 0; i < N; i++) + { + GdkRGBA color; + + create_random_color (&color); + expected = create_texture (GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED, TEXTURE_METHOD_LOCAL, 4, 4, &color); + test = create_texture (format, method, 4, 4, &color); + + compare_textures_float (expected, test, G_MINFLOAT, gdk_memory_format_has_alpha (format)); + + g_object_unref (expected); + g_object_unref (test); + } +} + + static void add_test (const char *name, GTestDataFunc func) @@ -508,6 +605,8 @@ main (int argc, char *argv[]) add_test ("/memorytexture/download_1x1", test_download_1x1); add_test ("/memorytexture/download_4x4", test_download_4x4); + add_test ("/memorytexture/download_float_1x1", test_download_float_1x1); + add_test ("/memorytexture/download_float_4x4", test_download_float_4x4); surface = gdk_surface_new_toplevel (gdk_display_get_default()); gl_renderer = gsk_ngl_renderer_new (); -- cgit v1.2.1