[gtk+/wip/ebassi/gsk-render-node-pool: 2/2] gsk: Use GskRenderer to create render nodes



commit c4bf786e42360735cb947bf76333df781c8670e7
Author: Emmanuele Bassi <ebassi gnome org>
Date:   Tue Jul 5 17:41:01 2016 +0100

    gsk: Use GskRenderer to create render nodes
    
    Instead of letting users create their own GskRenderNode instances we
    should cache render nodes inside GskRenderer. As rendering may end up
    resulting in thousands or more render nodes per frame, the memory
    pressure on the slice allocator may end up degrading our performance.
    By having render nodes cached and handed out from a pool we can recycle
    instances at every frame.

 gsk/gskrenderer.c          |   50 ++++++++++++++++++++++++++++++++++++++++++++
 gsk/gskrenderer.h          |    3 ++
 gsk/gskrendernode.c        |   39 +++++++++++++++++++++++++++++++--
 gsk/gskrendernode.h        |    2 -
 gsk/gskrendernodeprivate.h |    4 +++
 gtk/gtkwidget.c            |    4 +-
 6 files changed, 95 insertions(+), 7 deletions(-)
---
diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c
index f9a9fed..f5ea2d9 100644
--- a/gsk/gskrenderer.c
+++ b/gsk/gskrenderer.c
@@ -72,6 +72,9 @@ typedef struct
 
   int scale_factor;
 
+  GPtrArray *render_nodes;
+  int last_render_node;
+
   gboolean is_realized : 1;
   gboolean auto_clear : 1;
   gboolean use_alpha : 1;
@@ -867,6 +870,11 @@ gsk_renderer_realize (GskRenderer *renderer)
     return TRUE;
 
   priv->is_realized = GSK_RENDERER_GET_CLASS (renderer)->realize (renderer);
+  if (priv->is_realized)
+    {
+      priv->render_nodes = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref);
+      priv->last_render_node = 0;
+    }
 
   return priv->is_realized;
 }
@@ -891,6 +899,9 @@ gsk_renderer_unrealize (GskRenderer *renderer)
 
   GSK_RENDERER_GET_CLASS (renderer)->unrealize (renderer);
 
+  g_clear_pointer (&priv->render_nodes, g_ptr_array_unref);
+  priv->last_render_node = 0;
+
   priv->is_realized = FALSE;
 }
 
@@ -930,6 +941,7 @@ gsk_renderer_render (GskRenderer       *renderer,
 
   g_clear_object (&priv->drawing_context);
   g_clear_pointer (&priv->root_node, gsk_render_node_unref);
+  priv->last_render_node = 0;
 }
 
 /**
@@ -1081,3 +1093,41 @@ gsk_renderer_get_for_display (GdkDisplay *display)
 
   return g_object_new (renderer_type, "display", display, NULL);
 }
+
+/**
+ * gsk_renderer_create_render_node:
+ * @renderer: a #GskRenderer
+ *
+ * Creates a new #GskRenderNode.
+ *
+ * Returns: (transfer full): the newly created #GskRenderNode
+ *
+ * Since: 3.22
+ */
+GskRenderNode *
+gsk_renderer_create_render_node (GskRenderer *renderer)
+{
+  GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
+  GskRenderNode *res;
+
+  g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL);
+
+  if (priv->last_render_node < priv->render_nodes->len)
+    {
+      int idx = priv->last_render_node;
+
+      priv->last_render_node += 1;
+
+      res = g_ptr_array_index (priv->render_nodes, idx);
+      gsk_render_node_clear (res);
+    }
+  else
+    {
+      res = gsk_render_node_new ();
+      g_ptr_array_add (priv->render_nodes, res);
+
+      priv->last_render_node = priv->render_nodes->len - 1;
+    }
+
+  return gsk_render_node_ref (res);
+}
diff --git a/gsk/gskrenderer.h b/gsk/gskrenderer.h
index ec1d3aa..b8cf446 100644
--- a/gsk/gskrenderer.h
+++ b/gsk/gskrenderer.h
@@ -101,6 +101,9 @@ void                    gsk_renderer_render                     (GskRenderer
                                                                  GskRenderNode           *root,
                                                                  GdkDrawingContext       *context);
 
+GDK_AVAILABLE_IN_3_22
+GskRenderNode *         gsk_renderer_create_render_node         (GskRenderer             *renderer);
+
 G_END_DECLS
 
 #endif /* __GSK_RENDERER_H__ */
diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c
index 9fe76d6..04f2bbd 100644
--- a/gsk/gskrendernode.c
+++ b/gsk/gskrendernode.c
@@ -144,10 +144,15 @@ gsk_render_node_finalize (GskRenderNode *self)
 {
   GskRenderNodeIter iter;
 
+  /* We need to drop the reference on each child
+   * before clearing the node
+   */
   gsk_render_node_iter_init (&iter, self);
   while (gsk_render_node_iter_next (&iter, NULL))
     gsk_render_node_iter_remove (&iter);
 
+  gsk_render_node_clear (self);
+
   g_type_free_instance ((GTypeInstance *) self);
 }
 
@@ -231,14 +236,12 @@ gsk_render_node_get_type (void)
   return gsk_render_node_type__volatile;
 }
 
-/**
+/*< private >
  * gsk_render_node_new:
  *
  * Creates a new #GskRenderNode, to be used with #GskRenderer.
  *
  * Returns: (transfer full): the newly created #GskRenderNode
- *
- * Since: 3.22
  */
 GskRenderNode *
 gsk_render_node_new (void)
@@ -246,6 +249,36 @@ gsk_render_node_new (void)
   return (GskRenderNode *) g_type_create_instance (GSK_TYPE_RENDER_NODE);
 }
 
+void
+gsk_render_node_clear (GskRenderNode *self)
+{
+  graphene_rect_init_from_rect (&self->bounds, graphene_rect_zero ());
+
+  graphene_matrix_init_identity (&self->transform);
+  graphene_matrix_init_identity (&self->child_transform);
+
+  self->opacity = 1.0;
+
+  self->is_mutable = TRUE;
+  self->opaque = FALSE;
+  self->hidden = FALSE;
+  self->needs_world_matrix_update = TRUE;
+
+  self->parent = NULL;
+  self->first_child = NULL;
+  self->last_child = NULL;
+  self->prev_sibling = NULL;
+  self->next_sibling = NULL;
+  self->n_children = 0;
+
+  self->age = 0;
+
+  g_free (self->name);
+  self->name = NULL;
+
+  g_clear_pointer (&self->surface, cairo_surface_destroy);
+}
+
 /**
  * gsk_render_node_ref:
  * @node: a #GskRenderNode
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index a4709ff..8cbd243 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -39,8 +39,6 @@ GDK_AVAILABLE_IN_3_22
 GType gsk_render_node_get_type (void) G_GNUC_CONST;
 
 GDK_AVAILABLE_IN_3_22
-GskRenderNode *         gsk_render_node_new                     (void);
-GDK_AVAILABLE_IN_3_22
 GskRenderNode *         gsk_render_node_ref                     (GskRenderNode *node);
 GDK_AVAILABLE_IN_3_22
 void                    gsk_render_node_unref                   (GskRenderNode *node);
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 9893f96..e1b7964 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -86,6 +86,10 @@ void gsk_render_node_update_world_matrix (GskRenderNode *node,
 void gsk_render_node_get_world_matrix (GskRenderNode     *node,
                                        graphene_matrix_t *mv);
 
+GskRenderNode *gsk_render_node_new (void);
+
+void gsk_render_node_clear (GskRenderNode *node);
+
 int gsk_render_node_get_size (GskRenderNode *root);
 
 G_END_DECLS
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 90e0f26..fd3c728 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -17479,7 +17479,7 @@ gtk_widget_get_render_node (GtkWidget   *widget,
       GskRenderNode *tmp;
       cairo_t *cr;
 
-      tmp = gsk_render_node_new ();
+      tmp = gsk_renderer_create_render_node (renderer);
       gsk_render_node_set_bounds (tmp, &bounds);
       gsk_render_node_set_transform (tmp, &m);
       cr = gsk_render_node_get_draw_context (tmp);
@@ -17501,7 +17501,7 @@ gtk_widget_get_render_node (GtkWidget   *widget,
           gboolean result;
           cairo_t *cr;
 
-          tmp = gsk_render_node_new ();
+          tmp = gsk_renderer_create_render_node (renderer);
           gsk_render_node_set_bounds (tmp, &bounds);
           gsk_render_node_set_transform (tmp, &m);
           cr = gsk_render_node_get_draw_context (tmp);


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