[gtk+/wip/alexl/rendertree] gsk: Add GskRenderTree



commit 1c54d0b79a7a0f50f27159b6dcb064422195d6b7
Author: Alexander Larsson <alexl redhat com>
Date:   Wed Dec 21 20:39:07 2016 +0100

    gsk: Add GskRenderTree
    
    A render tree owns all the nodes that are created during a frame,
    and they are allocated with a custom allocator. All the resources
    allocated for the tree are kept until destruction, and then
    it is all released at the same time.
    
    Allocation happes in chunks which makes both allocation and
    freeing very efficient, and also quite cache efficient.
    
    This somewhat changes the memory management of GskRenderNode. All
    nodes created by the tree are owned by the tree, and normally you
    don't need to ref them. If you want to keep them around you can still
    ref them, but that actually refs the entire tree.

 gsk/gskrenderer.c          |   12 +-
 gsk/gskrenderer.h          |    2 +-
 gsk/gskrendernode.c        |  165 ++++++++++++++++++++++++++-----
 gsk/gskrendernode.h        |   58 ++++++++---
 gsk/gskrendernodeimpl.c    |  233 ++++++++++++--------------------------------
 gsk/gskrendernodeprivate.h |   10 +-
 gtk/gtkcssimagecrossfade.c |    8 +--
 gtk/gtkcssimagelinear.c    |    4 +-
 gtk/gtkcssshadowvalue.c    |    8 +-
 gtk/gtkiconview.c          |    2 +
 gtk/gtkrenderbackground.c  |   10 +--
 gtk/gtkrenderborder.c      |    5 +-
 gtk/gtksnapshot.c          |   92 ++++++++++-------
 gtk/gtksnapshot.h          |    2 +
 gtk/gtksnapshotprivate.h   |    5 +-
 gtk/gtkstack.c             |    8 +-
 16 files changed, 334 insertions(+), 290 deletions(-)
---
diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c
index b50ebd7..8bb8483 100644
--- a/gsk/gskrenderer.c
+++ b/gsk/gskrenderer.c
@@ -609,38 +609,38 @@ gsk_renderer_unrealize (GskRenderer *renderer)
 /**
  * gsk_renderer_render:
  * @renderer: a #GskRenderer
- * @root: a #GskRenderNode
+ * @root_node: a #GskRenderNode
  * @context: The drawing context created via gsk_renderer_begin_draw_frame()
  *
  * Renders the scene graph, described by a tree of #GskRenderNode instances,
  * using the given #GdkDrawingContext.
  *
- * The @renderer will acquire a reference on the #GskRenderNode tree while
+ * The @renderer will acquire a reference on the #GskRenderNode while
  * the rendering is in progress.
  *
  * Since: 3.90
  */
 void
 gsk_renderer_render (GskRenderer       *renderer,
-                     GskRenderNode     *root,
+                     GskRenderNode     *root_node,
                      GdkDrawingContext *context)
 {
   GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer);
 
   g_return_if_fail (GSK_IS_RENDERER (renderer));
   g_return_if_fail (priv->is_realized);
-  g_return_if_fail (GSK_IS_RENDER_NODE (root));
+  g_return_if_fail (GSK_IS_RENDER_NODE (root_node));
   g_return_if_fail (priv->root_node == NULL);
   g_return_if_fail (GDK_IS_DRAWING_CONTEXT (context));
   g_return_if_fail (context == priv->drawing_context);
 
-  priv->root_node = gsk_render_node_ref (root);
+  priv->root_node = gsk_render_node_ref (root_node);
 
 #ifdef G_ENABLE_DEBUG
   gsk_profiler_reset (priv->profiler);
 #endif
 
-  GSK_RENDERER_GET_CLASS (renderer)->render (renderer, root);
+  GSK_RENDERER_GET_CLASS (renderer)->render (renderer, root_node);
 
 #ifdef G_ENABLE_DEBUG
   if (GSK_DEBUG_CHECK (RENDERER))
