[gtk+/wip/baedert/gl: 40/96] gl renderer: Implement rounded clip nodes



commit f0fafc370a77fd89a4cceb441514ec03852324f0
Author: Timm Bäder <mail baedert org>
Date:   Thu Nov 16 11:41:16 2017 +0100

    gl renderer: Implement rounded clip nodes
    
    mostly a proof of concept

 gsk/gskglrenderer.c                     |   55 ++++++++++++++++++-
 gsk/meson.build                         |    1 +
 gsk/resources/glsl/rounded_clip.fs.glsl |   91 +++++++++++++++++++++++++++++++
 3 files changed, 146 insertions(+), 1 deletions(-)
---
diff --git a/gsk/gskglrenderer.c b/gsk/gskglrenderer.c
index 8c6275e..9137914 100644
--- a/gsk/gskglrenderer.c
+++ b/gsk/gskglrenderer.c
@@ -44,6 +44,7 @@ dump_framebuffer (const char *filename, int w, int h)
 
 static void
 gsk_gl_renderer_setup_render_mode (GskGLRenderer *self);
+
 typedef struct {
   int id;
   /* Common locations (gl_common)*/
@@ -73,6 +74,11 @@ typedef struct {
       int start_point_location;
       int end_point_location;
     };
+    struct {
+      int clip_bounds_location;
+      int corner_widths_location;
+      int corner_heights_location;
+    };
   };
 } Program;
 
@@ -88,6 +94,7 @@ enum {
   MODE_TEXTURE,
   MODE_COLOR_MATRIX,
   MODE_LINEAR_GRADIENT,
+  MODE_ROUNDED_CLIP,
   N_MODES
 };
 
@@ -120,6 +127,11 @@ typedef struct {
       graphene_point_t start_point;
       graphene_point_t end_point;
     } linear_gradient_data;
+    struct {
+      graphene_rect_t clip_bounds;
+      float corner_widths[4];
+      float corner_heights[4];
+    } rounded_clip_data;
   };
 
   const char *name;
@@ -204,6 +216,7 @@ struct _GskGLRenderer
   Program color_program;
   Program color_matrix_program;
   Program linear_gradient_program;
+  Program rounded_clip_program;
 
   GArray *render_items;
 
@@ -432,6 +445,22 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
   INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, start_point_location, "uStartPoint");
   INIT_PROGRAM_UNIFORM_LOCATION (linear_gradient_program, end_point_location, "uEndPoint");
 
+  self->rounded_clip_program.id = gsk_shader_builder_create_program (builder,
+                                                                     "blit.vs.glsl",
+                                                                     "rounded_clip.fs.glsl",
+                                                                     &shader_error);
+  if (shader_error != NULL)
+    {
+      g_propagate_prefixed_error (error,
+                                  shader_error,
+                                  "Unable to create 'rounded_clip' program: ");
+      goto out;
+    }
+  init_common_locations (self, builder, &self->rounded_clip_program);
+  INIT_PROGRAM_UNIFORM_LOCATION (rounded_clip_program, clip_bounds_location, "uClipBounds");
+  INIT_PROGRAM_UNIFORM_LOCATION (rounded_clip_program, corner_widths_location, "uCornerWidths");
+  INIT_PROGRAM_UNIFORM_LOCATION (rounded_clip_program, corner_heights_location, "uCornerHeights");
+
   res = TRUE;
 
 out:
@@ -686,6 +715,21 @@ render_item (GskGLRenderer    *self,
         }
       break;
 
+      case MODE_ROUNDED_CLIP:
+        {
+          g_assert (item->program == &self->rounded_clip_program);
+          glUniform1i (item->program->source_location, 0);
+          gsk_gl_driver_bind_source_texture (self->gl_driver, item->render_target);
+          glUniform4f (item->program->clip_bounds_location,
+                       item->rounded_clip_data.clip_bounds.origin.x,
+                       item->rounded_clip_data.clip_bounds.origin.y,
+                       item->rounded_clip_data.clip_bounds.size.width,
+                       item->rounded_clip_data.clip_bounds.size.height);
+          glUniform4fv (item->program->corner_widths_location, 1, item->rounded_clip_data.corner_widths);
+          glUniform4fv (item->program->corner_heights_location, 1, item->rounded_clip_data.corner_heights);
+        }
+      break;
+
       default:
         g_assert_not_reached ();
     }
