[gtk+/wip/baedert/gl] gl renderer: try doing outset box shadows
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+/wip/baedert/gl] gl renderer: try doing outset box shadows
- Date: Thu, 21 Dec 2017 17:06:53 +0000 (UTC)
commit 4331412b7498a561cee036c140ef79e0d987e398
Author: Timm Bäder <mail baedert org>
Date: Thu Dec 21 18:09:32 2017 +0100
gl renderer: try doing outset box shadows
Still fall back in cases we can't handle that way.
gsk/gl/gskglrenderer.c | 332 ++++++++++++++++++++++++++++--
gsk/gl/gskglrenderops.c | 3 +-
gsk/resources/glsl/outset_shadow.fs.glsl | 17 +-
3 files changed, 322 insertions(+), 30 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index 5f84f4b..218450c 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -30,6 +30,8 @@
#define HIGHLIGHT_FALLBACK 0
#define DEBUG_OPS 0
+#define SHADOW_EXTRA_SIZE 4
+
#if DEBUG_OPS
#define OP_PRINT(format, ...) g_print(format, ## __VA_ARGS__)
#else
@@ -40,7 +42,6 @@
G_STMT_START{\
self->program_name ## _program.program_name.uniform_basename ## _location = \
glGetUniformLocation(self->program_name ## _program.id, "u_"
#uniform_basename);\
- g_assert_cmpint (self->program_name ## _program.program_name.uniform_basename ## _location,
, -1); \
}G_STMT_END
#define INIT_COMMON_UNIFORM_LOCATION(program_ptr, uniform_basename) \
@@ -49,7 +50,6 @@
glGetUniformLocation(program_ptr->id, "u_" #uniform_basename);\
}G_STMT_END
-
static void G_GNUC_UNUSED
dump_framebuffer (const char *filename, int w, int h)
{
@@ -150,6 +150,15 @@ color_matrix_modifies_alpha (GskRenderNode *node)
return !graphene_vec4_equal (&id_row3, &row3);
}
+static inline void
+gsk_rounded_rect_shrink_to_minimum (GskRoundedRect *self)
+{
+ self->bounds.size.width = ceilf (MAX (MAX (self->corner[0].width, self->corner[1].width),
+ MAX (self->corner[2].width, self->corner[3].width)) * 2);
+ self->bounds.size.height = ceilf (MAX (MAX (self->corner[0].height, self->corner[1].height),
+ MAX (self->corner[2].height, self->corner[3].height)) * 2);
+}
+
static void gsk_gl_renderer_setup_render_mode (GskGLRenderer *self);
static void add_offscreen_ops (GskGLRenderer *self,
RenderOpBuilder *builder,
@@ -861,30 +870,314 @@ render_outset_shadow_node (GskGLRenderer *self,
RenderOpBuilder *builder,
const GskQuadVertex *vertex_data)
{
+ const GskRoundedRect *outline = gsk_outset_shadow_node_peek_outline (node);
+ GskRoundedRect offset_outline;
+ const float blur_radius = gsk_outset_shadow_node_get_blur_radius (node);
+ const float spread = gsk_outset_shadow_node_get_spread (node);
+ const float dx = gsk_outset_shadow_node_get_dx (node);
+ const float dy = gsk_outset_shadow_node_get_dy (node);
+ const float min_x = outline->bounds.origin.x - spread - blur_radius;
+ const float min_y = outline->bounds.origin.y - spread - blur_radius;
+ const float max_x = min_x + outline->bounds.size.width + (spread+blur_radius) * 2;
+ const float max_y = min_y + outline->bounds.size.height + (spread +blur_radius) * 2;
+ float texture_width, texture_height;
+ int i;
RenderOp op;
+ graphene_matrix_t identity;
+ graphene_matrix_t prev_projection;
+ graphene_matrix_t prev_modelview;
+ graphene_rect_t prev_viewport;
+ graphene_matrix_t item_proj;
+ GskRoundedRect prev_clip, blit_clip;
+ int prev_render_target;
+ int texture_id, render_target;
+ int blurred_texture_id, blurred_render_target;
+
+ /* offset_outline is the minimal outline we need to draw the given drop shadow,
+ * enlarged by the spread and offset by the blur radius. */
+ offset_outline = *outline;
+ gsk_rounded_rect_shrink_to_minimum (&offset_outline);
+ gsk_rounded_rect_shrink (&offset_outline, -spread, -spread, -spread, -spread);
+ offset_outline.bounds.size.width += SHADOW_EXTRA_SIZE;
+ offset_outline.bounds.size.height += SHADOW_EXTRA_SIZE;
+ offset_outline.bounds.origin.x = blur_radius;
+ offset_outline.bounds.origin.y = blur_radius;
+
+ texture_width = offset_outline.bounds.size.width + (blur_radius * 2);
+ texture_height = offset_outline.bounds.size.height + (blur_radius * 2);
+
+ /* TODO: Find out if this happens too often.
+ * Is the condition used here really correct? */
+ for (i = 0; i < 4; i ++)
+ {
+ if (offset_outline.corner[i].width > spread ||
+ offset_outline.corner[i].height > spread)
+ {
+ g_warning ("'irregular' box shadow");
+ render_fallback_node (self, node, builder, vertex_data);
+ return;
+ }
+ }
+
+ texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
+ gsk_gl_driver_init_texture_empty (self->gl_driver, texture_id);
+ render_target = gsk_gl_driver_create_render_target (self->gl_driver, texture_id, FALSE, FALSE);
+
+
+ graphene_matrix_init_ortho (&item_proj,
+ 0, texture_width, 0, texture_height,
+ ORTHO_NEAR_PLANE, ORTHO_FAR_PLANE);
+ graphene_matrix_scale (&item_proj, 1, -1, 1);
+ graphene_matrix_init_identity (&identity);
+
+ prev_render_target = ops_set_render_target (builder, render_target);
+ op.op = OP_CLEAR;
+ ops_add (builder, &op);
+ prev_projection = ops_set_projection (builder, &item_proj);
+ prev_modelview = ops_set_modelview (builder, &identity);
+ prev_viewport = ops_set_viewport (builder, &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height));
+
+ /* Draw outline */
+ ops_set_program (builder, &self->color_program);
+ prev_clip = ops_set_clip (builder, &offset_outline);
+ ops_set_color (builder, gsk_outset_shadow_node_peek_color (node));
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { 0, }, { 0, 1 }, },
+ { { 0, texture_height }, { 0, 0 }, },
+ { { texture_width, }, { 1, 1 }, },
+
+ { { texture_width, texture_height }, { 1, 0 }, },
+ { { 0, texture_height }, { 0, 0 }, },
+ { { texture_width, }, { 1, 1 }, },
+ });
+
+ blurred_texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
+ gsk_gl_driver_bind_source_texture (self->gl_driver, blurred_texture_id);
+ gsk_gl_driver_init_texture_empty (self->gl_driver, blurred_texture_id);
+ blurred_render_target = gsk_gl_driver_create_render_target (self->gl_driver, blurred_texture_id, TRUE,
TRUE);
+
+ ops_set_render_target (builder, blurred_render_target);
+ op.op = OP_CLEAR;
+ ops_add (builder, &op);
- /* TODO: Implement blurred outset shadows as well */
- if (gsk_outset_shadow_node_get_blur_radius (node) > 0)
+ gsk_rounded_rect_init_from_rect (&blit_clip,
+ &GRAPHENE_RECT_INIT (0, 0, texture_width, texture_height), 0.0f);
+
+ if (blur_radius > 0)
{
- render_fallback_node (self, node, builder, vertex_data);
- return;
+ 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_clip (builder, &blit_clip);
+ ops_set_texture (builder, texture_id);
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { 0, 0 }, { 0, 0 }, },
+ { { 0, texture_height }, { 0, 1 }, },
+ { { texture_width, 0 }, { 1, 0 }, },
+
+ { { texture_width, texture_height }, { 1, 1 }, },
+ { { 0, texture_height }, { 0, 1 }, },
+ { { texture_width, 0 }, { 1, 0 }, },
+
+ });
+ ops_set_clip (builder, &prev_clip);
+ ops_set_viewport (builder, &prev_viewport);
+ ops_set_modelview (builder, &prev_modelview);
+ ops_set_projection (builder, &prev_projection);
+ ops_set_render_target (builder, prev_render_target);
+
+ ops_set_program (builder, &self->outset_shadow_program);
+ ops_set_texture (builder, blurred_texture_id);
op.op = OP_CHANGE_OUTSET_SHADOW;
- rgba_to_float (gsk_outset_shadow_node_peek_color (node), op.outset_shadow.color);
rounded_rect_to_floats (self, builder,
gsk_outset_shadow_node_peek_outline (node),
op.outset_shadow.outline,
op.outset_shadow.corner_widths,
op.outset_shadow.corner_heights);
- op.outset_shadow.radius = gsk_outset_shadow_node_get_blur_radius (node) * self->scale_factor;
- op.outset_shadow.spread = gsk_outset_shadow_node_get_spread (node) * self->scale_factor;
- op.outset_shadow.offset[0] = gsk_outset_shadow_node_get_dx (node) * self->scale_factor;
- op.outset_shadow.offset[1] = -gsk_outset_shadow_node_get_dy (node) * self->scale_factor;
-
- ops_set_program (builder, &self->outset_shadow_program);
ops_add (builder, &op);
- ops_draw (builder, vertex_data);
+
+ /* We use the one outset shadow op from above to draw all 8 sides/corners. */
+ {
+ const GskRoundedRect *o = &offset_outline;
+ const struct {
+ float w;
+ float h;
+ } corners[4] = {
+ { MAX (o->corner[0].width, spread) + blur_radius,
+ MAX (o->corner[0].height, spread) + blur_radius },
+ { MAX (o->corner[1].width, spread) + blur_radius,
+ MAX (o->corner[1].height, spread) + blur_radius },
+ { MAX (o->corner[2].width, spread) + blur_radius,
+ MAX (o->corner[2].height, spread) + blur_radius },
+ { MAX (o->corner[3].width, spread) + blur_radius,
+ MAX (o->corner[3].height, spread) + blur_radius }
+ };
+ float x1 = min_x + dx;
+ float x2 = x1 + corners[0].w - dx;
+ float y1 = min_y + dy;
+ float y2 = y1 + corners[0].h - dy;
+ float tx1 = 0;
+ float tx2 = ((corners[0].w - dx) / texture_width);
+ float ty1 = 1 - ((corners[0].h - dy) / texture_height);
+ float ty2 = 1;
+
+ /* Top left */
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { x1, y1 }, { tx1, ty2 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+
+ { { x2, y2 }, { tx2, ty1 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+ });
+
+ /* Top right */
+ x1 = max_x - corners[1].w ;
+ x2 = x1 + corners[1].w + dx;
+ y1 = min_y + dy;
+ y2 = y1 + corners[1].h - dy;
+ tx1 = 1 - ((corners[1].w + dx) / texture_width);
+ tx2 = 1;
+ ty1 = 1 - ((corners[1].h - dy) / texture_height);
+ ty2 = 1;
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { x1, y1 }, { tx1, ty2 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+
+ { { x2, y2 }, { tx2, ty1 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+ });
+
+ /* Bottom right */
+ x1 = max_x - corners[2].w ;
+ x2 = x1 + corners[2].w + dx;
+ y1 = max_y - corners[2].h ;
+ y2 = y1 + corners[2].h + dy;
+ tx1 = 1 - ((corners[2].w + dx) / texture_width);
+ tx2 = 1;
+ ty1 = 0;
+ ty2 = (corners[2].h + dy) / texture_height;
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { x1, y1 }, { tx1, ty2 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+
+ { { x2, y2 }, { tx2, ty1 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+ });
+
+ /* Bottom left */
+ x1 = min_x + dx;
+ x2 = x1 + corners[3].w - dx;
+ y1 = max_y - corners[3].h ;
+ y2 = y1 + corners[3].h + dy;
+ tx1 = 0;
+ tx2 = (corners[3].w - dx) / texture_width;
+ ty1 = 0;
+ ty2 = (corners[3].h + dy) / texture_height;
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { x1, y1 }, { tx1, ty2 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+
+ { { x2, y2 }, { tx2, ty1 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+ });
+
+ /* Left side */
+ x1 = min_x + dx;
+ x2 = x1 + corners[0].w - dx;
+ y1 = min_y + corners[0].h;
+ y2 = max_y - corners[3].h;
+ tx1 = 0;
+ tx2 = (x2 - x1) / texture_width;
+ ty1 = 1 - (corners[0].h / texture_height);
+ ty2 = ty1 - (SHADOW_EXTRA_SIZE / texture_height);
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { x1, y1 }, { tx1, ty2 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+
+ { { x2, y2 }, { tx2, ty1 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+ });
+
+ /* Right side */
+ x1 = max_x - spread - blur_radius;
+ x2 = max_x + dx;
+ y1 = min_y + corners[0].h;
+ y2 = max_y - corners[3].h;
+ tx1 = 1 - ((x2 - x1) / texture_width);
+ tx2 = 1;
+ ty1 = 1 - (corners[1].h) / texture_height;
+ ty2 = ty1 - (SHADOW_EXTRA_SIZE / texture_height);
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { x1, y1 }, { tx1, ty2 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+
+ { { x2, y2 }, { tx2, ty1 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+ });
+
+ /* Top side */
+ x1 = min_x + corners[0].w;
+ x2 = max_x - corners[1].w;
+ y1 = min_y + dy;
+ y2 = y1 + spread + blur_radius - dy;
+ tx1 = corners[1].w / texture_width;
+ tx2 = tx1 + (SHADOW_EXTRA_SIZE / texture_width);
+ ty1 = 1;
+ ty2 = 1 - ((y2 - y1) / texture_height);
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { x1, y1 }, { tx1, ty1 }, },
+ { { x1, y2 }, { tx1, ty2 }, },
+ { { x2, y1 }, { tx2, ty1 }, },
+
+ { { x2, y2 }, { tx2, ty2 }, },
+ { { x1, y2 }, { tx1, ty2 }, },
+ { { x2, y1 }, { tx2, ty1 }, },
+ });
+
+ /* Bottom side */
+ x1 = min_x + corners[0].w;
+ x2 = max_x - corners[1].w;
+ y1 = max_y - corners[3].h ;
+ y2 = y1 + corners[3].h + dy;
+ tx1 = corners[3].w / texture_width;
+ tx2 = tx1 + (SHADOW_EXTRA_SIZE / texture_width);
+ ty1 = 0;
+ ty2 = (y2 - y1) / texture_height;
+ ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
+ { { x1, y1 }, { tx1, ty2 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+
+ { { x2, y2 }, { tx2, ty1 }, },
+ { { x1, y2 }, { tx1, ty1 }, },
+ { { x2, y1 }, { tx2, ty2 }, },
+ });
+ }
+
+ ops_set_clip (builder, &prev_clip);
}
static inline void
@@ -1673,6 +1966,9 @@ gsk_gl_renderer_setup_render_mode (GskGLRenderer *self)
/*cairo_region_get_extents (clip, &extents);*/
cairo_region_get_rectangle (clip, 0, &extents);
+ g_message ("Scissor rectangle: %d, %d, %d, %d",
+ extents.x, extents.y, extents.width, extents.height);
+
glEnable (GL_SCISSOR_TEST);
glScissor (extents.x * self->scale_factor,
window_height - (extents.height * self->scale_factor) - (extents.y * self->scale_factor),
@@ -1936,6 +2232,8 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
continue;
if (op->op != OP_CHANGE_PROGRAM &&
+ op->op != OP_CHANGE_RENDER_TARGET &&
+ op->op != OP_CLEAR &&
program == NULL)
continue;
@@ -2004,15 +2302,15 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
apply_linear_gradient_op (program, op);
break;
- case OP_CHANGE_BLUR:
+ case OP_CHANGE_BLUR:
apply_blur_op (program, op);
break;
- case OP_CHANGE_INSET_SHADOW:
+ case OP_CHANGE_INSET_SHADOW:
apply_inset_shadow_op (program, op);
break;
- case OP_CHANGE_OUTSET_SHADOW:
+ case OP_CHANGE_OUTSET_SHADOW:
apply_outset_shadow_op (program, op);
break;
diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c
index 9e2f719..0520ff7 100644
--- a/gsk/gl/gskglrenderops.c
+++ b/gsk/gl/gskglrenderops.c
@@ -117,7 +117,8 @@ ops_set_modelview (RenderOpBuilder *builder,
graphene_matrix_t prev_mv;
RenderOp *last_op;
- if (memcmp (&builder->program_state[builder->current_program->index].modelview, modelview,
+ if (builder->current_program &&
+ memcmp (&builder->program_state[builder->current_program->index].modelview, modelview,
sizeof (graphene_matrix_t)) == 0)
return *modelview;
diff --git a/gsk/resources/glsl/outset_shadow.fs.glsl b/gsk/resources/glsl/outset_shadow.fs.glsl
index c927172..9456c07 100644
--- a/gsk/resources/glsl/outset_shadow.fs.glsl
+++ b/gsk/resources/glsl/outset_shadow.fs.glsl
@@ -3,9 +3,8 @@ uniform float u_blur_radius;
uniform vec4 u_color;
uniform vec2 u_offset;
uniform vec4 u_outline;
-uniform vec4 u_corner_widths;
-uniform vec4 u_corner_heights;
-
+uniform vec4 u_corner_widths = vec4(0, 0, 0, 0);
+uniform vec4 u_corner_heights = vec4(0, 0, 0, 0);
void main() {
vec4 f = gl_FragCoord;
@@ -13,15 +12,9 @@ void main() {
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 outside = rounded_rect_shrink(outline, vec4(- u_spread));
-
+ RoundedRect outline = RoundedRect(vec4(u_outline.xy, u_outline.xy + u_outline.zw), u_corner_widths,
u_corner_heights);
- 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 (outside, f.xy - offset) -
- rounded_rect_coverage (outline, f.xy),
- 0.0, 1.0);
+ vec4 color = Texture(u_source, vUv);
+ /*color *= (1 - clamp(rounded_rect_coverage (outline, f.xy), 0, 1));*/
setOutputColor(color);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]