From: Timm Bäder Date: Sun, 19 Jan 2020 16:11:57 +0000 (+0100) Subject: gl renderer: Transform rounded rect on the GPU X-Git-Tag: archive/raspbian/4.4.1+ds1-2+rpi1^2~18^2~20^2~203 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=c8fa1f19dbb490bc30a6dcb670a655720577e6e3;p=gtk4.git gl renderer: Transform rounded rect on the GPU Change the RoundedRect struct we use in our shaders so we can transform it using (affine) matrices. --- diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index ddead714c7..1dd08f88e7 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -535,17 +535,16 @@ transform_rect (GskGLRenderer *self, RenderOpBuilder *builder, const GskRoundedRect *rect) { - const float scale = ops_get_scale (builder); GskRoundedRect r; - int i; - ops_transform_bounds_modelview (builder, &rect->bounds, &r.bounds); + r.bounds.origin.x = builder->dx + rect->bounds.origin.x; + r.bounds.origin.y = builder->dy + rect->bounds.origin.y; + r.bounds.size = rect->bounds.size; - for (i = 0; i < 4; i ++) - { - r.corner[i].width = rect->corner[i].width * scale; - r.corner[i].height = rect->corner[i].height * scale; - } + r.corner[0] = rect->corner[0]; + r.corner[1] = rect->corner[1]; + r.corner[2] = rect->corner[2]; + r.corner[3] = rect->corner[3]; return r; } @@ -745,24 +744,22 @@ render_border_node (GskGLRenderer *self, GskRenderNode *node, RenderOpBuilder *builder) { - const float scale = ops_get_scale (builder); const float min_x = builder->dx + node->bounds.origin.x; const float min_y = builder->dy + node->bounds.origin.y; const float max_x = min_x + node->bounds.size.width; const float max_y = min_y + node->bounds.size.height; const GdkRGBA *colors = gsk_border_node_peek_colors (node); const GskRoundedRect *rounded_outline = gsk_border_node_peek_outline (node); - const float *og_widths = gsk_border_node_peek_widths (node); - float widths[4]; + const float *widths = gsk_border_node_peek_widths (node); int i; struct { float w; float h; } sizes[4]; - if (og_widths[0] == og_widths[1] && - og_widths[0] == og_widths[2] && - og_widths[0] == og_widths[3] && + if (widths[0] == widths[1] && + widths[0] == widths[2] && + widths[0] == widths[3] && gdk_rgba_equal (&colors[0], &colors[1]) && gdk_rgba_equal (&colors[0], &colors[2]) && gdk_rgba_equal (&colors[0], &colors[3])) @@ -773,7 +770,7 @@ render_border_node (GskGLRenderer *self, op = ops_begin (builder, OP_CHANGE_INSET_SHADOW); op->color = &colors[0]; op->outline = transform_rect (self, builder, rounded_outline); - op->spread = og_widths[0] * scale; + op->spread = widths[0]; op->offset[0] = 0; op->offset[1] = 0; @@ -781,9 +778,6 @@ render_border_node (GskGLRenderer *self, return; } - for (i = 0; i < 4; i ++) - widths[i] = og_widths[i]; - /* Top left */ if (widths[3] > 0) sizes[0].w = MAX (widths[3], rounded_outline->corner[0].width); @@ -829,9 +823,6 @@ render_border_node (GskGLRenderer *self, else sizes[3].h = 0; - for (i = 0; i < 4; i ++) - widths[i] *= scale; - { const GskQuadVertex side_data[4][6] = { /* Top */ @@ -1481,7 +1472,6 @@ render_unblurred_inset_shadow_node (GskGLRenderer *self, GskRenderNode *node, RenderOpBuilder *builder) { - const float scale = ops_get_scale (builder); const float blur_radius = gsk_inset_shadow_node_get_blur_radius (node); const float dx = gsk_inset_shadow_node_get_dx (node); const float dy = gsk_inset_shadow_node_get_dy (node); @@ -1494,9 +1484,9 @@ render_unblurred_inset_shadow_node (GskGLRenderer *self, op = ops_begin (builder, OP_CHANGE_INSET_SHADOW); op->color = gsk_inset_shadow_node_peek_color (node); op->outline = transform_rect (self, builder, gsk_inset_shadow_node_peek_outline (node)); - op->spread = spread * scale; - op->offset[0] = dx * scale; - op->offset[1] = dy * scale; + op->spread = spread; + op->offset[0] = dx; + op->offset[1] = dy; load_vertex_data (ops_draw (builder, NULL), node, builder); } @@ -1647,7 +1637,6 @@ render_unblurred_outset_shadow_node (GskGLRenderer *self, GskRenderNode *node, RenderOpBuilder *builder) { - const float scale = ops_get_scale (builder); const GskRoundedRect *outline = gsk_outset_shadow_node_peek_outline (node); const float spread = gsk_outset_shadow_node_get_spread (node); const float dx = gsk_outset_shadow_node_get_dx (node); @@ -1658,9 +1647,9 @@ render_unblurred_outset_shadow_node (GskGLRenderer *self, op = ops_begin (builder, OP_CHANGE_UNBLURRED_OUTSET_SHADOW); op->color = gsk_outset_shadow_node_peek_color (node); op->outline = transform_rect (self, builder, outline); - op->spread = spread * scale; - op->offset[0] = dx * scale; - op->offset[1] = dy * scale; + op->spread = spread; + op->offset[0] = dx; + op->offset[1] = dy; load_vertex_data (ops_draw (builder, NULL), node, builder); } diff --git a/gsk/resources/glsl/border.glsl b/gsk/resources/glsl/border.glsl index a47fe7e393..505c850217 100644 --- a/gsk/resources/glsl/border.glsl +++ b/gsk/resources/glsl/border.glsl @@ -25,6 +25,9 @@ void main() { RoundedRect outside = create_rect(u_outline_rect); RoundedRect inside = rounded_rect_shrink (outside, u_widths); + rounded_rect_transform(outside, u_modelview); + rounded_rect_transform(inside, u_modelview); + float alpha = clamp (rounded_rect_coverage (outside, f.xy) - rounded_rect_coverage (inside, f.xy), 0.0, 1.0); diff --git a/gsk/resources/glsl/inset_shadow.glsl b/gsk/resources/glsl/inset_shadow.glsl index 425b140391..087798abaf 100644 --- a/gsk/resources/glsl/inset_shadow.glsl +++ b/gsk/resources/glsl/inset_shadow.glsl @@ -20,15 +20,21 @@ _IN_ vec4 final_color; void main() { vec4 f = gl_FragCoord; - vec4 color; f.x += u_viewport.x; f.y = (u_viewport.y + u_viewport.w) - f.y; RoundedRect outside = create_rect(u_outline_rect); RoundedRect inside = rounded_rect_shrink(outside, vec4(u_spread)); - color = final_color * clamp (rounded_rect_coverage (outside, f.xy) - - rounded_rect_coverage (inside, f.xy - u_offset), - 0.0, 1.0); - setOutputColor(color); + + rounded_rect_offset(inside, u_offset); + + rounded_rect_transform(outside, u_modelview); + rounded_rect_transform(inside, u_modelview); + + float alpha = clamp (rounded_rect_coverage (outside, f.xy) - + rounded_rect_coverage (inside, f.xy), + 0.0, 1.0); + + setOutputColor(final_color * alpha); } diff --git a/gsk/resources/glsl/outset_shadow.glsl b/gsk/resources/glsl/outset_shadow.glsl index f0c5b3fede..ada444d612 100644 --- a/gsk/resources/glsl/outset_shadow.glsl +++ b/gsk/resources/glsl/outset_shadow.glsl @@ -26,6 +26,7 @@ void main() { f.y = (u_viewport.y + u_viewport.w) - f.y; RoundedRect outline = create_rect(u_outline_rect); + rounded_rect_transform(outline, u_modelview); float alpha = Texture(u_source, vUv).a; alpha *= (1.0 - clamp(rounded_rect_coverage(outline, f.xy), 0.0, 1.0)); diff --git a/gsk/resources/glsl/preamble.fs.glsl b/gsk/resources/glsl/preamble.fs.glsl index 00a8c2135e..056a4a27b7 100644 --- a/gsk/resources/glsl/preamble.fs.glsl +++ b/gsk/resources/glsl/preamble.fs.glsl @@ -6,7 +6,6 @@ precision highp float; precision highp float; #endif - uniform sampler2D u_source; uniform mat4 u_projection; uniform mat4 u_modelview; @@ -33,18 +32,24 @@ _IN_ vec2 vUv; struct RoundedRect { vec4 bounds; - vec4 corner_widths; - vec4 corner_heights; + // Look, arrays can't be in structs if you want to return the struct + // from a function in gles or whatever. Just kill me. + vec4 corner_points1; // xy = top left, zw = top right + vec4 corner_points2; // xy = bottom right, zw = bottom left }; // Transform from a GskRoundedRect to a RoundedRect as we need it. RoundedRect -create_rect(vec4 data[3]) +create_rect(vec4[3] data) { vec4 bounds = vec4(data[0].xy, data[0].xy + data[0].zw); - vec4 widths = vec4(data[1].x, data[1].z, data[2].x, data[2].z); - vec4 heights = vec4(data[1].y, data[1].w, data[2].y, data[2].w); - return RoundedRect(bounds, widths, heights); + + vec4 corner_points1 = vec4(bounds.xy + data[1].xy, + bounds.zy + vec2(data[1].zw * vec2(-1, 1))); + vec4 corner_points2 = vec4(bounds.zw + (data[2].xy * vec2(-1, -1)), + bounds.xw + vec2(data[2].zw * vec2(1, -1))); + + return RoundedRect(bounds, corner_points1, corner_points2); } float @@ -73,15 +78,15 @@ rounded_rect_coverage (RoundedRect r, vec2 p) p.x >= r.bounds.z || p.y >= r.bounds.w) return 0.0; - vec2 rad_tl = vec2(r.corner_widths.x, r.corner_heights.x); - vec2 rad_tr = vec2(r.corner_widths.y, r.corner_heights.y); - vec2 rad_br = vec2(r.corner_widths.z, r.corner_heights.z); - vec2 rad_bl = vec2(r.corner_widths.w, r.corner_heights.w); + vec2 rad_tl = r.corner_points1.xy - r.bounds.xy; + vec2 rad_tr = r.corner_points1.zw - r.bounds.zy; + vec2 rad_br = r.corner_points2.xy - r.bounds.zw; + vec2 rad_bl = r.corner_points2.zw - r.bounds.xw; - vec2 ref_tl = r.bounds.xy + vec2( r.corner_widths.x, r.corner_heights.x); - vec2 ref_tr = r.bounds.zy + vec2(-r.corner_widths.y, r.corner_heights.y); - vec2 ref_br = r.bounds.zw + vec2(-r.corner_widths.z, -r.corner_heights.z); - vec2 ref_bl = r.bounds.xw + vec2( r.corner_widths.w, -r.corner_heights.w); + vec2 ref_tl = r.corner_points1.xy; + vec2 ref_tr = r.corner_points1.zw; + vec2 ref_br = r.corner_points2.xy; + vec2 ref_bl = r.corner_points2.zw; float d_tl = ellipsis_coverage(p, ref_tl, rad_tl); float d_tr = ellipsis_coverage(p, ref_tr, rad_tr); @@ -103,26 +108,38 @@ RoundedRect rounded_rect_shrink (RoundedRect r, vec4 amount) { vec4 new_bounds = r.bounds + vec4(1.0,1.0,-1.0,-1.0) * amount.wxyz; - vec4 new_widths = vec4(0); - vec4 new_heights = vec4(0); + vec4 new_corner_points1 = r.corner_points1; + vec4 new_corner_points2 = r.corner_points2; - // Left top - if (r.corner_widths.x > 0.0) new_widths.x = r.corner_widths.x - amount.w; - if (r.corner_heights.x > 0.0) new_heights.x = r.corner_heights.x - amount.x; + if (r.corner_points1.xy == r.bounds.xy) new_corner_points1.xy = new_bounds.xy; + if (r.corner_points1.zw == r.bounds.zy) new_corner_points1.zw = new_bounds.zy; + if (r.corner_points2.xy == r.bounds.zw) new_corner_points2.xy = new_bounds.zw; + if (r.corner_points2.zw == r.bounds.xw) new_corner_points2.zw = new_bounds.xw; - // Top right - if (r.corner_widths.y > 0.0) new_widths.y = r.corner_widths.y - amount.y; - if (r.corner_heights.y > 0.0) new_heights.y = r.corner_heights.y - amount.x; + return RoundedRect (new_bounds, new_corner_points1, new_corner_points2); +} - // Bottom right - if (r.corner_widths.z > 0.0) new_widths.z = r.corner_widths.z - amount.y; - if (r.corner_heights.z > 0.0) new_heights.z = r.corner_heights.z - amount.z; +void +rounded_rect_offset(inout RoundedRect r, vec2 offset) +{ + r.bounds.xy += offset; + r.bounds.zw += offset; + r.corner_points1.xy += offset; + r.corner_points1.zw += offset; + r.corner_points2.xy += offset; + r.corner_points2.zw += offset; +} + +void rounded_rect_transform(inout RoundedRect r, mat4 mat) +{ + r.bounds.xy = (mat * vec4(r.bounds.xy, 0.0, 1.0)).xy; + r.bounds.zw = (mat * vec4(r.bounds.zw, 0.0, 1.0)).xy; - // Bottom left - if (r.corner_widths.w > 0.0) new_widths.w = r.corner_widths.w - amount.w; - if (r.corner_heights.w > 0.0) new_heights.w = r.corner_heights.w - amount.z; + r.corner_points1.xy = (mat * vec4(r.corner_points1.xy, 0.0, 1.0)).xy; + r.corner_points1.zw = (mat * vec4(r.corner_points1.zw, 0.0, 1.0)).xy; - return RoundedRect (new_bounds, new_widths, new_heights); + r.corner_points2.xy = (mat * vec4(r.corner_points2.xy, 0.0, 1.0)).xy; + r.corner_points2.zw = (mat * vec4(r.corner_points2.zw, 0.0, 1.0)).xy; } vec4 Texture(sampler2D sampler, vec2 texCoords) { @@ -141,6 +158,9 @@ void setOutputColor(vec4 color) { f.x += u_viewport.x; f.y = (u_viewport.y + u_viewport.w) - f.y; + + // We do *NOT* transform the clip rect here since we already + // need to do that on the CPU. #if GSK_GLES gl_FragColor = color * rounded_rect_coverage(create_rect(u_clip_rect), f.xy); #elif GSK_LEGACY diff --git a/gsk/resources/glsl/unblurred_outset_shadow.glsl b/gsk/resources/glsl/unblurred_outset_shadow.glsl index f48288d05c..c5190d392e 100644 --- a/gsk/resources/glsl/unblurred_outset_shadow.glsl +++ b/gsk/resources/glsl/unblurred_outset_shadow.glsl @@ -20,15 +20,21 @@ _IN_ vec4 final_color; void main() { vec4 f = gl_FragCoord; - vec4 color; f.x += u_viewport.x; f.y = (u_viewport.y + u_viewport.w) - f.y; RoundedRect inside = create_rect(u_outline_rect); RoundedRect outside = rounded_rect_shrink(inside, vec4(- u_spread)); - color = final_color * clamp (rounded_rect_coverage (outside, f.xy - u_offset) - - rounded_rect_coverage (inside, f.xy), - 0.0, 1.0); - setOutputColor(color); + + rounded_rect_offset(outside, u_offset); + + rounded_rect_transform(outside, u_modelview); + rounded_rect_transform(inside, u_modelview); + + float alpha = clamp (rounded_rect_coverage (outside, f.xy) - + rounded_rect_coverage (inside, f.xy), + 0.0, 1.0); + + setOutputColor(final_color * alpha); }