diff options
-rw-r--r-- | gsk/gl/gskglprograms.defs | 4 | ||||
-rw-r--r-- | gsk/gl/gskglrenderjob.c | 52 | ||||
-rw-r--r-- | gsk/gl/resources/mask.glsl | 19 | ||||
-rw-r--r-- | gsk/meson.build | 1 |
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([ |