@@ -844,14 +888,23 @@ gsk_gl_renderer_add_render_item (GskGLRenderer           *self,
     case GSK_ROUNDED_CLIP_NODE:
       {
         GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
+        const GskRoundedRect *clip = gsk_rounded_clip_node_peek_clip (node);
         graphene_matrix_t p;
         graphene_matrix_t identity;
+        int i;
 
         graphene_matrix_init_identity (&identity);
         init_framebuffer_for_node (self, &item, node, projection, &p);
         gsk_gl_renderer_add_render_item (self, &p, &identity, item.children, child,
                                          item.render_target);
-        item.mode = MODE_BLIT;
+        item.mode = MODE_ROUNDED_CLIP;
+        item.program = &self->rounded_clip_program;
+        item.rounded_clip_data.clip_bounds = clip->bounds;
+        for (i = 0; i < 4; i ++)
+          {
+            item.rounded_clip_data.corner_widths[i]  = MAX (clip->corner[i].width,  1);
+            item.rounded_clip_data.corner_heights[i] = MAX (clip->corner[i].height, 1);
+          }
       }
       break;
 
diff --git a/gsk/meson.build b/gsk/meson.build
index 95b093b..1820826 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -9,6 +9,7 @@ gsk_private_source_shaders = [
   'resources/glsl/color_matrix.vs.glsl',
   'resources/glsl/linear_gradient.fs.glsl',
   'resources/glsl/linear_gradient.vs.glsl',
+  'resources/glsl/rounded_clip.fs.glsl',
   'resources/glsl/es2_common.fs.glsl',
   'resources/glsl/es2_common.vs.glsl',
   'resources/glsl/gl3_common.fs.glsl',
diff --git a/gsk/resources/glsl/rounded_clip.fs.glsl b/gsk/resources/glsl/rounded_clip.fs.glsl
new file mode 100644
index 0000000..5589c12
--- /dev/null
+++ b/gsk/resources/glsl/rounded_clip.fs.glsl
@@ -0,0 +1,91 @@
+uniform vec4 uClipBounds;
+uniform vec4 uCornerWidths;
+uniform vec4 uCornerHeights;
+
+struct RoundedRect
+{
+  vec4 bounds;
+  vec4 corner_widths;
+  vec4 corner_heights;
+};
+
+float
+ellipsis_dist (vec2 p, vec2 radius)
+{
+  vec2 p0 = p / radius;
+  vec2 p1 = 2.0 * p0 / radius;
+
+  return (dot(p0, p0) - 1.0) / length (p1);
+}
+
+float
+ellipsis_coverage (vec2 point, vec2 center, vec2 radius)
+{
+  float d = ellipsis_dist (point - center, radius);
+  return clamp (0.5 - d, 0.0, 1.0);
+}
+
+float
+rounded_rect_coverage (RoundedRect r, vec2 p)
+{
+  if (p.x < r.bounds.x || p.y < r.bounds.y ||
+      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 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);
+
+  float d_tl = ellipsis_coverage(p, ref_tl, rad_tl);
+  float d_tr = ellipsis_coverage(p, ref_tr, rad_tr);
+  float d_br = ellipsis_coverage(p, ref_br, rad_br);
+  float d_bl = ellipsis_coverage(p, ref_bl, rad_bl);
+
+  vec4 corner_coverages = 1.0 - vec4(d_tl, d_tr, d_br, d_bl);
+
+  bvec4 is_out = bvec4(p.x < ref_tl.x && p.y < ref_tl.y,
+                       p.x > ref_tr.x && p.y < ref_tr.y,
+                       p.x > ref_br.x && p.y > ref_br.y,
+                       p.x < ref_bl.x && p.y > ref_bl.y);
+
+  return 1.0 - dot(vec4(is_out), corner_coverages);
+}
+
+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 = max (r.corner_widths - amount.wyyw, 0.0);
+  vec4 new_heights = max (r.corner_heights - amount.xxzz, 0.0);
+
+  return RoundedRect (new_bounds, new_widths, new_heights);
+}
+
+vec4 fragCoord() {
+  vec4 f = gl_FragCoord;
+  f.x += uViewport.x;
+  f.y = (uViewport.y + uViewport.w) - f.y;
+  return f;
+}
+
+vec4 clip(vec4 color) {
+  vec4 bounds = uClipBounds;
+  bounds.z = bounds.x + bounds.z;
+  bounds.w = bounds.y + bounds.w;
+
+  RoundedRect r = RoundedRect(bounds, uCornerWidths, uCornerHeights);
+
+  return color * rounded_rect_coverage(r, fragCoord().xy);
+}
+
+void main() {
+  vec4 diffuse = Texture(uSource, vUv);
+
+  setOutputColor(clip(diffuse) * uAlpha);
+}


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