From dc47abc60e21493d453a2310bdb3c1a76f17becd Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 13 Feb 2024 12:25:17 +0100 Subject: [PATCH 1/7] gpu: Don't oversize node image There's no need - even if given clip bounds - to render the parts outside the node. So clip to the node bounds. --- gsk/gpu/gskgpunodeprocessor.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index ac2ab41c89..d2e0f0a1aa 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -950,9 +950,13 @@ gsk_gpu_node_processor_get_node_as_image (GskGpuNodeProcessor *self, { if (!gsk_gpu_node_processor_clip_node_bounds (self, node, &clip)) return NULL; - clip_bounds = &clip; } - rect_round_to_pixels (clip_bounds, &self->scale, &self->offset, &clip); + else + { + if (!gsk_rect_intersection (clip_bounds, &node->bounds, &clip)) + return NULL; + } + rect_round_to_pixels (&clip, &self->scale, &self->offset, &clip); image = gsk_gpu_get_node_as_image (self->frame, &clip, From dbbc16947f79ca2c17fdfe1833ee80a61c9a0230 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 13 Feb 2024 12:55:42 +0100 Subject: [PATCH 2/7] gpu: Handle one layer of NULL return This isn't really a useful thing in itself, because none of the callers handle the NULL return. But the resulting crash is easier to debug when it's a NULL image than when add_node() is called on an uninitializes NodeProcessor. --- gsk/gpu/gskgpunodeprocessor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index d2e0f0a1aa..dce6f2ee3a 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -748,6 +748,8 @@ gsk_gpu_node_processor_create_offscreen (GskGpuFrame *frame, gsk_render_node_get_preferred_depth (node), scale, viewport); + if (image == NULL) + return NULL; gsk_gpu_node_processor_add_node (&self, node); From f9b66dff8b5858ff0c7024e2f0a1d8e8e3d125d5 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 13 Feb 2024 13:11:43 +0100 Subject: [PATCH 3/7] testsuite: Add a test for shadows with large offset This was causing crashes in the GPU renderer. Related: #6425 --- testsuite/gsk/compare/shadow-huge-offset.node | 10 ++++++++++ testsuite/gsk/compare/shadow-huge-offset.png | Bin 0 -> 144 bytes testsuite/gsk/meson.build | 1 + 3 files changed, 11 insertions(+) create mode 100644 testsuite/gsk/compare/shadow-huge-offset.node create mode 100644 testsuite/gsk/compare/shadow-huge-offset.png diff --git a/testsuite/gsk/compare/shadow-huge-offset.node b/testsuite/gsk/compare/shadow-huge-offset.node new file mode 100644 index 0000000000..fb08cdc4cb --- /dev/null +++ b/testsuite/gsk/compare/shadow-huge-offset.node @@ -0,0 +1,10 @@ +clip { + clip: -20000 0 50 50; + child: shadow { + shadows: red -20000 0 0; + child: color { + bounds: 0 0 50 50; + color: blue; + } + } +} diff --git a/testsuite/gsk/compare/shadow-huge-offset.png b/testsuite/gsk/compare/shadow-huge-offset.png new file mode 100644 index 0000000000000000000000000000000000000000..9a5764a9b2e6bb2f1829015252759d489970f477 GIT binary patch literal 144 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETa8DPxi4@=GhTEXDy L>gTe~DWM4f*sU)x literal 0 HcmV?d00001 diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index f78740e3c2..b979246ed5 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -137,6 +137,7 @@ compare_render_tests = [ 'scale0-crash', 'shadow-behind', 'shadow-clip-contents', + 'shadow-huge-offset', 'shadow-in-opacity', 'shadow-offset-to-outside-clip', 'shadow-opacity', From a1dda0ec3cc37f62d073817856a007ac645f79bf Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 13 Feb 2024 21:22:13 +0100 Subject: [PATCH 4/7] gpu: Adjust shadows clip by shadow offset When computing the clip of the shadow rect, don't forget that it will ultimately be offset by the shadow offset. Fixes #6425 --- gsk/gpu/gskgpunodeprocessor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index dce6f2ee3a..18ffdd1acd 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -1010,6 +1010,8 @@ gsk_gpu_node_processor_blur_op (GskGpuNodeProcessor *self, /* FIXME: Handle clip radius growing the clip too much */ gsk_gpu_node_processor_get_clip_bounds (self, &clip_rect); + clip_rect.origin.x -= shadow_offset->x; + clip_rect.origin.y -= shadow_offset->y; graphene_rect_inset (&clip_rect, 0.f, -clip_radius); if (!gsk_rect_intersection (rect, &clip_rect, &intermediate_rect)) return; From d4203d147a15d574706c8794c444038b1e3fc617 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 13 Feb 2024 21:25:24 +0100 Subject: [PATCH 5/7] testsuite: Add a test for shadow offset clipping --- testsuite/gsk/compare/shadow-offset-clip.node | 50 ++++++++++++++++++ testsuite/gsk/compare/shadow-offset-clip.png | Bin 0 -> 174 bytes testsuite/gsk/meson.build | 1 + 3 files changed, 51 insertions(+) create mode 100644 testsuite/gsk/compare/shadow-offset-clip.node create mode 100644 testsuite/gsk/compare/shadow-offset-clip.png diff --git a/testsuite/gsk/compare/shadow-offset-clip.node b/testsuite/gsk/compare/shadow-offset-clip.node new file mode 100644 index 0000000000..7f595d8998 --- /dev/null +++ b/testsuite/gsk/compare/shadow-offset-clip.node @@ -0,0 +1,50 @@ +clip { + clip: 10 -10 40 20; + child: shadow { + shadows: red 60 0 1; + child: color { + bounds: -25 -25 50 50; + color: blue; + } + } +} + +clip { + clip: -50 -10 40 20; + child: shadow { + shadows: red -60 0 1; + child: color { + bounds: -25 -25 50 50; + color: blue; + } + } +} + +clip { + clip: -10 10 20 40; + child: shadow { + shadows: red 0 60 1; + child: color { + bounds: -25 -25 50 50; + color: blue; + } + } +} + +clip { + clip: -10 -50 20 40; + child: shadow { + shadows: red 0 -60 1; + child: color { + bounds: -25 -25 50 50; + color: blue; + } + } +} + +/* cover the blur */ +border { + outline: -37 -37 74 74; + colors: black; + widths: 4; +} \ No newline at end of file diff --git a/testsuite/gsk/compare/shadow-offset-clip.png b/testsuite/gsk/compare/shadow-offset-clip.png new file mode 100644 index 0000000000000000000000000000000000000000..3270fb54d3ceb44f8d7e4f5fc62217f64dd4acbf GIT binary patch literal 174 zcmeAS@N?(olHy`uVBq!ia0vp^DImTEf}|>5 z`2{mLJiCzw1Px`WEQU+Lov>y}wY3^Fe@B3(7>+(5Q^ My85}Sb4q9e00ROt_5c6? literal 0 HcmV?d00001 diff --git a/testsuite/gsk/meson.build b/testsuite/gsk/meson.build index b979246ed5..c1ff8e2a12 100644 --- a/testsuite/gsk/meson.build +++ b/testsuite/gsk/meson.build @@ -139,6 +139,7 @@ compare_render_tests = [ 'shadow-clip-contents', 'shadow-huge-offset', 'shadow-in-opacity', + 'shadow-offset-clip', 'shadow-offset-to-outside-clip', 'shadow-opacity', 'shrink-rounded-border', From 9fc80a0bd59b514c5e162e45bf3dec0c130e9467 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 13 Feb 2024 21:39:39 +0100 Subject: [PATCH 6/7] gpu: Update blur code to newer internal API The recommended way to draw offscreens has been init_draw() for a bit, but apparently this code wasn't updated. --- gsk/gpu/gskgpunodeprocessor.c | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 18ffdd1acd..732d18fbbe 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -1003,7 +1003,6 @@ gsk_gpu_node_processor_blur_op (GskGpuNodeProcessor *self, graphene_vec2_t direction; graphene_rect_t clip_rect, intermediate_rect; graphene_point_t real_offset; - int width, height; float clip_radius; clip_radius = gsk_cairo_blur_compute_pixels (blur_radius / 2.0); @@ -1016,25 +1015,11 @@ gsk_gpu_node_processor_blur_op (GskGpuNodeProcessor *self, if (!gsk_rect_intersection (rect, &clip_rect, &intermediate_rect)) return; - width = ceilf (graphene_vec2_get_x (&self->scale) * intermediate_rect.size.width); - height = ceilf (graphene_vec2_get_y (&self->scale) * intermediate_rect.size.height); - - intermediate = gsk_gpu_device_create_offscreen_image (gsk_gpu_frame_get_device (self->frame), - FALSE, - source_depth, - width, height); - - gsk_gpu_node_processor_init (&other, - self->frame, - source_desc, - intermediate, - &(cairo_rectangle_int_t) { 0, 0, width, height }, - &intermediate_rect); - - gsk_gpu_render_pass_begin_op (other.frame, - intermediate, - &(cairo_rectangle_int_t) { 0, 0, width, height }, - GSK_RENDER_PASS_OFFSCREEN); + intermediate = gsk_gpu_node_processor_init_draw (&other, + self->frame, + source_depth, + &self->scale, + &intermediate_rect); gsk_gpu_node_processor_sync_globals (&other, 0); @@ -1048,11 +1033,7 @@ gsk_gpu_node_processor_blur_op (GskGpuNodeProcessor *self, source_rect, &direction); - gsk_gpu_render_pass_end_op (other.frame, - intermediate, - GSK_RENDER_PASS_OFFSCREEN); - - gsk_gpu_node_processor_finish (&other); + gsk_gpu_node_processor_finish_draw (&other, intermediate); real_offset = GRAPHENE_POINT_INIT (self->offset.x + shadow_offset->x, self->offset.y + shadow_offset->y); From ee34781a13b46f121c8fd6359eb4eb7f6ebf73ee Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Tue, 13 Feb 2024 21:44:02 +0100 Subject: [PATCH 7/7] gpu: Pixel-align the blur rectangle Fixes blurriness in shadows. Not sure to do a proper test for this feature. Usually proper pixel alignment is tested by drawing a crips line and checking that it is indeed crisp. But we are testing the blur operation here... Fixes #6380 --- gsk/gpu/gskgpunodeprocessor.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 732d18fbbe..e9e8a01d76 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -1015,6 +1015,8 @@ gsk_gpu_node_processor_blur_op (GskGpuNodeProcessor *self, if (!gsk_rect_intersection (rect, &clip_rect, &intermediate_rect)) return; + rect_round_to_pixels (&intermediate_rect, &self->scale, &self->offset, &intermediate_rect); + intermediate = gsk_gpu_node_processor_init_draw (&other, self->frame, source_depth,