[gtk/broadway-prune: 2/2] broadway: Prune fully clipped render nodes




commit d57e6b754f00bf9ec6e49812f57195c66a8a6f9e
Author: Alexander Larsson <alexl redhat com>
Date:   Wed Aug 26 18:08:00 2020 +0200

    broadway: Prune fully clipped render nodes
    
    If some node is fully outside the clip region we don't send it to the daemon.
    This helps a lot in how much data we send for scrolling viewports.
    
    However, sending partial trees makes node reuse a bit more tricky. We
    can't save for reuse any node that could possibly clip different depending on
    the clip region, as that could be different next frame. So, unless the
    node is fully contained in the current clip (and we thus know it is not
    parial) we don't allow reusing that next frame.
    
    This fixes #3086

 gdk/broadway/broadway-protocol.h   |   2 +-
 gsk/broadway/gskbroadwayrenderer.c | 132 +++++++++++++++++++++++++++++--------
 2 files changed, 107 insertions(+), 27 deletions(-)
---
diff --git a/gdk/broadway/broadway-protocol.h b/gdk/broadway/broadway-protocol.h
index 35fb02cab2..9b56dff6df 100644
--- a/gdk/broadway/broadway-protocol.h
+++ b/gdk/broadway/broadway-protocol.h
@@ -8,7 +8,7 @@ typedef struct  {
     gint32 width, height;
 } BroadwayRect;
 
-typedef enum { /* Sync changes with broadway.js */
+typedef enum { /* Sync changes with broadway.js and node_type_is_container() */
   BROADWAY_NODE_TEXTURE = 0,
   BROADWAY_NODE_CONTAINER = 1,
   BROADWAY_NODE_COLOR = 2,
diff --git a/gsk/broadway/gskbroadwayrenderer.c b/gsk/broadway/gskbroadwayrenderer.c
index b56a095f73..e18b03f826 100644
--- a/gsk/broadway/gskbroadwayrenderer.c
+++ b/gsk/broadway/gskbroadwayrenderer.c
@@ -90,6 +90,23 @@ add_uint32 (GArray *nodes, guint32 v)
   g_array_append_val (nodes, v);
 }
 
+static guint
+add_uint32_placeholder (GArray *nodes)
+{
+  guint pos = nodes->len;
+  guint32 v = 0;
+
+  g_array_append_val (nodes, v);
+  return pos;
+}
+
+static void
+set_uint32_at (GArray *nodes, guint index, guint32 v)
+{
+  g_array_index (nodes, guint32, index) = v;
+}
+
+
 static void
 add_float (GArray *nodes, float f)
 {
@@ -212,10 +229,9 @@ collect_reused_node (GskRenderer *renderer,
 
   if (self->last_node_lookup &&
       (old_id = GPOINTER_TO_INT(g_hash_table_lookup (self->last_node_lookup, node))) != 0)
-    {
-      g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER (old_id));
-      collect_reused_child_nodes (renderer, node);
-    }
+    g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER (old_id));
+
+  collect_reused_child_nodes (renderer, node);
 }
 
 
@@ -298,10 +314,46 @@ collect_reused_child_nodes (GskRenderer *renderer,
     }
 }
 
