[gtk/mask-nodes: 121/123] gl: Add a shader for mask nodes




commit 09673f45b2283faa92b805fbef40cb951b893a16
Author: Matthias Clasen <mclasen redhat com>
Date:   Mon Dec 14 15:32:58 2020 -0500

    gl: Add a shader for mask nodes

 gsk/gl/gskglrenderer.c         | 72 +++++++++++++++++++++++++++++++++++++++++-
 gsk/gl/gskglrenderopsprivate.h |  7 +++-
 gsk/gl/opbuffer.c              |  1 +
 gsk/gl/opbuffer.h              |  7 ++++
 gsk/meson.build                |  1 +
 gsk/resources/glsl/mask.glsl   | 45 ++++++++++++++++++++++++++
 6 files changed, 131 insertions(+), 2 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 1317893f8b..c00805c6e5 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -2716,6 +2716,52 @@ render_cross_fade_node (GskGLRenderer   *self,
   load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
 }
 
+static inline void
+render_mask_node (GskGLRenderer   *self,
+                  GskRenderNode   *node,
+                  RenderOpBuilder *builder)
+{
+  GskRenderNode *source = gsk_mask_node_get_source (node);
+  GskRenderNode *mask = gsk_mask_node_get_mask (node);
+  TextureRegion source_region;
+  TextureRegion mask_region;
+  gboolean is_offscreen1, is_offscreen2;
+  OpMask *op;
+
+  if (!add_offscreen_ops (self, builder,
+                          &node->bounds,
+                          source,
+                          &source_region, &is_offscreen1,
+                          FORCE_OFFSCREEN | RESET_CLIP))
+    {
+      gsk_gl_renderer_add_render_ops (self, source, builder);
+      return;
+    }
+
+  if (!add_offscreen_ops (self, builder,
+                          &node->bounds,
+                          mask,
+                          &mask_region, &is_offscreen2,
+                          FORCE_OFFSCREEN | RESET_CLIP))
+    {
+      gsk_gl_renderer_add_render_ops (self, source, builder);
+      return;
+    }
+
+  ops_set_program (builder, &self->programs->mask_program);
+
+  op = ops_begin (builder, OP_CHANGE_MASK);
+  op->mask = mask_region.texture_id;
+  op->texture_rect[0] = 0;
+  op->texture_rect[1] = 0;
+  op->texture_rect[2] = 1;
+  op->texture_rect[3] = 1;
+
+  ops_set_texture (builder, source_region.texture_id);
+
+  load_offscreen_vertex_data (ops_draw (builder, NULL), node, builder);
+}
+
 static inline void
 render_blend_node (GskGLRenderer   *self,
                    GskRenderNode   *node,
@@ -3203,6 +3249,17 @@ apply_repeat_op (const Program  *program,
   glUniform4fv (program->repeat.texture_rect_location, 1, op->texture_rect);
 }
 
+static inline void
+apply_mask_op (const Program *program,
+               const OpMask  *op)
+{
+  OP_PRINT (" -> Mask ");
+  glUniform4fv (program->mask.texture_rect_location, 1, op->texture_rect);
+  glUniform1i (program->mask.mask_location, 1);
+  glActiveTexture (GL_TEXTURE0 + 1);
+  glBindTexture (GL_TEXTURE_2D, op->mask);
+}
+
 static void
 gsk_gl_renderer_dispose (GObject *gobject)
 {
@@ -3326,6 +3383,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
     { "/org/gtk/libgsk/glsl/outset_shadow.glsl",             "outset shadow" },
     { "/org/gtk/libgsk/glsl/repeat.glsl",                    "repeat" },
     { "/org/gtk/libgsk/glsl/unblurred_outset_shadow.glsl",   "unblurred_outset shadow" },
+    { "/org/gtk/libgsk/glsl/mask.glsl",                      "mask" },
   };
 
   gsk_gl_shader_builder_init (&shader_builder,
@@ -3421,6 +3479,10 @@ gsk_gl_renderer_create_programs (GskGLRenderer  *self,
   INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, progress);
   INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, source2);
 
+  /* mask */
+  INIT_PROGRAM_UNIFORM_LOCATION (mask, mask);
+  INIT_PROGRAM_UNIFORM_LOCATION (mask, texture_rect);
+
   /* blend */
   INIT_PROGRAM_UNIFORM_LOCATION (blend, source2);
   INIT_PROGRAM_UNIFORM_LOCATION (blend, mode);
@@ -3805,12 +3867,15 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer   *self,
       render_gl_shader_node (self, node, builder);
     break;
 
+    case GSK_MASK_NODE:
+      render_mask_node (self, node, builder);
+    break;
+
     case GSK_REPEATING_LINEAR_GRADIENT_NODE:
     case GSK_REPEATING_RADIAL_GRADIENT_NODE:
     case GSK_FILL_NODE:
     case GSK_STROKE_NODE:
     case GSK_CAIRO_NODE:
-    case GSK_MASK_NODE:
     default:
       {
         render_fallback_node (self, node, builder);
@@ -4113,6 +4178,11 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self)
           apply_blend_op (program, ptr);
           break;
 
+        case OP_CHANGE_MASK:
+          g_assert (program == &self->programs->mask_program);
+          apply_mask_op (program, ptr);
+          break;
+
         case OP_CHANGE_LINEAR_GRADIENT:
           apply_linear_gradient_op (program, ptr);
           break;
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index 24544b0d44..3d02866b83 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -13,7 +13,7 @@
 #include "opbuffer.h"
 
 #define GL_N_VERTICES 6
-#define GL_N_PROGRAMS 15
+#define GL_N_PROGRAMS 16
 #define GL_MAX_GRADIENT_STOPS 6
 
 typedef struct
@@ -179,6 +179,10 @@ struct _Program
       int texture_locations[4];
       GError *compile_error;
     } glshader;
