gl: Support mask nodes
authorMatthias Clasen <mclasen@redhat.com>
Sat, 11 Feb 2023 15:38:56 +0000 (10:38 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Sun, 12 Feb 2023 13:35:25 +0000 (08:35 -0500)
Add a shader for masking.

gsk/gl/gskglprograms.defs
gsk/gl/gskglrenderjob.c
gsk/gl/resources/mask.glsl [new file with mode: 0644]
gsk/meson.build

index 1ff99fab89ab89943be7bbe3f5a4350891cad066..3301529f9c2a9bce64a8f54bff574a5ea81f54e2 100644 (file)
@@ -60,6 +60,10 @@ GSK_GL_DEFINE_PROGRAM (linear_gradient,
                        GSK_GL_ADD_UNIFORM (3, LINEAR_GRADIENT_POINTS, u_points)
                        GSK_GL_ADD_UNIFORM (4, LINEAR_GRADIENT_REPEAT, u_repeat))
 
+GSK_GL_DEFINE_PROGRAM (mask,
+                       GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("mask.glsl")),
+                       GSK_GL_ADD_UNIFORM (1, MASK_SOURCE, u_mask))
+
 GSK_GL_DEFINE_PROGRAM (outset_shadow,
                        GSK_GL_SHADER_SINGLE (GSK_GL_SHADER_RESOURCE ("outset_shadow.glsl")),
                        GSK_GL_ADD_UNIFORM (1, OUTSET_SHADOW_OUTLINE_RECT, u_outline_rect))
index 2db40bd25fb200893ab4f30d13b5345135a1e791..0c9c09ba45fb313a58791b59b11ae24420dd27c5 100644 (file)
@@ -3277,6 +3277,56 @@ gsk_gl_render_job_visit_blend_node (GskGLRenderJob      *job,
   gsk_gl_render_job_end_draw (job);
 }
 
+static inline void
+gsk_gl_render_job_visit_mask_node (GskGLRenderJob       *job,
+                                    const GskRenderNode *node)
+{
+  const GskRenderNode *source = gsk_mask_node_get_source (node);
+  const GskRenderNode *mask = gsk_mask_node_get_mask (node);
+  GskGLRenderOffscreen source_offscreen = {0};
+  GskGLRenderOffscreen mask_offscreen = {0};
+
+  source_offscreen.bounds = &node->bounds;
+  source_offscreen.force_offscreen = TRUE;
+  source_offscreen.reset_clip = TRUE;
+
+  mask_offscreen.bounds = &node->bounds;
+  mask_offscreen.force_offscreen = TRUE;
+  mask_offscreen.reset_clip = TRUE;
+
+  /* TODO: We create 2 textures here as big as the mask node, but both
+   * nodes might be a lot smaller than that.
+   */
+  if (!gsk_gl_render_job_visit_node_with_offscreen (job, source, &source_offscreen))
+    {
+      gsk_gl_render_job_visit_node (job, source);
+      return;
+    }
+
+  g_assert (source_offscreen.was_offscreen);
+
+  if (!gsk_gl_render_job_visit_node_with_offscreen (job, mask, &mask_offscreen))
+    {
+      return;
+    }
+
+  g_assert (mask_offscreen.was_offscreen);
+
+  gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, mask));
+  gsk_gl_program_set_uniform_texture (job->current_program,
+                                      UNIFORM_SHARED_SOURCE, 0,
+                                      GL_TEXTURE_2D,
+                                      GL_TEXTURE0,
+                                      source_offscreen.texture_id);
+  gsk_gl_program_set_uniform_texture (job->current_program,
+                                      UNIFORM_MASK_SOURCE, 0,
+                                      GL_TEXTURE_2D,
+                                      GL_TEXTURE1,
+                                      mask_offscreen.texture_id);
+  gsk_gl_render_job_draw_offscreen_rect (job, &node->bounds);
+  gsk_gl_render_job_end_draw (job);
+}
+
 static inline void
 gsk_gl_render_job_visit_color_matrix_node (GskGLRenderJob      *job,
                                            const GskRenderNode *node)
@@ -3870,7 +3920,7 @@ gsk_gl_render_job_visit_node (GskGLRenderJob      *job,
     break;
 
     case GSK_MASK_NODE:
-      gsk_gl_render_job_visit_as_fallback (job, node);
+      gsk_gl_render_job_visit_mask_node (job, node);
     break;
 
     case GSK_OPACITY_NODE:
diff --git a/gsk/gl/resources/mask.glsl b/gsk/gl/resources/mask.glsl
new file mode 100644 (file)
index 0000000..9c187b5
--- /dev/null
@@ -0,0 +1,19 @@
+// VERTEX_SHADER:
+// mask.glsl
+
+void main() {
+  gl_Position = u_projection * u_modelview * vec4(aPosition, 0.0, 1.0);
+
+  vUv = vec2(aUv.x, aUv.y);
+}
+
+// FRAGMENT_SHADER:
+// mask.glsl
+
+uniform sampler2D u_mask;
+
+void main() {
+  vec4 source = GskTexture(u_source, vUv);
+  vec4 mask = GskTexture(u_mask, vUv);
+  gskSetOutputColor(vec4 (source * mask.a));
+}
index 02e9c58954d7d2fa107683ec498b23fad489fc57..7746aeffc45a13fde63e9b9bf6cd20e19cdef963 100644 (file)
@@ -19,6 +19,7 @@ gsk_private_gl_shaders = [
   'gl/resources/repeat.glsl',
   'gl/resources/custom.glsl',
   'gl/resources/filled_border.glsl',
+  'gl/resources/mask.glsl',
 ]
 
 gsk_public_sources = files([