+static gboolean
+node_is_visible (GskRenderNode *node,
+                 graphene_rect_t *clip_bounds)
+{
+  if (clip_bounds == NULL ||
+      graphene_rect_intersection (clip_bounds, &node->bounds, NULL))
+    return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+node_is_fully_visible (GskRenderNode *node,
+                       graphene_rect_t *clip_bounds)
+{
+  if (clip_bounds == NULL ||
+      graphene_rect_contains_rect (clip_bounds, &node->bounds))
+    return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+node_type_is_container (BroadwayNodeType type)
+{
+  return
+    type == BROADWAY_NODE_SHADOW ||
+    type == BROADWAY_NODE_OPACITY ||
+    type == BROADWAY_NODE_ROUNDED_CLIP ||
+    type == BROADWAY_NODE_CLIP ||
+    type == BROADWAY_NODE_TRANSFORM ||
+    type == BROADWAY_NODE_DEBUG ||
+    type == BROADWAY_NODE_CONTAINER;
+}
+
 static gboolean
 add_new_node (GskRenderer *renderer,
               GskRenderNode *node,
-              BroadwayNodeType type)
+              BroadwayNodeType type,
+              graphene_rect_t *clip_bounds)
 {
   GskBroadwayRenderer *self = GSK_BROADWAY_RENDERER (renderer);
   guint32 id, old_id;
@@ -319,7 +371,21 @@ add_new_node (GskRenderer *renderer,
     }
 
   id = ++self->next_node_id;
-  g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(id));
+
+  /* Never try to reuse partially visible container types the next
+   * frame, as they could be be partial due to pruning against clip_bounds,
+   * and the clip_bounds may be different the next frame. However, anything
+   * that is fully visible will not be pruned, so is ok to reuse.
+   *
+   * Note: its quite possible that the node is fully visible, but contains
+   * a clip node which means the tree under that partial. That is fine and we can
+   * still reuse *this* node next frame, but we can't use the child that is
+   * partial, for example in a different place, because then it might see
+   * the partial region of the tree.
+   */
+  if (!node_type_is_container (type) ||
+      node_is_fully_visible (node, clip_bounds))
+    g_hash_table_insert (self->node_lookup, node, GINT_TO_POINTER(id));
 
   add_uint32 (self->nodes, type);
   add_uint32 (self->nodes, id);
@@ -497,7 +563,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
     /* Leaf nodes */
 
     case GSK_TEXTURE_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
+      if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE, clip_bounds))
         {
           GdkTexture *texture = gsk_texture_node_get_texture (node);
           guint32 texture_id;
@@ -512,7 +578,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       return;
 
     case GSK_CAIRO_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
+      if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE, clip_bounds))
         {
           cairo_surface_t *surface = gsk_cairo_node_peek_surface (node);
           cairo_surface_t *image_surface = NULL;
@@ -548,7 +614,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       return;
 
     case GSK_COLOR_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_COLOR))
+      if (add_new_node (renderer, node, BROADWAY_NODE_COLOR, clip_bounds))
         {
           add_rect (nodes, &node->bounds, offset_x, offset_y);
           add_rgba (nodes, gsk_color_node_peek_color (node));
@@ -556,7 +622,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       return;
 
     case GSK_BORDER_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_BORDER))
+      if (add_new_node (renderer, node, BROADWAY_NODE_BORDER, clip_bounds))
         {
           int i;
           add_rounded_rect (nodes, gsk_border_node_peek_outline (node), offset_x, offset_y);
@@ -568,7 +634,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       return;
 
     case GSK_OUTSET_SHADOW_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_OUTSET_SHADOW))
+      if (add_new_node (renderer, node, BROADWAY_NODE_OUTSET_SHADOW, clip_bounds))
         {
           add_rounded_rect (nodes, gsk_outset_shadow_node_peek_outline (node), offset_x, offset_y);
           add_rgba (nodes, gsk_outset_shadow_node_peek_color (node));
@@ -580,7 +646,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       return;
 
     case GSK_INSET_SHADOW_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_INSET_SHADOW))
+      if (add_new_node (renderer, node, BROADWAY_NODE_INSET_SHADOW, clip_bounds))
         {
           add_rounded_rect (nodes, gsk_inset_shadow_node_peek_outline (node), offset_x, offset_y);
           add_rgba (nodes, gsk_inset_shadow_node_peek_color (node));
@@ -592,7 +658,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       return;
 
     case GSK_LINEAR_GRADIENT_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_LINEAR_GRADIENT))
+      if (add_new_node (renderer, node, BROADWAY_NODE_LINEAR_GRADIENT, clip_bounds))
         {
           guint i, n;
 
@@ -609,7 +675,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       /* Bin nodes */
 
     case GSK_SHADOW_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_SHADOW))
+      if (add_new_node (renderer, node, BROADWAY_NODE_SHADOW, clip_bounds))
         {
           gsize i, n_shadows = gsk_shadow_node_get_n_shadows (node);
 
@@ -629,7 +695,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       return;
 
     case GSK_OPACITY_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_OPACITY))
