From b28c3ef3d96edb17e3c819895177bb4293ac4790 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Fri, 25 Feb 2022 03:40:57 +0100 Subject: [PATCH 1/3] renderers: Handle large viewports When large viewports are passed to gsk_renderer_render_texture(), don't fail (or even return NULL). Instead, draw multiple tiles and assemble them into a memory texture. Tests added to the testsuite for this. --- gsk/gl/gskglrenderer.c | 40 +++++++++++++++++++++++-- gsk/gskcairorenderer.c | 38 ++++++++++++++++++++++- testsuite/gsk/compare/huge-height.node | 7 +++++ testsuite/gsk/compare/huge-height.png | Bin 0 -> 689 bytes testsuite/gsk/compare/huge-width.node | 7 +++++ testsuite/gsk/compare/huge-width.png | Bin 0 -> 657 bytes testsuite/gsk/meson.build | 2 ++ 7 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 testsuite/gsk/compare/huge-height.node create mode 100644 testsuite/gsk/compare/huge-height.png create mode 100644 testsuite/gsk/compare/huge-width.node create mode 100644 testsuite/gsk/compare/huge-width.png diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index fe244a7a4f..d1b40d225e 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -306,10 +306,9 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer, GskGLRenderer *self = (GskGLRenderer *)renderer; GskGLRenderTarget *render_target; GskGLRenderJob *job; - GdkTexture *texture = NULL; + GdkTexture *texture; guint texture_id; - int width; - int height; + int width, height, max_size; int format; g_assert (GSK_IS_GL_RENDERER (renderer)); @@ -317,6 +316,37 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer, width = ceilf (viewport->size.width); height = ceilf (viewport->size.height); + max_size = self->command_queue->max_texture_size; + if (width > max_size || height > max_size) + { + gsize x, y, size, stride; + GBytes *bytes; + guchar *data; + + stride = width * 4; + size = stride * height; + data = g_malloc_n (stride, height); + + for (y = 0; y < height; y += max_size) + { + for (x = 0; x < width; x += max_size) + { + texture = gsk_gl_renderer_render_texture (renderer, root, + &GRAPHENE_RECT_INIT (x, y, + MIN (max_size, viewport->size.width - x), + MIN (max_size, viewport->size.height - y))); + gdk_texture_download (texture, + data + stride * y + x * 4, + stride); + g_object_unref (texture); + } + } + + bytes = g_bytes_new_take (data, size); + texture = gdk_memory_texture_new (width, height, GDK_MEMORY_DEFAULT, bytes, stride); + g_bytes_unref (bytes); + return texture; + } format = gsk_render_node_prefers_high_depth (root) ? GL_RGBA32F : GL_RGBA8; @@ -342,6 +372,10 @@ gsk_gl_renderer_render_texture (GskRenderer *renderer, gsk_gl_driver_after_frame (self->driver); } + else + { + g_assert_not_reached (); + } return g_steal_pointer (&texture); } diff --git a/gsk/gskcairorenderer.c b/gsk/gskcairorenderer.c index 3135acfdb1..24675ce35f 100644 --- a/gsk/gskcairorenderer.c +++ b/gsk/gskcairorenderer.c @@ -107,8 +107,44 @@ gsk_cairo_renderer_render_texture (GskRenderer *renderer, GdkTexture *texture; cairo_surface_t *surface; cairo_t *cr; + int width, height; + /* limit from cairo's source code */ +#define MAX_IMAGE_SIZE 32767 - surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, ceil (viewport->size.width), ceil (viewport->size.height)); + width = ceil (viewport->size.width); + height = ceil (viewport->size.height); + if (width > MAX_IMAGE_SIZE || height > MAX_IMAGE_SIZE) + { + gsize x, y, size, stride; + GBytes *bytes; + guchar *data; + + stride = width * 4; + size = stride * height; + data = g_malloc_n (stride, height); + + for (y = 0; y < height; y += MAX_IMAGE_SIZE) + { + for (x = 0; x < width; x += MAX_IMAGE_SIZE) + { + texture = gsk_cairo_renderer_render_texture (renderer, root, + &GRAPHENE_RECT_INIT (x, y, + MIN (MAX_IMAGE_SIZE, viewport->size.width - x), + MIN (MAX_IMAGE_SIZE, viewport->size.height - y))); + gdk_texture_download (texture, + data + stride * y + x * 4, + stride); + g_object_unref (texture); + } + } + + bytes = g_bytes_new_take (data, size); + texture = gdk_memory_texture_new (width, height, GDK_MEMORY_DEFAULT, bytes, stride); + g_bytes_unref (bytes); + return texture; + } + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); cr = cairo_create (surface); cairo_translate (cr, - viewport->origin.x, - viewport->origin.y); diff --git a/testsuite/gsk/compare/huge-height.node b/testsuite/gsk/compare/huge-height.node new file mode 100644 index 0000000000..ce33081ff8 --- /dev/null +++ b/testsuite/gsk/compare/huge-height.node @@ -0,0 +1,7 @@ +color { + color: transparent; + /* - more than 32k, to trip modern GPUs and Cairo + * - non-integer to test rounding code + */ + bounds: 0 0 135.7 33333.3; +} diff --git a/testsuite/gsk/compare/huge-height.png b/testsuite/gsk/compare/huge-height.png new file mode 100644 index 0000000000000000000000000000000000000000..0162f5307ba54a20143f54fc2b064efcab3d63d1 GIT binary patch literal 689 zcmeAS@N?(olHy`uVBq!ia0vp^9SjUjW{k{0mZj~E^FWF@z$e5NNH4Fly#=HgOM?7@ z862M7NMm4Nit%)D43Ut0d(e;(D0N8T_wqPi{sbU%6pV%dWg&2fTO*i(G4pF~FUTBE LS3j3^P6 Date: Sat, 26 Feb 2022 04:36:24 +0100 Subject: [PATCH 2/3] flattenlistmodel: Fix indentation --- gtk/gtkflattenlistmodel.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/gtk/gtkflattenlistmodel.c b/gtk/gtkflattenlistmodel.c index 15a164f5c9..74f3b7795a 100644 --- a/gtk/gtkflattenlistmodel.c +++ b/gtk/gtkflattenlistmodel.c @@ -72,8 +72,8 @@ static GParamSpec *properties[NUM_PROPERTIES] = { NULL, }; static FlattenNode * gtk_flatten_list_model_get_nth (GtkRbTree *tree, - guint position, - guint *model_position) + guint position, + guint *model_position) { FlattenNode *node, *tmp; guint model_n_items; @@ -110,8 +110,8 @@ gtk_flatten_list_model_get_nth (GtkRbTree *tree, static FlattenNode * gtk_flatten_list_model_get_nth_model (GtkRbTree *tree, - guint position, - guint *items_before) + guint position, + guint *items_before) { FlattenNode *node, *tmp; guint before; @@ -202,11 +202,11 @@ G_DEFINE_TYPE_WITH_CODE (GtkFlattenListModel, gtk_flatten_list_model, G_TYPE_OBJ G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, gtk_flatten_list_model_model_init)) static void -gtk_flatten_list_model_items_changed_cb (GListModel *model, - guint position, - guint removed, - guint added, - gpointer _node) +gtk_flatten_list_model_items_changed_cb (GListModel *model, + guint position, + guint removed, + guint added, + gpointer _node) { FlattenNode *node = _node, *parent, *left; GtkFlattenListModel *self = node->list; @@ -323,10 +323,10 @@ gtk_flatten_list_model_set_property (GObject *object, } static void -gtk_flatten_list_model_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +gtk_flatten_list_model_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { GtkFlattenListModel *self = GTK_FLATTEN_LIST_MODEL (object); From bffa5dfddde61d416bb2955f46baecc091090a1d Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 26 Feb 2022 03:04:53 +0100 Subject: [PATCH 3/3] listview: Fix return_if_fail()s --- gtk/gtkgridview.c | 2 +- gtk/gtklistitemmanager.c | 2 +- gtk/gtklistview.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gtk/gtkgridview.c b/gtk/gtkgridview.c index c6cefbb10e..9b903dc5e0 100644 --- a/gtk/gtkgridview.c +++ b/gtk/gtkgridview.c @@ -1291,7 +1291,7 @@ gtk_grid_view_set_factory (GtkGridView *self, GtkListItemFactory *factory) { g_return_if_fail (GTK_IS_GRID_VIEW (self)); - g_return_if_fail (factory == NULL || GTK_LIST_ITEM_FACTORY (factory)); + g_return_if_fail (factory == NULL || GTK_IS_LIST_ITEM_FACTORY (factory)); if (factory == gtk_list_item_manager_get_factory (self->item_manager)) return; diff --git a/gtk/gtklistitemmanager.c b/gtk/gtklistitemmanager.c index 1a0ff55161..bfc6860293 100644 --- a/gtk/gtklistitemmanager.c +++ b/gtk/gtklistitemmanager.c @@ -825,7 +825,7 @@ gtk_list_item_manager_set_factory (GtkListItemManager *self, GSList *l; g_return_if_fail (GTK_IS_LIST_ITEM_MANAGER (self)); - g_return_if_fail (GTK_IS_LIST_ITEM_FACTORY (factory)); + g_return_if_fail (factory == NULL || GTK_IS_LIST_ITEM_FACTORY (factory)); if (self->factory == factory) return; diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c index 1868bdc36e..e968f8437a 100644 --- a/gtk/gtklistview.c +++ b/gtk/gtklistview.c @@ -1032,7 +1032,7 @@ gtk_list_view_set_factory (GtkListView *self, GtkListItemFactory *factory) { g_return_if_fail (GTK_IS_LIST_VIEW (self)); - g_return_if_fail (factory == NULL || GTK_LIST_ITEM_FACTORY (factory)); + g_return_if_fail (factory == NULL || GTK_IS_LIST_ITEM_FACTORY (factory)); if (factory == gtk_list_item_manager_get_factory (self->item_manager)) return;