[gtk] gl renderer: Add a clip stack
- From: Timm Bäder <baedert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk] gl renderer: Add a clip stack
- Date: Mon, 31 Dec 2018 11:45:05 +0000 (UTC)
commit 1d3aa9207c44c4820de8b758b6dee3b3c68be966
Author: Timm Bäder <mail baedert org>
Date: Sun Dec 30 15:25:01 2018 +0100
gl renderer: Add a clip stack
So we can check that the currently set clip is the first one and now
intersect with it. This first clip is always the entire viewport or the
entire render_area and we don't want to end up drawing things to a
texture because of it.
gsk/gl/gskglrenderer.c | 122 +++++++++++++++++++++++++++++------------
gsk/gl/gskglrenderops.c | 56 ++++++++++++++++---
gsk/gl/gskglrenderopsprivate.h | 9 ++-
3 files changed, 142 insertions(+), 45 deletions(-)
---
diff --git a/gsk/gl/gskglrenderer.c b/gsk/gl/gskglrenderer.c
index ff66e803e9..da97872828 100644
--- a/gsk/gl/gskglrenderer.c
+++ b/gsk/gl/gskglrenderer.c
@@ -895,7 +895,6 @@ render_clip_node (GskGLRenderer *self,
GskRenderNode *node,
RenderOpBuilder *builder)
{
- GskRoundedRect prev_clip;
GskRenderNode *child = gsk_clip_node_get_child (node);
graphene_rect_t transformed_clip;
graphene_rect_t intersection;
@@ -905,16 +904,41 @@ render_clip_node (GskGLRenderer *self,
ops_transform_bounds_modelview (builder, &transformed_clip, &transformed_clip);
graphene_rect_intersection (&transformed_clip,
- &builder->current_clip.bounds,
+ &builder->current_clip->bounds,
&intersection);
gsk_rounded_rect_init_from_rect (&child_clip, &intersection, 0.0f);
- prev_clip = ops_set_clip (builder, &child_clip);
+ ops_push_clip (builder, &child_clip);
gsk_gl_renderer_add_render_ops (self, child, builder);
- ops_set_clip (builder, &prev_clip);
+ ops_pop_clip (builder);
}
+static gboolean
+gsk_rounded_rect_intersection (const GskRoundedRect *self,
+ const GskRoundedRect *other,
+ GskRoundedRect *out_intersection)
+{
+ const graphene_rect_t *self_bounds = &self->bounds;
+ const graphene_rect_t *other_bounds = &other->bounds;
+
+ if (graphene_rect_contains_rect (self_bounds, other_bounds))
+ {
+ *out_intersection = *other;
+ return TRUE;
+ }
+
+ /* TODO: There are a few cases here that we can express using a single
+ * rounded rectangle, which are even interesting in every day usage.
+ * For example, a partially scrolled-away rounded rectangle
+ * might just work.
+ */
+
+ return FALSE;
+}
+
+
+
static inline void
render_rounded_clip_node (GskGLRenderer *self,
GskRenderNode *node,
@@ -923,31 +947,41 @@ render_rounded_clip_node (GskGLRenderer *self,
const float scale = ops_get_scale (builder);
GskRoundedRect child_clip = *gsk_rounded_clip_node_peek_clip (node);
GskRoundedRect transformed_clip;
- GskRoundedRect prev_clip;
GskRenderNode *child = gsk_rounded_clip_node_get_child (node);
+ GskRoundedRect intersection;
+ gboolean need_offscreen;
int i;
transformed_clip = child_clip;
ops_transform_bounds_modelview (builder, &child_clip.bounds, &transformed_clip.bounds);
- if (graphene_rect_contains_rect (&builder->current_clip.bounds,
- &transformed_clip.bounds))
+ if (!ops_has_clip (builder))
+ {
+ intersection = transformed_clip;
+ need_offscreen = FALSE;
+ }
+ else
+ {
+ need_offscreen = !gsk_rounded_rect_intersection (builder->current_clip,
+ &transformed_clip,
+ &intersection);
+ }
+
+ if (!need_offscreen)
{
/* If they don't intersect at all, we can simply set
* the new clip and add the render ops */
for (i = 0; i < 4; i ++)
{
- transformed_clip.corner[i].width *= scale;
- transformed_clip.corner[i].height *= scale;
+ intersection.corner[i].width *= scale;
+ intersection.corner[i].height *= scale;
}
- prev_clip = ops_set_clip (builder, &transformed_clip);
+ ops_push_clip (builder, &intersection);
gsk_gl_renderer_add_render_ops (self, child, builder);
-
- ops_set_clip (builder, &prev_clip);
+ ops_pop_clip (builder);
}
- else if (graphene_rect_intersection (&builder->current_clip.bounds,
- &transformed_clip.bounds, NULL))
+ else
{
const float min_x = builder->dx + node->bounds.origin.x;
const float min_y = builder->dy + node->bounds.origin.y;
@@ -973,12 +1007,12 @@ render_rounded_clip_node (GskGLRenderer *self,
child_clip.corner[i].height *= scale;
}
- prev_clip = ops_set_clip (builder, &child_clip);
+ ops_push_clip (builder, &child_clip);
add_offscreen_ops (self, builder, &node->bounds,
child,
&texture_id, &is_offscreen, TRUE, FALSE);
+ ops_pop_clip (builder);
- ops_set_clip (builder, &prev_clip);
ops_set_program (builder, &self->blit_program);
ops_set_texture (builder, texture_id);
@@ -1205,7 +1239,7 @@ render_outset_shadow_node (GskGLRenderer *self,
int texture_id, render_target;
int blurred_render_target;
int prev_render_target;
- GskRoundedRect prev_clip, blit_clip;
+ GskRoundedRect blit_clip;
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);
@@ -1228,7 +1262,7 @@ render_outset_shadow_node (GskGLRenderer *self,
/* Draw outline */
ops_set_program (builder, &self->color_program);
- prev_clip = ops_set_clip (builder, &offset_outline);
+ ops_push_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 }, },
@@ -1246,6 +1280,7 @@ render_outset_shadow_node (GskGLRenderer *self,
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);
+ ops_pop_clip (builder);
op.op = OP_CLEAR;
ops_add (builder, &op);
@@ -1259,7 +1294,7 @@ render_outset_shadow_node (GskGLRenderer *self,
op.blur.radius = blur_radius;
ops_add (builder, &op);
- ops_set_clip (builder, &blit_clip);
+ ops_push_clip (builder, &blit_clip);
ops_set_texture (builder, texture_id);
ops_draw (builder, (GskQuadVertex[GL_N_VERTICES]) {
{ { 0, 0 }, { 0, 1 }, },
@@ -1272,7 +1307,7 @@ render_outset_shadow_node (GskGLRenderer *self,
});
- ops_set_clip (builder, &prev_clip);
+ ops_pop_clip (builder);
ops_set_viewport (builder, &prev_viewport);
ops_pop_modelview (builder);
ops_set_projection (builder, &prev_projection);
@@ -2254,7 +2289,7 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
&node->bounds,
&transformed_node_bounds);
- if (!graphene_rect_intersection (&builder->current_clip.bounds,
+ if (!graphene_rect_intersection (&builder->current_clip->bounds,
&transformed_node_bounds, NULL))
return;
}
@@ -2384,7 +2419,6 @@ add_offscreen_ops (GskGLRenderer *self,
graphene_matrix_t prev_projection;
graphene_rect_t prev_viewport;
graphene_matrix_t item_proj;
- GskRoundedRect prev_clip;
float prev_opacity;
int texture_id = 0;
@@ -2444,10 +2478,10 @@ add_offscreen_ops (GskGLRenderer *self,
bounds->origin.y * scale,
width, height));
if (reset_clip)
- prev_clip = ops_set_clip (builder,
- &GSK_ROUNDED_RECT_INIT (bounds->origin.x * scale,
- bounds->origin.y * scale,
- width, height));
+ ops_push_clip (builder,
+ &GSK_ROUNDED_RECT_INIT (bounds->origin.x * scale,
+ bounds->origin.y * scale,
+ width, height));
builder->dx = 0;
builder->dy = 0;
@@ -2460,7 +2494,7 @@ add_offscreen_ops (GskGLRenderer *self,
builder->dy = dy;
if (reset_clip)
- ops_set_clip (builder, &prev_clip);
+ ops_pop_clip (builder);
ops_set_viewport (builder, &prev_viewport);
ops_pop_modelview (builder);
@@ -2696,25 +2730,34 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
render_op_builder.current_opacity = 1.0f;
render_op_builder.render_ops = self->render_ops;
ops_push_modelview (&render_op_builder, &modelview);
+ cairo_rectangle_int_t render_extents;
+
+ /*cairo_region_get_extents (self->render_region, &render_extents);*/
/* Initial clip is self->render_region! */
if (self->render_region != NULL)
{
- cairo_rectangle_int_t render_extents;
+ GskRoundedRect transformed_render_region = { 0, };
+ /*cairo_rectangle_int_t render_extents;*/
cairo_region_get_extents (self->render_region, &render_extents);
- render_op_builder.current_clip = GSK_ROUNDED_RECT_INIT (render_extents.x,
- render_extents.y,
- render_extents.width,
- render_extents.height);
ops_transform_bounds_modelview (&render_op_builder,
- &render_op_builder.current_clip.bounds,
- &render_op_builder.current_clip.bounds);
+ &GRAPHENE_RECT_INIT (render_extents.x,
+ render_extents.y,
+ render_extents.width,
+ render_extents.height),
+ &transformed_render_region.bounds);
+ ops_push_clip (&render_op_builder, &transformed_render_region);
}
else
{
- gsk_rounded_rect_init_from_rect (&render_op_builder.current_clip, viewport, 0.0f);
+ ops_push_clip (&render_op_builder,
+ &GSK_ROUNDED_RECT_INIT (viewport->origin.x,
+ viewport->origin.y,
+ viewport->size.width,
+ viewport->size.height));
}
+ /*gsk_rounded_rect_init_from_rect (&render_op_builder.current_clip, viewport, 0.0f);*/
if (fbo_id != 0)
@@ -2722,9 +2765,18 @@ gsk_gl_renderer_do_render (GskRenderer *renderer,
gsk_gl_renderer_add_render_ops (self, root, &render_op_builder);
+ /*if (self->render_region)*/
+ /*add_rect_outline_ops (self, &render_op_builder,*/
+ /*&GRAPHENE_RECT_INIT (*/
+ /*render_extents.x,*/
+ /*render_extents.y,*/
+ /*render_extents.width,*/
+ /*render_extents.height));*/
+
/* We correctly reset the state everywhere */
g_assert_cmpint (render_op_builder.current_render_target, ==, fbo_id);
ops_pop_modelview (&render_op_builder);
+ ops_pop_clip (&render_op_builder);
ops_finish (&render_op_builder);
/*g_message ("Ops: %u", self->render_ops->len);*/
diff --git a/gsk/gl/gskglrenderops.c b/gsk/gl/gskglrenderops.c
index db77ea7c68..86b44e06e2 100644
--- a/gsk/gl/gskglrenderops.c
+++ b/gsk/gl/gskglrenderops.c
@@ -12,6 +12,9 @@ ops_finish (RenderOpBuilder *builder)
{
if (builder->mv_stack)
g_array_free (builder->mv_stack, TRUE);
+
+ if (builder->clip_stack)
+ g_array_free (builder->clip_stack, TRUE);
}
static inline void
@@ -208,9 +211,9 @@ ops_set_program (RenderOpBuilder *builder,
memcmp (&builder->current_clip, &program_state->clip, sizeof (GskRoundedRect)) != 0)
{
op.op = OP_CHANGE_CLIP;
- op.clip = builder->current_clip;
+ op.clip = *builder->current_clip;
g_array_append_val (builder->render_ops, op);
- program_state->clip = builder->current_clip;
+ program_state->clip = *builder->current_clip;
}
if (program_state->opacity != builder->current_opacity)
@@ -224,12 +227,11 @@ ops_set_program (RenderOpBuilder *builder,
builder->current_program_state = &builder->program_state[program->index];
}
-GskRoundedRect
+static void
ops_set_clip (RenderOpBuilder *builder,
const GskRoundedRect *clip)
{
RenderOp *last_op;
- GskRoundedRect prev_clip;
if (builder->render_ops->len > 0)
{
@@ -251,11 +253,49 @@ ops_set_clip (RenderOpBuilder *builder,
if (builder->current_program != NULL)
builder->current_program_state->clip = *clip;
+}
+
+void
+ops_push_clip (RenderOpBuilder *self,
+ const GskRoundedRect *clip)
+{
+ if (G_UNLIKELY (self->clip_stack == NULL))
+ self->clip_stack = g_array_new (FALSE, TRUE, sizeof (GskRoundedRect));
+
+ g_assert (self->clip_stack != NULL);
+
+ g_array_append_val (self->clip_stack, *clip);
+ self->current_clip = &g_array_index (self->clip_stack, GskRoundedRect, self->clip_stack->len - 1);
+ ops_set_clip (self, clip);
+}
+
+void
+ops_pop_clip (RenderOpBuilder *self)
+{
+ const GskRoundedRect *head;
+
+ g_assert (self->clip_stack);
+ g_assert (self->clip_stack->len >= 1);
- prev_clip = builder->current_clip;
- builder->current_clip = *clip;
+ self->clip_stack->len --;
+ head = &g_array_index (self->clip_stack, GskRoundedRect, self->clip_stack->len - 1);
- return prev_clip;
+ if (self->clip_stack->len >= 1)
+ {
+ self->current_clip = head;
+ ops_set_clip (self, head);
+ }
+ else
+ {
+ self->current_clip = NULL;
+ }
+}
+
+gboolean
+ops_has_clip (RenderOpBuilder *self)
+{
+ return self->clip_stack != NULL &&
+ self->clip_stack->len > 1;
}
static void
@@ -301,7 +341,7 @@ ops_push_modelview (RenderOpBuilder *builder,
MatrixStackEntry *entry;
if (G_UNLIKELY (builder->mv_stack == NULL))
- builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
+ builder->mv_stack = g_array_new (FALSE, TRUE, sizeof (MatrixStackEntry));
g_assert (builder->mv_stack != NULL);
diff --git a/gsk/gl/gskglrenderopsprivate.h b/gsk/gl/gskglrenderopsprivate.h
index 1d1594172d..67c50641e1 100644
--- a/gsk/gl/gskglrenderopsprivate.h
+++ b/gsk/gl/gskglrenderopsprivate.h
@@ -248,7 +248,6 @@ typedef struct
const Program *current_program;
int current_render_target;
int current_texture;
- GskRoundedRect current_clip;
graphene_matrix_t current_projection;
graphene_rect_t current_viewport;
@@ -264,6 +263,10 @@ typedef struct
GArray *mv_stack;
/* Pointer into mv_stack */
const graphene_matrix_t *current_modelview;
+
+ /* Same thing */
+ GArray *clip_stack;
+ const GskRoundedRect *current_clip;
} RenderOpBuilder;
@@ -282,8 +285,10 @@ float ops_get_scale (const RenderOpBuilder *builder);
void ops_set_program (RenderOpBuilder *builder,
const Program *program);
-GskRoundedRect ops_set_clip (RenderOpBuilder *builder,
+void ops_push_clip (RenderOpBuilder *builder,
const GskRoundedRect *clip);
+void ops_pop_clip (RenderOpBuilder *builder);
+gboolean ops_has_clip (RenderOpBuilder *builder);
void ops_transform_bounds_modelview (const RenderOpBuilder *builder,
const graphene_rect_t *src,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]