[gtk/wip/baedert/gl-rework: 59/71] gl renderer: Transform rounded rect on the GPU



commit 78eadc729f4be1d36c2a0bf658894221270856f2
Author: Timm Bäder <mail baedert org>
Date:   Sun Jan 19 17:11:57 2020 +0100

    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.

 gsk/gl/gskglrenderer.c                          | 47 ++++++---------
 gsk/resources/glsl/border.glsl                  |  3 +
 gsk/resources/glsl/inset_shadow.glsl            | 16 +++--
 gsk/resources/glsl/outset_shadow.glsl           |  1 +
 gsk/resources/glsl/preamble.fs.glsl             | 80 +++++++++++++++----------
 gsk/resources/glsl/unblurred_outset_shadow.glsl | 16 +++--
 6 files changed, 94 insertions(+), 69 deletions(-)
---
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);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]