+      if (add_new_node (renderer, node, BROADWAY_NODE_OPACITY, clip_bounds))
         {
           add_float (nodes, gsk_opacity_node_get_opacity (node));
           gsk_broadway_renderer_add_node (renderer,
@@ -639,7 +705,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       return;
 
     case GSK_ROUNDED_CLIP_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_ROUNDED_CLIP))
+      if (add_new_node (renderer, node, BROADWAY_NODE_ROUNDED_CLIP, clip_bounds))
         {
           const GskRoundedRect *rclip = gsk_rounded_clip_node_peek_clip (node);
           graphene_rect_t child_bounds = rclip->bounds;
@@ -657,7 +723,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       return;
 
     case GSK_CLIP_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_CLIP))
+      if (add_new_node (renderer, node, BROADWAY_NODE_CLIP, clip_bounds))
         {
           const graphene_rect_t *clip = gsk_clip_node_peek_clip (node);
           graphene_rect_t child_bounds = *clip;
@@ -679,7 +745,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
         GskTransform *transform = gsk_transform_node_get_transform (node);
         GskTransformCategory category = gsk_transform_get_category (transform);
 
-        if (add_new_node (renderer, node, BROADWAY_NODE_TRANSFORM)) {
+        if (add_new_node (renderer, node, BROADWAY_NODE_TRANSFORM, clip_bounds)) {
           if (category >= GSK_TRANSFORM_CATEGORY_2D_TRANSLATE)
             {
               float dx, dy;
@@ -717,7 +783,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       return;
 
     case GSK_DEBUG_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_DEBUG))
+      if (add_new_node (renderer, node, BROADWAY_NODE_DEBUG, clip_bounds))
         {
           const char *message = gsk_debug_node_get_message (node);
           add_string (nodes, message);
@@ -729,14 +795,28 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       /* Generic nodes */
 
     case GSK_CONTAINER_NODE:
-      if (add_new_node (renderer, node, BROADWAY_NODE_CONTAINER))
+      if (add_new_node (renderer, node, BROADWAY_NODE_CONTAINER, clip_bounds))
         {
-          guint i;
+          guint i, placeholder;
+          guint32 n_children = 0;
 
-          add_uint32 (nodes, gsk_container_node_get_n_children (node));
+          placeholder = add_uint32_placeholder (nodes);
           for (i = 0; i < gsk_container_node_get_n_children (node); i++)
-            gsk_broadway_renderer_add_node (renderer,
-                                            gsk_container_node_get_child (node, i), offset_x, offset_y, 
clip_bounds);
+            {
+              /* We prune fully clipped children, but we only do this for container_node, as
+               * we don't have a way for any other nodes to say there are children missing (i.e.
+               * bins always assume there is a child).
+               * Pruning is really only useful for large sets of children anyway, so thats
+               * probably fine. */
+              GskRenderNode *child = gsk_container_node_get_child (node, i);
+              if (node_is_visible (child, clip_bounds))
+                {
+                  n_children++;
+                  gsk_broadway_renderer_add_node (renderer,
+                                                  child, offset_x, offset_y, clip_bounds);
+                }
+            }
+          set_uint32_at (nodes, placeholder, n_children);
         }
       return;
 
@@ -749,7 +829,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
             const graphene_vec4_t *color_offset = gsk_color_matrix_node_peek_color_offset (node);
             GdkTexture *texture = gsk_texture_node_get_texture (child);
             GdkTexture *colorized_texture = get_colorized_texture (texture, color_matrix, color_offset);
-            if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
+            if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE, clip_bounds))
               {
                 guint32 texture_id = gdk_broadway_display_ensure_texture (display, colorized_texture);
                 add_rect (nodes, &child->bounds, offset_x, offset_y);
@@ -771,7 +851,7 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
       break; /* Fallback */
     }
 
-  if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE))
+  if (add_new_node (renderer, node, BROADWAY_NODE_TEXTURE, clip_bounds))
     {
       GdkTexture *texture;
       cairo_surface_t *surface;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]