From: Benjamin Otte Date: Fri, 25 Feb 2022 02:40:57 +0000 (+0100) Subject: renderers: Handle large viewports X-Git-Tag: archive/raspbian/4.8.3+ds-2+rpi1~3^2~20^2~4^2~360^2~2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=b28c3ef3d96edb17e3c819895177bb4293ac4790;p=gtk4.git 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. --- 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 0000000000..0162f5307b Binary files /dev/null and b/testsuite/gsk/compare/huge-height.png differ diff --git a/testsuite/gsk/compare/huge-width.node b/testsuite/gsk/compare/huge-width.node new file mode 100644 index 0000000000..db9533bf57 --- /dev/null +++ b/testsuite/gsk/compare/huge-width.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 33333.3 135.7; +} diff --git a/testsuite/gsk/compare/huge-width.png b/testsuite/gsk/compare/huge-width.png new file mode 100644 index 0000000000..e7d0e91314 Binary files /dev/null and b/testsuite/gsk/compare/huge-width.png differ diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index 71e18f824d..106661a708 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -58,6 +58,8 @@ compare_render_tests = [ 'empty-shadow', 'empty-texture', 'empty-transform', + 'huge-height', + 'huge-width', 'inset-shadow-multiple', 'invalid-transform', 'issue-3615',