[gtk/gtk-4-6] renderers: Handle large viewports
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/gtk-4-6] renderers: Handle large viewports
- Date: Wed, 16 Mar 2022 02:20:17 +0000 (UTC)
commit 50554bb92b165f9e331cc842ea4310baec0acfd8
Author: Benjamin Otte <otte redhat com>
Date: Fri Feb 25 03:40:57 2022 +0100
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(-)
---
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',
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]