From 11543a229abfa5c5daaa44ec9a7e86613bd4ffd1 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 14 Jul 2024 00:51:05 +0200 Subject: [PATCH 01/11] texturedownloader: Add color state ... and plumb the color state through the downloading machinery, where no matter what path it takes it ends up in gdk_memory_convert_color_state() or gdk_memory_convert(). The 2nd of those has been expanded to optionally do colorstate conversion when the 2 colorstates are different. --- gdk/gdkdmabuf.c | 14 +++++++-- gdk/gdkdmabufdownloader.c | 3 +- gdk/gdkdmabufdownloaderprivate.h | 2 ++ gdk/gdkdmabufprivate.h | 1 + gdk/gdkdmabuftexture.c | 7 +++-- gdk/gdkgltexture.c | 26 ++++++++++++++-- gdk/gdkmemoryformat.c | 27 ++++++++++++++--- gdk/gdkmemoryformatprivate.h | 2 ++ gdk/gdkmemorytexture.c | 5 +++- gdk/gdktexture.c | 5 +++- gdk/gdktexturedownloader.c | 49 +++++++++++++++++++++++++++++-- gdk/gdktexturedownloader.h | 7 ++++- gdk/gdktexturedownloaderprivate.h | 1 + gdk/gdktextureprivate.h | 2 ++ gsk/gl/gskglglyphlibrary.c | 2 ++ gsk/gl/gskglrenderer.c | 2 ++ gsk/gpu/gskgpuframe.c | 4 +++ gsk/gpu/gskgpuframeprivate.h | 1 + gsk/gpu/gskgpurenderer.c | 2 ++ 19 files changed, 144 insertions(+), 18 deletions(-) diff --git a/gdk/gdkdmabuf.c b/gdk/gdkdmabuf.c index 46b5006ae6..b0d96ac9df 100644 --- a/gdk/gdkdmabuf.c +++ b/gdk/gdkdmabuf.c @@ -2062,13 +2062,21 @@ out: void gdk_dmabuf_download_mmap (GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride) { GdkMemoryFormat src_format = gdk_texture_get_format (texture); + GdkColorState *src_color_state = gdk_texture_get_color_state (texture); if (format == src_format) - gdk_dmabuf_do_download_mmap (texture, data, stride); + { + gdk_dmabuf_do_download_mmap (texture, data, stride); + gdk_memory_convert_color_state (data, stride, format, + src_color_state, color_state, + gdk_texture_get_width (texture), + gdk_texture_get_height (texture)); + } else { unsigned int width, height; @@ -2083,8 +2091,8 @@ gdk_dmabuf_download_mmap (GdkTexture *texture, gdk_dmabuf_do_download_mmap (texture, src_data, src_stride); - gdk_memory_convert (data, stride, format, - src_data, src_stride, src_format, + gdk_memory_convert (data, stride, format, color_state, + src_data, src_stride, src_format, src_color_state, width, height); g_free (src_data); diff --git a/gdk/gdkdmabufdownloader.c b/gdk/gdkdmabufdownloader.c index 95e5a56411..9326a96691 100644 --- a/gdk/gdkdmabufdownloader.c +++ b/gdk/gdkdmabufdownloader.c @@ -35,6 +35,7 @@ void gdk_dmabuf_downloader_download (GdkDmabufDownloader *self, GdkDmabufTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride) { @@ -43,6 +44,6 @@ gdk_dmabuf_downloader_download (GdkDmabufDownloader *self, g_return_if_fail (GDK_IS_DMABUF_DOWNLOADER (self)); iface = GDK_DMABUF_DOWNLOADER_GET_IFACE (self); - iface->download (self, texture, format, data, stride); + iface->download (self, texture, format, color_state, data, stride); } diff --git a/gdk/gdkdmabufdownloaderprivate.h b/gdk/gdkdmabufdownloaderprivate.h index e149a43ead..6053bfbfa7 100644 --- a/gdk/gdkdmabufdownloaderprivate.h +++ b/gdk/gdkdmabufdownloaderprivate.h @@ -20,6 +20,7 @@ struct _GdkDmabufDownloaderInterface void (* download) (GdkDmabufDownloader *downloader, GdkDmabufTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride); }; @@ -31,6 +32,7 @@ gboolean gdk_dmabuf_downloader_supports (GdkDmabufDownlo void gdk_dmabuf_downloader_download (GdkDmabufDownloader *downloader, GdkDmabufTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride); diff --git a/gdk/gdkdmabufprivate.h b/gdk/gdkdmabufprivate.h index e3b2f01308..fd32390256 100644 --- a/gdk/gdkdmabufprivate.h +++ b/gdk/gdkdmabufprivate.h @@ -29,6 +29,7 @@ void gdk_dmabuf_close_fds (GdkDmabuf GdkDmabufFormats * gdk_dmabuf_get_mmap_formats (void) G_GNUC_CONST; void gdk_dmabuf_download_mmap (GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride); diff --git a/gdk/gdkdmabuftexture.c b/gdk/gdkdmabuftexture.c index 61e93181fb..62fea85f25 100644 --- a/gdk/gdkdmabuftexture.c +++ b/gdk/gdkdmabuftexture.c @@ -97,6 +97,7 @@ struct _Download { GdkDmabufTexture *texture; GdkMemoryFormat format; + GdkColorState *color_state; guchar *data; gsize stride; volatile int spinlock; @@ -110,6 +111,7 @@ gdk_dmabuf_texture_invoke_callback (gpointer data) gdk_dmabuf_downloader_download (download->texture->downloader, download->texture, download->format, + download->color_state, download->data, download->stride); @@ -121,16 +123,17 @@ gdk_dmabuf_texture_invoke_callback (gpointer data) static void gdk_dmabuf_texture_download (GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride) { GdkDmabufTexture *self = GDK_DMABUF_TEXTURE (texture); - Download download = { self, format, data, stride, 0 }; + Download download = { self, format, color_state, data, stride, 0 }; if (self->downloader == NULL) { #ifdef HAVE_DMABUF - gdk_dmabuf_download_mmap (texture, format, data, stride); + gdk_dmabuf_download_mmap (texture, format, color_state, data, stride); #endif return; } diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index b23fa38577..cf70085f90 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -137,6 +137,7 @@ typedef struct _Download Download; struct _Download { GdkMemoryFormat format; + GdkColorState *color_state; guchar *data; gsize stride; }; @@ -211,6 +212,14 @@ gdk_gl_texture_do_download (GdkGLTexture *self, gl_format, gl_type, download->data); + + gdk_memory_convert_color_state (download->data, + download->stride, + download->format, + download->color_state, + texture->color_state, + texture->width, + texture->height); } else { @@ -227,14 +236,15 @@ gdk_gl_texture_do_download (GdkGLTexture *self, gdk_memory_convert (download->data, download->stride, download->format, + download->color_state, pixels, stride, format, + texture->color_state, texture->width, texture->height); g_free (pixels); - } } else @@ -288,6 +298,14 @@ gdk_gl_texture_do_download (GdkGLTexture *self, gl_read_format, gl_read_type, download->data); + + gdk_memory_convert_color_state (download->data, + download->stride, + download->format, + download->color_state, + texture->color_state, + texture->width, + texture->height); } else { @@ -379,9 +397,11 @@ gdk_gl_texture_do_download (GdkGLTexture *self, gdk_memory_convert (download->data, download->stride, download->format, + download->color_state, pixels, stride, actual_format, + texture->color_state, texture->width, texture->height); @@ -395,6 +415,7 @@ gdk_gl_texture_do_download (GdkGLTexture *self, static void gdk_gl_texture_download (GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride) { @@ -403,11 +424,12 @@ gdk_gl_texture_download (GdkTexture *texture, if (self->saved) { - gdk_texture_do_download (self->saved, format, data, stride); + gdk_texture_do_download (self->saved, format, color_state, data, stride); return; } download.format = format; + download.color_state = color_state; download.data = data; download.stride = stride; diff --git a/gdk/gdkmemoryformat.c b/gdk/gdkmemoryformat.c index 8af756ea4b..2eefe74792 100644 --- a/gdk/gdkmemoryformat.c +++ b/gdk/gdkmemoryformat.c @@ -1846,9 +1846,11 @@ void gdk_memory_convert (guchar *dest_data, gsize dest_stride, GdkMemoryFormat dest_format, + GdkColorState *dest_cs, const guchar *src_data, gsize src_stride, GdkMemoryFormat src_format, + GdkColorState *src_cs, gsize width, gsize height) { @@ -1856,7 +1858,9 @@ gdk_memory_convert (guchar *dest_data, const GdkMemoryFormatDescription *src_desc = &memory_formats[src_format]; float (*tmp)[4]; gsize y; + GdkFloatColorConvert convert_func = NULL; void (*func) (guchar *, const guchar *, gsize) = NULL; + gboolean needs_premultiply, needs_unpremultiply; g_assert (dest_format < GDK_MEMORY_N_FORMATS); g_assert (src_format < GDK_MEMORY_N_FORMATS); @@ -1866,7 +1870,7 @@ gdk_memory_convert (guchar *dest_data, g_assert (dest_data + gdk_memory_format_min_buffer_size (dest_format, dest_stride, width, height) <= src_data || src_data + gdk_memory_format_min_buffer_size (src_format, src_stride, width, height) <= dest_data); - if (src_format == dest_format) + if (src_format == dest_format && gdk_color_state_equal (dest_cs, src_cs)) { gsize bytes_per_row = src_desc->bytes_per_pixel * width; @@ -1886,7 +1890,9 @@ gdk_memory_convert (guchar *dest_data, return; } - if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED) + if (!gdk_color_state_equal (dest_cs, src_cs)) + convert_func = gdk_color_state_get_convert_to (src_cs, dest_cs); + else if (src_format == GDK_MEMORY_R8G8B8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED) func = r8g8b8a8_to_r8g8b8a8_premultiplied; else if (src_format == GDK_MEMORY_B8G8R8A8 && dest_format == GDK_MEMORY_R8G8B8A8_PREMULTIPLIED) func = r8g8b8a8_to_b8g8r8a8_premultiplied; @@ -1936,12 +1942,25 @@ gdk_memory_convert (guchar *dest_data, tmp = g_malloc (sizeof (*tmp) * width); + if (convert_func) + { + needs_unpremultiply = src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED; + needs_premultiply = src_desc->alpha != GDK_MEMORY_ALPHA_OPAQUE && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT; + } + else + { + needs_unpremultiply = src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT; + needs_premultiply = src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT; + } + for (y = 0; y < height; y++) { src_desc->to_float (tmp, src_data, width); - if (src_desc->alpha == GDK_MEMORY_ALPHA_PREMULTIPLIED && dest_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT) + if (needs_unpremultiply) unpremultiply (tmp, width); - else if (src_desc->alpha == GDK_MEMORY_ALPHA_STRAIGHT && dest_desc->alpha != GDK_MEMORY_ALPHA_STRAIGHT) + if (convert_func) + convert_func (src_cs, tmp, width); + if (needs_premultiply) premultiply (tmp, width); dest_desc->from_float (dest_data, tmp, width); src_data += src_stride; diff --git a/gdk/gdkmemoryformatprivate.h b/gdk/gdkmemoryformatprivate.h index 55bc292395..f72f0aabe6 100644 --- a/gdk/gdkmemoryformatprivate.h +++ b/gdk/gdkmemoryformatprivate.h @@ -95,9 +95,11 @@ const char * gdk_memory_format_get_name (GdkMemoryFormat void gdk_memory_convert (guchar *dest_data, gsize dest_stride, GdkMemoryFormat dest_format, + GdkColorState *src_cs, const guchar *src_data, gsize src_stride, GdkMemoryFormat src_format, + GdkColorState *dest_cs, gsize width, gsize height); void gdk_memory_convert_color_state (guchar *data, diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index 76e05c01b3..b715a7ddf7 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -58,6 +58,7 @@ gdk_memory_texture_dispose (GObject *object) static void gdk_memory_texture_download (GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride) { @@ -65,9 +66,11 @@ gdk_memory_texture_download (GdkTexture *texture, gdk_memory_convert (data, stride, format, + color_state, (guchar *) g_bytes_get_data (self->bytes, NULL), self->stride, texture->format, + texture->color_state, gdk_texture_get_width (texture), gdk_texture_get_height (texture)); } @@ -217,7 +220,7 @@ gdk_memory_texture_from_texture (GdkTexture *texture) stride = texture->width * gdk_memory_format_bytes_per_pixel (texture->format); data = g_malloc_n (stride, texture->height); - gdk_texture_do_download (texture, texture->format, data, stride); + gdk_texture_do_download (texture, texture->format, texture->color_state, data, stride); bytes = g_bytes_new_take (data, stride * texture->height); result = gdk_memory_texture_new (texture->width, texture->height, diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c index a600f44489..17dfd45cf6 100644 --- a/gdk/gdktexture.c +++ b/gdk/gdktexture.c @@ -262,6 +262,7 @@ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GdkTexture, gdk_texture, G_TYPE_OBJECT, static void gdk_texture_default_download (GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride) { @@ -821,10 +822,11 @@ gdk_texture_get_color_state (GdkTexture *self) void gdk_texture_do_download (GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride) { - GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, data, stride); + GDK_TEXTURE_GET_CLASS (texture)->download (texture, format, color_state, data, stride); } static gboolean @@ -1006,6 +1008,7 @@ gdk_texture_download (GdkTexture *texture, gdk_texture_do_download (texture, GDK_MEMORY_DEFAULT, + GDK_COLOR_STATE_SRGB, data, stride); } diff --git a/gdk/gdktexturedownloader.c b/gdk/gdktexturedownloader.c index 7ce693c7f4..e22199de7b 100644 --- a/gdk/gdktexturedownloader.c +++ b/gdk/gdktexturedownloader.c @@ -36,6 +36,7 @@ #include "gdktexturedownloaderprivate.h" +#include "gdkcolorstateprivate.h" #include "gdkmemoryformatprivate.h" #include "gdkmemorytextureprivate.h" #include "gdktextureprivate.h" @@ -51,12 +52,14 @@ gdk_texture_downloader_init (GdkTextureDownloader *self, { self->texture = g_object_ref (texture); self->format = GDK_MEMORY_DEFAULT; + self->color_state = gdk_color_state_ref (GDK_COLOR_STATE_SRGB); } void gdk_texture_downloader_finish (GdkTextureDownloader *self) { g_object_unref (self->texture); + gdk_color_state_unref (self->color_state); } /** @@ -199,6 +202,45 @@ gdk_texture_downloader_get_format (const GdkTextureDownloader *self) return self->format; } +/** + * gdk_texture_downloader_set_color_state: + * @self: a texture downloader + * @color_state: the color state to use + * + * Sets the color state the downloader will convert the data to. + * + * By default, the sRGB colorstate returned by [func@ColorState.get_srgb] + * is used. + * + * Since: 4.16 + */ +void +gdk_texture_downloader_set_color_state (GdkTextureDownloader *self, + GdkColorState *color_state) +{ + if (self->color_state == color_state) + return; + + gdk_color_state_unref (self->color_state); + self->color_state = gdk_color_state_ref (color_state); +} + +/** + * gdk_texture_downloader_get_color_state: + * @self: a texture downloader + * + * Gets the color state that the data will be downloaded in. + * + * Returns: The color state of the download + * + * Since: 4.16 + **/ +GdkColorState * +gdk_texture_downloader_get_color_state (const GdkTextureDownloader *self) +{ + return self->color_state; +} + /** * gdk_texture_downloader_download_into: * @self: a texture downloader @@ -219,7 +261,7 @@ gdk_texture_downloader_download_into (const GdkTextureDownloader *self, g_return_if_fail (data != NULL); g_return_if_fail (stride >= gdk_texture_get_width (self->texture) * gdk_memory_format_bytes_per_pixel (self->format)); - gdk_texture_do_download (self->texture, self->format, data, stride); + gdk_texture_do_download (self->texture, self->format, self->color_state, data, stride); } /** @@ -250,7 +292,8 @@ gdk_texture_downloader_download_bytes (const GdkTextureDownloader *self, g_return_val_if_fail (out_stride != NULL, NULL); if (GDK_IS_MEMORY_TEXTURE (self->texture) && - gdk_texture_get_format (self->texture) == self->format) + gdk_texture_get_format (self->texture) == self->format && + gdk_color_state_equal (gdk_texture_get_color_state (self->texture), self->color_state)) { GdkMemoryTexture *memtex = GDK_MEMORY_TEXTURE (self->texture); @@ -260,7 +303,7 @@ gdk_texture_downloader_download_bytes (const GdkTextureDownloader *self, stride = self->texture->width * gdk_memory_format_bytes_per_pixel (self->format); data = g_malloc_n (stride, self->texture->height); - gdk_texture_do_download (self->texture, self->format, data, stride); + gdk_texture_do_download (self->texture, self->format, self->color_state, data, stride); *out_stride = stride; return g_bytes_new_take (data, stride * self->texture->height); diff --git a/gdk/gdktexturedownloader.h b/gdk/gdktexturedownloader.h index e8c7df9a8b..a6bb681ccd 100644 --- a/gdk/gdktexturedownloader.h +++ b/gdk/gdktexturedownloader.h @@ -30,7 +30,7 @@ G_BEGIN_DECLS GDK_AVAILABLE_IN_4_10 GType gdk_texture_downloader_get_type (void) G_GNUC_CONST; GDK_AVAILABLE_IN_4_10 -GdkTextureDownloader * gdk_texture_downloader_new (GdkTexture *texture); +GdkTextureDownloader * gdk_texture_downloader_new (GdkTexture *texture); GDK_AVAILABLE_IN_4_10 GdkTextureDownloader * gdk_texture_downloader_copy (const GdkTextureDownloader *self); @@ -48,6 +48,11 @@ void gdk_texture_downloader_set_format (GdkTextureDownl GdkMemoryFormat format); GDK_AVAILABLE_IN_4_10 GdkMemoryFormat gdk_texture_downloader_get_format (const GdkTextureDownloader *self); +GDK_AVAILABLE_IN_4_16 +void gdk_texture_downloader_set_color_state (GdkTextureDownloader *self, + GdkColorState *color_state); +GDK_AVAILABLE_IN_4_16 +GdkColorState * gdk_texture_downloader_get_color_state (const GdkTextureDownloader *self); GDK_AVAILABLE_IN_4_10 diff --git a/gdk/gdktexturedownloaderprivate.h b/gdk/gdktexturedownloaderprivate.h index 867788d3fb..16a924ff37 100644 --- a/gdk/gdktexturedownloaderprivate.h +++ b/gdk/gdktexturedownloaderprivate.h @@ -28,6 +28,7 @@ struct _GdkTextureDownloader /*< private >*/ GdkTexture *texture; GdkMemoryFormat format; + GdkColorState *color_state; }; void gdk_texture_downloader_init (GdkTextureDownloader *self, diff --git a/gdk/gdktextureprivate.h b/gdk/gdktextureprivate.h index d46d2d2bc4..007f3c244e 100644 --- a/gdk/gdktextureprivate.h +++ b/gdk/gdktextureprivate.h @@ -48,6 +48,7 @@ struct _GdkTextureClass { /* mandatory: Download in the given format into data */ void (* download) (GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride); }; @@ -62,6 +63,7 @@ GdkMemoryDepth gdk_texture_get_depth (GdkTexture void gdk_texture_do_download (GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride); void gdk_texture_diff (GdkTexture *self, diff --git a/gsk/gl/gskglglyphlibrary.c b/gsk/gl/gskglglyphlibrary.c index ef26de9876..c6d85f7809 100644 --- a/gsk/gl/gskglglyphlibrary.c +++ b/gsk/gl/gskglglyphlibrary.c @@ -281,9 +281,11 @@ gsk_gl_glyph_library_upload_glyph (GskGLGlyphLibrary *self, pixel_data = free_data = g_malloc (width * height * 4); gdk_memory_convert (pixel_data, width * 4, GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + GDK_COLOR_STATE_SRGB, cairo_image_surface_get_data (surface), stride, GDK_MEMORY_DEFAULT, + GDK_COLOR_STATE_SRGB, width, height); stride = width * 4; gl_format = GL_RGBA; diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index d12a1d4f67..bd02c50888 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -104,6 +104,7 @@ static void gsk_gl_renderer_dmabuf_downloader_download (GdkDmabufDownloader *downloader_, GdkDmabufTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride) { @@ -125,6 +126,7 @@ gsk_gl_renderer_dmabuf_downloader_download (GdkDmabufDownloader *downloader_, downloader = gdk_texture_downloader_new (native); gdk_texture_downloader_set_format (downloader, format); + gdk_texture_downloader_set_color_state (downloader, color_state); gdk_texture_downloader_download_into (downloader, data, stride); gdk_texture_downloader_free (downloader); diff --git a/gsk/gpu/gskgpuframe.c b/gsk/gpu/gskgpuframe.c index 28d75876f0..fddfdeccbd 100644 --- a/gsk/gpu/gskgpuframe.c +++ b/gsk/gpu/gskgpuframe.c @@ -653,6 +653,7 @@ typedef struct _Download Download; struct _Download { GdkMemoryFormat format; + GdkColorState *color_state; guchar *data; gsize stride; }; @@ -666,6 +667,7 @@ do_download (gpointer user_data, gdk_texture_downloader_init (&downloader, texture); gdk_texture_downloader_set_format (&downloader, download->format); + gdk_texture_downloader_set_color_state (&downloader, download->color_state); gdk_texture_downloader_download_into (&downloader, download->data, download->stride); gdk_texture_downloader_finish (&downloader); @@ -677,6 +679,7 @@ gsk_gpu_frame_download_texture (GskGpuFrame *self, gint64 timestamp, GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride) { @@ -702,6 +705,7 @@ gsk_gpu_frame_download_texture (GskGpuFrame *self, do_download, g_memdup (&(Download) { .format = format, + .color_state = color_state, .data = data, .stride = stride }, sizeof (Download))); diff --git a/gsk/gpu/gskgpuframeprivate.h b/gsk/gpu/gskgpuframeprivate.h index 9e6d5bb0c9..90a7eef2b6 100644 --- a/gsk/gpu/gskgpuframeprivate.h +++ b/gsk/gpu/gskgpuframeprivate.h @@ -84,6 +84,7 @@ void gsk_gpu_frame_download_texture (GskGpuF gint64 timestamp, GdkTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride); GskGpuOp *gsk_gpu_frame_get_last_op (GskGpuFrame *self); diff --git a/gsk/gpu/gskgpurenderer.c b/gsk/gpu/gskgpurenderer.c index 57130e62c8..1ec4bbd0da 100644 --- a/gsk/gpu/gskgpurenderer.c +++ b/gsk/gpu/gskgpurenderer.c @@ -107,6 +107,7 @@ static void gsk_gpu_renderer_dmabuf_downloader_download (GdkDmabufDownloader *downloader, GdkDmabufTexture *texture, GdkMemoryFormat format, + GdkColorState *color_state, guchar *data, gsize stride) { @@ -121,6 +122,7 @@ gsk_gpu_renderer_dmabuf_downloader_download (GdkDmabufDownloader *downloader, g_get_monotonic_time (), GDK_TEXTURE (texture), format, + color_state, data, stride); From 3c8a93b972d15e6c093b694679d988f8f7325abd Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 14 Jul 2024 20:05:41 +0200 Subject: [PATCH 02/11] gdk: Add GdkMemoryTextureBuilder Same thing as dmabuf and GL texture builders. Preparation for adding color state support to texture constructors. As a bonus, we can now do update regions with memory textures. --- gdk/gdk.h | 1 + gdk/gdkmemorytexture.c | 40 +++ gdk/gdkmemorytexturebuilder.c | 656 ++++++++++++++++++++++++++++++++++ gdk/gdkmemorytexturebuilder.h | 83 +++++ gdk/gdkmemorytextureprivate.h | 3 + gdk/meson.build | 2 + 6 files changed, 785 insertions(+) create mode 100644 gdk/gdkmemorytexturebuilder.c create mode 100644 gdk/gdkmemorytexturebuilder.h diff --git a/gdk/gdk.h b/gdk/gdk.h index f63867c555..00ff4793db 100644 --- a/gdk/gdk.h +++ b/gdk/gdk.h @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index b715a7ddf7..d29c8df247 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -126,6 +126,46 @@ gdk_memory_sanitize (GBytes *bytes, return g_bytes_new_take (copy, copy_stride * height); } +GdkTexture * +gdk_memory_texture_new_from_builder (GdkMemoryTextureBuilder *builder) +{ + GdkMemoryTexture *self; + GdkTexture *texture, *update_texture; + + self = g_object_new (GDK_TYPE_MEMORY_TEXTURE, + "width", gdk_memory_texture_builder_get_width (builder), + "height", gdk_memory_texture_builder_get_height (builder), + "color-state", GDK_COLOR_STATE_SRGB, + NULL); + texture = GDK_TEXTURE (self); + + texture->format = gdk_memory_texture_builder_get_format (builder); + self->bytes = gdk_memory_sanitize (g_bytes_ref (gdk_memory_texture_builder_get_bytes (builder)), + texture->width, + texture->height, + texture->format, + gdk_memory_texture_builder_get_stride (builder), + &self->stride); + + update_texture = gdk_memory_texture_builder_get_update_texture (builder); + if (update_texture) + { + cairo_region_t *update_region = gdk_memory_texture_builder_get_update_region (builder); + if (update_region) + { + update_region = cairo_region_copy (update_region); + cairo_region_intersect_rectangle (update_region, + &(cairo_rectangle_int_t) { + 0, 0, + update_texture->width, update_texture->height + }); + gdk_texture_set_diff (GDK_TEXTURE (self), update_texture, update_region); + } + } + + return GDK_TEXTURE (self); +} + /** * gdk_memory_texture_new: * @width: the width of the texture diff --git a/gdk/gdkmemorytexturebuilder.c b/gdk/gdkmemorytexturebuilder.c new file mode 100644 index 0000000000..e74922a5f0 --- /dev/null +++ b/gdk/gdkmemorytexturebuilder.c @@ -0,0 +1,656 @@ +/* + * Copyright © 2024 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#include "config.h" + +#include "gdkmemorytexturebuilder.h" + +#include "gdkenumtypes.h" +#include "gdkmemorytextureprivate.h" + +#include + +struct _GdkMemoryTextureBuilder +{ + GObject parent_instance; + + GBytes *bytes; + gsize stride; + int width; + int height; + GdkMemoryFormat format; + + GdkTexture *update_texture; + cairo_region_t *update_region; +}; + +struct _GdkMemoryTextureBuilderClass +{ + GObjectClass parent_class; +}; + +/** + * GdkMemoryTextureBuilder: + * + * `GdkMemoryTextureBuilder` is a builder used to construct [class@Gdk.Texture] objects + * from system memory provided via [struct@GLib.Bytes]. + * + * The operation is quite simple: Create a texture builder, set all the necessary + * properties - keep in mind that the properties [property@Gdk.MemoryTextureBuilder:bytes], + * [property@Gdk.MemoryTextureBuilder:stride], [property@Gdk.MemoryTextureBuilder:width], + * and [property@Gdk.MemoryTextureBuilder:height] are mandatory - and then call + * [method@Gdk.MemoryTextureBuilder.build] to create the new texture. + * + * `GdkMemoryTextureBuilder` can be used for quick one-shot construction of + * textures as well as kept around and reused to construct multiple textures. + * + * Since: 4.16 + */ + +enum +{ + PROP_0, + PROP_BYTES, + PROP_FORMAT, + PROP_HEIGHT, + PROP_STRIDE, + PROP_UPDATE_REGION, + PROP_UPDATE_TEXTURE, + PROP_WIDTH, + + N_PROPS +}; + +G_DEFINE_TYPE (GdkMemoryTextureBuilder, gdk_memory_texture_builder, G_TYPE_OBJECT) + +static GParamSpec *properties[N_PROPS] = { NULL, }; + +static void +gdk_memory_texture_builder_dispose (GObject *object) +{ + GdkMemoryTextureBuilder *self = GDK_MEMORY_TEXTURE_BUILDER (object); + + g_clear_pointer (&self->bytes, g_bytes_unref); + + g_clear_object (&self->update_texture); + g_clear_pointer (&self->update_region, cairo_region_destroy); + + G_OBJECT_CLASS (gdk_memory_texture_builder_parent_class)->dispose (object); +} + +static void +gdk_memory_texture_builder_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GdkMemoryTextureBuilder *self = GDK_MEMORY_TEXTURE_BUILDER (object); + + switch (property_id) + { + case PROP_BYTES: + g_value_set_boxed (value, self->bytes); + break; + + case PROP_FORMAT: + g_value_set_enum (value, self->format); + break; + + case PROP_HEIGHT: + g_value_set_int (value, self->height); + break; + + case PROP_STRIDE: + g_value_set_uint64 (value, self->stride); + break; + + case PROP_UPDATE_REGION: + g_value_set_boxed (value, self->update_region); + break; + + case PROP_UPDATE_TEXTURE: + g_value_set_object (value, self->update_texture); + break; + + case PROP_WIDTH: + g_value_set_int (value, self->width); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gdk_memory_texture_builder_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GdkMemoryTextureBuilder *self = GDK_MEMORY_TEXTURE_BUILDER (object); + + switch (property_id) + { + case PROP_BYTES: + gdk_memory_texture_builder_set_bytes (self, g_value_get_boxed (value)); + break; + + case PROP_FORMAT: + gdk_memory_texture_builder_set_format (self, g_value_get_enum (value)); + break; + + case PROP_HEIGHT: + gdk_memory_texture_builder_set_height (self, g_value_get_int (value)); + break; + + case PROP_STRIDE: + gdk_memory_texture_builder_set_stride (self, g_value_get_uint64 (value)); + break; + + case PROP_UPDATE_REGION: + gdk_memory_texture_builder_set_update_region (self, g_value_get_boxed (value)); + break; + + case PROP_UPDATE_TEXTURE: + gdk_memory_texture_builder_set_update_texture (self, g_value_get_object (value)); + break; + + case PROP_WIDTH: + gdk_memory_texture_builder_set_width (self, g_value_get_int (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gdk_memory_texture_builder_class_init (GdkMemoryTextureBuilderClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = gdk_memory_texture_builder_dispose; + gobject_class->get_property = gdk_memory_texture_builder_get_property; + gobject_class->set_property = gdk_memory_texture_builder_set_property; + + /** + * GdkMemoryTextureBuilder:bytes: + * + * The bytes holding the data. + * + * Since: 4.16 + */ + properties[PROP_BYTES] = + g_param_spec_boxed ("bytes", NULL, NULL, + G_TYPE_BYTES, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GdkMemoryTextureBuilder:format: + * + * The format of the data. + * + * Since: 4.16 + */ + properties[PROP_FORMAT] = + g_param_spec_enum ("format", NULL, NULL, + GDK_TYPE_MEMORY_FORMAT, + GDK_MEMORY_R8G8B8A8_PREMULTIPLIED, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GdkMemoryTextureBuilder:height: + * + * The height of the texture. + * + * Since: 4.16 + */ + properties[PROP_HEIGHT] = + g_param_spec_int ("height", NULL, NULL, + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GdkMemoryTextureBuilder:stride: + * + * The rowstride of the texture. + * + * The rowstride is the number of bytes between the first pixel + * in a row of image data, and the first pixel in the next row. + * + * Since: 4.16 + */ + properties[PROP_STRIDE] = + g_param_spec_uint64 ("stride", NULL, NULL, + 0, G_MAXUINT64, 0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GdkMemoryTextureBuilder:update-region: + * + * The update region for [property@Gdk.MemoryTextureBuilder:update-texture]. + * + * Since: 4.16 + */ + properties[PROP_UPDATE_REGION] = + g_param_spec_boxed ("update-region", NULL, NULL, + CAIRO_GOBJECT_TYPE_REGION, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GdkMemoryTextureBuilder:update-texture: + * + * The texture [property@Gdk.MemoryTextureBuilder:update-region] is an update for. + * + * Since: 4.16 + */ + properties[PROP_UPDATE_TEXTURE] = + g_param_spec_object ("update-texture", NULL, NULL, + GDK_TYPE_TEXTURE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + /** + * GdkMemoryTextureBuilder:width: + * + * The width of the texture. + * + * Since: 4.16 + */ + properties[PROP_WIDTH] = + g_param_spec_int ("width", NULL, NULL, + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (gobject_class, N_PROPS, properties); +} + +static void +gdk_memory_texture_builder_init (GdkMemoryTextureBuilder *self) +{ + self->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; +} + +/** + * gdk_memory_texture_builder_new: (constructor): + * + * Creates a new texture builder. + * + * Returns: the new `GdkTextureBuilder` + * + * Since: 4.16 + **/ +GdkMemoryTextureBuilder * +gdk_memory_texture_builder_new (void) +{ + return g_object_new (GDK_TYPE_MEMORY_TEXTURE_BUILDER, NULL); +} + +/** + * gdk_memory_texture_builder_get_bytes: + * @self: a `GdkMemoryTextureBuilder` + * + * Gets the bytes previously set via gdk_memory_texture_builder_set_bytes() + * or %NULL if none was set. + * + * Returns: (transfer none) (nullable): The bytes + * + * Since: 4.16 + */ +GBytes * +gdk_memory_texture_builder_get_bytes (GdkMemoryTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self), NULL); + + return self->bytes; +} + +/** + * gdk_memory_texture_builder_set_bytes: (attributes org.gtk.Method.set_property=bytes) + * @self: a `GdkMemoryTextureBuilder` + * @bytes: (nullable): The bytes the texture shows or %NULL to unset + * + * Sets the data to be shown but the texture. + * + * The bytes must be set before calling [method@Gdk.MemoryTextureBuilder.build]. + * + * Since: 4.16 + */ +void +gdk_memory_texture_builder_set_bytes (GdkMemoryTextureBuilder *self, + GBytes *bytes) +{ + g_return_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self)); + g_return_if_fail (bytes != NULL); + + if (self->bytes == bytes) + return; + + g_clear_pointer (&self->bytes, g_bytes_unref); + self->bytes = bytes; + if (bytes) + g_bytes_ref (bytes); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BYTES]); +} + +/** + * gdk_memory_texture_builder_get_height: (attributes org.gtk.Method.get_property=height) + * @self: a `GdkMemoryTextureBuilder` + * + * Gets the height previously set via gdk_memory_texture_builder_set_height() + * or 0 if the height wasn't set. + * + * Returns: The height + * + * Since: 4.16 + */ +int +gdk_memory_texture_builder_get_height (GdkMemoryTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self), 0); + + return self->height; +} + +/** + * gdk_memory_texture_builder_set_height: (attributes org.gtk.Method.set_property=height) + * @self: a `GdkMemoryTextureBuilder` + * @height: The texture's height or 0 to unset + * + * Sets the height of the texture. + * + * The height must be set before calling [method@Gdk.MemoryTextureBuilder.build]. + * + * Since: 4.16 + */ +void +gdk_memory_texture_builder_set_height (GdkMemoryTextureBuilder *self, + int height) +{ + g_return_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self)); + + if (self->height == height) + return; + + self->height = height; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_HEIGHT]); +} + +/** + * gdk_memory_texture_builder_get_width: (attributes org.gtk.Method.get_property=width) + * @self: a `GdkMemoryTextureBuilder` + * + * Gets the width previously set via gdk_memory_texture_builder_set_width() + * or 0 if the width wasn't set. + * + * Returns: The width + * + * Since: 4.16 + */ +int +gdk_memory_texture_builder_get_width (GdkMemoryTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self), 0); + + return self->width; +} + +/** + * gdk_memory_texture_builder_set_width: (attributes org.gtk.Method.set_property=width) + * @self: a `GdkMemoryTextureBuilder` + * @width: The texture's width or 0 to unset + * + * Sets the width of the texture. + * + * The width must be set before calling [method@Gdk.MemoryTextureBuilder.build]. + * + * Since: 4.16 + */ +void +gdk_memory_texture_builder_set_width (GdkMemoryTextureBuilder *self, + int width) +{ + g_return_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self)); + + if (self->width == width) + return; + + self->width = width; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_WIDTH]); +} + +/* gdk_memory_texture_builder_get_stride: (attributes org.gtk.Method.get_property=stride) */ +/** + * gdk_memory_texture_builder_get_stride: + * @self: a `GdkMemoryTextureBuilder` + * + * Gets the stride previously set via gdk_memory_texture_builder_set_stride(). + * + * Returns: the stride + * + * Since: 4.16 + */ +gsize +gdk_memory_texture_builder_get_stride (GdkMemoryTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self), 0); + + return self->stride; +} + + /* gdk_memory_texture_builder_set_stride: (attributes org.gtk.Method.set_property=stride) */ +/** + * gdk_memory_texture_builder_set_stride: + * @self: a `GdkMemoryTextureBuilder` + * @stride: the stride or 0 to unset + * + * Sets the rowstride of the bytes used. + * + * The rowstride must be set before calling [method@Gdk.MemoryTextureBuilder.build]. + * + * Since: 4.16 + */ +void +gdk_memory_texture_builder_set_stride (GdkMemoryTextureBuilder *self, + gsize stride) +{ + g_return_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self)); + + if (self->stride == stride) + return; + + self->stride = stride; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_STRIDE]); +} + +/** + * gdk_memory_texture_builder_get_format: (attributes org.gtk.Method.get_property=format) + * @self: a `GdkMemoryTextureBuilder` + * + * Gets the format previously set via gdk_memory_texture_builder_set_format(). + * + * Returns: The format + * + * Since: 4.16 + */ +GdkMemoryFormat +gdk_memory_texture_builder_get_format (GdkMemoryTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self), GDK_MEMORY_R8G8B8A8_PREMULTIPLIED); + + return self->format; +} + +/** + * gdk_memory_texture_builder_set_format: (attributes org.gtk.Method.set_property=format) + * @self: a `GdkMemoryTextureBuilder` + * @format: The texture's format + * + * Sets the format of the bytes. + * + * The default is `GDK_MEMORY_R8G8B8A8_PREMULTIPLIED`. + * + * Since: 4.16 + */ +void +gdk_memory_texture_builder_set_format (GdkMemoryTextureBuilder *self, + GdkMemoryFormat format) +{ + g_return_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self)); + + if (self->format == format) + return; + + self->format = format; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_FORMAT]); +} + +/** + * gdk_memory_texture_builder_get_update_texture: (attributes org.gtk.Method.get_property=update-texture) + * @self: a `GdkMemoryTextureBuilder` + * + * Gets the texture previously set via gdk_memory_texture_builder_set_update_texture() + * or %NULL if none was set. + * + * Returns: (transfer none) (nullable): The update texture + * + * Since: 4.16 + */ +GdkTexture * +gdk_memory_texture_builder_get_update_texture (GdkMemoryTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self), NULL); + + return self->update_texture; +} + +/** + * gdk_memory_texture_builder_set_update_texture: (attributes org.gtk.Method.set_property=update-texture) + * @self: a `GdkMemoryTextureBuilder` + * @texture: (nullable): the texture to update + * + * Sets the texture to be updated by this texture. + * + * See [method@Gdk.MemoryTextureBuilder.set_update_region] for an explanation. + * + * Since: 4.16 + */ +void +gdk_memory_texture_builder_set_update_texture (GdkMemoryTextureBuilder *self, + GdkTexture *texture) +{ + g_return_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self)); + g_return_if_fail (texture == NULL || GDK_IS_TEXTURE (texture)); + + if (!g_set_object (&self->update_texture, texture)) + return; + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_TEXTURE]); +} + +/** + * gdk_memory_texture_builder_get_update_region: (attributes org.gtk.Method.get_property=update-region) + * @self: a `GdkMemoryTextureBuilder` + * + * Gets the region previously set via gdk_memory_texture_builder_set_update_region() + * or %NULL if none was set. + * + * Returns: (transfer none) (nullable): The update region + * + * Since: 4.16 + */ +cairo_region_t * +gdk_memory_texture_builder_get_update_region (GdkMemoryTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self), NULL); + + return self->update_region; +} + +/** + * gdk_memory_texture_builder_set_update_region: (attributes org.gtk.Method.set_property=update-region) + * @self: a `GdkMemoryTextureBuilder` + * @region: (nullable): the region to update + * + * Sets the region to be updated by this texture. + * + * Together with [property@Gdk.MemoryTextureBuilder:update-texture], + * this describes an update of a previous texture. + * + * When rendering animations of large textures, it is possible that + * consecutive textures are only updating contents in parts of the texture. + * It is then possible to describe this update via these two properties, + * so that GTK can avoid rerendering parts that did not change. + * + * An example would be a screen recording where only the mouse pointer moves. + * + * Since: 4.16 + */ +void +gdk_memory_texture_builder_set_update_region (GdkMemoryTextureBuilder *self, + cairo_region_t *region) +{ + g_return_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self)); + + if (self->update_region == region) + return; + + g_clear_pointer (&self->update_region, cairo_region_destroy); + + if (region) + self->update_region = cairo_region_reference (region); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_UPDATE_REGION]); +} + +/** + * gdk_memory_texture_builder_build: + * @self: a `GdkMemoryTextureBuilder` + * + * Builds a new `GdkTexture` with the values set up in the builder. + * + * Note that it is a programming error to call this function if any mandatory + * property has not been set. + * + * It is possible to call this function multiple times to create multiple textures, + * possibly with changing properties in between. + * + * Returns: (transfer full): a newly built `GdkTexture` + * + * Since: 4.16 + */ +GdkTexture * +gdk_memory_texture_builder_build (GdkMemoryTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self), NULL); + g_return_val_if_fail (self->width > 0, NULL); + g_return_val_if_fail (self->height > 0, NULL); + g_return_val_if_fail (self->bytes != NULL, NULL); + g_return_val_if_fail (self->stride >= self->width * gdk_memory_format_bytes_per_pixel (self->format), NULL); + /* needs to be this complex to support subtexture of the bottom right part */ + g_return_val_if_fail (g_bytes_get_size (self->bytes) >= gdk_memory_format_min_buffer_size (self->format, self->stride, self->width, self->height), NULL); + + return gdk_memory_texture_new_from_builder (self); +} diff --git a/gdk/gdkmemorytexturebuilder.h b/gdk/gdkmemorytexturebuilder.h new file mode 100644 index 0000000000..81266d2977 --- /dev/null +++ b/gdk/gdkmemorytexturebuilder.h @@ -0,0 +1,83 @@ +/* + * Copyright © 2024 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + +#pragma once + +#if !defined (__GDK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +#define GDK_TYPE_MEMORY_TEXTURE_BUILDER (gdk_memory_texture_builder_get_type ()) +GDK_AVAILABLE_IN_4_16 +GDK_DECLARE_INTERNAL_TYPE (GdkMemoryTextureBuilder, gdk_memory_texture_builder, GDK, MEMORY_TEXTURE_BUILDER, GObject) + +GDK_AVAILABLE_IN_4_16 +GdkMemoryTextureBuilder * gdk_memory_texture_builder_new (void); + +GDK_AVAILABLE_IN_4_16 +GBytes * gdk_memory_texture_builder_get_bytes (GdkMemoryTextureBuilder *self) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_16 +void gdk_memory_texture_builder_set_bytes (GdkMemoryTextureBuilder *self, + GBytes *bytes); + +GDK_AVAILABLE_IN_4_16 +gsize gdk_memory_texture_builder_get_stride (GdkMemoryTextureBuilder *self) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_16 +void gdk_memory_texture_builder_set_stride (GdkMemoryTextureBuilder *self, + gsize stride); + +GDK_AVAILABLE_IN_4_16 +int gdk_memory_texture_builder_get_width (GdkMemoryTextureBuilder *self) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_16 +void gdk_memory_texture_builder_set_width (GdkMemoryTextureBuilder *self, + int width); + +GDK_AVAILABLE_IN_4_16 +int gdk_memory_texture_builder_get_height (GdkMemoryTextureBuilder *self) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_16 +void gdk_memory_texture_builder_set_height (GdkMemoryTextureBuilder *self, + int height); + +GDK_AVAILABLE_IN_4_16 +GdkMemoryFormat gdk_memory_texture_builder_get_format (GdkMemoryTextureBuilder *self) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_16 +void gdk_memory_texture_builder_set_format (GdkMemoryTextureBuilder *self, + GdkMemoryFormat format); + +GDK_AVAILABLE_IN_4_16 +GdkTexture * gdk_memory_texture_builder_get_update_texture (GdkMemoryTextureBuilder *self) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_16 +void gdk_memory_texture_builder_set_update_texture (GdkMemoryTextureBuilder *self, + GdkTexture *texture); + +GDK_AVAILABLE_IN_4_16 +cairo_region_t * gdk_memory_texture_builder_get_update_region (GdkMemoryTextureBuilder *self) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_16 +void gdk_memory_texture_builder_set_update_region (GdkMemoryTextureBuilder *self, + cairo_region_t *region); + +GDK_AVAILABLE_IN_4_16 +GdkTexture * gdk_memory_texture_builder_build (GdkMemoryTextureBuilder *self); + +G_END_DECLS + diff --git a/gdk/gdkmemorytextureprivate.h b/gdk/gdkmemorytextureprivate.h index b866a3871f..64b4ac5c15 100644 --- a/gdk/gdkmemorytextureprivate.h +++ b/gdk/gdkmemorytextureprivate.h @@ -21,6 +21,7 @@ #include "gdkmemorytexture.h" +#include "gdkmemorytexturebuilder.h" #include "gdktextureprivate.h" G_BEGIN_DECLS @@ -35,6 +36,8 @@ GdkTexture * gdk_memory_texture_new_subtexture (GdkMemoryTexture * int width, int height); +GdkTexture * gdk_memory_texture_new_from_builder (GdkMemoryTextureBuilder *builder); + GBytes * gdk_memory_texture_get_bytes (GdkMemoryTexture *self, gsize *out_stride); diff --git a/gdk/meson.build b/gdk/meson.build index 67cd1a0546..9e201bb517 100644 --- a/gdk/meson.build +++ b/gdk/meson.build @@ -46,6 +46,7 @@ gdk_public_sources = files([ 'gdkkeyuni.c', 'gdkmemoryformat.c', 'gdkmemorytexture.c', + 'gdkmemorytexturebuilder.c', 'gdkmonitor.c', 'gdkpaintable.c', 'gdkpango.c', @@ -106,6 +107,7 @@ gdk_public_headers = files([ 'gdkkeys.h', 'gdkkeysyms.h', 'gdkmemorytexture.h', + 'gdkmemorytexturebuilder.h', 'gdkmonitor.h', 'gdkpaintable.h', 'gdkpango.h', From 05953a20cc751d3660aab8e2a4aabe90f3b9329b Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 16 Jul 2024 19:48:06 +0200 Subject: [PATCH 03/11] testsuite: Allow colorstate properties to have SRGB as default value This needs custom code because boxed paramspecs always default to NULL. But we want to always default to SRGB. --- testsuite/gtk/defaultvalue.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/testsuite/gtk/defaultvalue.c b/testsuite/gtk/defaultvalue.c index b771255a2d..4734f80120 100644 --- a/testsuite/gtk/defaultvalue.c +++ b/testsuite/gtk/defaultvalue.c @@ -29,7 +29,11 @@ check_property (const char *output, char *v, *dv, *msg; if (g_param_value_defaults (pspec, value)) - return; + return; + + if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_COLOR_STATE && + g_value_get_boxed (value) == gdk_color_state_get_srgb ()) + return; g_value_init (&default_value, G_PARAM_SPEC_VALUE_TYPE (pspec)); g_param_value_set_default (pspec, &default_value); From 5e1c3c5d69143bdcd9399c9e9dd216354338176f Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 14 Jul 2024 21:52:00 +0200 Subject: [PATCH 04/11] gdk: Add GdkMemoryTexture::color-state This allows setting the color state of textures. --- gdk/gdkmemorytexture.c | 2 +- gdk/gdkmemorytexturebuilder.c | 73 +++++++++++++++++++++++++++++++++++ gdk/gdkmemorytexturebuilder.h | 6 +++ 3 files changed, 80 insertions(+), 1 deletion(-) diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index d29c8df247..8c93586402 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -135,7 +135,7 @@ gdk_memory_texture_new_from_builder (GdkMemoryTextureBuilder *builder) self = g_object_new (GDK_TYPE_MEMORY_TEXTURE, "width", gdk_memory_texture_builder_get_width (builder), "height", gdk_memory_texture_builder_get_height (builder), - "color-state", GDK_COLOR_STATE_SRGB, + "color-state", gdk_memory_texture_builder_get_color_state (builder), NULL); texture = GDK_TEXTURE (self); diff --git a/gdk/gdkmemorytexturebuilder.c b/gdk/gdkmemorytexturebuilder.c index e74922a5f0..84115365b2 100644 --- a/gdk/gdkmemorytexturebuilder.c +++ b/gdk/gdkmemorytexturebuilder.c @@ -21,6 +21,7 @@ #include "gdkmemorytexturebuilder.h" +#include "gdkcolorstate.h" #include "gdkenumtypes.h" #include "gdkmemorytextureprivate.h" @@ -35,6 +36,7 @@ struct _GdkMemoryTextureBuilder int width; int height; GdkMemoryFormat format; + GdkColorState *color_state; GdkTexture *update_texture; cairo_region_t *update_region; @@ -67,6 +69,7 @@ enum { PROP_0, PROP_BYTES, + PROP_COLOR_STATE, PROP_FORMAT, PROP_HEIGHT, PROP_STRIDE, @@ -87,6 +90,7 @@ gdk_memory_texture_builder_dispose (GObject *object) GdkMemoryTextureBuilder *self = GDK_MEMORY_TEXTURE_BUILDER (object); g_clear_pointer (&self->bytes, g_bytes_unref); + g_clear_pointer (&self->color_state, gdk_color_state_unref); g_clear_object (&self->update_texture); g_clear_pointer (&self->update_region, cairo_region_destroy); @@ -108,6 +112,10 @@ gdk_memory_texture_builder_get_property (GObject *object, g_value_set_boxed (value, self->bytes); break; + case PROP_COLOR_STATE: + g_value_set_boxed (value, self->color_state); + break; + case PROP_FORMAT: g_value_set_enum (value, self->format); break; @@ -152,6 +160,10 @@ gdk_memory_texture_builder_set_property (GObject *object, gdk_memory_texture_builder_set_bytes (self, g_value_get_boxed (value)); break; + case PROP_COLOR_STATE: + gdk_memory_texture_builder_set_color_state (self, g_value_get_boxed (value)); + break; + case PROP_FORMAT: gdk_memory_texture_builder_set_format (self, g_value_get_enum (value)); break; @@ -203,6 +215,18 @@ gdk_memory_texture_builder_class_init (GdkMemoryTextureBuilderClass *klass) G_TYPE_BYTES, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** + * GdkMemoryTextureBuilder:color-state: + * + * The colorstate describing the data. + * + * Since: 4.16 + */ + properties[PROP_COLOR_STATE] = + g_param_spec_boxed ("color-state", NULL, NULL, + GDK_TYPE_COLOR_STATE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** * GdkMemoryTextureBuilder:format: * @@ -286,6 +310,7 @@ static void gdk_memory_texture_builder_init (GdkMemoryTextureBuilder *self) { self->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; + self->color_state = gdk_color_state_ref (gdk_color_state_get_srgb ()); } /** @@ -351,6 +376,54 @@ gdk_memory_texture_builder_set_bytes (GdkMemoryTextureBuilder *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_BYTES]); } +/** + * gdk_memory_texture_builder_get_color_state: (attributes org.gtk.Method.get_property=color-state) + * @self: a `GdkMemoryTextureBuilder` + * + * Gets the colorstate previously set via gdk_memory_texture_builder_set_color_state(). + * + * Returns: (transfer none): The colorstate + * + * Since: 4.16 + */ +GdkColorState * +gdk_memory_texture_builder_get_color_state (GdkMemoryTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self), NULL); + + return self->color_state; +} + +/** + * gdk_memory_texture_builder_set_color_state: (attributes org.gtk.Method.set_property=color-state) + * @self: a `GdkMemoryTextureBuilder` + * @color_state: (nullable): The colorstate describing the data + * + * Sets the colorstate describing the data. + * + * By default, the sRGB colorstate is used. If you don't know + * what colorstates are, this is probably the right thing. + * + * Since: 4.16 + */ +void +gdk_memory_texture_builder_set_color_state (GdkMemoryTextureBuilder *self, + GdkColorState *color_state) +{ + g_return_if_fail (GDK_IS_MEMORY_TEXTURE_BUILDER (self)); + g_return_if_fail (color_state != NULL); + + if (self->color_state == color_state) + return; + + g_clear_pointer (&self->color_state, gdk_color_state_unref); + self->color_state = color_state; + if (color_state) + gdk_color_state_ref (color_state); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_STATE]); +} + /** * gdk_memory_texture_builder_get_height: (attributes org.gtk.Method.get_property=height) * @self: a `GdkMemoryTextureBuilder` diff --git a/gdk/gdkmemorytexturebuilder.h b/gdk/gdkmemorytexturebuilder.h index 81266d2977..67c451836b 100644 --- a/gdk/gdkmemorytexturebuilder.h +++ b/gdk/gdkmemorytexturebuilder.h @@ -64,6 +64,12 @@ GDK_AVAILABLE_IN_4_16 void gdk_memory_texture_builder_set_format (GdkMemoryTextureBuilder *self, GdkMemoryFormat format); +GDK_AVAILABLE_IN_4_16 +GdkColorState * gdk_memory_texture_builder_get_color_state (GdkMemoryTextureBuilder *self) G_GNUC_PURE; +GDK_AVAILABLE_IN_4_16 +void gdk_memory_texture_builder_set_color_state (GdkMemoryTextureBuilder *self, + GdkColorState *color_state); + GDK_AVAILABLE_IN_4_16 GdkTexture * gdk_memory_texture_builder_get_update_texture (GdkMemoryTextureBuilder *self) G_GNUC_PURE; GDK_AVAILABLE_IN_4_16 From 77da45a17343748c6e1ac8757126b29da2c9d60b Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 14 Jul 2024 21:13:10 +0200 Subject: [PATCH 05/11] testsuite: Update colorstate test --- testsuite/gdk/colorstate.c | 163 +++++++++++++++++++++++++++---------- testsuite/gdk/meson.build | 2 +- 2 files changed, 119 insertions(+), 46 deletions(-) diff --git a/testsuite/gdk/colorstate.c b/testsuite/gdk/colorstate.c index 28746e5fb3..9b4d0c9fe8 100644 --- a/testsuite/gdk/colorstate.c +++ b/testsuite/gdk/colorstate.c @@ -1,35 +1,76 @@ #include -#include -#include #include -static void -test_srgb (void) +static GdkColorState * +get_color_state (guint id, + const char **out_name) { - GdkColorState *srgb; - GdkColorState *srgb_linear; + const char *unused; - srgb = gdk_color_state_get_srgb (); - srgb_linear = gdk_color_state_get_srgb_linear (); + if (out_name == NULL) + out_name = &unused; - g_assert_true (gdk_color_state_equal (srgb, srgb)); - g_assert_true (gdk_color_state_equal (srgb_linear, srgb_linear)); - g_assert_false (gdk_color_state_equal (srgb, srgb_linear)); + switch (id) + { + case 0: + *out_name = "srgb"; + return gdk_color_state_ref (gdk_color_state_get_srgb ()); + case 1: + *out_name = "srgb-linear"; + return gdk_color_state_ref (gdk_color_state_get_srgb_linear ()); + case 2: + *out_name = "rec2100-pq"; + return gdk_color_state_ref (gdk_color_state_get_rec2100_pq ()); + case 3: + *out_name = "rec2100-linear"; + return gdk_color_state_ref (gdk_color_state_get_rec2100_linear ()); + default: + return NULL; + } +} + +static void +test_equal (void) +{ + GdkColorState *csi, *csj; + guint i, j; + + for (i = 0; ; i++) + { + csi = get_color_state (i, NULL); + if (csi == NULL) + break; + + g_assert_true (gdk_color_state_equal (csi, csi)); + + for (j = 0; ; j++) + { + csj = get_color_state (j, NULL); + if (csj == NULL) + break; + + if (i != j) + g_assert_false (gdk_color_state_equal (csi, csj)); + else + g_assert_true (gdk_color_state_equal (csi, csj)); /* might break for non-default? */ + } + } } static float image_distance (const guchar *data, + gsize stride, const guchar *data2, + gsize stride2, gsize width, - gsize height, - gsize stride) + gsize height) { float dist = 0; for (gsize i = 0; i < height; i++) { const float *p = (const float *) (data + i * stride); - const float *p2 = (const float *) (data2 + i * stride); + const float *p2 = (const float *) (data2 + i * stride2); for (gsize j = 0; j < width; j++) { @@ -50,56 +91,72 @@ image_distance (const guchar *data, static void test_convert (gconstpointer testdata) { - GdkColorState *cs; + GdkColorState *cs = (GdkColorState *) testdata; char *path; - GdkTexture *texture; + GdkTexture *texture, *texture2; GdkTextureDownloader *downloader; + GdkMemoryTextureBuilder *membuild; GError *error = NULL; - GBytes *bytes; - const guchar *data; - guchar *data2; + GBytes *bytes, *bytes2; + const guchar *data, *data2; + gsize stride, stride2; gsize width, height; - gsize size; - gsize stride; + GdkMemoryFormat test_format; - cs = gdk_color_state_get_by_id ((GdkColorStateId) GPOINTER_TO_UINT (testdata)); + if (g_test_rand_bit ()) + test_format = GDK_MEMORY_R32G32B32A32_FLOAT_PREMULTIPLIED; + else + test_format = GDK_MEMORY_R32G32B32A32_FLOAT; path = g_test_build_filename (G_TEST_DIST, "image-data", "image.png", NULL); + /* Create a texture */ texture = gdk_texture_new_from_filename (path, &error); g_assert_no_error (error); - + g_assert_true (gdk_color_state_equal (gdk_texture_get_color_state (texture), + gdk_color_state_get_srgb ())); width = gdk_texture_get_width (texture); height = gdk_texture_get_height (texture); + /* download the texture as float for later comparison */ downloader = gdk_texture_downloader_new (texture); - gdk_texture_downloader_set_format (downloader, GDK_MEMORY_R32G32B32A32_FLOAT); - + gdk_texture_downloader_set_format (downloader, test_format); + gdk_texture_downloader_set_color_state (downloader, gdk_texture_get_color_state (texture)); bytes = gdk_texture_downloader_download_bytes (downloader, &stride); - data = g_bytes_get_data (bytes, &size); - data2 = g_memdup2 (data, size); + data = g_bytes_get_data (bytes, NULL); - gdk_memory_convert_color_state (data2, - stride, - GDK_MEMORY_R32G32B32A32_FLOAT, - gdk_texture_get_color_state (texture), - cs, - width, - height); + /* Download the texture into the test colorstate, this does a conversion */ + gdk_texture_downloader_set_color_state (downloader, cs); + bytes2 = gdk_texture_downloader_download_bytes (downloader, &stride2); - gdk_memory_convert_color_state (data2, - stride, - GDK_MEMORY_R32G32B32A32_FLOAT, - cs, - gdk_texture_get_color_state (texture), - width, - height); + /* Create a new texture in the test colorstate with the just downloaded data */ + membuild = gdk_memory_texture_builder_new (); + gdk_memory_texture_builder_set_format (membuild, test_format); + gdk_memory_texture_builder_set_color_state (membuild, cs); + gdk_memory_texture_builder_set_width (membuild, width); + gdk_memory_texture_builder_set_height (membuild, height); + gdk_memory_texture_builder_set_bytes (membuild, bytes2); + gdk_memory_texture_builder_set_stride (membuild, stride2); + texture2 = gdk_memory_texture_builder_build (membuild); + g_object_unref (membuild); + g_bytes_unref (bytes2); - g_assert_true (image_distance (data, data2, width, height, stride) < 0.001); + /* Download the data of the new texture in the original texture's colorstate. + * This does the reverse conversion. */ + gdk_texture_downloader_set_texture (downloader, texture2); + gdk_texture_downloader_set_color_state (downloader, gdk_texture_get_color_state (texture)); + bytes2 = gdk_texture_downloader_download_bytes (downloader, &stride2); + data2 = g_bytes_get_data (bytes2, NULL); - g_free (data2); + /* Check that the conversions produce pixels that are close enough */ + g_assert_cmpfloat (image_distance (data, stride, data2, stride2, width, height), <, 0.001); + + g_test_message ("%g\n", image_distance (data, stride, data2, stride2, width, height)); + + g_bytes_unref (bytes2); g_bytes_unref (bytes); gdk_texture_downloader_free (downloader); + g_object_unref (texture2); g_object_unref (texture); g_free (path); } @@ -107,10 +164,26 @@ test_convert (gconstpointer testdata) int main (int argc, char *argv[]) { + guint i; + (g_test_init) (&argc, &argv, NULL); - g_test_add_func ("/colorstate/srgb", test_srgb); - g_test_add_data_func ("/colorstate/convert/srgb<->srgb-linear", GUINT_TO_POINTER (GDK_COLOR_STATE_ID_SRGB_LINEAR), test_convert); + g_test_add_func ("/colorstate/equal", test_equal); + + for (i = 0; ; i++) + { + GdkColorState *csi; + const char *cs_name; + char *test_name; + + csi = get_color_state (i, &cs_name); + if (csi == NULL) + break; + + test_name = g_strdup_printf ("/colorstate/convert/srgb/%s", cs_name); + g_test_add_data_func_full (test_name, csi, test_convert, (GDestroyNotify) gdk_color_state_unref); + g_free (test_name); + } return g_test_run (); } diff --git a/testsuite/gdk/meson.build b/testsuite/gdk/meson.build index b28e82f0b8..56c9897753 100644 --- a/testsuite/gdk/meson.build +++ b/testsuite/gdk/meson.build @@ -10,6 +10,7 @@ tests = [ { 'name': 'array' }, { 'name': 'cairo' }, { 'name': 'clipboard', 'parallel': false, 'suites': 'flaky' }, + { 'name': 'colorstate' }, { 'name': 'contentformats' }, { 'name': 'contentserializer' }, { 'name': 'cursor' }, @@ -57,7 +58,6 @@ foreach t : tests endforeach internal_tests = [ - { 'name': 'colorstate' }, { 'name': 'dihedral' }, { 'name': 'image' }, { 'name': 'texture' }, From 0ee8ca43d1957bf1b93493591e148e79842691c7 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 7 Jun 2024 08:49:44 -0400 Subject: [PATCH 06/11] gl texture: color state support --- gdk/gdkgltexture.c | 2 +- gdk/gdkgltexturebuilder.c | 70 +++++++++++++++++++++++++++++++++++++++ gdk/gdkgltexturebuilder.h | 6 ++++ 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c index cf70085f90..6c90efa9d0 100644 --- a/gdk/gdkgltexture.c +++ b/gdk/gdkgltexture.c @@ -511,7 +511,7 @@ gdk_gl_texture_new_from_builder (GdkGLTextureBuilder *builder, self = g_object_new (GDK_TYPE_GL_TEXTURE, "width", gdk_gl_texture_builder_get_width (builder), "height", gdk_gl_texture_builder_get_height (builder), - "color-state", GDK_COLOR_STATE_SRGB, + "color-state", gdk_gl_texture_builder_get_color_state (builder), NULL); self->context = g_object_ref (gdk_gl_texture_builder_get_context (builder)); diff --git a/gdk/gdkgltexturebuilder.c b/gdk/gdkgltexturebuilder.c index 761b4ef70e..f1bc872809 100644 --- a/gdk/gdkgltexturebuilder.c +++ b/gdk/gdkgltexturebuilder.c @@ -23,6 +23,7 @@ #include "gdkenumtypes.h" #include "gdkglcontext.h" +#include "gdkcolorstate.h" #include "gdkgltextureprivate.h" #include @@ -38,6 +39,7 @@ struct _GdkGLTextureBuilder GdkMemoryFormat format; gboolean has_mipmap; gpointer sync; + GdkColorState *color_state; GdkTexture *update_texture; cairo_region_t *update_region; @@ -75,6 +77,7 @@ enum PROP_HEIGHT, PROP_ID, PROP_SYNC, + PROP_COLOR_STATE, PROP_UPDATE_REGION, PROP_UPDATE_TEXTURE, PROP_WIDTH, @@ -95,6 +98,7 @@ gdk_gl_texture_builder_dispose (GObject *object) g_clear_object (&self->update_texture); g_clear_pointer (&self->update_region, cairo_region_destroy); + g_clear_pointer (&self->color_state, gdk_color_state_unref); G_OBJECT_CLASS (gdk_gl_texture_builder_parent_class)->dispose (object); } @@ -133,6 +137,10 @@ gdk_gl_texture_builder_get_property (GObject *object, g_value_set_pointer (value, self->sync); break; + case PROP_COLOR_STATE: + g_value_set_boxed (value, self->color_state); + break; + case PROP_UPDATE_REGION: g_value_set_boxed (value, self->update_region); break; @@ -185,6 +193,10 @@ gdk_gl_texture_builder_set_property (GObject *object, gdk_gl_texture_builder_set_sync (self, g_value_get_pointer (value)); break; + case PROP_COLOR_STATE: + gdk_gl_texture_builder_set_color_state (self, g_value_get_boxed (value)); + break; + case PROP_UPDATE_REGION: gdk_gl_texture_builder_set_update_region (self, g_value_get_boxed (value)); break; @@ -286,6 +298,18 @@ gdk_gl_texture_builder_class_init (GdkGLTextureBuilderClass *klass) g_param_spec_pointer ("sync", NULL, NULL, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** + * GdkGLTextureBuilder:color-state: + * + * The color state of the texture. + * + * Since: 4.16 + */ + properties[PROP_COLOR_STATE] = + g_param_spec_boxed ("color-state", NULL, NULL, + GDK_TYPE_COLOR_STATE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** * GdkGLTextureBuilder:update-region: (attributes org.gtk.Property.get=gdk_gl_texture_builder_get_update_region org.gtk.Property.set=gdk_gl_texture_builder_set_update_region) * @@ -329,6 +353,7 @@ static void gdk_gl_texture_builder_init (GdkGLTextureBuilder *self) { self->format = GDK_MEMORY_R8G8B8A8_PREMULTIPLIED; + self->color_state = gdk_color_state_ref (gdk_color_state_get_srgb ()); } /** @@ -616,6 +641,51 @@ gdk_gl_texture_builder_set_sync (GdkGLTextureBuilder *self, g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SYNC]); } +/** + * gdk_gl_texture_builder_get_color_state: (attributes org.gtk.Method.get_property=color-state) + * @self: a `GdkGLTextureBuilder` + * + * Gets the color state previously set via gdk_gl_texture_builder_set_color_state(). + * + * Returns: the color state + * + * Since: 4.16 + */ +GdkColorState * +gdk_gl_texture_builder_get_color_state (GdkGLTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self), NULL); + + return self->color_state; +} + +/** + * gdk_gl_texture_builder_set_color_state: (attributes org.gtk.Method.set_property=color-state) + * @self: a `GdkGLTextureBuilder` + * @color_state: a `GdkColorState` + * + * Sets the color state for the texture. + * + * By default, the sRGB colorstate is used. If you don't know what + * colorstates are, this is probably the right thing. + * + * Since: 4.16 + */ +void +gdk_gl_texture_builder_set_color_state (GdkGLTextureBuilder *self, + GdkColorState *color_state) +{ + g_return_if_fail (GDK_IS_GL_TEXTURE_BUILDER (self)); + g_return_if_fail (color_state != NULL); + + if (gdk_color_state_equal (self->color_state, color_state)) + return; + + g_clear_pointer (&self->color_state, gdk_color_state_unref); + self->color_state = gdk_color_state_ref (color_state); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_STATE]); +} + /** * gdk_gl_texture_builder_get_format: (attributes org.gtk.Method.get_property=format) * @self: a `GdkGLTextureBuilder` diff --git a/gdk/gdkgltexturebuilder.h b/gdk/gdkgltexturebuilder.h index 8bf105064b..ccad7be93e 100644 --- a/gdk/gdkgltexturebuilder.h +++ b/gdk/gdkgltexturebuilder.h @@ -76,6 +76,12 @@ GDK_AVAILABLE_IN_4_12 void gdk_gl_texture_builder_set_sync (GdkGLTextureBuilder *self, gpointer sync); +GDK_AVAILABLE_IN_4_16 +GdkColorState * gdk_gl_texture_builder_get_color_state (GdkGLTextureBuilder *self); +GDK_AVAILABLE_IN_4_16 +void gdk_gl_texture_builder_set_color_state (GdkGLTextureBuilder *self, + GdkColorState *color_state); + GDK_AVAILABLE_IN_4_12 GdkTexture * gdk_gl_texture_builder_get_update_texture (GdkGLTextureBuilder *self) G_GNUC_PURE; GDK_AVAILABLE_IN_4_12 From b33b68ef7529c81f5d0ee580ac7af3b08c7b98a8 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Fri, 7 Jun 2024 08:49:59 -0400 Subject: [PATCH 07/11] dmabuf texture: color state support --- gdk/gdkdmabuftexture.c | 2 +- gdk/gdkdmabuftexturebuilder.c | 72 ++++++++++++ gdk/gdkdmabuftexturebuilder.h | 6 + testsuite/gtk/defaultvalue.c | 202 +++++++++++++++++----------------- 4 files changed, 180 insertions(+), 102 deletions(-) diff --git a/gdk/gdkdmabuftexture.c b/gdk/gdkdmabuftexture.c index 62fea85f25..fb5450532b 100644 --- a/gdk/gdkdmabuftexture.c +++ b/gdk/gdkdmabuftexture.c @@ -204,7 +204,7 @@ gdk_dmabuf_texture_new_from_builder (GdkDmabufTextureBuilder *builder, self = g_object_new (GDK_TYPE_DMABUF_TEXTURE, "width", width, "height", height, - "color-state", GDK_COLOR_STATE_SRGB, + "color-state", gdk_dmabuf_texture_builder_get_color_state (builder), NULL); g_set_object (&self->display, display); diff --git a/gdk/gdkdmabuftexturebuilder.c b/gdk/gdkdmabuftexturebuilder.c index 6508d9c2cf..055ed6f9ea 100644 --- a/gdk/gdkdmabuftexturebuilder.c +++ b/gdk/gdkdmabuftexturebuilder.c @@ -24,6 +24,7 @@ #include "gdkdebugprivate.h" #include "gdkdisplay.h" #include "gdkenumtypes.h" +#include "gdkcolorstate.h" #include "gdkdmabuftextureprivate.h" #include "gdkdmabuftexturebuilderprivate.h" @@ -41,6 +42,8 @@ struct _GdkDmabufTextureBuilder GdkDmabuf dmabuf; + GdkColorState *color_state; + GdkTexture *update_texture; cairo_region_t *update_region; }; @@ -124,6 +127,7 @@ enum PROP_MODIFIER, PROP_PREMULTIPLIED, PROP_N_PLANES, + PROP_COLOR_STATE, PROP_UPDATE_REGION, PROP_UPDATE_TEXTURE, @@ -141,6 +145,7 @@ gdk_dmabuf_texture_builder_dispose (GObject *object) g_clear_object (&self->update_texture); g_clear_pointer (&self->update_region, cairo_region_destroy); + g_clear_pointer (&self->color_state, gdk_color_state_unref); G_OBJECT_CLASS (gdk_dmabuf_texture_builder_parent_class)->dispose (object); } @@ -183,6 +188,10 @@ gdk_dmabuf_texture_builder_get_property (GObject *object, g_value_set_uint (value, self->dmabuf.n_planes); break; + case PROP_COLOR_STATE: + g_value_set_boxed (value, self->color_state); + break; + case PROP_UPDATE_REGION: g_value_set_boxed (value, self->update_region); break; @@ -235,6 +244,10 @@ gdk_dmabuf_texture_builder_set_property (GObject *object, gdk_dmabuf_texture_builder_set_n_planes (self, g_value_get_uint (value)); break; + case PROP_COLOR_STATE: + gdk_dmabuf_texture_builder_set_color_state (self, g_value_get_boxed (value)); + break; + case PROP_UPDATE_REGION: gdk_dmabuf_texture_builder_set_update_region (self, g_value_get_boxed (value)); break; @@ -347,6 +360,18 @@ gdk_dmabuf_texture_builder_class_init (GdkDmabufTextureBuilderClass *klass) 1, GDK_DMABUF_MAX_PLANES, 1, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** + * GdkDmabufTextureBuilder:color-state: + * + * The color state of the texture. + * + * Since: 4.16 + */ + properties[PROP_COLOR_STATE] = + g_param_spec_boxed ("color-state", NULL, NULL, + GDK_TYPE_COLOR_STATE, + G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS); + /** * GdkDmabufTextureBuilder:update-region: (attributes org.gtk.Property.get=gdk_dmabuf_texture_builder_get_update_region org.gtk.Property.set=gdk_dmabuf_texture_builder_set_update_region) * @@ -383,6 +408,8 @@ gdk_dmabuf_texture_builder_init (GdkDmabufTextureBuilder *self) for (int i = 0; i < GDK_DMABUF_MAX_PLANES; i++) self->dmabuf.planes[i].fd = -1; + + self->color_state = gdk_color_state_ref (gdk_color_state_get_srgb ()); } /** @@ -843,6 +870,51 @@ gdk_dmabuf_texture_builder_set_offset (GdkDmabufTextureBuilder *self, self->dmabuf.planes[plane].offset = offset; } +/** + * gdk_dmabuf_texture_builder_get_color_state: (attributes org.gtk.Method.get_property=color-state) + * @self: a `GdkDmabufTextureBuilder` + * + * Gets the color state previously set via gdk_dmabuf_texture_builder_set_color_state(). + * + * Returns: the color state + * + * Since: 4.16 + */ +GdkColorState * +gdk_dmabuf_texture_builder_get_color_state (GdkDmabufTextureBuilder *self) +{ + g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL); + + return self->color_state; +} + +/** + * gdk_dmabuf_texture_builder_set_color_state: (attributes org.gtk.Method.set_property=color-state) + * @self: a `GdkDmabufTextureBuilder` + * @color_state: a `GdkColorState` + * + * Sets the color state for the texture. + * + * By default, the sRGB colorstate is used. If you don't know what + * colorstates are, this is probably the right thing. + * + * Since: 4.16 + */ +void +gdk_dmabuf_texture_builder_set_color_state (GdkDmabufTextureBuilder *self, + GdkColorState *color_state) +{ + g_return_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self)); + g_return_if_fail (color_state != NULL); + + if (gdk_color_state_equal (self->color_state, color_state)) + return; + + g_clear_pointer (&self->color_state, gdk_color_state_unref); + self->color_state = gdk_color_state_ref (color_state); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_COLOR_STATE]); +} + /** * gdk_dmabuf_texture_builder_get_update_texture: (attributes org.gtk.Method.get_property=update-texture) * @self: a `GdkDmabufTextureBuilder` diff --git a/gdk/gdkdmabuftexturebuilder.h b/gdk/gdkdmabuftexturebuilder.h index 88ecfea5cf..28a0f45d6e 100644 --- a/gdk/gdkdmabuftexturebuilder.h +++ b/gdk/gdkdmabuftexturebuilder.h @@ -100,6 +100,12 @@ void gdk_dmabuf_texture_builder_set_offset (GdkDmabufT unsigned int plane, unsigned int offset); +GDK_AVAILABLE_IN_4_16 +GdkColorState * gdk_dmabuf_texture_builder_get_color_state (GdkDmabufTextureBuilder *self); +GDK_AVAILABLE_IN_4_16 +void gdk_dmabuf_texture_builder_set_color_state (GdkDmabufTextureBuilder *self, + GdkColorState *color_state); + GDK_AVAILABLE_IN_4_14 GdkTexture * gdk_dmabuf_texture_builder_get_update_texture (GdkDmabufTextureBuilder *self) G_GNUC_PURE; GDK_AVAILABLE_IN_4_14 diff --git a/testsuite/gtk/defaultvalue.c b/testsuite/gtk/defaultvalue.c index 4734f80120..4f1988699d 100644 --- a/testsuite/gtk/defaultvalue.c +++ b/testsuite/gtk/defaultvalue.c @@ -22,8 +22,8 @@ static void check_property (const char *output, - GParamSpec *pspec, - GValue *value) + GParamSpec *pspec, + GValue *value) { GValue default_value = G_VALUE_INIT; char *v, *dv, *msg; @@ -42,12 +42,12 @@ check_property (const char *output, dv = g_strdup_value_contents (&default_value); msg = g_strdup_printf ("%s %s.%s: %s != %s\n", - output, - g_type_name (pspec->owner_type), - pspec->name, - dv, v); + output, + g_type_name (pspec->owner_type), + pspec->name, + dv, v); g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, - G_STRFUNC, msg); + G_STRFUNC, msg); g_free (msg); g_free (v); @@ -159,16 +159,16 @@ G_GNUC_END_IGNORE_DEPRECATIONS gboolean check = TRUE; if (pspec->owner_type != type) - continue; + continue; if ((pspec->flags & G_PARAM_READABLE) == 0) - continue; + continue; /* This is set by the treelistmodel, plain * g_object_new() will crash here */ if (g_type_is_a (type, GTK_TYPE_TREE_LIST_ROW) && - (strcmp (pspec->name, "item") == 0)) - continue; + (strcmp (pspec->name, "item") == 0)) + continue; /* This is set via class_init, and we have a11y tests to verify it */ if (g_type_is_a (type, GTK_TYPE_ACCESSIBLE) && @@ -181,121 +181,121 @@ G_GNUC_END_IGNORE_DEPRECATIONS check = FALSE; if (g_type_is_a (type, GDK_TYPE_CLIPBOARD) && - strcmp (pspec->name, "display") == 0) - check = FALSE; + strcmp (pspec->name, "display") == 0) + check = FALSE; /* These are set in init() */ if ((g_type_is_a (type, GDK_TYPE_CLIPBOARD) || g_type_is_a (type, GDK_TYPE_CONTENT_PROVIDER) || g_type_is_a (type, GTK_TYPE_DROP_TARGET)) && - strcmp (pspec->name, "formats") == 0) - check = FALSE; + strcmp (pspec->name, "formats") == 0) + check = FALSE; if (g_type_is_a (type, GDK_TYPE_CONTENT_PROVIDER) && - strcmp (pspec->name, "storable-formats") == 0) - check = FALSE; + strcmp (pspec->name, "storable-formats") == 0) + check = FALSE; if (g_type_is_a (type, GDK_TYPE_DMABUF_TEXTURE_BUILDER) && - strcmp (pspec->name, "display") == 0) - check = FALSE; + strcmp (pspec->name, "display") == 0) + check = FALSE; G_GNUC_BEGIN_IGNORE_DEPRECATIONS /* set in the constructor */ if (g_type_is_a (type, GSK_TYPE_GL_SHADER) && - strcmp (pspec->name, "source") == 0) - check = FALSE; + strcmp (pspec->name, "source") == 0) + check = FALSE; G_GNUC_END_IGNORE_DEPRECATIONS /* This one has a special-purpose default value */ if (g_type_is_a (type, GTK_TYPE_DIALOG) && - (strcmp (pspec->name, "use-header-bar") == 0)) - check = FALSE; + (strcmp (pspec->name, "use-header-bar") == 0)) + check = FALSE; if (g_type_is_a (type, GTK_TYPE_ASSISTANT) && - (strcmp (pspec->name, "use-header-bar") == 0 || + (strcmp (pspec->name, "use-header-bar") == 0 || strcmp (pspec->name, "pages") == 0)) /* pages always gets a non-NULL value */ - check = FALSE; + check = FALSE; if (g_type_is_a (type, GTK_TYPE_STACK) && - (strcmp (pspec->name, "pages") == 0)) /* pages always gets a non-NULL value */ - check = FALSE; + (strcmp (pspec->name, "pages") == 0)) /* pages always gets a non-NULL value */ + check = FALSE; if (g_type_is_a (type, GTK_TYPE_NOTEBOOK) && - (strcmp (pspec->name, "pages") == 0)) /* pages always gets a non-NULL value */ - check = FALSE; + (strcmp (pspec->name, "pages") == 0)) /* pages always gets a non-NULL value */ + check = FALSE; if (g_type_is_a (type, GTK_TYPE_COMBO_BOX) && (strcmp (pspec->name, "child") == 0)) check = FALSE; if (g_type_is_a (type, GTK_TYPE_POPOVER) && - (strcmp (pspec->name, "pointing-to") == 0)) - check = FALSE; + (strcmp (pspec->name, "pointing-to") == 0)) + check = FALSE; if (g_type_is_a (type, GDK_TYPE_DISPLAY_MANAGER) && - (strcmp (pspec->name, "default-display") == 0)) - check = FALSE; + (strcmp (pspec->name, "default-display") == 0)) + check = FALSE; if (g_type_is_a (type, GDK_TYPE_DISPLAY) && - (strcmp (pspec->name, "dmabuf-formats") == 0)) - check = FALSE; + (strcmp (pspec->name, "dmabuf-formats") == 0)) + check = FALSE; if (g_type_is_a (type, GDK_TYPE_MONITOR) && (strcmp (pspec->name, "geometry") == 0)) check = FALSE; if (g_type_is_a (type, GTK_TYPE_ABOUT_DIALOG) && - (strcmp (pspec->name, "program-name") == 0)) - check = FALSE; + (strcmp (pspec->name, "program-name") == 0)) + check = FALSE; /* These are set to the current date */ if (g_type_is_a (type, GTK_TYPE_CALENDAR) && - (strcmp (pspec->name, "year") == 0 || - strcmp (pspec->name, "month") == 0 || - strcmp (pspec->name, "day") == 0)) - check = FALSE; + (strcmp (pspec->name, "year") == 0 || + strcmp (pspec->name, "month") == 0 || + strcmp (pspec->name, "day") == 0)) + check = FALSE; if (g_type_is_a (type, GTK_TYPE_CELL_AREA_CONTEXT) && - (strcmp (pspec->name, "minimum-width") == 0 || - strcmp (pspec->name, "minimum-height") == 0 || - strcmp (pspec->name, "natural-width") == 0 || - strcmp (pspec->name, "natural-height") == 0)) - check = FALSE; + (strcmp (pspec->name, "minimum-width") == 0 || + strcmp (pspec->name, "minimum-height") == 0 || + strcmp (pspec->name, "natural-width") == 0 || + strcmp (pspec->name, "natural-height") == 0)) + check = FALSE; if (g_type_is_a (type, GTK_TYPE_CELL_RENDERER_TEXT) && - (strcmp (pspec->name, "background-gdk") == 0 || - strcmp (pspec->name, "foreground-gdk") == 0 || - strcmp (pspec->name, "background-rgba") == 0 || - strcmp (pspec->name, "foreground-rgba") == 0 || - strcmp (pspec->name, "font") == 0 || - strcmp (pspec->name, "font-desc") == 0)) - check = FALSE; + (strcmp (pspec->name, "background-gdk") == 0 || + strcmp (pspec->name, "foreground-gdk") == 0 || + strcmp (pspec->name, "background-rgba") == 0 || + strcmp (pspec->name, "foreground-rgba") == 0 || + strcmp (pspec->name, "font") == 0 || + strcmp (pspec->name, "font-desc") == 0)) + check = FALSE; if (g_type_is_a (type, GTK_TYPE_CELL_VIEW) && - (strcmp (pspec->name, "background-gdk") == 0 || - strcmp (pspec->name, "foreground-gdk") == 0 || - strcmp (pspec->name, "foreground-rgba") == 0 || - strcmp (pspec->name, "background-rgba") == 0 || + (strcmp (pspec->name, "background-gdk") == 0 || + strcmp (pspec->name, "foreground-gdk") == 0 || + strcmp (pspec->name, "foreground-rgba") == 0 || + strcmp (pspec->name, "background-rgba") == 0 || strcmp (pspec->name, "cell-area") == 0 || strcmp (pspec->name, "cell-area-context") == 0)) - check = FALSE; + check = FALSE; if (g_type_is_a (type, GTK_TYPE_COLOR_BUTTON) && - (strcmp (pspec->name, "color") == 0 || - strcmp (pspec->name, "rgba") == 0)) - check = FALSE; + (strcmp (pspec->name, "color") == 0 || + strcmp (pspec->name, "rgba") == 0)) + check = FALSE; if (g_type_is_a (type, GTK_TYPE_COLUMN_VIEW) && (strcmp (pspec->name, "columns") == 0 || - strcmp (pspec->name, "sorter") == 0)) - check = FALSE; + strcmp (pspec->name, "sorter") == 0)) + check = FALSE; G_GNUC_BEGIN_IGNORE_DEPRECATIONS if (g_type_is_a (type, GTK_TYPE_COMBO_BOX) && - (strcmp (pspec->name, "cell-area") == 0 || + (strcmp (pspec->name, "cell-area") == 0 || strcmp (pspec->name, "cell-area-context") == 0)) - check = FALSE; + check = FALSE; G_GNUC_END_IGNORE_DEPRECATIONS @@ -303,21 +303,21 @@ G_GNUC_END_IGNORE_DEPRECATIONS * and buffer gets created on-demand */ if (g_type_is_a (type, GTK_TYPE_ENTRY) && - (strcmp (pspec->name, "invisible-char") == 0 || + (strcmp (pspec->name, "invisible-char") == 0 || strcmp (pspec->name, "buffer") == 0)) - check = FALSE; + check = FALSE; if (g_type_is_a (type, GTK_TYPE_TEXT) && - (strcmp (pspec->name, "invisible-char") == 0 || + (strcmp (pspec->name, "invisible-char") == 0 || strcmp (pspec->name, "buffer") == 0)) - check = FALSE; + check = FALSE; G_GNUC_BEGIN_IGNORE_DEPRECATIONS if (g_type_is_a (type, GTK_TYPE_ENTRY_COMPLETION) && - (strcmp (pspec->name, "cell-area") == 0 || + (strcmp (pspec->name, "cell-area") == 0 || strcmp (pspec->name, "cell-area-context") == 0)) - check = FALSE; + check = FALSE; G_GNUC_END_IGNORE_DEPRECATIONS @@ -329,8 +329,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS check = FALSE; if (g_type_is_a (type, GTK_TYPE_TREE_LIST_MODEL) && - (strcmp (pspec->name, "item-type") == 0)) /* might be a treelistrow */ - check = FALSE; + (strcmp (pspec->name, "item-type") == 0)) /* might be a treelistrow */ + check = FALSE; /* This is set in init() */ if (g_type_is_a (type, GTK_TYPE_FONT_CHOOSER_WIDGET) && @@ -340,30 +340,30 @@ G_GNUC_END_IGNORE_DEPRECATIONS G_GNUC_BEGIN_IGNORE_DEPRECATIONS if (g_type_is_a (type, GTK_TYPE_ICON_VIEW) && - (strcmp (pspec->name, "cell-area") == 0 || + (strcmp (pspec->name, "cell-area") == 0 || strcmp (pspec->name, "cell-area-context") == 0)) - check = FALSE; + check = FALSE; G_GNUC_END_IGNORE_DEPRECATIONS if (g_type_is_a (type, GTK_TYPE_MESSAGE_DIALOG) && (strcmp (pspec->name, "image") == 0 || strcmp (pspec->name, "message-area") == 0)) - check = FALSE; + check = FALSE; if (g_type_is_a (type, GTK_TYPE_PANED) && - strcmp (pspec->name, "max-position") == 0) - check = FALSE; + strcmp (pspec->name, "max-position") == 0) + check = FALSE; if (g_type_is_a (type, GTK_TYPE_PRINT_OPERATION) && - strcmp (pspec->name, "job-name") == 0) - check = FALSE; + strcmp (pspec->name, "job-name") == 0) + check = FALSE; #ifdef G_OS_UNIX if (g_type_is_a (type, GTK_TYPE_PRINT_UNIX_DIALOG) && - (strcmp (pspec->name, "page-setup") == 0 || - strcmp (pspec->name, "print-settings") == 0)) - check = FALSE; + (strcmp (pspec->name, "page-setup") == 0 || + strcmp (pspec->name, "print-settings") == 0)) + check = FALSE; #endif if (g_type_is_a (type, GTK_TYPE_PROGRESS_BAR) && @@ -373,7 +373,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS /* filename value depends on $HOME */ if (g_type_is_a (type, GTK_TYPE_RECENT_MANAGER) && (strcmp (pspec->name, "filename") == 0 || - strcmp (pspec->name, "size") == 0)) + strcmp (pspec->name, "size") == 0)) check = FALSE; if (g_type_is_a (type, GTK_TYPE_SCALE_BUTTON) && @@ -381,15 +381,15 @@ G_GNUC_END_IGNORE_DEPRECATIONS check = FALSE; if (g_type_is_a (type, GTK_TYPE_SCROLLED_WINDOW) && - (strcmp (pspec->name, "hadjustment") == 0 || + (strcmp (pspec->name, "hadjustment") == 0 || strcmp (pspec->name, "vadjustment") == 0)) - check = FALSE; + check = FALSE; if (g_type_is_a (type, GTK_TYPE_SETTINGS)) check = FALSE; if (g_type_is_a (type, GTK_TYPE_SHORTCUT) && - (strcmp (pspec->name, "action") == 0 || + (strcmp (pspec->name, "action") == 0 || strcmp (pspec->name, "trigger") == 0)) check = FALSE; @@ -411,9 +411,9 @@ G_GNUC_END_IGNORE_DEPRECATIONS if (g_type_is_a (type, GTK_TYPE_TEXT_TAG) && (strcmp (pspec->name, "background-gdk") == 0 || strcmp (pspec->name, "foreground-gdk") == 0 || - strcmp (pspec->name, "language") == 0 || - strcmp (pspec->name, "font") == 0 || - strcmp (pspec->name, "font-desc") == 0)) + strcmp (pspec->name, "language") == 0 || + strcmp (pspec->name, "font") == 0 || + strcmp (pspec->name, "font-desc") == 0)) check = FALSE; if (g_type_is_a (type, GTK_TYPE_TEXT_VIEW) && @@ -421,25 +421,25 @@ G_GNUC_END_IGNORE_DEPRECATIONS check = FALSE; if (g_type_is_a (type, GTK_TYPE_TREE_VIEW) && - (strcmp (pspec->name, "hadjustment") == 0 || + (strcmp (pspec->name, "hadjustment") == 0 || strcmp (pspec->name, "vadjustment") == 0)) - check = FALSE; + check = FALSE; if (g_type_is_a (type, GTK_TYPE_TREE_VIEW_COLUMN) && - (strcmp (pspec->name, "cell-area") == 0 || + (strcmp (pspec->name, "cell-area") == 0 || strcmp (pspec->name, "cell-area-context") == 0)) - check = FALSE; + check = FALSE; if (g_type_is_a (type, GTK_TYPE_VIEWPORT) && - (strcmp (pspec->name, "hadjustment") == 0 || + (strcmp (pspec->name, "hadjustment") == 0 || strcmp (pspec->name, "vadjustment") == 0)) - check = FALSE; + check = FALSE; if (g_type_is_a (type, GTK_TYPE_WIDGET) && (strcmp (pspec->name, "name") == 0 || - strcmp (pspec->name, "display") == 0 || - strcmp (pspec->name, "style") == 0)) - check = FALSE; + strcmp (pspec->name, "display") == 0 || + strcmp (pspec->name, "style") == 0)) + check = FALSE; /* resize-grip-visible is determined at runtime */ if (g_type_is_a (type, GTK_TYPE_WINDOW) && @@ -559,10 +559,10 @@ main (int argc, char **argv) continue; testname = g_strdup_printf ("/Default Values/%s", - g_type_name (otypes[i])); + g_type_name (otypes[i])); g_test_add_data_func (testname, &otypes[i], - test_type); + test_type); g_free (testname); } From 03daf42fb55f8f0f7d683304826977c9aa2fffd0 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 8 May 2022 10:12:59 -0400 Subject: [PATCH 08/11] png: Port to MemoryTextureBuilder --- gdk/loaders/gdkpng.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/gdk/loaders/gdkpng.c b/gdk/loaders/gdkpng.c index de9fb3ca68..1b2a485656 100644 --- a/gdk/loaders/gdkpng.c +++ b/gdk/loaders/gdkpng.c @@ -21,7 +21,7 @@ #include #include "gdkmemoryformatprivate.h" -#include "gdkmemorytexture.h" +#include "gdkmemorytexturebuilder.h" #include "gdkprofilerprivate.h" #include "gdktexturedownloaderprivate.h" #include "gsk/gl/fp16private.h" @@ -143,6 +143,7 @@ gdk_load_png (GBytes *bytes, gsize i, stride; int depth, color_type; int interlace; + GdkMemoryTextureBuilder *builder; GdkMemoryFormat format; guchar *buffer = NULL; guchar **row_pointers = NULL; @@ -297,7 +298,14 @@ gdk_load_png (GBytes *bytes, png_read_end (png, info); out_bytes = g_bytes_new_take (buffer, height * stride); - texture = gdk_memory_texture_new (width, height, format, out_bytes, stride); + builder = gdk_memory_texture_builder_new (); + gdk_memory_texture_builder_set_format (builder, format); + gdk_memory_texture_builder_set_width (builder, width); + gdk_memory_texture_builder_set_height (builder, height); + gdk_memory_texture_builder_set_bytes (builder, out_bytes); + gdk_memory_texture_builder_set_stride (builder, stride); + texture = gdk_memory_texture_builder_build (builder); + g_object_unref (builder); g_bytes_unref (out_bytes); if (options && png_get_text (png, info, &text, &num_texts)) From 6c33afc13cfb4ea9d74e2fe7d7ff6e478b4981d7 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 16 Jul 2024 21:14:13 +0200 Subject: [PATCH 09/11] png: Move texture data download further down We only download the data when we actually need it for writing into the PNG stream. This allows modifying the download parameters (in particular color state in the next commit) while writing out their settings, so the code for selecting the right colorstate liives in only one place. We have to be careful though, because the download now happens after the setjmp(), so we need to make sure the error path handles both cases without leaking: Where the download has happened and where it hasn't. --- gdk/loaders/gdkpng.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/gdk/loaders/gdkpng.c b/gdk/loaders/gdkpng.c index 1b2a485656..32c9fa5361 100644 --- a/gdk/loaders/gdkpng.c +++ b/gdk/loaders/gdkpng.c @@ -451,15 +451,11 @@ gdk_save_png (GdkTexture *texture) return NULL; } - gdk_texture_downloader_init (&downloader, texture); - gdk_texture_downloader_set_format (&downloader, format); - bytes = gdk_texture_downloader_download_bytes (&downloader, &stride); - gdk_texture_downloader_finish (&downloader); - data = g_bytes_get_data (bytes, NULL); + bytes = NULL; if (sigsetjmp (png_jmpbuf (png), 1)) { - g_bytes_unref (bytes); + g_clear_pointer (&bytes, g_bytes_unref); g_free (io.data); png_destroy_read_struct (&png, &info, NULL); return NULL; @@ -479,6 +475,12 @@ gdk_save_png (GdkTexture *texture) png_set_swap (png); #endif + gdk_texture_downloader_init (&downloader, texture); + gdk_texture_downloader_set_format (&downloader, format); + bytes = gdk_texture_downloader_download_bytes (&downloader, &stride); + gdk_texture_downloader_finish (&downloader); + data = g_bytes_get_data (bytes, NULL); + for (y = 0; y < height; y++) png_write_row (png, data + y * stride); From 31e0ec71f29f78a2a9d26d12ce1632d5eff5d91b Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 16 Jul 2024 17:48:50 +0200 Subject: [PATCH 10/11] png: Add color state support When loading or saving png files, encode the CICP flags of the color state into the PNG. When loading, decode the CICP flags if available and detect the colorstate they use. If we do not support the cicp tags, we do not load the image. So far, we ignore the ICC profiles. Includes regeneration of nodeparse test *reference* output to include the new tags we write to PNGs. The original tests do not include those tags, so we implicitly test that we read untagged files correctly. --- gdk/loaders/gdkpng.c | 177 ++++++++++++++++++ .../nodeparser/empty-texture-scale.ref.node | 5 +- .../gsk/nodeparser/empty-texture.ref.node | 5 +- .../gsk/nodeparser/texture-fail.ref.node | 5 +- testsuite/gsk/nodeparser/texture-names.node | 4 +- .../nodeparser/texture-scale-filters.ref.node | 16 +- .../texture-scale-unknown-filter.ref.node | 5 +- 7 files changed, 199 insertions(+), 18 deletions(-) diff --git a/gdk/loaders/gdkpng.c b/gdk/loaders/gdkpng.c index 32c9fa5361..17d207587c 100644 --- a/gdk/loaders/gdkpng.c +++ b/gdk/loaders/gdkpng.c @@ -20,11 +20,13 @@ #include "gdkpngprivate.h" #include +#include "gdkcolorstateprivate.h" #include "gdkmemoryformatprivate.h" #include "gdkmemorytexturebuilder.h" #include "gdkprofilerprivate.h" #include "gdktexturedownloaderprivate.h" #include "gsk/gl/fp16private.h" + #include #include @@ -126,6 +128,160 @@ png_simple_warning_callback (png_structp png, { } +/* }}} */ +/* {{{ Color profile handling */ + +typedef struct +{ + gboolean cicp_chunk_read; + int color_primaries; + int transfer_function; + int matrix_coefficients; + int full_range; +} CICPData; + +static int +png_read_chunk_func (png_structp png, + png_unknown_chunkp chunk) +{ + if (strcmp ((char *) chunk->name, "cICP") == 0 && + chunk->size == 4) + { + CICPData *cicp = png_get_user_chunk_ptr (png); + + cicp->cicp_chunk_read = TRUE; + + cicp->color_primaries = chunk->data[0]; + cicp->transfer_function = chunk->data[1]; + cicp->matrix_coefficients = chunk->data[2]; + cicp->full_range = chunk->data[3]; + + return 1; + } + + return 0; +} + +/* we use "chunk_read" here to mean "is supported" */ +static const CICPData colorstate_cicp[GDK_COLOR_STATE_N_IDS] = { + [GDK_COLOR_STATE_ID_SRGB] = { TRUE, 1, 13, 0, 1 }, + [GDK_COLOR_STATE_ID_SRGB_LINEAR] = { TRUE, 1, 8, 0, 1 }, + [GDK_COLOR_STATE_ID_REC2100_PQ] = { TRUE, 9, 16, 0, 1 }, + [GDK_COLOR_STATE_ID_REC2100_LINEAR] = { TRUE, 9, 8, 0, 1 } +}; + +static GdkColorState * +gdk_png_get_color_state_from_cicp (const CICPData *cicp) +{ + gsize i; + + for (i = 0; i < GDK_COLOR_STATE_N_IDS; i++) + { + if (!colorstate_cicp[i].cicp_chunk_read) + continue; + + if (colorstate_cicp[i].color_primaries == cicp->color_primaries && + colorstate_cicp[i].transfer_function == cicp->transfer_function && + colorstate_cicp[i].matrix_coefficients == cicp->matrix_coefficients && + colorstate_cicp[i].full_range == cicp->full_range) + return gdk_color_state_ref ((GdkColorState *) &gdk_default_color_states[i]); + } + + return NULL; +} + +static GdkColorState * +gdk_png_get_color_state (png_struct *png, + png_info *info, + GError **error) +{ + GdkColorState *color_state; + CICPData *cicp; + int intent; + + cicp = png_get_user_chunk_ptr (png); + + if (cicp->cicp_chunk_read) + { + color_state = gdk_png_get_color_state_from_cicp (cicp); + if (color_state) + { + g_debug ("Color state from cICP data: %s", gdk_color_state_get_name (color_state)); + return color_state; + } + else + { + g_set_error (error, + GDK_TEXTURE_ERROR, GDK_TEXTURE_ERROR_UNSUPPORTED_CONTENT, + /* Translators: the variables at the end are just the numbers as they appear in the PNG */ + _("Unsupported CICP color properties: %d/%d/%d %d"), + cicp->color_primaries, + cicp->transfer_function, + cicp->matrix_coefficients, + cicp->full_range); + } + } + +#if 0 + if (png_get_iCCP (png, info, &name, NULL, &icc_data, &icc_len)) + { + } +#endif + + if (png_get_sRGB (png, info, &intent)) + return gdk_color_state_ref (GDK_COLOR_STATE_SRGB); + + /* If neither of those is valid, the result is sRGB */ + if (!png_get_valid (png, info, PNG_INFO_gAMA) && + !png_get_valid (png, info, PNG_INFO_cHRM)) + return GDK_COLOR_STATE_SRGB; + + g_debug ("Failed to find color state, assuming SRGB"); + + return GDK_COLOR_STATE_SRGB; +} + +static void +gdk_png_set_color_state (png_struct *png, + png_info *info, + GdkColorState *color_state, + png_byte *chunk_data) +{ + const CICPData *cicp; + + if (GDK_IS_DEFAULT_COLOR_STATE (color_state)) + cicp = &colorstate_cicp[GDK_DEFAULT_COLOR_STATE_ID (color_state)]; + else + cicp = NULL; + + if (cicp && cicp->cicp_chunk_read) + { + png_unknown_chunk chunk = { + .name = { 'c', 'I', 'C', 'P', '\0' }, + .data = chunk_data, + .size = 4, + .location = PNG_HAVE_IHDR, + }; + + chunk_data[0] = (png_byte) cicp->color_primaries; + chunk_data[1] = (png_byte) cicp->transfer_function; + chunk_data[2] = (png_byte) cicp->matrix_coefficients; + chunk_data[3] = (png_byte) cicp->full_range; + + png_set_unknown_chunks (png, info, &chunk, 1); + } + else + { + /* unsupported color state. Fall back to sRGB */ + gdk_color_state_unref (color_state); + color_state = gdk_color_state_ref (gdk_color_state_get_srgb ()); + } + + /* For good measure, we add an sRGB chunk too */ + if (gdk_color_state_equal (color_state, GDK_COLOR_STATE_SRGB)) + png_set_sRGB (png, info, PNG_sRGB_INTENT_PERCEPTUAL); +} + /* }}} */ /* {{{ Public API */ @@ -148,8 +304,11 @@ gdk_load_png (GBytes *bytes, guchar *buffer = NULL; guchar **row_pointers = NULL; GBytes *out_bytes; + GdkColorState *color_state; GdkTexture *texture; int bpp; + CICPData cicp = { FALSE, }; + G_GNUC_UNUSED gint64 before = GDK_PROFILER_CURRENT_TIME; io.data = (guchar *)g_bytes_get_data (bytes, &io.size); @@ -170,6 +329,7 @@ gdk_load_png (GBytes *bytes, g_error ("Out of memory"); png_set_read_fn (png, &io, png_read_func); + png_set_read_user_chunk_fn (png, &cicp, png_read_chunk_func); if (sigsetjmp (png_jmpbuf (png), 1)) { @@ -267,6 +427,10 @@ gdk_load_png (GBytes *bytes, return NULL; } + color_state = gdk_png_get_color_state (png, info, error); + if (color_state == NULL) + return NULL; + bpp = gdk_memory_format_bytes_per_pixel (format); if (!g_size_checked_mul (&stride, width, bpp) || !g_size_checked_add (&stride, stride, (8 - stride % 8) % 8)) @@ -282,6 +446,7 @@ gdk_load_png (GBytes *bytes, if (!buffer || !row_pointers) { + gdk_color_state_unref (color_state); g_free (buffer); g_free (row_pointers); png_destroy_read_struct (&png, &info, NULL); @@ -300,6 +465,7 @@ gdk_load_png (GBytes *bytes, out_bytes = g_bytes_new_take (buffer, height * stride); builder = gdk_memory_texture_builder_new (); gdk_memory_texture_builder_set_format (builder, format); + gdk_memory_texture_builder_set_color_state (builder, color_state); gdk_memory_texture_builder_set_width (builder, width); gdk_memory_texture_builder_set_height (builder, height); gdk_memory_texture_builder_set_bytes (builder, out_bytes); @@ -307,6 +473,7 @@ gdk_load_png (GBytes *bytes, texture = gdk_memory_texture_builder_build (builder); g_object_unref (builder); g_bytes_unref (out_bytes); + gdk_color_state_unref (color_state); if (options && png_get_text (png, info, &text, &num_texts)) { @@ -345,11 +512,14 @@ gdk_save_png (GdkTexture *texture) GBytes *bytes; gsize stride; const guchar *data; + GdkColorState *color_state; int png_format; int depth; + png_byte chunk_data[4]; width = gdk_texture_get_width (texture); height = gdk_texture_get_height (texture); + color_state = gdk_texture_get_color_state (texture); format = gdk_texture_get_format (texture); switch (format) @@ -444,6 +614,8 @@ gdk_save_png (GdkTexture *texture) /* 2^31-1 is the maximum size for PNG files */ png_set_user_limits (png, (1u << 31) - 1, (1u << 31) - 1); + png_set_keep_unknown_chunks (png, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0); + info = png_create_info_struct (png); if (!info) { @@ -451,10 +623,12 @@ gdk_save_png (GdkTexture *texture) return NULL; } + gdk_color_state_ref (color_state); bytes = NULL; if (sigsetjmp (png_jmpbuf (png), 1)) { + gdk_color_state_unref (color_state); g_clear_pointer (&bytes, g_bytes_unref); g_free (io.data); png_destroy_read_struct (&png, &info, NULL); @@ -469,6 +643,8 @@ gdk_save_png (GdkTexture *texture) PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + gdk_png_set_color_state (png, info, color_state, chunk_data); + png_write_info (png, info); #if G_BYTE_ORDER == G_LITTLE_ENDIAN @@ -488,6 +664,7 @@ gdk_save_png (GdkTexture *texture) png_destroy_write_struct (&png, &info); + gdk_color_state_unref (color_state); g_bytes_unref (bytes); return g_bytes_new_take (io.data, io.size); diff --git a/testsuite/gsk/nodeparser/empty-texture-scale.ref.node b/testsuite/gsk/nodeparser/empty-texture-scale.ref.node index ebb5554c0b..d91d33481d 100644 --- a/testsuite/gsk/nodeparser/empty-texture-scale.ref.node +++ b/testsuite/gsk/nodeparser/empty-texture-scale.ref.node @@ -1,7 +1,8 @@ texture-scale { bounds: 0 0 50 50; texture: url("data:image/png;base64,\ -iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAKUlEQVQYlWP8z3DmPwMaYGQwYUQX\ -Y0IXwAUGUCGGoxkYGBiweXAoeAYAz44F3e3U1xUAAAAASUVORK5CYII=\ +iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\ +AZxpOzIAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\ +FQAAAABJRU5ErkJggg==\ "); } diff --git a/testsuite/gsk/nodeparser/empty-texture.ref.node b/testsuite/gsk/nodeparser/empty-texture.ref.node index 24c011e86a..4a52442007 100644 --- a/testsuite/gsk/nodeparser/empty-texture.ref.node +++ b/testsuite/gsk/nodeparser/empty-texture.ref.node @@ -1,7 +1,8 @@ texture { bounds: 0 0 50 50; texture: url("data:image/png;base64,\ -iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAKUlEQVQYlWP8z3DmPwMaYGQwYUQX\ -Y0IXwAUGUCGGoxkYGBiweXAoeAYAz44F3e3U1xUAAAAASUVORK5CYII=\ +iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\ +AZxpOzIAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\ +FQAAAABJRU5ErkJggg==\ "); } diff --git a/testsuite/gsk/nodeparser/texture-fail.ref.node b/testsuite/gsk/nodeparser/texture-fail.ref.node index 24c011e86a..4a52442007 100644 --- a/testsuite/gsk/nodeparser/texture-fail.ref.node +++ b/testsuite/gsk/nodeparser/texture-fail.ref.node @@ -1,7 +1,8 @@ texture { bounds: 0 0 50 50; texture: url("data:image/png;base64,\ -iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAKUlEQVQYlWP8z3DmPwMaYGQwYUQX\ -Y0IXwAUGUCGGoxkYGBiweXAoeAYAz44F3e3U1xUAAAAASUVORK5CYII=\ +iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\ +AZxpOzIAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\ +FQAAAABJRU5ErkJggg==\ "); } diff --git a/testsuite/gsk/nodeparser/texture-names.node b/testsuite/gsk/nodeparser/texture-names.node index 3c314c4333..c03aef5571 100644 --- a/testsuite/gsk/nodeparser/texture-names.node +++ b/testsuite/gsk/nodeparser/texture-names.node @@ -1,8 +1,8 @@ texture { bounds: 0 0 1 1; texture: "texture1" url("data:image/png;base64,\ -iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWP4z8DwHwAFAAH/q842\ -iQAAAABJRU5ErkJggg==\ +iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\ +AZxpOzIAAAANSURBVAiZY/jPwPAfAAUAAf+rzjaJAAAAAElFTkSuQmCC\ "); } texture { diff --git a/testsuite/gsk/nodeparser/texture-scale-filters.ref.node b/testsuite/gsk/nodeparser/texture-scale-filters.ref.node index 42dbc94234..ac17829ce7 100644 --- a/testsuite/gsk/nodeparser/texture-scale-filters.ref.node +++ b/testsuite/gsk/nodeparser/texture-scale-filters.ref.node @@ -1,30 +1,30 @@ texture-scale { bounds: 0 0 50 50; texture: url("data:image/png;base64,\ -iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWP8z8Dwn4EIwESMolGF\ -1FMIAD2cAhL1w47oAAAAAElFTkSuQmCC\ +iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\ +AZxpOzIAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\ "); } texture-scale { bounds: 0 0 50 50; texture: url("data:image/png;base64,\ -iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWP8z8Dwn4EIwESMolGF\ -1FMIAD2cAhL1w47oAAAAAElFTkSuQmCC\ +iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\ +AZxpOzIAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\ "); } texture-scale { bounds: 0 0 50 50; filter: nearest; texture: url("data:image/png;base64,\ -iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWP8z8Dwn4EIwESMolGF\ -1FMIAD2cAhL1w47oAAAAAElFTkSuQmCC\ +iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\ +AZxpOzIAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\ "); } texture-scale { bounds: 0 0 50 50; filter: trilinear; texture: url("data:image/png;base64,\ -iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAGElEQVQYlWP8z8Dwn4EIwESMolGF\ -1FMIAD2cAhL1w47oAAAAAElFTkSuQmCC\ +iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\ +AZxpOzIAAAAYSURBVBiVY/zPwPCfgQjARIyiUYXUUwgAPZwCEvXDjugAAAAASUVORK5CYII=\ "); } diff --git a/testsuite/gsk/nodeparser/texture-scale-unknown-filter.ref.node b/testsuite/gsk/nodeparser/texture-scale-unknown-filter.ref.node index ebb5554c0b..d91d33481d 100644 --- a/testsuite/gsk/nodeparser/texture-scale-unknown-filter.ref.node +++ b/testsuite/gsk/nodeparser/texture-scale-unknown-filter.ref.node @@ -1,7 +1,8 @@ texture-scale { bounds: 0 0 50 50; texture: url("data:image/png;base64,\ -iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAKUlEQVQYlWP8z3DmPwMaYGQwYUQX\ -Y0IXwAUGUCGGoxkYGBiweXAoeAYAz44F3e3U1xUAAAAASUVORK5CYII=\ +iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAARjSUNQAQ0A\ +AZxpOzIAAAApSURBVBiVY/zPcOY/AxpgZDBhRBdjQhfABQZQIYajGRgYGLB5cCh4BgDPjgXd7dTX\ +FQAAAABJRU5ErkJggg==\ "); } From 9be7104b716051d10b6dc343746d5814c337eba2 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 16 Jul 2024 17:43:27 +0200 Subject: [PATCH 11/11] testsuite: Add a save=>load cycle test for PNGs with colorstates --- testsuite/gdk/colorstate.c | 41 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/testsuite/gdk/colorstate.c b/testsuite/gdk/colorstate.c index 9b4d0c9fe8..b6c778df60 100644 --- a/testsuite/gdk/colorstate.c +++ b/testsuite/gdk/colorstate.c @@ -161,6 +161,44 @@ test_convert (gconstpointer testdata) g_free (path); } +static void +test_png (gconstpointer testdata) +{ + GdkColorState *cs = (GdkColorState *) testdata; + static const float texture_data[] = { 0,0,0,1, 0,0,1,1, 0,1,0,1, 0,1,1,1, + 1,0,0,1, 1,0,1,1, 1,1,0,1, 1,1,1,1 }; + static gsize width = 4, height = 2, stride = 4 * 4 * sizeof (float); + GdkMemoryTextureBuilder *membuild; + GdkTexture *saved, *loaded; + GBytes *bytes; + GError *error = NULL; + + membuild = gdk_memory_texture_builder_new (); + gdk_memory_texture_builder_set_format (membuild, GDK_MEMORY_R32G32B32A32_FLOAT); + gdk_memory_texture_builder_set_color_state (membuild, cs); + gdk_memory_texture_builder_set_width (membuild, width); + gdk_memory_texture_builder_set_height (membuild, height); + bytes = g_bytes_new_static (texture_data, sizeof (texture_data)); + gdk_memory_texture_builder_set_bytes (membuild, bytes); + g_bytes_unref (bytes); + gdk_memory_texture_builder_set_stride (membuild, stride); + saved = gdk_memory_texture_builder_build (membuild); + g_object_unref (membuild); + + bytes = gdk_texture_save_to_png_bytes (saved); + loaded = gdk_texture_new_from_bytes (bytes, &error); + g_assert_nonnull (loaded); + g_assert_no_error (error); + g_bytes_unref (bytes); + + g_assert_cmpint (gdk_texture_get_width (saved), ==, gdk_texture_get_width (loaded)); + g_assert_cmpint (gdk_texture_get_height (saved), ==, gdk_texture_get_height (loaded)); + g_assert_true (gdk_color_state_equal (gdk_texture_get_color_state (saved), gdk_texture_get_color_state (loaded))); + + g_object_unref (saved); + g_object_unref (loaded); +} + int main (int argc, char *argv[]) { @@ -183,6 +221,9 @@ main (int argc, char *argv[]) test_name = g_strdup_printf ("/colorstate/convert/srgb/%s", cs_name); g_test_add_data_func_full (test_name, csi, test_convert, (GDestroyNotify) gdk_color_state_unref); g_free (test_name); + test_name = g_strdup_printf ("/colorstate/png/%s", cs_name); + g_test_add_data_func_full (test_name, csi, test_png, (GDestroyNotify) gdk_color_state_unref); + g_free (test_name); } return g_test_run ();