From cf39c80fe22fe872eacb7c55ed85aaa7d002596e Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 23 Jul 2023 02:06:11 +0200 Subject: [PATCH 01/10] docs: Update for recent rendernode-tool changes --- docs/reference/gtk/gtk4-rendernode-tool.rst | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/reference/gtk/gtk4-rendernode-tool.rst b/docs/reference/gtk/gtk4-rendernode-tool.rst index c9188de329..12d268ba4e 100644 --- a/docs/reference/gtk/gtk4-rendernode-tool.rst +++ b/docs/reference/gtk/gtk4-rendernode-tool.rst @@ -14,7 +14,7 @@ SYNOPSIS | | **gtk4-rendernode-tool** info [OPTIONS...] | **gtk4-rendernode-tool** show [OPTIONS...] -| **gtk4-rendernode-tool** render [OPTIONS...] +| **gtk4-rendernode-tool** render [OPTIONS...] [] DESCRIPTION ----------- @@ -43,9 +43,5 @@ The name of the file to write can be specified as a second FILE argument. ``--renderer=RENDERER`` - Use the given renderer. This option accepts the same values as the - ``GSK_RENDERER`` environment variable. - -``--force`` - - Overwrite an existing file. + Use the given renderer. Use ``--renderer=help`` to get a information + about poassible values for the ``RENDERER``. From 1aa7f18b231b94eac8f0d812f6ea452f7aec57a8 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 23 Jul 2023 22:30:26 +0200 Subject: [PATCH 02/10] vulkan: Remove unused variable It's only used when printing debug stuff. Debug stuff is not that important. --- gsk/vulkan/gskvulkanglyphcache.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/gsk/vulkan/gskvulkanglyphcache.c b/gsk/vulkan/gskvulkanglyphcache.c index a86d197e06..693e3b6166 100644 --- a/gsk/vulkan/gskvulkanglyphcache.c +++ b/gsk/vulkan/gskvulkanglyphcache.c @@ -30,7 +30,6 @@ typedef struct { GskVulkanImage *image; int width, height; int x, y, y0; - int num_glyphs; guint old_pixels; } Atlas; @@ -70,7 +69,6 @@ create_atlas (GskVulkanGlyphCache *cache) atlas->y = 0; atlas->x = 0; atlas->image = NULL; - atlas->num_glyphs = 0; atlas->image = gsk_vulkan_image_new_for_atlas (cache->vulkan, atlas->width, atlas->height); @@ -213,8 +211,6 @@ add_to_cache (GskVulkanGlyphCache *cache, atlas->x = atlas->x + width_with_padding; atlas->y = MAX (atlas->y, atlas->y0 + height_with_padding); - atlas->num_glyphs++; - gsk_vulkan_upload_glyph_op (render, atlas->image, &(cairo_rectangle_int_t) { @@ -239,9 +235,8 @@ add_to_cache (GskVulkanGlyphCache *cache, for (i = 0; i < cache->atlases->len; i++) { atlas = g_ptr_array_index (cache->atlases, i); - g_print ("\tAtlas %d (%dx%d): %d glyphs, %.2g%% old pixels, filled to %d, %d / %d\n", + g_print ("\tAtlas %d (%dx%d): %.2g%% old pixels, filled to %d, %d / %d\n", i, atlas->width, atlas->height, - atlas->num_glyphs, 100.0 * (double)atlas->old_pixels / (double)(atlas->width * atlas->height), atlas->x, atlas->y0, atlas->y); } From ae509406f19b7cb705eb910ebf37159065b564ce Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 24 Jul 2023 16:12:51 +0200 Subject: [PATCH 03/10] memorytexture: Add a check Sophie Herold was running into this problem while coding, so let's help people by catching it early. --- gdk/gdkmemorytexture.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gdk/gdkmemorytexture.c b/gdk/gdkmemorytexture.c index 85d9ba0a25..0e8e2cc78d 100644 --- a/gdk/gdkmemorytexture.c +++ b/gdk/gdkmemorytexture.c @@ -151,6 +151,8 @@ gdk_memory_texture_new (int width, g_return_val_if_fail (height > 0, NULL); g_return_val_if_fail (bytes != NULL, NULL); g_return_val_if_fail (stride >= width * gdk_memory_format_bytes_per_pixel (format), NULL); + /* needs to be this complex to support subtexture of the bottom right part */ + g_return_val_if_fail (g_bytes_get_size (bytes) >= stride * (height - 1) + width * gdk_memory_format_bytes_per_pixel (format), NULL); bytes = gdk_memory_sanitize (bytes, width, height, format, stride, &stride); From 89b4f12b38a9d7944cea26f617ea53f09c25c192 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 27 Jul 2023 10:12:23 +0200 Subject: [PATCH 04/10] vulkan: Plug a memleak --- gsk/vulkan/gskvulkancommandpool.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gsk/vulkan/gskvulkancommandpool.c b/gsk/vulkan/gskvulkancommandpool.c index 197e0aec2a..0da12c0b0e 100644 --- a/gsk/vulkan/gskvulkancommandpool.c +++ b/gsk/vulkan/gskvulkancommandpool.c @@ -56,6 +56,7 @@ gsk_vulkan_command_pool_free (GskVulkanCommandPool *self) self->vk_command_pool, NULL); + g_object_unref (self->vulkan); g_free (self); } From c8f385e3bc524c31ee3a5dbaf08ccedd56991624 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Thu, 27 Jul 2023 10:13:26 +0200 Subject: [PATCH 05/10] vulkancontext: Do proper refcounting - fix a memleak - call unref() instead of new() - remove idle handler on dispose What was I doing when I wrote the pipeline cache code? --- gdk/gdkvulkancontext.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gdk/gdkvulkancontext.c b/gdk/gdkvulkancontext.c index 4034833603..49e461ef0f 100644 --- a/gdk/gdkvulkancontext.c +++ b/gdk/gdkvulkancontext.c @@ -1009,6 +1009,7 @@ gdk_display_load_pipeline_cache (GdkDisplay *display) &result) != VK_SUCCESS) result = VK_NULL_HANDLE; + g_object_unref (cache_file); g_free (data); g_free (display->vk_pipeline_cache_etag); display->vk_pipeline_cache_etag = etag; @@ -1644,7 +1645,6 @@ gdk_display_unref_vulkan (GdkDisplay *display) if (display->vulkan_refcount > 0) return; - display->vk_shader_modules = g_hash_table_new (g_str_hash, g_str_equal); g_hash_table_iter_init (&iter, display->vk_shader_modules); while (g_hash_table_iter_next (&iter, &key, &value)) { @@ -1653,9 +1653,11 @@ gdk_display_unref_vulkan (GdkDisplay *display) value, NULL); } + g_hash_table_unref (display->vk_shader_modules); if (display->vk_save_pipeline_cache_source) { + g_clear_handle_id (&display->vk_save_pipeline_cache_source, g_source_remove); gdk_vulkan_save_pipeline_cache_cb (display); g_assert (display->vk_save_pipeline_cache_source == 0); } From 166777dd554592ba24fa6f0f796a4fd4c8cdc6c9 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 30 Jul 2023 01:40:49 +0200 Subject: [PATCH 06/10] rendernode-tool: Move code No functional changes yet. --- tools/gtk-rendernode-tool-render.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/gtk-rendernode-tool-render.c b/tools/gtk-rendernode-tool-render.c index 77be8ea412..066ac661c8 100644 --- a/tools/gtk-rendernode-tool-render.c +++ b/tools/gtk-rendernode-tool-render.c @@ -61,18 +61,7 @@ render_file (const char *filename, GdkSurface *window; GError *error = NULL; - node = load_node_file (filename); - - if (renderer_name) - g_object_set_data_full (G_OBJECT (gdk_display_get_default ()), "gsk-renderer", - g_strdup (renderer_name), g_free); - - window = gdk_surface_new_toplevel (gdk_display_get_default ()); - renderer = gsk_renderer_new_for_surface (window); - - texture = gsk_renderer_render_texture (renderer, node, NULL); - - save_to = (char *)save_file; + save_to = (char *) save_file; if (save_to == NULL) { @@ -85,6 +74,17 @@ render_file (const char *filename, } } + node = load_node_file (filename); + + if (renderer_name) + g_object_set_data_full (G_OBJECT (gdk_display_get_default ()), "gsk-renderer", + g_strdup (renderer_name), g_free); + + window = gdk_surface_new_toplevel (gdk_display_get_default ()); + renderer = gsk_renderer_new_for_surface (window); + + texture = gsk_renderer_render_texture (renderer, node, NULL); + if (g_str_has_suffix (save_to, ".tif") || g_str_has_suffix (save_to, ".tiff")) bytes = gdk_texture_save_to_tiff_bytes (texture); From 3f16f7e0d4ff44ff62d10fc0b4c2fb230999f36d Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 30 Jul 2023 20:00:34 +0200 Subject: [PATCH 07/10] rendernode-tool: Add another magic format Make .svg use the Cairo renderer to save to an SVG file. It's useful when comparing rendering behavior and times with web browsers (as long as one is aware that browsers build a full DOM tree out of those SVGs). --- tools/gtk-rendernode-tool-render.c | 105 ++++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 17 deletions(-) diff --git a/tools/gtk-rendernode-tool-render.c b/tools/gtk-rendernode-tool-render.c index 066ac661c8..c8d98da3f8 100644 --- a/tools/gtk-rendernode-tool-render.c +++ b/tools/gtk-rendernode-tool-render.c @@ -28,6 +28,9 @@ #include #include #include "gtk-rendernode-tool.h" +#ifdef CAIRO_HAS_SVG_SURFACE +#include +#endif static char * get_save_filename (const char *filename) @@ -48,6 +51,58 @@ get_save_filename (const char *filename) return result; } +#ifdef CAIRO_HAS_SVG_SURFACE +static cairo_status_t +cairo_serializer_write (gpointer user_data, + const unsigned char *data, + unsigned int length) +{ + g_byte_array_append (user_data, data, length); + + return CAIRO_STATUS_SUCCESS; +} + +static GBytes * +create_svg (GskRenderNode *node, + GError **error) +{ + cairo_surface_t *surface; + cairo_t *cr; + graphene_rect_t bounds; + GByteArray *array; + + gsk_render_node_get_bounds (node, &bounds); + array = g_byte_array_new (); + + surface = cairo_svg_surface_create_for_stream (cairo_serializer_write, + array, + bounds.size.width, + bounds.size.height); + cairo_svg_surface_set_document_unit (surface, CAIRO_SVG_UNIT_PX); + cairo_surface_set_device_offset (surface, -bounds.origin.x, -bounds.origin.y); + + cr = cairo_create (surface); + gsk_render_node_draw (node, cr); + cairo_destroy (cr); + + cairo_surface_finish (surface); + if (cairo_surface_status (surface) == CAIRO_STATUS_SUCCESS) + { + cairo_surface_destroy (surface); + return g_byte_array_free_to_bytes (array); + } + else + { + g_set_error (error, + G_IO_ERROR, G_IO_ERROR_FAILED, + "%s", cairo_status_to_string (cairo_surface_status (surface))); + cairo_surface_destroy (surface); + g_byte_array_unref (array); + return NULL; + } +} +#endif + static void render_file (const char *filename, const char *renderer_name, @@ -55,10 +110,7 @@ render_file (const char *filename, { GskRenderNode *node; GBytes *bytes; - GdkTexture *texture; char *save_to; - GskRenderer *renderer; - GdkSurface *window; GError *error = NULL; save_to = (char *) save_file; @@ -76,20 +128,40 @@ render_file (const char *filename, node = load_node_file (filename); - if (renderer_name) - g_object_set_data_full (G_OBJECT (gdk_display_get_default ()), "gsk-renderer", - g_strdup (renderer_name), g_free); - - window = gdk_surface_new_toplevel (gdk_display_get_default ()); - renderer = gsk_renderer_new_for_surface (window); - - texture = gsk_renderer_render_texture (renderer, node, NULL); - - if (g_str_has_suffix (save_to, ".tif") || - g_str_has_suffix (save_to, ".tiff")) - bytes = gdk_texture_save_to_tiff_bytes (texture); +#ifdef CAIRO_HAS_SVG_SURFACE + if (g_str_has_suffix (save_to, ".svg")) + { + bytes = create_svg (node, &error); + if (bytes == NULL) + { + g_printerr (_("Failed to generate SVG: %s\n"), error->message); + exit (1); + } + } else - bytes = gdk_texture_save_to_png_bytes (texture); +#endif + { + GdkTexture *texture; + GskRenderer *renderer; + GdkSurface *window; + + if (renderer_name) + g_object_set_data_full (G_OBJECT (gdk_display_get_default ()), "gsk-renderer", + g_strdup (renderer_name), g_free); + + window = gdk_surface_new_toplevel (gdk_display_get_default ()); + renderer = gsk_renderer_new_for_surface (window); + + texture = gsk_renderer_render_texture (renderer, node, NULL); + + if (g_str_has_suffix (save_to, ".tif") || + g_str_has_suffix (save_to, ".tiff")) + bytes = gdk_texture_save_to_tiff_bytes (texture); + else + bytes = gdk_texture_save_to_png_bytes (texture); + + g_object_unref (texture); + } if (g_file_set_contents (save_to, g_bytes_get_data (bytes, NULL), @@ -110,7 +182,6 @@ render_file (const char *filename, if (save_to != save_file) g_free (save_to); - g_object_unref (texture); gsk_render_node_unref (node); } From 2ad11e12d464334984362a1d3f247e9b84e14650 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Mon, 24 Jul 2023 05:56:47 +0200 Subject: [PATCH 08/10] vulkan: Plug a memleak Yay, we no longer leak swapchain images --- gsk/vulkan/gskvulkanrender.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gsk/vulkan/gskvulkanrender.c b/gsk/vulkan/gskvulkanrender.c index 9e3c0cbca9..8637ed5f64 100644 --- a/gsk/vulkan/gskvulkanrender.c +++ b/gsk/vulkan/gskvulkanrender.c @@ -483,7 +483,7 @@ gsk_vulkan_render_add_node (GskVulkanRender *self, cairo_region_get_extents (self->clip, &extents); gsk_vulkan_render_pass_begin_op (self, - g_object_ref (self->target), + self->target, &extents, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); @@ -499,7 +499,7 @@ gsk_vulkan_render_add_node (GskVulkanRender *self, gsk_vulkan_render_pass_free (render_pass); gsk_vulkan_render_pass_end_op (self, - g_object_ref (self->target), + self->target, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); if (download_func) From e98ae233fc05e1960656e44c8f2664aa7ba6f6e4 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 23 Jul 2023 01:57:06 +0200 Subject: [PATCH 09/10] vulkan: Fix a memleak --- gsk/vulkan/gskvulkanrenderpass.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gsk/vulkan/gskvulkanrenderpass.c b/gsk/vulkan/gskvulkanrenderpass.c index 56f190580c..2bd3367f44 100644 --- a/gsk/vulkan/gskvulkanrenderpass.c +++ b/gsk/vulkan/gskvulkanrenderpass.c @@ -162,7 +162,7 @@ gsk_vulkan_render_pass_upload_texture (GskVulkanRender *render, gdk_texture_get_format (texture), width, height); gsk_vulkan_render_pass_begin_op (render, - g_object_ref (better_image), + better_image, &(cairo_rectangle_int_t) { 0, 0, width, height }, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); From e00e6f3d5da2c40917f7b3bea3778a3dd99360ef Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 23 Jul 2023 18:26:52 +0200 Subject: [PATCH 10/10] vulkan: Clear Cairo surfaces on upload The memory isn't guaranteed to be all zeroes and we don't want glitches. --- gsk/vulkan/gskvulkanuploadop.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/gsk/vulkan/gskvulkanuploadop.c b/gsk/vulkan/gskvulkanuploadop.c index 428590f559..afb0904456 100644 --- a/gsk/vulkan/gskvulkanuploadop.c +++ b/gsk/vulkan/gskvulkanuploadop.c @@ -287,6 +287,9 @@ gsk_vulkan_upload_cairo_op_draw (GskVulkanOp *op, width / self->viewport.size.width, height / self->viewport.size.height); cr = cairo_create (surface); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); cairo_translate (cr, -self->viewport.origin.x, -self->viewport.origin.y); gsk_render_node_draw (self->node, cr); @@ -402,6 +405,9 @@ gsk_vulkan_upload_glyph_op_draw (GskVulkanOp *op, cairo_surface_set_device_scale (surface, self->scale, self->scale); cr = cairo_create (surface); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + cairo_paint (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); /* Make sure the entire surface is initialized to black */ cairo_set_source_rgba (cr, 0, 0, 0, 0);