From da6096faaf59e055367a115dc47035f8994f9cae Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 11 Apr 2021 21:13:47 -0400 Subject: [PATCH 1/4] ngl: Add code to dump shadows This can be helpful in understanding shadow bugs. --- gsk/ngl/gsknglshadowlibrary.c | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/gsk/ngl/gsknglshadowlibrary.c b/gsk/ngl/gsknglshadowlibrary.c index bcf524c8b7..301a3c1624 100644 --- a/gsk/ngl/gsknglshadowlibrary.c +++ b/gsk/ngl/gsknglshadowlibrary.c @@ -202,6 +202,31 @@ gsk_ngl_shadow_library_lookup (GskNglShadowLibrary *self, return ret->texture_id; } +#if 0 +static void +write_shadow_to_png (const Shadow *shadow) +{ + int width = shadow->outline.bounds.size.width + (shadow->outline.bounds.origin.x * 2); + int height = shadow->outline.bounds.size.height + (shadow->outline.bounds.origin.y * 2); + int stride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, width); + guchar *data = g_malloc (height * stride); + cairo_surface_t *s; + char *filename = g_strdup_printf ("shadow_cache_%d_%d_%d.png", + width, height, shadow->texture_id); + + glBindTexture (GL_TEXTURE_2D, shadow->texture_id); + glGetTexImage (GL_TEXTURE_2D, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data); + s = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_ARGB32, + width, height, + stride); + cairo_surface_write_to_png (s, filename); + + cairo_surface_destroy (s); + g_free (data); + g_free (filename); +} +#endif + void gsk_ngl_shadow_library_begin_frame (GskNglShadowLibrary *self) { @@ -211,6 +236,14 @@ gsk_ngl_shadow_library_begin_frame (GskNglShadowLibrary *self) g_return_if_fail (GSK_IS_NGL_SHADOW_LIBRARY (self)); +#if 0 + for (i = 0, p = self->shadows->len; i < p; i++) + { + const Shadow *shadow = &g_array_index (self->shadows, Shadow, i); + write_shadow_to_png (shadow); + } +#endif + watermark = self->driver->current_frame_id - MAX_UNUSED_FRAMES; for (i = 0, p = self->shadows->len; i < p; i++) From 46270d3dcd81f4437f4441c3f5439ba17f246de1 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 11 Apr 2021 22:02:44 -0400 Subject: [PATCH 2/4] ngl: Fix a case of flipped shadow In the non-sliced case, we were rendering the shadow upside down. --- gsk/ngl/gsknglrenderjob.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c index 60f0cff82c..4a3d1394b7 100644 --- a/gsk/ngl/gsknglrenderjob.c +++ b/gsk/ngl/gsknglrenderjob.c @@ -2433,7 +2433,7 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job, float min_x = floorf (outline->bounds.origin.x - spread - half_blur_extra + dx); float min_y = floorf (outline->bounds.origin.y - spread - half_blur_extra + dy); - offscreen.was_offscreen = FALSE; + offscreen.was_offscreen = TRUE; offscreen.texture_id = blurred_texture_id; init_full_texture_region (&offscreen); From f3bf4e487690443ba6f3acc341ad7f7293b0aae4 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 11 Apr 2021 22:09:45 -0400 Subject: [PATCH 3/4] ngl: Don't slice unsliceable shadows When the corners are too big to make slicing work, don't do it, since it leads to broken results. --- gsk/ngl/gsknglrenderjob.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c index 4a3d1394b7..5c34d1273b 100644 --- a/gsk/ngl/gsknglrenderjob.c +++ b/gsk/ngl/gsknglrenderjob.c @@ -2311,6 +2311,8 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job, int cached_tid; gboolean do_slicing; guint16 color[4]; + float half_width = outline->bounds.size.width / 2; + float half_height = outline->bounds.size.height / 2; rgba_to_half (gsk_outset_shadow_node_get_color (node), color); @@ -2319,7 +2321,15 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job, scaled_outline = *outline; if (outline->bounds.size.width < blur_extra || - outline->bounds.size.height < blur_extra) + outline->bounds.size.height < blur_extra || + outline->corner[0].width >= half_width || + outline->corner[1].width >= half_width || + outline->corner[2].width >= half_width || + outline->corner[3].width >= half_width || + outline->corner[0].height >= half_height || + outline->corner[1].height >= half_height || + outline->corner[2].height >= half_height || + outline->corner[3].height >= half_height) { do_slicing = FALSE; gsk_rounded_rect_shrink (&scaled_outline, -spread, -spread, -spread, -spread); From 849692b24ba2073f9ef1edfe5de9ec6a6b169bd8 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 11 Apr 2021 22:26:36 -0400 Subject: [PATCH 4/4] ngl: Fix unevenly scaled shadows Ensure that we don't cut them off at the edges. --- gsk/ngl/gsknglrenderjob.c | 16 +++-- gsk/ngl/gskngltexturepool.c | 5 +- gsk/ngl/gskngltexturepoolprivate.h | 3 +- gsk/ngl/ninesliceprivate.h | 101 +++++++++++++++-------------- 4 files changed, 65 insertions(+), 60 deletions(-) diff --git a/gsk/ngl/gsknglrenderjob.c b/gsk/ngl/gsknglrenderjob.c index 5c34d1273b..e23d4741c6 100644 --- a/gsk/ngl/gsknglrenderjob.c +++ b/gsk/ngl/gsknglrenderjob.c @@ -2299,7 +2299,8 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job, float blur_radius = gsk_outset_shadow_node_get_blur_radius (node); float blur_extra = blur_radius * 2.0f; /* 2.0 = shader radius_multiplier */ float half_blur_extra = blur_extra / 2.0f; - int extra_blur_pixels = ceilf (half_blur_extra * scale_x); + int extra_blur_pixels_x = ceilf (half_blur_extra * scale_x); + int extra_blur_pixels_y = ceilf (half_blur_extra * scale_y); float spread = gsk_outset_shadow_node_get_spread (node); float dx = gsk_outset_shadow_node_get_dx (node); float dy = gsk_outset_shadow_node_get_dy (node); @@ -2352,10 +2353,10 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job, texture_width = (int)ceil ((scaled_outline.bounds.size.width + blur_extra) * scale_x); texture_height = (int)ceil ((scaled_outline.bounds.size.height + blur_extra) * scale_y); - scaled_outline.bounds.origin.x = extra_blur_pixels; - scaled_outline.bounds.origin.y = extra_blur_pixels; - scaled_outline.bounds.size.width = texture_width - (extra_blur_pixels * 2); - scaled_outline.bounds.size.height = texture_height - (extra_blur_pixels * 2); + scaled_outline.bounds.origin.x = extra_blur_pixels_x; + scaled_outline.bounds.origin.y = extra_blur_pixels_y; + scaled_outline.bounds.size.width = texture_width - (extra_blur_pixels_x * 2); + scaled_outline.bounds.size.height = texture_height - (extra_blur_pixels_y * 2); for (guint i = 0; i < G_N_ELEMENTS (scaled_outline.corner); i++) { @@ -2493,12 +2494,13 @@ gsk_ngl_render_job_visit_blurred_outset_shadow_node (GskNglRenderJob *job, GskNglTexture *texture; texture = gsk_ngl_driver_get_texture_by_id (job->driver, blurred_texture_id); - slices = gsk_ngl_texture_get_nine_slice (texture, &scaled_outline, extra_blur_pixels); + slices = gsk_ngl_texture_get_nine_slice (texture, &scaled_outline, extra_blur_pixels_x, extra_blur_pixels_y); offscreen.was_offscreen = TRUE; /* Our texture coordinates MUST be scaled, while the actual vertex coords - * MUST NOT be scaled. */ + * MUST NOT be scaled. + */ left_width = slices[NINE_SLICE_TOP_LEFT].rect.width / scale_x; right_width = slices[NINE_SLICE_TOP_RIGHT].rect.width / scale_x; diff --git a/gsk/ngl/gskngltexturepool.c b/gsk/ngl/gskngltexturepool.c index 707ae37455..c5a1d04c4e 100644 --- a/gsk/ngl/gskngltexturepool.c +++ b/gsk/ngl/gskngltexturepool.c @@ -170,7 +170,8 @@ gsk_ngl_texture_new (guint texture_id, const GskNglTextureNineSlice * gsk_ngl_texture_get_nine_slice (GskNglTexture *texture, const GskRoundedRect *outline, - float extra_pixels) + float extra_pixels_x, + float extra_pixels_y) { g_assert (texture != NULL); g_assert (outline != NULL); @@ -180,7 +181,7 @@ gsk_ngl_texture_get_nine_slice (GskNglTexture *texture, texture->nine_slice = g_new0 (GskNglTextureNineSlice, 9); nine_slice_rounded_rect (texture->nine_slice, outline); - nine_slice_grow (texture->nine_slice, extra_pixels); + nine_slice_grow (texture->nine_slice, extra_pixels_x, extra_pixels_y); nine_slice_to_texture_coords (texture->nine_slice, texture->width, texture->height); } diff --git a/gsk/ngl/gskngltexturepoolprivate.h b/gsk/ngl/gskngltexturepoolprivate.h index ac8e326eb5..548fe83f4f 100644 --- a/gsk/ngl/gskngltexturepoolprivate.h +++ b/gsk/ngl/gskngltexturepoolprivate.h @@ -94,7 +94,8 @@ GskNglTexture *gsk_ngl_texture_new (guint gint64 frame_id); const GskNglTextureNineSlice *gsk_ngl_texture_get_nine_slice (GskNglTexture *texture, const GskRoundedRect *outline, - float extra_pixels); + float extra_pixels_x, + float extra_pixels_y); void gsk_ngl_texture_free (GskNglTexture *texture); G_END_DECLS diff --git a/gsk/ngl/ninesliceprivate.h b/gsk/ngl/ninesliceprivate.h index fe787acc1d..5fa191db39 100644 --- a/gsk/ngl/ninesliceprivate.h +++ b/gsk/ngl/ninesliceprivate.h @@ -159,121 +159,122 @@ nine_slice_to_texture_coords (GskNglTextureNineSlice *slices, static inline void nine_slice_grow (GskNglTextureNineSlice *slices, - int amount) + int amount_x, + int amount_y) { - if (amount == 0) + if (amount_x == 0 && amount_y == 0) return; /* top left */ - slices[0].rect.x -= amount; - slices[0].rect.y -= amount; - if (amount > slices[0].rect.width) - slices[0].rect.width += amount * 2; + slices[0].rect.x -= amount_x; + slices[0].rect.y -= amount_y; + if (amount_x > slices[0].rect.width) + slices[0].rect.width += amount_x * 2; else - slices[0].rect.width += amount; + slices[0].rect.width += amount_x; - if (amount > slices[0].rect.height) - slices[0].rect.height += amount * 2; + if (amount_y > slices[0].rect.height) + slices[0].rect.height += amount_y * 2; else - slices[0].rect.height += amount; + slices[0].rect.height += amount_y; /* Top center */ - slices[1].rect.y -= amount; - if (amount > slices[1].rect.height) - slices[1].rect.height += amount * 2; + slices[1].rect.y -= amount_y; + if (amount_y > slices[1].rect.height) + slices[1].rect.height += amount_y * 2; else - slices[1].rect.height += amount; + slices[1].rect.height += amount_y; /* top right */ - slices[2].rect.y -= amount; - if (amount > slices[2].rect.width) + slices[2].rect.y -= amount_y; + if (amount_x > slices[2].rect.width) { - slices[2].rect.x -= amount; - slices[2].rect.width += amount * 2; + slices[2].rect.x -= amount_x; + slices[2].rect.width += amount_x * 2; } else { - slices[2].rect.width += amount; + slices[2].rect.width += amount_x; } - if (amount > slices[2].rect.height) - slices[2].rect.height += amount * 2; + if (amount_y > slices[2].rect.height) + slices[2].rect.height += amount_y * 2; else - slices[2].rect.height += amount; + slices[2].rect.height += amount_y; - slices[3].rect.x -= amount; - if (amount > slices[3].rect.width) - slices[3].rect.width += amount * 2; + slices[3].rect.x -= amount_x; + if (amount_x > slices[3].rect.width) + slices[3].rect.width += amount_x * 2; else - slices[3].rect.width += amount; + slices[3].rect.width += amount_x; /* Leave center alone */ - if (amount > slices[5].rect.width) + if (amount_x > slices[5].rect.width) { - slices[5].rect.x -= amount; - slices[5].rect.width += amount * 2; + slices[5].rect.x -= amount_x; + slices[5].rect.width += amount_x * 2; } else { - slices[5].rect.width += amount; + slices[5].rect.width += amount_x; } /* Bottom left */ - slices[6].rect.x -= amount; - if (amount > slices[6].rect.width) + slices[6].rect.x -= amount_x; + if (amount_x > slices[6].rect.width) { - slices[6].rect.width += amount * 2; + slices[6].rect.width += amount_x * 2; } else { - slices[6].rect.width += amount; + slices[6].rect.width += amount_x; } - if (amount > slices[6].rect.height) + if (amount_y > slices[6].rect.height) { - slices[6].rect.y -= amount; - slices[6].rect.height += amount * 2; + slices[6].rect.y -= amount_y; + slices[6].rect.height += amount_y * 2; } else { - slices[6].rect.height += amount; + slices[6].rect.height += amount_y; } /* Bottom center */ - if (amount > slices[7].rect.height) + if (amount_y > slices[7].rect.height) { - slices[7].rect.y -= amount; - slices[7].rect.height += amount * 2; + slices[7].rect.y -= amount_y; + slices[7].rect.height += amount_y * 2; } else { - slices[7].rect.height += amount; + slices[7].rect.height += amount_y; } - if (amount > slices[8].rect.width) + if (amount_x > slices[8].rect.width) { - slices[8].rect.x -= amount; - slices[8].rect.width += amount * 2; + slices[8].rect.x -= amount_x; + slices[8].rect.width += amount_x * 2; } else { - slices[8].rect.width += amount; + slices[8].rect.width += amount_x; } - if (amount > slices[8].rect.height) + if (amount_y > slices[8].rect.height) { - slices[8].rect.y -= amount; - slices[8].rect.height += amount * 2; + slices[8].rect.y -= amount_y; + slices[8].rect.height += amount_y * 2; } else { - slices[8].rect.height += amount; + slices[8].rect.height += amount_y; } #ifdef DEBUG_NINE_SLICE