[gtk] gl renderer: Add a clip stack



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]