diff --git a/gsk/gskrenderer.h b/gsk/gskrenderer.h
index 53fccf0..5361af4 100644
--- a/gsk/gskrenderer.h
+++ b/gsk/gskrenderer.h
@@ -78,7 +78,7 @@ GdkDrawingContext *     gsk_renderer_begin_draw_frame           (GskRenderer
                                                                  const cairo_region_t    *region);
 GDK_AVAILABLE_IN_3_90
 void                    gsk_renderer_render                     (GskRenderer             *renderer,
-                                                                 GskRenderNode           *root,
+                                                                 GskRenderNode           *root_node,
                                                                  GdkDrawingContext       *context);
 GDK_AVAILABLE_IN_3_90
 void                    gsk_renderer_end_draw_frame             (GskRenderer             *renderer,
diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c
index d1fdb4f..31d1857 100644
--- a/gsk/gskrendernode.c
+++ b/gsk/gskrendernode.c
@@ -53,6 +53,112 @@
 
 #include <gobject/gvaluecollector.h>
 
+#define ALLOCATE_CHUNK_SIZE (16*1024 - 2*sizeof(gsize))
+
+#define ALIGN(size, base)       ((base) * (gsize) (((size) + (base) - 1) / (base)))
+
+struct _GskRenderTree
+{
+  GObject parent_instance;
+
+  guint8 *chunk;
+  gsize chunk_offset;
+  int chunk_count;
+
+  GPtrArray *destroy_list;
+};
+
+G_DEFINE_TYPE (GskRenderTree, gsk_render_tree, G_TYPE_OBJECT)
+
+static void
+gsk_render_tree_finalize (GObject *gobject)
+{
+  GskRenderTree *self = GSK_RENDER_TREE (gobject);
+  int i;
+
+  /* We free in reverse order, because the notify may touch
+     something allocated before it */
+  for (i = self->destroy_list->len - 2; i >= 0 ; i -= 2)
+    {
+      GDestroyNotify notify = g_ptr_array_index (self->destroy_list, i);
+      gpointer data = g_ptr_array_index (self->destroy_list, i + 1);
+      notify (data);
+    }
+
+  g_ptr_array_free (self->destroy_list, TRUE);
+
+  G_OBJECT_CLASS (gsk_render_tree_parent_class)->finalize (gobject);
+}
+
+static void
+gsk_render_tree_class_init (GskRenderTreeClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gsk_render_tree_finalize;
+}
+
+static void
+gsk_render_tree_init (GskRenderTree *self)
+{
+  self->destroy_list = g_ptr_array_new ();
+}
+
+void
+gsk_render_tree_add_cleanup (GskRenderTree  *self,
+                             GDestroyNotify notify,
+                             gpointer data)
+{
+  g_ptr_array_add (self->destroy_list, notify);
+  g_ptr_array_add (self->destroy_list, data);
+}
+
+/* Note: Align-size must be a power of two */
+gpointer
+gsk_render_tree_allocate (GskRenderTree *self, gsize n_bytes, gsize align_size)
+{
+  gpointer data = NULL;
+
+  if (n_bytes >= ALLOCATE_CHUNK_SIZE / 4)
+    {
+      data = g_malloc0 (n_bytes);
+      gsk_render_tree_add_cleanup (self, g_free, data);
+    }
+  else
+    {
+      self->chunk_offset = (self->chunk_offset + align_size - 1) & ~(align_size - 1);
+      if (self->chunk == NULL || (ALLOCATE_CHUNK_SIZE - self->chunk_offset) < n_bytes)
+        {
+          self->chunk = g_malloc (ALLOCATE_CHUNK_SIZE);
+          gsk_render_tree_add_cleanup (self, g_free, self->chunk);
+          self->chunk_offset = 0;
+        }
+
+      data = self->chunk + self->chunk_offset;
+      self->chunk_offset += n_bytes;
+      memset (data, 0, n_bytes);
+    }
+
+  return data;
+}
+
+GskRenderNode *
+gsk_render_tree_ref_foreign (GskRenderTree  *tree, GskRenderNode *node)
+{
+  if (node->tree != tree)
+    gsk_render_tree_add_cleanup (tree, (GDestroyNotify)gsk_render_node_unref, gsk_render_node_ref (node));
+
+  return node;
+}
+
+
+GskRenderTree *
+gsk_render_tree_new ()
+{
+  return g_object_new (GSK_TYPE_RENDER_TREE,
+                       NULL);
+}
+
 /**
  * GskRenderNode: (ref-func gsk_render_node_ref) (unref-func gsk_render_node_unref)
  *
@@ -65,40 +171,34 @@ G_DEFINE_BOXED_TYPE (GskRenderNode, gsk_render_node,
                      gsk_render_node_ref,
                      gsk_render_node_unref)
 
-static void
-gsk_render_node_finalize (GskRenderNode *self)
-{
-  self->node_class->finalize (self);
-
-  g_clear_pointer (&self->name, g_free);
-
-  g_free (self);
-}
-
 /*< private >
- * gsk_render_node_new:
+ * gsk_render_tree_new_node:
  * @node_class: class structure for this node
  *
  * Returns: (transfer full): the newly created #GskRenderNode
  */
 GskRenderNode *
-gsk_render_node_new (const GskRenderNodeClass *node_class, gsize extra_size)
+gsk_render_tree_new_node (GskRenderTree *self, const GskRenderNodeClass *node_class, gsize extra_size)
 {
-  GskRenderNode *self;
+  GskRenderNode *node;
 
   g_return_val_if_fail (node_class != NULL, NULL);
   g_return_val_if_fail (node_class->node_type != GSK_NOT_A_RENDER_NODE, NULL);
 
-  self = g_malloc0 (node_class->struct_size + extra_size);
+  node = gsk_render_tree_allocate (self, node_class->struct_size + extra_size, 2*sizeof(gsize));
 
-  self->node_class = node_class;
+  node->node_class = node_class;
+  node->tree = self;
+  node->min_filter = GSK_SCALING_FILTER_NEAREST;
+  node->mag_filter = GSK_SCALING_FILTER_NEAREST;
 
-  self->ref_count = 1;
-
-  self->min_filter = GSK_SCALING_FILTER_NEAREST;
-  self->mag_filter = GSK_SCALING_FILTER_NEAREST;
+  return node;
+}
 
-  return self;
+GskRenderTree *
+gsk_render_node_get_tree (GskRenderNode *self)
+{
+  return self->tree;
 }
 
 /**
@@ -106,6 +206,10 @@ gsk_render_node_new (const GskRenderNodeClass *node_class, gsize extra_size)
  * @node: a #GskRenderNode
  *
  * Acquires a reference on the given #GskRenderNode.
+ * All nodes are owned by the tree they are part of, so normally you don't
+ * need to ref individual nodes.
+ *
+ * Note: This keeps the whole tree alive for the lifetime of the node.
  *
  * Returns: (transfer none): the #GskRenderNode with an additional reference
  *
@@ -114,9 +218,12 @@ gsk_render_node_new (const GskRenderNodeClass *node_class, gsize extra_size)
 GskRenderNode *
 gsk_render_node_ref (GskRenderNode *node)
 {
+  GskRenderTree *tree;
+
   g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL);
 
-  g_atomic_int_inc (&node->ref_count);
+  tree = gsk_render_node_get_tree (node);
+  g_object_ref (tree);
 
   return node;
 }
@@ -135,10 +242,12 @@ gsk_render_node_ref (GskRenderNode *node)
 void
 gsk_render_node_unref (GskRenderNode *node)
 {
+  GskRenderTree *tree;
+
   g_return_if_fail (GSK_IS_RENDER_NODE (node));
 
-  if (g_atomic_int_dec_and_test (&node->ref_count))
-    gsk_render_node_finalize (node);
+  tree = gsk_render_node_get_tree (node);
+  g_object_unref (tree);
 }
 
 /**
@@ -207,10 +316,16 @@ void
 gsk_render_node_set_name (GskRenderNode *node,
                           const char    *name)
 {
+  GskRenderTree *tree;
+  char *new_name;
+
   g_return_if_fail (GSK_IS_RENDER_NODE (node));
 
-  g_free (node->name);
-  node->name = g_strdup (name);
+  tree = gsk_render_node_get_tree (node);
+
+  new_name = gsk_render_tree_allocate (tree, strlen (name) + 1, 1);
+  strcpy (new_name, name);
+  node->name = new_name;
 }
 
 /**
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index fad1e53..00c87f3 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -28,10 +28,15 @@
 
 G_BEGIN_DECLS
 
-#define GSK_TYPE_RENDER_NODE (gsk_render_node_get_type ())
+#define GSK_TYPE_RENDER_TREE (gsk_render_tree_get_type ())
+
+GDK_AVAILABLE_IN_3_90
+G_DECLARE_FINAL_TYPE (GskRenderTree, gsk_render_tree, GSK, RENDER_TREE, GObject)
 
+#define GSK_TYPE_RENDER_NODE (gsk_render_node_get_type ())
 #define GSK_IS_RENDER_NODE(obj) ((obj) != NULL)
 
+typedef struct _GskRenderTree           GskRenderTree;
 typedef struct _GskRenderNode           GskRenderNode;
 typedef struct _GskColorStop            GskColorStop;
 typedef struct _GskShadow               GskShadow;
@@ -52,6 +57,9 @@ struct _GskShadow
 };
 
 GDK_AVAILABLE_IN_3_90
+GskRenderTree * gsk_render_tree_new (void);
+
+GDK_AVAILABLE_IN_3_90
 GType gsk_render_node_get_type (void) G_GNUC_CONST;
 
 GDK_AVAILABLE_IN_3_90
@@ -63,40 +71,47 @@ GDK_AVAILABLE_IN_3_90
 GskRenderNodeType       gsk_render_node_get_node_type           (GskRenderNode *node);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_color_node_new                      (const GdkRGBA            *rgba,
+GskRenderNode *         gsk_color_node_new                      (GskRenderTree            *tree,
+                                                                 const GdkRGBA            *rgba,
                                                                  const graphene_rect_t    *bounds);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_texture_node_new                    (GskTexture               *texture,
+GskRenderNode *         gsk_texture_node_new                    (GskRenderTree            *tree,
+                                                                 GskTexture               *texture,
                                                                  const graphene_rect_t    *bounds);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_linear_gradient_node_new            (const graphene_rect_t    *bounds,
+GskRenderNode *         gsk_linear_gradient_node_new            (GskRenderTree            *tree,
+                                                                 const graphene_rect_t    *bounds,
                                                                  const graphene_point_t   *start,
                                                                  const graphene_point_t   *end,
                                                                  const GskColorStop       *color_stops,
                                                                  gsize                     n_color_stops);
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_repeating_linear_gradient_node_new  (const graphene_rect_t    *bounds,
+GskRenderNode *         gsk_repeating_linear_gradient_node_new  (GskRenderTree            *tree,
+                                                                 const graphene_rect_t    *bounds,
                                                                  const graphene_point_t   *start,
                                                                  const graphene_point_t   *end,
                                                                  const GskColorStop       *color_stops,
                                                                  gsize                     n_color_stops);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_border_node_new                     (const GskRoundedRect     *outline,
+GskRenderNode *         gsk_border_node_new                     (GskRenderTree            *tree,
+                                                                 const GskRoundedRect     *outline,
                                                                  const float               border_width[4],
                                                                  const GdkRGBA             border_color[4]);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_inset_shadow_node_new               (const GskRoundedRect     *outline,
+GskRenderNode *         gsk_inset_shadow_node_new               (GskRenderTree            *tree,
+                                                                 const GskRoundedRect     *outline,
                                                                  const GdkRGBA            *color,
                                                                  float                     dx,
                                                                  float                     dy,
                                                                  float                     spread,
                                                                  float                     blur_radius);
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_outset_shadow_node_new              (const GskRoundedRect     *outline,
+GskRenderNode *         gsk_outset_shadow_node_new              (GskRenderTree            *tree,
+                                                                 const GskRoundedRect     *outline,
                                                                  const GdkRGBA            *color,
                                                                  float                     dx,
                                                                  float                     dy,
@@ -104,13 +119,15 @@ GskRenderNode *         gsk_outset_shadow_node_new              (const GskRounde
                                                                  float                     blur_radius);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_cairo_node_new                      (const graphene_rect_t    *bounds);
+GskRenderNode *         gsk_cairo_node_new                      (GskRenderTree            *tree,
+                                                                 const graphene_rect_t    *bounds);
 GDK_AVAILABLE_IN_3_90
 cairo_t *               gsk_cairo_node_get_draw_context         (GskRenderNode            *node,
                                                                  GskRenderer              *renderer);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_container_node_new                  (GskRenderNode           **children,
+GskRenderNode *         gsk_container_node_new                  (GskRenderTree            *tree,
+                                                                 GskRenderNode           **children,
                                                                  guint                     n_children);
 GDK_AVAILABLE_IN_3_90
 guint                   gsk_container_node_get_n_children       (GskRenderNode            *node);
@@ -119,41 +136,48 @@ GskRenderNode *         gsk_container_node_get_child            (GskRenderNode
                                                                  guint                     idx);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_transform_node_new                  (GskRenderNode            *child,
+GskRenderNode *         gsk_transform_node_new                  (GskRenderTree            *tree,
+                                                                 GskRenderNode            *child,
                                                                  const graphene_matrix_t  *transform);
 GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_transform_node_get_child            (GskRenderNode            *node);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_opacity_node_new                    (GskRenderNode            *child,
+GskRenderNode *         gsk_opacity_node_new                    (GskRenderTree            *tree,
+                                                                 GskRenderNode            *child,
                                                                  double                    opacity);
 GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_opacity_node_get_child              (GskRenderNode            *node);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_clip_node_new                       (GskRenderNode            *child,
+GskRenderNode *         gsk_clip_node_new                       (GskRenderTree            *tree,
+                                                                 GskRenderNode            *child,
                                                                  const graphene_rect_t    *clip);
 GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_clip_node_get_child                 (GskRenderNode            *node);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_rounded_clip_node_new               (GskRenderNode            *child,
+GskRenderNode *         gsk_rounded_clip_node_new               (GskRenderTree            *tree,
+                                                                 GskRenderNode            *child,
                                                                  const GskRoundedRect     *clip);
 GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_rounded_clip_node_get_child         (GskRenderNode            *node);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_shadow_node_new                     (GskRenderNode            *child,
+GskRenderNode *         gsk_shadow_node_new                     (GskRenderTree            *tree,
+                                                                 GskRenderNode            *child,
                                                                  const GskShadow          *shadows,
                                                                  gsize                     n_shadows);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_blend_node_new                      (GskRenderNode            *bottom,
+GskRenderNode *         gsk_blend_node_new                      (GskRenderTree            *tree,
+                                                                 GskRenderNode            *bottom,
                                                                  GskRenderNode            *top,
                                                                  GskBlendMode              blend_mode);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_cross_fade_node_new                 (GskRenderNode            *start,
+GskRenderNode *         gsk_cross_fade_node_new                 (GskRenderTree            *tree,
+                                                                 GskRenderNode            *start,
                                                                  GskRenderNode            *end,
                                                                  double                    progress);
 
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 26ef037..75c3d60 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -36,11 +36,6 @@ struct _GskColorNode
 };
 
 static void
-gsk_color_node_finalize (GskRenderNode *node)
-{
-}
-
-static void
 gsk_color_node_draw (GskRenderNode *node,
                      cairo_t       *cr)
 {
@@ -58,7 +53,6 @@ static const GskRenderNodeClass GSK_COLOR_NODE_CLASS = {
   GSK_COLOR_NODE,
   sizeof (GskColorNode),
   "GskColorNode",
-  gsk_color_node_finalize,
   gsk_color_node_draw,
 };
 
@@ -83,7 +77,8 @@ gsk_color_node_peek_color (GskRenderNode *node)
  * Since: 3.90
  */
 GskRenderNode *
-gsk_color_node_new (const GdkRGBA         *rgba,
+gsk_color_node_new (GskRenderTree         *tree,
+                    const GdkRGBA         *rgba,
                     const graphene_rect_t *bounds)
 {
   GskColorNode *self;
@@ -91,7 +86,7 @@ gsk_color_node_new (const GdkRGBA         *rgba,
   g_return_val_if_fail (rgba != NULL, NULL);
   g_return_val_if_fail (bounds != NULL, NULL);
 
-  self = (GskColorNode *) gsk_render_node_new (&GSK_COLOR_NODE_CLASS, 0);
+  self = (GskColorNode *) gsk_render_tree_new_node (tree, &GSK_COLOR_NODE_CLASS, 0);
 
   self->color = *rgba;
   graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
@@ -115,11 +110,6 @@ struct _GskLinearGradientNode
 };
 
 static void
-gsk_linear_gradient_node_finalize (GskRenderNode *node)
-{
-}
-
-static void
 gsk_linear_gradient_node_draw (GskRenderNode *node,
                                cairo_t       *cr)
 {
@@ -156,7 +146,6 @@ static const GskRenderNodeClass GSK_LINEAR_GRADIENT_NODE_CLASS = {
   GSK_LINEAR_GRADIENT_NODE,
   sizeof (GskLinearGradientNode),
   "GskLinearGradientNode",
-  gsk_linear_gradient_node_finalize,
   gsk_linear_gradient_node_draw,
 };
 
@@ -164,7 +153,6 @@ static const GskRenderNodeClass GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS = {
   GSK_REPEATING_LINEAR_GRADIENT_NODE,
   sizeof (GskLinearGradientNode),
   "GskLinearGradientNode",
-  gsk_linear_gradient_node_finalize,
   gsk_linear_gradient_node_draw,
 };
 
@@ -181,7 +169,8 @@ static const GskRenderNodeClass GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_linear_gradient_node_new (const graphene_rect_t  *bounds,
+gsk_linear_gradient_node_new (GskRenderTree          *tree,
+                              const graphene_rect_t  *bounds,
                               const graphene_point_t *start,
                               const graphene_point_t *end,
                               const GskColorStop     *color_stops,
@@ -194,7 +183,7 @@ gsk_linear_gradient_node_new (const graphene_rect_t  *bounds,
   g_return_val_if_fail (end != NULL, NULL);
   g_return_val_if_fail (color_stops != NULL, NULL);
 
-  self = (GskLinearGradientNode *) gsk_render_node_new (&GSK_LINEAR_GRADIENT_NODE_CLASS, sizeof 
(GskColorStop) * n_color_stops);
+  self = (GskLinearGradientNode *) gsk_render_tree_new_node (tree, &GSK_LINEAR_GRADIENT_NODE_CLASS, sizeof 
(GskColorStop) * n_color_stops);
 
   graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
   graphene_point_init_from_point (&self->start, start);
@@ -207,7 +196,8 @@ gsk_linear_gradient_node_new (const graphene_rect_t  *bounds,
 }
 
 GskRenderNode *
-gsk_repeating_linear_gradient_node_new (const graphene_rect_t  *bounds,
+gsk_repeating_linear_gradient_node_new (GskRenderTree          *tree,
+                                        const graphene_rect_t  *bounds,
                                         const graphene_point_t *start,
                                         const graphene_point_t *end,
                                         const GskColorStop     *color_stops,
@@ -220,7 +210,7 @@ gsk_repeating_linear_gradient_node_new (const graphene_rect_t  *bounds,
   g_return_val_if_fail (end != NULL, NULL);
   g_return_val_if_fail (color_stops != NULL, NULL);
 
-  self = (GskLinearGradientNode *) gsk_render_node_new (&GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS, sizeof 
(GskColorStop) * n_color_stops);
+  self = (GskLinearGradientNode *) gsk_render_tree_new_node (tree, 
&GSK_REPEATING_LINEAR_GRADIENT_NODE_CLASS, sizeof (GskColorStop) * n_color_stops);
 
   graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
   graphene_point_init_from_point (&self->start, start);
@@ -246,11 +236,6 @@ struct _GskBorderNode
 };
 
 static void
-gsk_border_node_finalize (GskRenderNode *node)
-{
-}
-
-static void
 gsk_border_node_draw (GskRenderNode *node,
                        cairo_t       *cr)
 {
@@ -337,7 +322,6 @@ static const GskRenderNodeClass GSK_BORDER_NODE_CLASS = {
   GSK_BORDER_NODE,
   sizeof (GskBorderNode),
   "GskBorderNode",
-  gsk_border_node_finalize,
   gsk_border_node_draw,
 };
 
@@ -383,7 +367,8 @@ gsk_border_node_peek_color (GskRenderNode *node,
  * Since: 3.90
  */
 GskRenderNode *
-gsk_border_node_new (const GskRoundedRect     *outline,
+gsk_border_node_new (GskRenderTree            *tree,
+                     const GskRoundedRect     *outline,
                      const float               border_width[4],
                      const GdkRGBA             border_color[4])
 {
@@ -393,7 +378,7 @@ gsk_border_node_new (const GskRoundedRect     *outline,
   g_return_val_if_fail (border_width != NULL, NULL);
   g_return_val_if_fail (border_color != NULL, NULL);
 
-  self = (GskBorderNode *) gsk_render_node_new (&GSK_BORDER_NODE_CLASS, 0);
+  self = (GskBorderNode *) gsk_render_tree_new_node (tree, &GSK_BORDER_NODE_CLASS, 0);
 
   gsk_rounded_rect_init_copy (&self->outline, outline);
   memcpy (self->border_width, border_width, sizeof (self->border_width));
@@ -416,14 +401,6 @@ struct _GskTextureNode
 };
 
 static void
-gsk_texture_node_finalize (GskRenderNode *node)
-{
-  GskTextureNode *self = (GskTextureNode *) node;
-
-  gsk_texture_unref (self->texture);
-}
-
-static void
 gsk_texture_node_draw (GskRenderNode *node,
                        cairo_t       *cr)
 {
@@ -451,7 +428,6 @@ static const GskRenderNodeClass GSK_TEXTURE_NODE_CLASS = {
   GSK_TEXTURE_NODE,
   sizeof (GskTextureNode),
   "GskTextureNode",
-  gsk_texture_node_finalize,
   gsk_texture_node_draw,
 };
 
@@ -478,7 +454,8 @@ gsk_texture_node_get_texture (GskRenderNode *node)
  * Since: 3.90
  */
 GskRenderNode *
-gsk_texture_node_new (GskTexture            *texture,
+gsk_texture_node_new (GskRenderTree         *tree,
+                      GskTexture            *texture,
                       const graphene_rect_t *bounds)
 {
   GskTextureNode *self;
@@ -486,9 +463,11 @@ gsk_texture_node_new (GskTexture            *texture,
   g_return_val_if_fail (GSK_IS_TEXTURE (texture), NULL);
   g_return_val_if_fail (bounds != NULL, NULL);
 
-  self = (GskTextureNode *) gsk_render_node_new (&GSK_TEXTURE_NODE_CLASS, 0);
+  self = (GskTextureNode *) gsk_render_tree_new_node (tree, &GSK_TEXTURE_NODE_CLASS, 0);
+
+  gsk_render_tree_add_cleanup (tree, (GDestroyNotify)gsk_texture_unref, gsk_texture_ref (texture));
 
-  self->texture = gsk_texture_ref (texture);
+  self->texture = texture;
   graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
 
   return &self->render_node;
@@ -510,11 +489,6 @@ struct _GskInsetShadowNode
   float blur_radius;
 };
 
-static void
-gsk_inset_shadow_node_finalize (GskRenderNode *node)
-{
-}
-
 static gboolean
 has_empty_clip (cairo_t *cr)
 {
@@ -902,7 +876,6 @@ static const GskRenderNodeClass GSK_INSET_SHADOW_NODE_CLASS = {
   GSK_INSET_SHADOW_NODE,
   sizeof (GskInsetShadowNode),
   "GskInsetShadowNode",
-  gsk_inset_shadow_node_finalize,
   gsk_inset_shadow_node_draw,
 };
 
@@ -923,7 +896,8 @@ static const GskRenderNodeClass GSK_INSET_SHADOW_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_inset_shadow_node_new (const GskRoundedRect *outline,
+gsk_inset_shadow_node_new (GskRenderTree        *tree,
+                           const GskRoundedRect *outline,
                            const GdkRGBA        *color,
                            float                 dx,
                            float                 dy,
@@ -935,7 +909,7 @@ gsk_inset_shadow_node_new (const GskRoundedRect *outline,
   g_return_val_if_fail (outline != NULL, NULL);
   g_return_val_if_fail (color != NULL, NULL);
 
-  self = (GskInsetShadowNode *) gsk_render_node_new (&GSK_INSET_SHADOW_NODE_CLASS, 0);
+  self = (GskInsetShadowNode *) gsk_render_tree_new_node (tree, &GSK_INSET_SHADOW_NODE_CLASS, 0);
 
   gsk_rounded_rect_init_copy (&self->outline, outline);
   self->color = *color;
@@ -966,11 +940,6 @@ struct _GskOutsetShadowNode
 };
 
 static void
-gsk_outset_shadow_node_finalize (GskRenderNode *node)
-{
-}
-
-static void
 gsk_outset_shadow_get_extents (GskOutsetShadowNode *self,
                                float               *top,
                                float               *right,
@@ -1094,7 +1063,6 @@ static const GskRenderNodeClass GSK_OUTSET_SHADOW_NODE_CLASS = {
   GSK_OUTSET_SHADOW_NODE,
   sizeof (GskOutsetShadowNode),
   "GskOutsetShadowNode",
-  gsk_outset_shadow_node_finalize,
   gsk_outset_shadow_node_draw,
 };
 
@@ -1115,7 +1083,8 @@ static const GskRenderNodeClass GSK_OUTSET_SHADOW_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_outset_shadow_node_new (const GskRoundedRect *outline,
+gsk_outset_shadow_node_new (GskRenderTree        *tree,
+                            const GskRoundedRect *outline,
                             const GdkRGBA        *color,
                             float                 dx,
                             float                 dy,
@@ -1128,7 +1097,7 @@ gsk_outset_shadow_node_new (const GskRoundedRect *outline,
   g_return_val_if_fail (outline != NULL, NULL);
   g_return_val_if_fail (color != NULL, NULL);
 
-  self = (GskOutsetShadowNode *) gsk_render_node_new (&GSK_OUTSET_SHADOW_NODE_CLASS, 0);
+  self = (GskOutsetShadowNode *) gsk_render_tree_new_node (tree, &GSK_OUTSET_SHADOW_NODE_CLASS, 0);
 
   gsk_rounded_rect_init_copy (&self->outline, outline);
   self->color = *color;
@@ -1161,15 +1130,6 @@ struct _GskCairoNode
 };
 
 static void
-gsk_cairo_node_finalize (GskRenderNode *node)
-{
-  GskCairoNode *self = (GskCairoNode *) node;
-
-  if (self->surface)
-    cairo_surface_destroy (self->surface);
-}
-
-static void
 gsk_cairo_node_draw (GskRenderNode *node,
                      cairo_t       *cr)
 {
@@ -1186,7 +1146,6 @@ static const GskRenderNodeClass GSK_CAIRO_NODE_CLASS = {
   GSK_CAIRO_NODE,
   sizeof (GskCairoNode),
   "GskCairoNode",
-  gsk_cairo_node_finalize,
   gsk_cairo_node_draw,
 };
 
@@ -1221,13 +1180,14 @@ gsk_cairo_node_get_surface (GskRenderNode *node)
  * Since: 3.90
  */
 GskRenderNode *
-gsk_cairo_node_new (const graphene_rect_t *bounds)
+gsk_cairo_node_new (GskRenderTree         *tree,
+                    const graphene_rect_t *bounds)
 {
   GskCairoNode *self;
 
   g_return_val_if_fail (bounds != NULL, NULL);
 
-  self = (GskCairoNode *) gsk_render_node_new (&GSK_CAIRO_NODE_CLASS, 0);
+  self = (GskCairoNode *) gsk_render_tree_new_node (tree, &GSK_CAIRO_NODE_CLASS, 0);
 
   graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
 
@@ -1271,6 +1231,8 @@ gsk_cairo_node_get_draw_context (GskRenderNode *node,
     }
   else if (self->surface == NULL)
     {
+      GskRenderTree *tree = gsk_render_node_get_tree (node);
+
       if (renderer)
         {
           self->surface = gsk_renderer_create_cairo_surface (renderer,
@@ -1284,6 +1246,7 @@ gsk_cairo_node_get_draw_context (GskRenderNode *node,
                                                       ceilf (node->bounds.size.width),
                                                       ceilf (node->bounds.size.height));
         }
+      gsk_render_tree_add_cleanup (tree, (GDestroyNotify)cairo_surface_destroy, self->surface);
       res = cairo_create (self->surface);
     }
   else
@@ -1331,16 +1294,6 @@ struct _GskContainerNode
 };
 
 static void
-gsk_container_node_finalize (GskRenderNode *node)
-{
-  GskContainerNode *container = (GskContainerNode *) node;
-  guint i;
-
-  for (i = 0; i < container->n_children; i++)
-    gsk_render_node_unref (container->children[i]);
-}
-
-static void
 gsk_container_node_draw (GskRenderNode *node,
                          cairo_t       *cr)
 {
@@ -1374,7 +1327,6 @@ static const GskRenderNodeClass GSK_CONTAINER_NODE_CLASS = {
   GSK_CONTAINER_NODE,
   sizeof (GskContainerNode),
   "GskContainerNode",
-  gsk_container_node_finalize,
   gsk_container_node_draw,
 };
 
@@ -1391,18 +1343,19 @@ static const GskRenderNodeClass GSK_CONTAINER_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_container_node_new (GskRenderNode **children,
+gsk_container_node_new (GskRenderTree  *tree,
+                        GskRenderNode **children,
                         guint           n_children)
 {
   GskContainerNode *container;
   guint i;
 
-  container = (GskContainerNode *) gsk_render_node_new (&GSK_CONTAINER_NODE_CLASS, sizeof (GskRenderNode *) 
* n_children);
+  container = (GskContainerNode *) gsk_render_tree_new_node (tree, &GSK_CONTAINER_NODE_CLASS, sizeof 
(GskRenderNode *) * n_children);
 
   container->n_children = n_children;
 
   for (i = 0; i < container->n_children; i++)
-    container->children[i] = gsk_render_node_ref (children[i]);
+    container->children[i] = gsk_render_tree_ref_foreign (tree, children[i]);
 
   gsk_container_node_get_bounds (container, &container->render_node.bounds);
 
@@ -1454,14 +1407,6 @@ struct _GskTransformNode
 };
 
 static void
-gsk_transform_node_finalize (GskRenderNode *node)
-{
-  GskTransformNode *self = (GskTransformNode *) node;
-
-  gsk_render_node_unref (self->child);
-}
-
-static void
 gsk_transform_node_draw (GskRenderNode *node,
                          cairo_t       *cr)
 {
@@ -1490,7 +1435,6 @@ static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = {
   GSK_TRANSFORM_NODE,
   sizeof (GskTransformNode),
   "GskTransformNode",
-  gsk_transform_node_finalize,
   gsk_transform_node_draw,
 };
 
@@ -1507,7 +1451,8 @@ static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_transform_node_new (GskRenderNode           *child,
+gsk_transform_node_new (GskRenderTree           *tree,
+                        GskRenderNode           *child,
                         const graphene_matrix_t *transform)
 {
   GskTransformNode *self;
@@ -1515,9 +1460,9 @@ gsk_transform_node_new (GskRenderNode           *child,
   g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
   g_return_val_if_fail (transform != NULL, NULL);
 
-  self = (GskTransformNode *) gsk_render_node_new (&GSK_TRANSFORM_NODE_CLASS, 0);
+  self = (GskTransformNode *) gsk_render_tree_new_node (tree, &GSK_TRANSFORM_NODE_CLASS, 0);
 
-  self->child = gsk_render_node_ref (child);
+  self->child = gsk_render_tree_ref_foreign (tree, child);
   graphene_matrix_init_from_matrix (&self->transform, transform);
 
   graphene_matrix_transform_bounds (&self->transform,
@@ -1568,14 +1513,6 @@ struct _GskOpacityNode
 };
 
 static void
-gsk_opacity_node_finalize (GskRenderNode *node)
-{
-  GskOpacityNode *self = (GskOpacityNode *) node;
-
-  gsk_render_node_unref (self->child);
-}
-
-static void
 gsk_opacity_node_draw (GskRenderNode *node,
                        cairo_t       *cr)
 {
@@ -1602,7 +1539,6 @@ static const GskRenderNodeClass GSK_OPACITY_NODE_CLASS = {
   GSK_OPACITY_NODE,
   sizeof (GskOpacityNode),
   "GskOpacityNode",
-  gsk_opacity_node_finalize,
   gsk_opacity_node_draw,
 };
 
@@ -1619,16 +1555,17 @@ static const GskRenderNodeClass GSK_OPACITY_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_opacity_node_new (GskRenderNode *child,
+gsk_opacity_node_new (GskRenderTree *tree,
+                      GskRenderNode *child,
                       double         opacity)
 {
   GskOpacityNode *self;
 
   g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
 
-  self = (GskOpacityNode *) gsk_render_node_new (&GSK_OPACITY_NODE_CLASS, 0);
+  self = (GskOpacityNode *) gsk_render_tree_new_node (tree, &GSK_OPACITY_NODE_CLASS, 0);
 
-  self->child = gsk_render_node_ref (child);
+  self->child = gsk_render_tree_ref_foreign (tree, child);
   self->opacity = CLAMP (opacity, 0.0, 1.0);
 
   graphene_rect_init_from_rect (&self->render_node.bounds, &child->bounds);
@@ -1677,14 +1614,6 @@ struct _GskClipNode
 };
 
 static void
-gsk_clip_node_finalize (GskRenderNode *node)
-{
-  GskClipNode *self = (GskClipNode *) node;
-
-  gsk_render_node_unref (self->child);
-}
-
-static void
 gsk_clip_node_draw (GskRenderNode *node,
                     cairo_t       *cr)
 {
@@ -1706,7 +1635,6 @@ static const GskRenderNodeClass GSK_CLIP_NODE_CLASS = {
   GSK_CLIP_NODE,
   sizeof (GskClipNode),
   "GskClipNode",
-  gsk_clip_node_finalize,
   gsk_clip_node_draw,
 };
 
@@ -1723,7 +1651,8 @@ static const GskRenderNodeClass GSK_CLIP_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_clip_node_new (GskRenderNode         *child,
+gsk_clip_node_new (GskRenderTree         *tree,
+                   GskRenderNode         *child,
                    const graphene_rect_t *clip)
 {
   GskClipNode *self;
@@ -1731,9 +1660,9 @@ gsk_clip_node_new (GskRenderNode         *child,
   g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
   g_return_val_if_fail (clip != NULL, NULL);
 
-  self = (GskClipNode *) gsk_render_node_new (&GSK_CLIP_NODE_CLASS, 0);
+  self = (GskClipNode *) gsk_render_tree_new_node (tree, &GSK_CLIP_NODE_CLASS, 0);
 
-  self->child = gsk_render_node_ref (child);
+  self->child = gsk_render_tree_ref_foreign (tree, child);
   graphene_rect_normalize_r (clip, &self->clip);
 
   graphene_rect_intersection (&self->clip, &child->bounds, &self->render_node.bounds);
@@ -1782,14 +1711,6 @@ struct _GskRoundedClipNode
 };
 
 static void
-gsk_rounded_clip_node_finalize (GskRenderNode *node)
-{
-  GskRoundedClipNode *self = (GskRoundedClipNode *) node;
-
-  gsk_render_node_unref (self->child);
-}
-
-static void
 gsk_rounded_clip_node_draw (GskRenderNode *node,
                             cairo_t       *cr)
 {
@@ -1809,7 +1730,6 @@ static const GskRenderNodeClass GSK_ROUNDED_CLIP_NODE_CLASS = {
   GSK_ROUNDED_CLIP_NODE,
   sizeof (GskRoundedClipNode),
   "GskRoundedClipNode",
-  gsk_rounded_clip_node_finalize,
   gsk_rounded_clip_node_draw,
 };
 
@@ -1826,7 +1746,8 @@ static const GskRenderNodeClass GSK_ROUNDED_CLIP_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_rounded_clip_node_new (GskRenderNode         *child,
+gsk_rounded_clip_node_new (GskRenderTree         *tree,
+                           GskRenderNode         *child,
                            const GskRoundedRect  *clip)
 {
   GskRoundedClipNode *self;
@@ -1834,9 +1755,9 @@ gsk_rounded_clip_node_new (GskRenderNode         *child,
   g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
   g_return_val_if_fail (clip != NULL, NULL);
 
-  self = (GskRoundedClipNode *) gsk_render_node_new (&GSK_ROUNDED_CLIP_NODE_CLASS, 0);
+  self = (GskRoundedClipNode *) gsk_render_tree_new_node (tree, &GSK_ROUNDED_CLIP_NODE_CLASS, 0);
 
-  self->child = gsk_render_node_ref (child);
+  self->child = gsk_render_tree_ref_foreign (tree, child);
   gsk_rounded_rect_init_copy (&self->clip, clip);
 
   graphene_rect_intersection (&self->clip.bounds, &child->bounds, &self->render_node.bounds);
@@ -1887,14 +1808,6 @@ struct _GskShadowNode
 };
 
 static void
-gsk_shadow_node_finalize (GskRenderNode *node)
-{
-  GskShadowNode *self = (GskShadowNode *) node;
-
-  gsk_render_node_unref (self->child);
-}
-
-static void
 gsk_shadow_node_draw (GskRenderNode *node,
                       cairo_t       *cr)
 {
@@ -1959,7 +1872,6 @@ static const GskRenderNodeClass GSK_SHADOW_NODE_CLASS = {
   GSK_SHADOW_NODE,
   sizeof (GskShadowNode),
   "GskShadowNode",
-  gsk_shadow_node_finalize,
   gsk_shadow_node_draw,
 };
 
@@ -1977,7 +1889,8 @@ static const GskRenderNodeClass GSK_SHADOW_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_shadow_node_new (GskRenderNode         *child,
+gsk_shadow_node_new (GskRenderTree         *tree,
+                     GskRenderNode         *child,
                      const GskShadow       *shadows,
                      gsize                  n_shadows)
 {
@@ -1987,9 +1900,9 @@ gsk_shadow_node_new (GskRenderNode         *child,
   g_return_val_if_fail (shadows != NULL, NULL);
   g_return_val_if_fail (n_shadows > 0, NULL);
 
-  self = (GskShadowNode *) gsk_render_node_new (&GSK_SHADOW_NODE_CLASS, n_shadows * sizeof (GskShadow));
+  self = (GskShadowNode *) gsk_render_tree_new_node (tree, &GSK_SHADOW_NODE_CLASS, n_shadows * sizeof 
(GskShadow));
 
-  self->child = gsk_render_node_ref (child);
+  self->child = gsk_render_tree_ref_foreign (tree, child);
   memcpy (&self->shadows, shadows, n_shadows * sizeof (GskShadow));
   self->n_shadows = n_shadows;
 
@@ -2086,15 +1999,6 @@ gsk_blend_mode_to_cairo_operator (GskBlendMode blend_mode)
 }
 
 static void
-gsk_blend_node_finalize (GskRenderNode *node)
-{
-  GskBlendNode *self = (GskBlendNode *) node;
-
-  gsk_render_node_unref (self->bottom);
-  gsk_render_node_unref (self->top);
-}
-
-static void
 gsk_blend_node_draw (GskRenderNode *node,
                      cairo_t       *cr)
 {
@@ -2118,7 +2022,6 @@ static const GskRenderNodeClass GSK_BLEND_NODE_CLASS = {
   GSK_BLEND_NODE,
   sizeof (GskBlendNode),
   "GskBlendNode",
-  gsk_blend_node_finalize,
   gsk_blend_node_draw,
 };
 
@@ -2136,7 +2039,8 @@ static const GskRenderNodeClass GSK_BLEND_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_blend_node_new (GskRenderNode *bottom,
+gsk_blend_node_new (GskRenderTree *tree,
+                    GskRenderNode *bottom,
                     GskRenderNode *top,
                     GskBlendMode   blend_mode)
 {
@@ -2145,10 +2049,10 @@ gsk_blend_node_new (GskRenderNode *bottom,
   g_return_val_if_fail (GSK_IS_RENDER_NODE (bottom), NULL);
   g_return_val_if_fail (GSK_IS_RENDER_NODE (top), NULL);
 
-  self = (GskBlendNode *) gsk_render_node_new (&GSK_BLEND_NODE_CLASS, 0);
+  self = (GskBlendNode *) gsk_render_tree_new_node (tree, &GSK_BLEND_NODE_CLASS, 0);
 
-  self->bottom = gsk_render_node_ref (bottom);
-  self->top = gsk_render_node_ref (top);
+  self->bottom = gsk_render_tree_ref_foreign (tree, bottom);
+  self->top = gsk_render_tree_ref_foreign (tree, top);
   self->blend_mode = blend_mode;
 
   graphene_rect_union (&bottom->bounds, &top->bounds, &self->render_node.bounds);
@@ -2200,15 +2104,6 @@ struct _GskCrossFadeNode
 };
 
 static void
-gsk_cross_fade_node_finalize (GskRenderNode *node)
-{
-  GskCrossFadeNode *self = (GskCrossFadeNode *) node;
-
-  gsk_render_node_unref (self->start);
-  gsk_render_node_unref (self->end);
-}
-
-static void
 gsk_cross_fade_node_draw (GskRenderNode *node,
                           cairo_t       *cr)
 {
@@ -2232,7 +2127,6 @@ static const GskRenderNodeClass GSK_CROSS_FADE_NODE_CLASS = {
   GSK_CROSS_FADE_NODE,
   sizeof (GskCrossFadeNode),
   "GskCrossFadeNode",
-  gsk_cross_fade_node_finalize,
   gsk_cross_fade_node_draw,
 };
 
@@ -2250,7 +2144,8 @@ static const GskRenderNodeClass GSK_CROSS_FADE_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_cross_fade_node_new (GskRenderNode *start,
+gsk_cross_fade_node_new (GskRenderTree *tree,
+                         GskRenderNode *start,
                          GskRenderNode *end,
                          double         progress)
 {
@@ -2259,10 +2154,10 @@ gsk_cross_fade_node_new (GskRenderNode *start,
   g_return_val_if_fail (GSK_IS_RENDER_NODE (start), NULL);
   g_return_val_if_fail (GSK_IS_RENDER_NODE (end), NULL);
 
-  self = (GskCrossFadeNode *) gsk_render_node_new (&GSK_CROSS_FADE_NODE_CLASS, 0);
+  self = (GskCrossFadeNode *) gsk_render_tree_new_node (tree, &GSK_CROSS_FADE_NODE_CLASS, 0);
 
-  self->start = gsk_render_node_ref (start);
-  self->end = gsk_render_node_ref (end);
+  self->start = gsk_render_tree_ref_foreign (tree, start);
+  self->end = gsk_render_tree_ref_foreign (tree, end);
   self->progress = CLAMP (progress, 0.0, 1.0);
 
   graphene_rect_union (&start->bounds, &end->bounds, &self->render_node.bounds);
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 8eacb7a..8af09e1 100644
--- a/gsk/gskrendernodeprivate.h
+++ b/gsk/gskrendernodeprivate.h
@@ -13,8 +13,7 @@ typedef struct _GskRenderNodeClass GskRenderNodeClass;
 struct _GskRenderNode
 {
   const GskRenderNodeClass *node_class;
-
-  volatile int ref_count;
+  GskRenderTree *tree;
 
   /* Use for debugging */
   char *name;
@@ -31,13 +30,16 @@ struct _GskRenderNodeClass
   GskRenderNodeType node_type;
   gsize struct_size;
   const char *type_name;
-  void (* finalize) (GskRenderNode *node);
   void (* draw) (GskRenderNode *node,
                  cairo_t       *cr);
 };
 
-GskRenderNode *gsk_render_node_new (const GskRenderNodeClass *node_class, gsize extra_size);
+GskRenderNode *gsk_render_tree_new_node (GskRenderTree  *tree, const GskRenderNodeClass *node_class, gsize 
extra_size);
+gpointer gsk_render_tree_allocate (GskRenderTree *self, gsize n_bytes, gsize align_size);
+void gsk_render_tree_add_cleanup (GskRenderTree  *tree, GDestroyNotify notify, gpointer data);
+GskRenderNode *gsk_render_tree_ref_foreign (GskRenderTree  *tree, GskRenderNode *node);
 
+GskRenderTree *gsk_render_node_get_tree (GskRenderNode *self);
 void gsk_render_node_get_bounds (GskRenderNode   *node,
                                  graphene_rect_t *frame);
 double gsk_opacity_node_get_opacity (GskRenderNode *node);
diff --git a/gtk/gtkcssimagecrossfade.c b/gtk/gtkcssimagecrossfade.c
index 546c272..287eaad 100644
--- a/gtk/gtkcssimagecrossfade.c
+++ b/gtk/gtkcssimagecrossfade.c
@@ -139,28 +139,22 @@ gtk_css_image_cross_fade_snapshot (GtkCssImage *image,
 
       if (start_node && end_node)
         {
-          GskRenderNode *node = gsk_cross_fade_node_new (start_node, end_node, cross_fade->progress);
+          GskRenderNode *node = gsk_cross_fade_node_new (gtk_snapshot_get_tree (snapshot), start_node, 
end_node, cross_fade->progress);
 
           gsk_render_node_set_name (node, "CrossFade");
           gtk_snapshot_append_node (snapshot, node);
-
-          gsk_render_node_unref (node);
-          gsk_render_node_unref (start_node);
-          gsk_render_node_unref (end_node);
         }
       else if (start_node)
         {
           gtk_snapshot_push_opacity (snapshot, cross_fade->progress, "CrossFadeStart");
           gtk_snapshot_append_node (snapshot, start_node);
           gtk_snapshot_pop_and_append (snapshot);
-          gsk_render_node_unref (start_node);
         }
       else if (end_node)
         {
           gtk_snapshot_push_opacity (snapshot, 1.0 - cross_fade->progress, "CrossFadeEnd");
           gtk_snapshot_append_node (snapshot, end_node);
           gtk_snapshot_pop_and_append (snapshot);
-          gsk_render_node_unref (end_node);
         }
     }
 }
diff --git a/gtk/gtkcssimagelinear.c b/gtk/gtkcssimagelinear.c
index 0e415d6..062123b 100644
--- a/gtk/gtkcssimagelinear.c
+++ b/gtk/gtkcssimagelinear.c
@@ -223,6 +223,7 @@ gtk_css_image_linear_snapshot (GtkCssImage        *image,
   if (linear->repeating)
     {
       node = gsk_repeating_linear_gradient_node_new (
+          gtk_snapshot_get_tree (snapshot),
           &GRAPHENE_RECT_INIT (off_x, off_y, width, height),
           &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 
0.5)),
           &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5),   off_y + height / 2 + y * (end - 0.5)),
@@ -232,6 +233,7 @@ gtk_css_image_linear_snapshot (GtkCssImage        *image,
   else
     {
       node = gsk_linear_gradient_node_new (
+          gtk_snapshot_get_tree (snapshot),
           &GRAPHENE_RECT_INIT (off_x, off_y, width, height),
           &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (start - 0.5), off_y + height / 2 + y * (start - 
0.5)),
           &GRAPHENE_POINT_INIT (off_x + width / 2 + x * (end - 0.5),   off_y + height / 2 + y * (end - 0.5)),
@@ -243,8 +245,6 @@ gtk_css_image_linear_snapshot (GtkCssImage        *image,
   g_free (name);
 
   gtk_snapshot_append_node (snapshot, node);
-
-  gsk_render_node_unref (node);
 }
 
 
diff --git a/gtk/gtkcssshadowvalue.c b/gtk/gtkcssshadowvalue.c
index bcb874d..1528c5c 100644
--- a/gtk/gtkcssshadowvalue.c
+++ b/gtk/gtkcssshadowvalue.c
@@ -1052,7 +1052,8 @@ gtk_css_shadow_value_snapshot_outset (const GtkCssValue    *shadow,
   gsk_rounded_rect_init_copy (&outline, border_box);
   gsk_rounded_rect_offset (&outline, off_x, off_y);
 
-  node = gsk_outset_shadow_node_new (&outline, 
+  node = gsk_outset_shadow_node_new (gtk_snapshot_get_tree (snapshot),
+                                     &outline,
                                      _gtk_css_rgba_value_get_rgba (shadow->color),
                                      _gtk_css_number_value_get (shadow->hoffset, 0),
                                      _gtk_css_number_value_get (shadow->voffset, 0),
@@ -1060,7 +1061,6 @@ gtk_css_shadow_value_snapshot_outset (const GtkCssValue    *shadow,
                                      _gtk_css_number_value_get (shadow->radius, 0));
   gsk_render_node_set_name (node, "Outset Shadow");
   gtk_snapshot_append_node (snapshot, node);
-  gsk_render_node_unref (node);
 }
 
 void
@@ -1082,7 +1082,8 @@ gtk_css_shadow_value_snapshot_inset (const GtkCssValue   *shadow,
   gsk_rounded_rect_init_copy (&outline, padding_box);
   gsk_rounded_rect_offset (&outline, off_x, off_y);
 
-  node = gsk_inset_shadow_node_new (&outline, 
+  node = gsk_inset_shadow_node_new (gtk_snapshot_get_tree (snapshot),
+                                     &outline,
                                     _gtk_css_rgba_value_get_rgba (shadow->color),
                                     _gtk_css_number_value_get (shadow->hoffset, 0),
                                     _gtk_css_number_value_get (shadow->voffset, 0),
@@ -1090,6 +1091,5 @@ gtk_css_shadow_value_snapshot_inset (const GtkCssValue   *shadow,
                                     _gtk_css_number_value_get (shadow->radius, 0));
   gsk_render_node_set_name (node, "Inset Shadow");
   gtk_snapshot_append_node (snapshot, node);
-  gsk_render_node_unref (node);
 }
 
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index e3690ad..cd4326a 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -7024,6 +7024,8 @@ gtk_icon_view_create_drag_icon (GtkIconView *icon_view,
           gsk_render_node_draw (node, cr);
          cairo_destroy (cr);
 
+          gsk_render_node_unref (node);
+
          return surface;
        }
     }
diff --git a/gtk/gtkrenderbackground.c b/gtk/gtkrenderbackground.c
index 051a9fd..71088d1 100644
--- a/gtk/gtkrenderbackground.c
+++ b/gtk/gtkrenderbackground.c
@@ -685,19 +685,15 @@ gtk_css_style_snapshot_background (GtkCssStyle      *style,
 
               /* XXX: Is this necessary? Do we need a NULL node? */
               if (top == NULL)
-                top = gsk_container_node_new (NULL, 0);
+                top = gsk_container_node_new (gtk_snapshot_get_tree (snapshot), NULL, 0);
               if (bottom == NULL)
-                bottom = gsk_container_node_new (NULL, 0);
+                bottom = gsk_container_node_new (gtk_snapshot_get_tree (snapshot), NULL, 0);
 
-              blend = gsk_blend_node_new (bottom, top, blend_mode);
+              blend = gsk_blend_node_new (gtk_snapshot_get_tree (snapshot), bottom, top, blend_mode);
               gsk_render_node_set_name (blend, "BackgroundBlend");
 
               gtk_snapshot_push (snapshot, TRUE, "BackgroundBlendGroup");
               gtk_snapshot_append_node (snapshot, blend);
-
-              gsk_render_node_unref (blend);
-              gsk_render_node_unref (top);
-              gsk_render_node_unref (bottom);
             }
         }
 
diff --git a/gtk/gtkrenderborder.c b/gtk/gtkrenderborder.c
index d6223c4..76620ac 100644
--- a/gtk/gtkrenderborder.c
+++ b/gtk/gtkrenderborder.c
@@ -436,11 +436,10 @@ snapshot_frame_fill (GtkSnapshot          *snapshot,
   gtk_snapshot_get_offset (snapshot, &off_x, &off_y);
   gsk_rounded_rect_init_copy (&offset_outline, outline);
   gsk_rounded_rect_offset (&offset_outline, off_x, off_y);
-  
-  node = gsk_border_node_new (&offset_outline, border_width, colors);
+
+  node = gsk_border_node_new (snapshot->tree, &offset_outline, border_width, colors);
   gsk_render_node_set_name (node, "Border");
   gtk_snapshot_append_node (snapshot, node);
-  gsk_render_node_unref (node);
 }
 
 static void
diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c
index 9c9161b..4c91f23 100644
--- a/gtk/gtksnapshot.c
+++ b/gtk/gtksnapshot.c
@@ -49,7 +49,8 @@
  */
 
 static GskRenderNode *
-gtk_snapshot_collect_default (GskRenderNode **nodes,
+gtk_snapshot_collect_default (GtkSnapshot    *snapshot,
+                              GskRenderNode **nodes,
                               guint           n_nodes,
                               const char     *name,
                               gpointer        unused)
@@ -62,11 +63,11 @@ gtk_snapshot_collect_default (GskRenderNode **nodes,
     }
   else if (n_nodes == 1)
     {
-      node = gsk_render_node_ref (nodes[0]);
+      node = nodes[0];
     }
   else
     {
-      node = gsk_container_node_new (nodes, n_nodes);
+      node = gsk_container_node_new (snapshot->tree, nodes, n_nodes);
       gsk_render_node_set_name (node, name);
     }
 
@@ -76,6 +77,7 @@ gtk_snapshot_collect_default (GskRenderNode **nodes,
 static GtkSnapshotState *
 gtk_snapshot_state_new (GtkSnapshotState       *parent,
                         char                   *name,
+                        GskRenderTree          *tree,
                         cairo_region_t         *clip,
                         double                  translate_x,
                         double                  translate_y,
@@ -86,10 +88,11 @@ gtk_snapshot_state_new (GtkSnapshotState       *parent,
 
   state = g_slice_new0 (GtkSnapshotState);
 
-  state->nodes = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref);
+  state->nodes = g_ptr_array_new ();
 
   state->parent = parent;
   state->name = name;
+  state->tree = tree;
   if (clip)
     state->clip_region = cairo_region_reference (clip);
   state->translate_x = translate_x;
@@ -124,6 +127,7 @@ gtk_snapshot_init (GtkSnapshot          *snapshot,
 
   snapshot->state = NULL;
   snapshot->renderer = renderer;
+  snapshot->tree = gsk_render_tree_new ();
 
   if (name)
     {
@@ -138,6 +142,7 @@ gtk_snapshot_init (GtkSnapshot          *snapshot,
 
   snapshot->state = gtk_snapshot_state_new (NULL,
                                             str,
+                                            snapshot->tree,
                                             (cairo_region_t *) clip,
                                             0, 0,
                                             gtk_snapshot_collect_default,
@@ -148,7 +153,7 @@ GskRenderNode *
 gtk_snapshot_finish (GtkSnapshot *snapshot)
 {
   GskRenderNode *result;
-  
+
   result = gtk_snapshot_pop (snapshot);
 
   if (snapshot->state != NULL)
@@ -156,6 +161,9 @@ gtk_snapshot_finish (GtkSnapshot *snapshot)
       g_warning ("Too many gtk_snapshot_push() calls.");
     }
 
+  gsk_render_node_ref (result);
+  g_clear_object (&snapshot->tree);
+
   return result;
 }
 
@@ -197,6 +205,7 @@ gtk_snapshot_push (GtkSnapshot           *snapshot,
     {
       snapshot->state = gtk_snapshot_state_new (snapshot->state,
                                                 str,
+                                                snapshot->state->tree,
                                                 snapshot->state->clip_region,
                                                 snapshot->state->translate_x,
                                                 snapshot->state->translate_y,
@@ -207,6 +216,7 @@ gtk_snapshot_push (GtkSnapshot           *snapshot,
     {
       snapshot->state = gtk_snapshot_state_new (snapshot->state,
                                                 str,
+                                                snapshot->state->tree,
                                                 NULL,
                                                 0, 0,
                                                 gtk_snapshot_collect_default,
@@ -215,21 +225,21 @@ gtk_snapshot_push (GtkSnapshot           *snapshot,
 }
 
 static GskRenderNode *
-gtk_snapshot_collect_transform (GskRenderNode **nodes,
+gtk_snapshot_collect_transform (GtkSnapshot    *snapshot,
+                                GskRenderNode **nodes,
                                 guint           n_nodes,
                                 const char     *name,
                                 gpointer        transform)
 {
   GskRenderNode *node, *transform_node;
 
-  node = gtk_snapshot_collect_default (nodes, n_nodes, name, NULL);
+  node = gtk_snapshot_collect_default (snapshot, nodes, n_nodes, name, NULL);
   if (node == NULL)
     return NULL;
 
-  transform_node = gsk_transform_node_new (node, transform);
+  transform_node = gsk_transform_node_new (snapshot->tree, node, transform);
   gsk_render_node_set_name (transform_node, name);
 
-  gsk_render_node_unref (node);
   g_slice_free (graphene_matrix_t, transform);
 
   return transform_node;
@@ -269,6 +279,7 @@ gtk_snapshot_push_transform (GtkSnapshot             *snapshot,
 
   snapshot->state = gtk_snapshot_state_new (snapshot->state,
                                             str,
+                                            snapshot->state->tree,
                                             NULL,
                                             0, 0,
                                             gtk_snapshot_collect_transform,
@@ -276,21 +287,21 @@ gtk_snapshot_push_transform (GtkSnapshot             *snapshot,
 }
 
 static GskRenderNode *
-gtk_snapshot_collect_opacity (GskRenderNode **nodes,
+gtk_snapshot_collect_opacity (GtkSnapshot    *snapshot,
+                              GskRenderNode **nodes,
                               guint           n_nodes,
                               const char     *name,
                               gpointer        opacity)
 {
   GskRenderNode *node, *opacity_node;
 
-  node = gtk_snapshot_collect_default (nodes, n_nodes, name, NULL);
+  node = gtk_snapshot_collect_default (snapshot, nodes, n_nodes, name, NULL);
   if (node == NULL)
     return NULL;
 
-  opacity_node = gsk_opacity_node_new (node, *(double *) opacity);
+  opacity_node = gsk_opacity_node_new (snapshot->tree, node, *(double *) opacity);
   gsk_render_node_set_name (opacity_node, name);
 
-  gsk_render_node_unref (node);
   g_free (opacity);
 
   return opacity_node;
@@ -320,6 +331,7 @@ gtk_snapshot_push_opacity (GtkSnapshot *snapshot,
 
   snapshot->state = gtk_snapshot_state_new (snapshot->state,
                                             str,
+                                            snapshot->state->tree,
                                             snapshot->state->clip_region,
                                             snapshot->state->translate_x,
                                             snapshot->state->translate_y,
@@ -338,21 +350,21 @@ rectangle_init_from_graphene (cairo_rectangle_int_t *cairo,
 }
 
 static GskRenderNode *
-gtk_snapshot_collect_clip (GskRenderNode **nodes,
+gtk_snapshot_collect_clip (GtkSnapshot *snapshot,
+                           GskRenderNode **nodes,
                            guint           n_nodes,
                            const char     *name,
                            gpointer        bounds)
 {
   GskRenderNode *node, *clip_node;
 
-  node = gtk_snapshot_collect_default (nodes, n_nodes, name, NULL);
+  node = gtk_snapshot_collect_default (snapshot, nodes, n_nodes, name, NULL);
   if (node == NULL)
     return NULL;
 
-  clip_node = gsk_clip_node_new (node, bounds);
+  clip_node = gsk_clip_node_new (snapshot->tree, node, bounds);
   gsk_render_node_set_name (clip_node, name);
 
-  gsk_render_node_unref (node);
   g_slice_free (graphene_rect_t, bounds);
 
   return clip_node;
@@ -395,6 +407,7 @@ gtk_snapshot_push_clip (GtkSnapshot           *snapshot,
     }
   snapshot->state = gtk_snapshot_state_new (snapshot->state,
                                             str,
+                                            snapshot->state->tree,
                                             clip,
                                             snapshot->state->translate_x,
                                             snapshot->state->translate_y,
@@ -405,21 +418,21 @@ gtk_snapshot_push_clip (GtkSnapshot           *snapshot,
 }
 
 static GskRenderNode *
-gtk_snapshot_collect_rounded_clip (GskRenderNode **nodes,
+gtk_snapshot_collect_rounded_clip (GtkSnapshot *snapshot,
+                                   GskRenderNode **nodes,
                                    guint           n_nodes,
                                    const char     *name,
                                    gpointer        bounds)
 {
   GskRenderNode *node, *clip_node;
 
-  node = gtk_snapshot_collect_default (nodes, n_nodes, name, NULL);
+  node = gtk_snapshot_collect_default (snapshot, nodes, n_nodes, name, NULL);
   if (node == NULL)
     return NULL;
 
-  clip_node = gsk_rounded_clip_node_new (node, bounds);
+  clip_node = gsk_rounded_clip_node_new (snapshot->tree, node, bounds);
   gsk_render_node_set_name (clip_node, name);
 
-  gsk_render_node_unref (node);
   g_slice_free (GskRoundedRect, bounds);
 
   return clip_node;
@@ -463,6 +476,7 @@ gtk_snapshot_push_rounded_clip (GtkSnapshot          *snapshot,
     }
   snapshot->state = gtk_snapshot_state_new (snapshot->state,
                                             str,
+                                            snapshot->state->tree,
                                             clip,
                                             snapshot->state->translate_x,
                                             snapshot->state->translate_y,
@@ -478,7 +492,8 @@ typedef struct {
 } Shadow;
 
 static GskRenderNode *
-gtk_snapshot_collect_shadow (GskRenderNode **nodes,
+gtk_snapshot_collect_shadow (GtkSnapshot *snapshot,
+                             GskRenderNode **nodes,
                              guint           n_nodes,
                              const char     *name,
                              gpointer        data)
@@ -486,14 +501,13 @@ gtk_snapshot_collect_shadow (GskRenderNode **nodes,
   Shadow *shadow = data;
   GskRenderNode *node, *shadow_node;
 
-  node = gtk_snapshot_collect_default (nodes, n_nodes, name, NULL);
+  node = gtk_snapshot_collect_default (snapshot, nodes, n_nodes, name, NULL);
   if (node == NULL)
     return NULL;
 
-  shadow_node = gsk_shadow_node_new (node, shadow->shadows, shadow->n_shadows);
+  shadow_node = gsk_shadow_node_new (snapshot->tree, node, shadow->shadows, shadow->n_shadows);
   gsk_render_node_set_name (shadow_node, name);
 
-  gsk_render_node_unref (node);
   g_free (shadow);
 
   return shadow_node;
@@ -523,9 +537,10 @@ gtk_snapshot_push_shadow (GtkSnapshot            *snapshot,
     }
   else
     str = NULL;
-  
+
   snapshot->state = gtk_snapshot_state_new (snapshot->state,
                                             str,
+                                            snapshot->state->tree,
                                             snapshot->state->clip_region,
                                             snapshot->state->translate_x,
                                             snapshot->state->translate_y,
@@ -561,7 +576,8 @@ gtk_snapshot_pop (GtkSnapshot *snapshot)
   state = snapshot->state;
   snapshot->state = state->parent;
 
-  node = state->collect_func ((GskRenderNode **) state->nodes->pdata,
+  node = state->collect_func (snapshot,
+                              (GskRenderNode **) state->nodes->pdata,
                               state->nodes->len,
                               state->name,
                               state->collect_data);
@@ -587,10 +603,7 @@ gtk_snapshot_pop_and_append (GtkSnapshot *snapshot)
 
   node = gtk_snapshot_pop (snapshot);
   if (node)
-    {
-      gtk_snapshot_append_node (snapshot, node);
-      gsk_render_node_unref (node);
-    }
+    gtk_snapshot_append_node (snapshot, node);
 }
 
 /**
@@ -658,6 +671,12 @@ gtk_snapshot_get_offset (GtkSnapshot *snapshot,
     *y = snapshot->state->translate_y;
 }
 
+GskRenderTree *
+gtk_snapshot_get_tree (GtkSnapshot *snapshot)
+{
+  return snapshot->tree;
+}
+
 /**
  * gtk_snapshot_append_node:
  * @snapshot: a #GtkSnapshot
@@ -677,7 +696,7 @@ gtk_snapshot_append_node (GtkSnapshot   *snapshot,
 
   if (snapshot->state)
     {
-      g_ptr_array_add (snapshot->state->nodes, gsk_render_node_ref (node));
+      g_ptr_array_add (snapshot->state->nodes, node);
     }
   else
     {
@@ -714,7 +733,7 @@ gtk_snapshot_append_cairo_node (GtkSnapshot           *snapshot,
   g_return_val_if_fail (bounds != NULL, NULL);
 
   graphene_rect_offset_r (bounds, snapshot->state->translate_x, snapshot->state->translate_y, &real_bounds);
-  node = gsk_cairo_node_new (&real_bounds);
+  node = gsk_cairo_node_new (snapshot->tree, &real_bounds);
 
   if (name)
     {
@@ -731,7 +750,6 @@ gtk_snapshot_append_cairo_node (GtkSnapshot           *snapshot,
     }
 
   gtk_snapshot_append_node (snapshot, node);
-  gsk_render_node_unref (node);
 
   cr = gsk_cairo_node_get_draw_context (node, snapshot->renderer);
 
@@ -766,7 +784,7 @@ gtk_snapshot_append_texture_node (GtkSnapshot            *snapshot,
   g_return_if_fail (bounds != NULL);
 
   graphene_rect_offset_r (bounds, snapshot->state->translate_x, snapshot->state->translate_y, &real_bounds);
-  node = gsk_texture_node_new (texture, &real_bounds);
+  node = gsk_texture_node_new (snapshot->tree, texture, &real_bounds);
 
   if (name)
     {
@@ -783,7 +801,6 @@ gtk_snapshot_append_texture_node (GtkSnapshot            *snapshot,
     }
 
   gtk_snapshot_append_node (snapshot, node);
-  gsk_render_node_unref (node);
 }
 
 /**
@@ -814,7 +831,7 @@ gtk_snapshot_append_color_node (GtkSnapshot           *snapshot,
   g_return_if_fail (bounds != NULL);
 
   graphene_rect_offset_r (bounds, snapshot->state->translate_x, snapshot->state->translate_y, &real_bounds);
-  node = gsk_color_node_new (color, &real_bounds);
+  node = gsk_color_node_new (snapshot->tree, color, &real_bounds);
 
   if (name)
     {
@@ -831,7 +848,6 @@ gtk_snapshot_append_color_node (GtkSnapshot           *snapshot,
     }
 
   gtk_snapshot_append_node (snapshot, node);
-  gsk_render_node_unref (node);
 }
 
 /**
diff --git a/gtk/gtksnapshot.h b/gtk/gtksnapshot.h
index 22a12a3..3eea3c7 100644
--- a/gtk/gtksnapshot.h
+++ b/gtk/gtksnapshot.h
@@ -80,6 +80,8 @@ GDK_AVAILABLE_IN_3_90
 void            gtk_snapshot_get_offset                 (GtkSnapshot            *snapshot,
                                                          double                 *x,
                                                          double                 *y);
+GDK_AVAILABLE_IN_3_90
+GskRenderTree *gtk_snapshot_get_tree                   (GtkSnapshot            *snapshot);
 
 GDK_AVAILABLE_IN_3_90
 void            gtk_snapshot_append_node                (GtkSnapshot            *snapshot,
diff --git a/gtk/gtksnapshotprivate.h b/gtk/gtksnapshotprivate.h
index 7eba0f4..e939ead 100644
--- a/gtk/gtksnapshotprivate.h
+++ b/gtk/gtksnapshotprivate.h
@@ -24,7 +24,8 @@ G_BEGIN_DECLS
 
 typedef struct _GtkSnapshotState GtkSnapshotState;
 
-typedef GskRenderNode * (* GtkSnapshotCollectFunc) (GskRenderNode **nodes,
+typedef GskRenderNode * (* GtkSnapshotCollectFunc) (GtkSnapshot    *snapshot,
+                                                    GskRenderNode **nodes,
                                                     guint           n_nodes,
                                                     const char     *name,
                                                     gpointer        user_data);
@@ -33,6 +34,7 @@ struct _GtkSnapshotState {
   GtkSnapshotState      *parent;
 
   char                  *name;
+  GskRenderTree         *tree;
   GPtrArray             *nodes;
 
   cairo_region_t        *clip_region;
@@ -47,6 +49,7 @@ struct _GtkSnapshot {
   GtkSnapshotState      *state;
 
   GskRenderer           *renderer;
+  GskRenderTree         *tree;
 };
 
 void            gtk_snapshot_init               (GtkSnapshot             *state,
diff --git a/gtk/gtkstack.c b/gtk/gtkstack.c
index df58019..0e386e3 100644
--- a/gtk/gtkstack.c
+++ b/gtk/gtkstack.c
@@ -1932,12 +1932,11 @@ gtk_stack_snapshot_crossfade (GtkWidget   *widget,
       gtk_snapshot_push_transform (snapshot, &identity, "CrossFadeStart");
       gtk_snapshot_append_node (snapshot, priv->last_visible_node);
       start_node = gtk_snapshot_pop (snapshot);
-      node = gsk_cross_fade_node_new (start_node, end_node, progress);
-      gsk_render_node_unref (start_node);
+      node = gsk_cross_fade_node_new (gtk_snapshot_get_tree (snapshot), start_node, end_node, progress);
     }
   else
     {
-      node = gsk_opacity_node_new (end_node, 1.0 - progress);
+      node = gsk_opacity_node_new (gtk_snapshot_get_tree (snapshot), end_node, 1.0 - progress);
     }
 
   name = g_strdup_printf ("CrossFade<%g>", progress);
@@ -1945,9 +1944,6 @@ gtk_stack_snapshot_crossfade (GtkWidget   *widget,
   g_free (name);
 
   gtk_snapshot_append_node (snapshot, node);
-
-  gsk_render_node_unref (node);
-  gsk_render_node_unref (end_node);
 }
 
 static void


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