From 9e6a3f537bfbaa7e3dcada5728513cf9b993b55a Mon Sep 17 00:00:00 2001 From: Daniel van Vugt Date: Mon, 10 May 2021 17:18:55 +0800 Subject: [PATCH] background-content: Shrink and optimize the rounded-clip shader The main benefit being it now fits within the hardware limits for the i915 Mesa driver, and runs on the GPU instead of software fallback. Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4251, https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4425 Part-of: --- src/compositor/meta-background-content.c | 131 +++++++---------------- 1 file changed, 39 insertions(+), 92 deletions(-) diff --git a/src/compositor/meta-background-content.c b/src/compositor/meta-background-content.c index 86f777752..eeae41c62 100644 --- a/src/compositor/meta-background-content.c +++ b/src/compositor/meta-background-content.c @@ -135,77 +135,50 @@ typedef enum "cogl_color_out.rgb = cogl_color_out.rgb * pixel_brightness;\n" \ "cogl_color_out.rgb += (rand(position) - 0.5) / 255.0;\n" \ -/* The ellipsis_dist(), ellipsis_coverage() and rounded_rect_coverage() are - * copied from GSK, see gsk_ellipsis_dist(), gsk_ellipsis_coverage(), and - * gsk_rounded_rect_coverage() here: - * https://gitlab.gnome.org/GNOME/gtk/-/blob/4.3.1/gsk/gl/resources/preamble.fs.glsl - */ #define ROUNDED_CLIP_FRAGMENT_SHADER_DECLARATIONS \ -"uniform vec4 bounds; // x, y: top left; w, v: bottom right \n"\ -"uniform vec4 corner_centers_1; // x, y: top left; w, v: top right \n"\ -"uniform vec4 corner_centers_2; // x, y: bottom right; w, v: bottom left \n"\ +"uniform vec4 bounds; // x, y: top left; z, w: bottom right \n"\ +"uniform float clip_radius; \n"\ "uniform vec2 pixel_step; \n"\ " \n"\ "float \n"\ -"ellipsis_dist (vec2 p, vec2 radius) \n"\ +"rounded_rect_coverage (vec2 p) \n"\ "{ \n"\ -" if (radius == vec2(0, 0)) \n"\ -" return 0.0; \n"\ +" float center_left = bounds.x + clip_radius; \n"\ +" float center_right = bounds.z - clip_radius; \n"\ +" float center_x; \n"\ " \n"\ -" vec2 p0 = p / radius; \n"\ -" vec2 p1 = (2.0 * p0) / radius; \n"\ +" if (p.x < center_left) \n"\ +" center_x = center_left; \n"\ +" else if (p.x > center_right) \n"\ +" center_x = center_right; \n"\ +" else \n"\ +" return 1.0; // The vast majority of pixels exit early here \n"\ " \n"\ -" return (dot(p0, p0) - 1.0) / length (p1); \n"\ -"} \n"\ +" float center_top = bounds.y + clip_radius; \n"\ +" float center_bottom = bounds.w - clip_radius; \n"\ +" float center_y; \n"\ " \n"\ -"float \n"\ -"ellipsis_coverage (vec2 point, vec2 center, vec2 radius) \n"\ -"{ \n"\ -" float d = ellipsis_dist ((point - center), radius); \n"\ -" return clamp (0.5 - d, 0.0, 1.0); \n"\ -"} \n"\ -" \n"\ -"float \n"\ -"rounded_rect_coverage (vec4 bounds, \n"\ -" vec4 corner_centers_1, \n"\ -" vec4 corner_centers_2, \n"\ -" vec2 p) \n"\ -"{ \n"\ -" if (p.x < bounds.x || p.y < bounds.y || \n"\ -" p.x >= bounds.z || p.y >= bounds.w) \n"\ -" return 0.0; \n"\ -" \n"\ -" vec2 ref_tl = corner_centers_1.xy; \n"\ -" vec2 ref_tr = corner_centers_1.zw; \n"\ -" vec2 ref_br = corner_centers_2.xy; \n"\ -" vec2 ref_bl = corner_centers_2.zw; \n"\ -" \n"\ -" if (p.x >= ref_tl.x && p.x >= ref_bl.x && \n"\ -" p.x <= ref_tr.x && p.x <= ref_br.x) \n"\ +" if (p.y < center_top) \n"\ +" center_y = center_top; \n"\ +" else if (p.y > center_bottom) \n"\ +" center_y = center_bottom; \n"\ +" else \n"\ " return 1.0; \n"\ " \n"\ -" if (p.y >= ref_tl.y && p.y >= ref_tr.y && \n"\ -" p.y <= ref_bl.y && p.y <= ref_br.y) \n"\ +" vec2 delta = p - vec2 (center_x, center_y); \n"\ +" float dist_squared = dot (delta, delta); \n"\ +" \n"\ +" // Fully outside the circle \n"\ +" if (dist_squared >= (clip_radius * clip_radius)) \n"\ +" return 0.0; \n"\ +" \n"\ +" // Fully inside the circle \n"\ +" float inner_radius = clip_radius - 1.0; \n"\ +" if (dist_squared <= (inner_radius * inner_radius)) \n"\ " return 1.0; \n"\ " \n"\ -" vec2 rad_tl = corner_centers_1.xy - bounds.xy; \n"\ -" vec2 rad_tr = corner_centers_1.zw - bounds.zy; \n"\ -" vec2 rad_br = corner_centers_2.xy - bounds.zw; \n"\ -" vec2 rad_bl = corner_centers_2.zw - bounds.xw; \n"\ -" \n"\ -" float d_tl = ellipsis_coverage(p, ref_tl, rad_tl); \n"\ -" float d_tr = ellipsis_coverage(p, ref_tr, rad_tr); \n"\ -" float d_br = ellipsis_coverage(p, ref_br, rad_br); \n"\ -" float d_bl = ellipsis_coverage(p, ref_bl, rad_bl); \n"\ -" \n"\ -" vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl); \n"\ -" \n"\ -" bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y, \n"\ -" p.x > ref_tr.x && p.y < ref_tr.y, \n"\ -" p.x > ref_br.x && p.y > ref_br.y, \n"\ -" p.x < ref_bl.x && p.y > ref_bl.y); \n"\ -" \n"\ -" return 1.0 - dot(vec4(is_out), corner_coverages); \n"\ +" // Only pixels on the edge of the curve need expensive antialiasing \n"\ +" return clip_radius - sqrt (dist_squared); \n"\ "} \n" #define ROUNDED_CLIP_FRAGMENT_SHADER_CODE \ @@ -213,10 +186,7 @@ typedef enum " \n"\ "texture_coord = cogl_tex_coord0_in.xy / pixel_step; \n"\ " \n"\ -"cogl_color_out *= rounded_rect_coverage (bounds, \n"\ -" corner_centers_1, \n"\ -" corner_centers_2, \n"\ -" texture_coord); \n" +"cogl_color_out *= rounded_rect_coverage (texture_coord); \n" typedef struct _MetaBackgroundLayer MetaBackgroundLayer; @@ -540,45 +510,22 @@ setup_pipeline (MetaBackgroundContent *self, bounds_y2, }; - float corner_centers_1[] = { - bounds_x1 + clip_radius, - bounds_y1 + clip_radius, - bounds_x2 - clip_radius, - bounds_y1 + clip_radius, - }; - - float corner_centers_2[] = { - bounds_x2 - clip_radius, - bounds_y2 - clip_radius, - bounds_x1 + clip_radius, - bounds_y2 - clip_radius, - }; - int bounds_uniform_location; - int corner_centers_1_uniform_location; - int corner_centers_2_uniform_location; + int clip_radius_uniform_location; bounds_uniform_location = cogl_pipeline_get_uniform_location (self->pipeline, "bounds"); - corner_centers_1_uniform_location = - cogl_pipeline_get_uniform_location (self->pipeline, "corner_centers_1"); - corner_centers_2_uniform_location = - cogl_pipeline_get_uniform_location (self->pipeline, "corner_centers_2"); + clip_radius_uniform_location = + cogl_pipeline_get_uniform_location (self->pipeline, "clip_radius"); cogl_pipeline_set_uniform_float (self->pipeline, bounds_uniform_location, 4, 1, bounds); - cogl_pipeline_set_uniform_float (self->pipeline, - corner_centers_1_uniform_location, - 4, 1, - corner_centers_1); - - cogl_pipeline_set_uniform_float (self->pipeline, - corner_centers_2_uniform_location, - 4, 1, - corner_centers_2); + cogl_pipeline_set_uniform_1f (self->pipeline, + clip_radius_uniform_location, + clip_radius); self->changed &= ~CHANGED_ROUNDED_CLIP_PARAMETERS; }