+    struct {
+      int mask_location;
+      int texture_rect_location;
+    } mask;
   };
   ProgramState state;
 };
@@ -203,6 +207,7 @@ typedef struct {
       Program outset_shadow_program;
       Program repeat_program;
       Program unblurred_outset_shadow_program;
+      Program mask_program;
     };
   };
   GHashTable *custom_programs; /* GskGLShader -> Program* */
diff --git a/gsk/gl/opbuffer.c b/gsk/gl/opbuffer.c
index 806b8f7ca4..49ce68eb5d 100644
--- a/gsk/gl/opbuffer.c
+++ b/gsk/gl/opbuffer.c
@@ -34,6 +34,7 @@ static guint op_sizes[OP_LAST] = {
   sizeof (OpGLShader),
   sizeof (OpExtraTexture),
   sizeof (OpConicGradient),
+  sizeof (OpMask),
 };
 
 void
diff --git a/gsk/gl/opbuffer.h b/gsk/gl/opbuffer.h
index 08f48b7c5f..97bdd4f4a5 100644
--- a/gsk/gl/opbuffer.h
+++ b/gsk/gl/opbuffer.h
@@ -42,6 +42,7 @@ typedef enum
   OP_CHANGE_GL_SHADER_ARGS             = 28,
   OP_CHANGE_EXTRA_SOURCE_TEXTURE       = 29,
   OP_CHANGE_CONIC_GRADIENT             = 30,
+  OP_CHANGE_MASK                       = 31,
   OP_LAST
 } OpKind;
 
@@ -222,6 +223,12 @@ typedef struct
   const guchar *uniform_data;
 } OpGLShader;
 
+typedef struct
+{
+  int mask;
+  float texture_rect[4];
+} OpMask;
+
 void     op_buffer_init            (OpBuffer *buffer);
 void     op_buffer_destroy         (OpBuffer *buffer);
 void     op_buffer_clear           (OpBuffer *buffer);
diff --git a/gsk/meson.build b/gsk/meson.build
index 6ba45c6eff..5925594c29 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -18,6 +18,7 @@ gsk_private_gl_shaders = [
   'resources/glsl/blend.glsl',
   'resources/glsl/repeat.glsl',
   'resources/glsl/custom.glsl',
+  'resources/glsl/mask.glsl',
 ]
 
 gsk_public_sources = files([
diff --git a/gsk/resources/glsl/mask.glsl b/gsk/resources/glsl/mask.glsl
new file mode 100644
index 0000000000..cd1a75edf6
--- /dev/null
+++ b/gsk/resources/glsl/mask.glsl
@@ -0,0 +1,45 @@
+// VERTEX_SHADER:
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+uniform sampler2D u_mask;
+uniform vec4 u_texture_rect;
+
+void main() {
+  vec4 source = GskTexture(u_source, vUv);
+  vec2 tc;
+
+  if (vUv.x < u_texture_rect.x || vUv.x > u_texture_rect.z)
+    {
+      gskSetOutputColor(vec4 (0, 0, 0, 0));
+      return;
+    }
+
+  tc.x = (vUv.x - u_texture_rect.x) / (u_texture_rect.z - u_texture_rect.x);
+
+  if (u_texture_rect.y <= u_texture_rect.w)
+    {
+      if (vUv.y < u_texture_rect.y || vUv.y > u_texture_rect.w)
+        {
+          gskSetOutputColor(vec4 (0, 0, 0, 0));
+          return;
+        }
+      tc.y = (vUv.y - u_texture_rect.y) / (u_texture_rect.w - u_texture_rect.y);
+    }
+  else
+    {
+      if (vUv.y < u_texture_rect.w || vUv.y > u_texture_rect.y)
+        {
+          gskSetOutputColor(vec4 (0, 0, 0, 0));
+          return;
+        }
+      tc.y =  1.0 - (vUv.y - u_texture_rect.w) / (u_texture_rect.y - u_texture_rect.w);
+    }
+
+  vec4 mask = GskTexture(u_mask, tc);
+  gskSetOutputColor(vec4 (source * mask.a));
+}


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