From e95b356465596e34eeb6234bc1d890f1613b3aa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= Date: Fri, 1 Dec 2017 10:27:31 +0100 Subject: [PATCH] gl renderer: Implement simple shadow nodes --- gsk/gl/gskglrenderer.c | 77 +++++++++++++++++++++++++++++-- gsk/gl/gskglrenderopsprivate.h | 8 +++- gsk/meson.build | 1 + gsk/resources/glsl/shadow.fs.glsl | 13 ++++++ 4 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 gsk/resources/glsl/shadow.fs.glsl diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index d421734e32..d3c59fc65a 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -171,6 +171,7 @@ struct _GskGLRenderer Program blur_program; Program inset_shadow_program; Program outset_shadow_program; + Program shadow_program; }; }; @@ -321,6 +322,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, { "blur", "blit.vs.glsl", "blur.fs.glsl" }, { "inset shadow", "blit.vs.glsl", "inset_shadow.fs.glsl" }, { "outset shadow", "blit.vs.glsl", "outset_shadow.fs.glsl" }, + { "shadow", "blit.vs.glsl", "shadow.fs.glsl" }, }; builder = gsk_shader_builder_new (); @@ -431,6 +433,9 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, INIT_PROGRAM_UNIFORM_LOCATION2 (outset_shadow, corner_widths); INIT_PROGRAM_UNIFORM_LOCATION2 (outset_shadow, corner_heights); + /* shadow */ + INIT_PROGRAM_UNIFORM_LOCATION2 (shadow, color); + g_object_unref (builder); return TRUE; } @@ -664,7 +669,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, float max_y = min_y + node->bounds.size.height; /* Default vertex data */ - GskQuadVertex vertex_data[GL_N_VERTICES] = { + const GskQuadVertex vertex_data[GL_N_VERTICES] = { { { min_x, min_y }, { 0, 0 }, }, { { min_x, max_y }, { 0, 1 }, }, { { max_x, min_y }, { 1, 0 }, }, @@ -967,6 +972,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, } break; + case GSK_COLOR_MATRIX_NODE: { int texture_id; @@ -1100,10 +1106,70 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, } break; -do_default: + case GSK_SHADOW_NODE: + { + GskRenderNode *child = gsk_shadow_node_get_child (node); + gsize n_shadows = gsk_shadow_node_get_n_shadows (node); + guint i; + + /* TODO: shadow nodes are most commonly used for text and icon shadows. + * In both cases, we can avoit the RTT case! + * if the child is neither a text node nor a texture node though, we need + * to fall back to rendering it to a texture and then applying the shadow on that one.*/ + + for (i = 0; i < n_shadows; i ++) + { + const GskShadow *shadow = gsk_shadow_node_peek_shadow (node, i); + int texture_id; + gboolean is_offscreen; + graphene_matrix_t offset_matrix; + graphene_matrix_t prev_modelview; + + /* TODO: Implement blurred shadow nodes */; + if (shadow->radius > 0) + { + /* TODO: This draws the entire node, not just one shadow. */ + render_fallback_node (self, node, builder, vertex_data); + continue; + } + + add_offscreen_ops (self, builder, min_x, max_x, min_y, max_y, child, &texture_id, &is_offscreen); + + ops_set_program (builder, &self->shadow_program); + ops_set_color (builder, &shadow->color); + ops_set_texture (builder, texture_id); + + offset_matrix = builder->current_modelview; + graphene_matrix_translate (&offset_matrix, &GRAPHENE_POINT3D_INIT (shadow->dx, shadow->dy, 0)); + prev_modelview = ops_set_modelview (builder, &offset_matrix); + + if (is_offscreen) + { + GskQuadVertex vertex_data[GL_N_VERTICES] = { + { { min_x, min_y }, { 0, 1 }, }, + { { min_x, max_y }, { 0, 0 }, }, + { { max_x, min_y }, { 1, 1 }, }, + + { { max_x, max_y }, { 1, 0 }, }, + { { min_x, max_y }, { 0, 0 }, }, + { { max_x, min_y }, { 1, 1 }, }, + }; + ops_draw (builder, vertex_data); + } + else + { + ops_draw (builder, vertex_data); + } + + ops_set_modelview (builder, &prev_modelview); + } + + /* Now draw the child normally */ + gsk_gl_renderer_add_render_ops (self, child, builder); + } + break; case GSK_REPEATING_LINEAR_GRADIENT_NODE: - case GSK_SHADOW_NODE: case GSK_BORDER_NODE: case GSK_CROSS_FADE_NODE: case GSK_BLEND_NODE: @@ -1307,7 +1373,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self, case OP_CHANGE_COLOR: OP_PRINT (" -> Color: (%f, %f, %f, %f)", op->color.red, op->color.green, op->color.blue, op->color.alpha); - g_assert (program == &self->color_program || program == &self->coloring_program); + g_assert (program == &self->color_program || program == &self->coloring_program || + program == &self->shadow_program); + /* TODO: We use color.color_location here and this is right for all three of the programs above, + * but that's just a coincidence. */ glUniform4f (program->color.color_location, op->color.red, op->color.green, op->color.blue, op->color.alpha); break; diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index ec9bc944f6..f577bd7e3a 100644 --- a/gsk/gl/gskglrenderopsprivate.h +++ b/gsk/gl/gskglrenderopsprivate.h @@ -10,7 +10,7 @@ #include "gskglrendererprivate.h" #define GL_N_VERTICES 6 -#define GL_N_PROGRAMS 9 +#define GL_N_PROGRAMS 10 enum { OP_NONE, @@ -59,6 +59,9 @@ typedef struct struct { int color_location; } coloring; + struct { + int color_location; + } shadow; struct { int color_matrix_location; int color_offset_location; @@ -146,6 +149,9 @@ typedef struct float offset[2]; float color[4]; } outset_shadow; + struct { + float color[4]; + } shadow; }; } RenderOp; diff --git a/gsk/meson.build b/gsk/meson.build index f05cb343e0..54828e7aa8 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -11,6 +11,7 @@ gsk_private_source_shaders = [ 'resources/glsl/blur.fs.glsl', 'resources/glsl/inset_shadow.fs.glsl', 'resources/glsl/outset_shadow.fs.glsl', + 'resources/glsl/shadow.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/shadow.fs.glsl b/gsk/resources/glsl/shadow.fs.glsl new file mode 100644 index 0000000000..3426ba35fc --- /dev/null +++ b/gsk/resources/glsl/shadow.fs.glsl @@ -0,0 +1,13 @@ +uniform vec4 u_color; + +void main() { + vec4 diffuse = Texture(u_source, vUv); + vec4 color = u_color; + + // pre-multiply + color.rgb *= color.a; + + color = vec4(u_color.rgb * diffuse.a, diffuse.a); + + setOutputColor(color); +}