diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c index 11c088d0b6..7dfa0126c1 100644 --- a/gsk/gl/gskglrenderer.c +++ b/gsk/gl/gskglrenderer.c @@ -209,6 +209,7 @@ struct _GskGLRenderer Program blur_program; Program inset_shadow_program; Program outset_shadow_program; + Program unblurred_outset_shadow_program; Program shadow_program; Program border_program; Program cross_fade_program; @@ -860,6 +861,36 @@ render_inset_shadow_node (GskGLRenderer *self, ops_draw (builder, vertex_data); } +static inline void +render_unblurred_outset_shadow_node (GskGLRenderer *self, + GskRenderNode *node, + RenderOpBuilder *builder, + const GskQuadVertex *vertex_data) +{ + const float spread = gsk_outset_shadow_node_get_spread (node); + GskRoundedRect r = *gsk_outset_shadow_node_peek_outline (node); + RenderOp op; + + op.op = OP_CHANGE_UNBLURRED_OUTSET_SHADOW; + rgba_to_float (gsk_outset_shadow_node_peek_color (node), op.unblurred_outset_shadow.color); + + gsk_rounded_rect_shrink (&r, -spread, -spread, -spread, -spread); + + rounded_rect_to_floats (self, builder, + &r, + op.unblurred_outset_shadow.outline, + op.unblurred_outset_shadow.corner_widths, + op.unblurred_outset_shadow.corner_heights); + + op.unblurred_outset_shadow.spread = gsk_outset_shadow_node_get_spread (node) * self->scale_factor; + op.unblurred_outset_shadow.offset[0] = gsk_outset_shadow_node_get_dx (node) * self->scale_factor; + op.unblurred_outset_shadow.offset[1] = -gsk_outset_shadow_node_get_dy (node) * self->scale_factor; + + ops_set_program (builder, &self->unblurred_outset_shadow_program); + ops_add (builder, &op); + ops_draw (builder, vertex_data); +} + static inline void render_outset_shadow_node (GskGLRenderer *self, GskRenderNode *node, @@ -953,19 +984,12 @@ render_outset_shadow_node (GskGLRenderer *self, gsk_rounded_rect_init_from_rect (&blit_clip, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height), 0.0f); - if (blur_radius > 0) - { - ops_set_program (builder, &self->blur_program); - op.op = OP_CHANGE_BLUR; - op.blur.size.width = texture_width; - op.blur.size.height = texture_height; - op.blur.radius = blur_radius; - ops_add (builder, &op); - } - else - { - ops_set_program (builder, &self->blit_program); - } + ops_set_program (builder, &self->blur_program); + op.op = OP_CHANGE_BLUR; + op.blur.size.width = texture_width; + op.blur.size.height = texture_height; + op.blur.radius = blur_radius; + ops_add (builder, &op); ops_set_clip (builder, &blit_clip); ops_set_texture (builder, texture_id); @@ -1536,6 +1560,22 @@ apply_inset_shadow_op (const Program *program, glUniform4fv (program->inset_shadow.corner_widths_location, 1, op->inset_shadow.corner_widths); glUniform4fv (program->inset_shadow.corner_heights_location, 1, op->inset_shadow.corner_heights); } + +static inline void +apply_unblurred_outset_shadow_op (const Program *program, + const RenderOp *op) +{ + OP_PRINT (" -> unblurred outset shadow"); + glUniform4fv (program->unblurred_outset_shadow.color_location, 1, op->unblurred_outset_shadow.color); + glUniform2fv (program->unblurred_outset_shadow.offset_location, 1, op->unblurred_outset_shadow.offset); + glUniform1f (program->unblurred_outset_shadow.spread_location, op->unblurred_outset_shadow.spread); + glUniform4fv (program->unblurred_outset_shadow.outline_location, 1, op->unblurred_outset_shadow.outline); + glUniform4fv (program->unblurred_outset_shadow.corner_widths_location, 1, + op->unblurred_outset_shadow.corner_widths); + glUniform4fv (program->unblurred_outset_shadow.corner_heights_location, 1, + op->unblurred_outset_shadow.corner_heights); +} + static inline void apply_outset_shadow_op (const Program *program, const RenderOp *op) @@ -1684,6 +1724,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" }, + { "unblurred outset shadow", "blit.vs.glsl", "unblurred_outset_shadow.fs.glsl" }, { "shadow", "blit.vs.glsl", "shadow.fs.glsl" }, { "border", "blit.vs.glsl", "border.fs.glsl" }, { "cross fade", "blit.vs.glsl", "cross_fade.fs.glsl" }, @@ -1795,6 +1836,14 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self, INIT_PROGRAM_UNIFORM_LOCATION (outset_shadow, corner_widths); INIT_PROGRAM_UNIFORM_LOCATION (outset_shadow, corner_heights); + /* unblurred outset shadow */ + INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, color); + INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, spread); + INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, offset); + INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, outline); + INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, corner_widths); + INIT_PROGRAM_UNIFORM_LOCATION (unblurred_outset_shadow, corner_heights); + /* shadow */ INIT_PROGRAM_UNIFORM_LOCATION (shadow, color); @@ -2109,7 +2158,10 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self, break; case GSK_OUTSET_SHADOW_NODE: - render_outset_shadow_node (self, node, builder); + if (gsk_outset_shadow_node_get_blur_radius (node) > 0) + render_outset_shadow_node (self, node, builder); + else + render_unblurred_outset_shadow_node (self, node, builder, vertex_data); break; case GSK_SHADOW_NODE: @@ -2346,6 +2398,10 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self, apply_border_op (program, op); break; + case OP_CHANGE_UNBLURRED_OUTSET_SHADOW: + apply_unblurred_outset_shadow_op (program, op); + break; + case OP_DRAW: OP_PRINT (" -> draw %ld, size %ld and program %d\n", op->draw.vao_offset, op->draw.vao_size, program->index); diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h index aaff53ce03..b700b75f94 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 12 +#define GL_N_PROGRAMS 13 enum { OP_NONE, @@ -32,8 +32,9 @@ enum { OP_CHANGE_BORDER = 16, OP_CHANGE_BORDER_COLOR = 17, OP_CHANGE_CROSS_FADE = 18, - OP_CLEAR = 19, - OP_DRAW = 20, + OP_CHANGE_UNBLURRED_OUTSET_SHADOW = 19, + OP_CLEAR = 20, + OP_DRAW = 21, }; typedef struct @@ -94,6 +95,14 @@ typedef struct int corner_widths_location; int corner_heights_location; } outset_shadow; + struct { + int outline_location; + int corner_widths_location; + int corner_heights_location; + int color_location; + int spread_location; + int offset_location; + } unblurred_outset_shadow; struct { int color_location; int widths_location; @@ -159,6 +168,15 @@ typedef struct float offset[2]; float color[4]; } outset_shadow; + struct { + float outline[4]; + float corner_widths[4]; + float corner_heights[4]; + float radius; + float spread; + float offset[2]; + float color[4]; + } unblurred_outset_shadow; struct { float color[4]; } shadow; diff --git a/gsk/meson.build b/gsk/meson.build index b852237629..d6e134246f 100644 --- a/gsk/meson.build +++ b/gsk/meson.build @@ -10,6 +10,7 @@ gsk_private_gl_shaders = [ 'resources/glsl/blur.fs.glsl', 'resources/glsl/inset_shadow.fs.glsl', 'resources/glsl/outset_shadow.fs.glsl', + 'resources/glsl/unblurred_outset_shadow.fs.glsl', 'resources/glsl/shadow.fs.glsl', 'resources/glsl/border.fs.glsl', 'resources/glsl/cross_fade.fs.glsl', diff --git a/gsk/resources/glsl/unblurred_outset_shadow.fs.glsl b/gsk/resources/glsl/unblurred_outset_shadow.fs.glsl new file mode 100644 index 0000000000..1ae48ecb49 --- /dev/null +++ b/gsk/resources/glsl/unblurred_outset_shadow.fs.glsl @@ -0,0 +1,25 @@ +uniform float u_spread; +uniform vec4 u_color; +uniform vec2 u_offset; +uniform vec4 u_outline; +uniform vec4 u_corner_widths; +uniform vec4 u_corner_heights; + + +void main() { + vec4 f = gl_FragCoord; + + f.x += u_viewport.x; + f.y = (u_viewport.y + u_viewport.w) - f.y; + + RoundedRect outline = RoundedRect(vec4(u_outline.xy, u_outline.xy + u_outline.zw), + u_corner_widths, u_corner_heights); + RoundedRect inside = rounded_rect_shrink(outline, vec4(u_spread)); + + vec2 offset = vec2(u_offset.x, - u_offset.y); + vec4 color = vec4(u_color.rgb * u_color.a, u_color.a); + color = color * clamp (rounded_rect_coverage (outline, f.xy - offset) - + rounded_rect_coverage (inside, f.xy), + 0.0, 1.0); + setOutputColor(color * u_alpha); +}