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: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1860>
This commit is contained in:
Daniel van Vugt 2021-05-10 17:18:55 +08:00
parent a8c18514a2
commit 9e6a3f537b

View File

@ -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;
}