summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2023-02-11 10:38:56 -0500
committerMatthias Clasen <mclasen@redhat.com>2023-02-12 08:35:25 -0500
commita9f50f1f7a72d11064ca60055ad2131590c6454d (patch)
treeafe0dd7c2952dd55e43f47963c4ab35528cbd670
parent0d58e5365d23f2823f085434857e9b25ea9441bb (diff)
downloadgtk+-a9f50f1f7a72d11064ca60055ad2131590c6454d.tar.gz
gl: Support mask nodes
Add a shader for masking.
-rw-r--r--gsk/gl/gskglprograms.defs4
-rw-r--r--gsk/gl/gskglrenderjob.c52
-rw-r--r--gsk/gl/resources/mask.glsl19
-rw-r--r--gsk/meson.build1
4 files changed, 75 insertions, 1 deletions
diff --git a/gsk/gl/gskglprograms.defs b/gsk/gl/gskglprograms.defs
index 1ff99fab89..3301529f9c 100644
--- a/gsk/gl/gskglprograms.defs
+++ b/gsk/gl/gskglprograms.defs
@@ -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))
diff --git a/gsk/gl/gskglrenderjob.c b/gsk/gl/gskglrenderjob.c
index 2db40bd25f..0c9c09ba45 100644
--- a/gsk/gl/gskglrenderjob.c
+++ b/gsk/gl/gskglrenderjob.c
@@ -3278,6 +3278,56 @@ gsk_gl_render_job_visit_blend_node (GskGLRenderJob *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
index 0000000000..9c187b5a4e
--- /dev/null
+++ b/gsk/gl/resources/mask.glsl
@@ -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));
+}
diff --git a/gsk/meson.build b/gsk/meson.build
index 02e9c58954..7746aeffc4 100644
--- a/gsk/meson.build
+++ b/gsk/meson.build
@@ -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([