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



commit 8ecbd85acc181378e6ed335541c556fcf6cc09f8
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        |  174 ++++++++++++++++---
 gsk/gskrendernode.h        |   66 +++++---
 gsk/gskrendernodeimpl.c    |  402 +++++++++++++++++---------------------------
 gsk/gskrendernodeprivate.h |   17 +-
 gtk/gtkcssimagecrossfade.c |    8 +-
 gtk/gtkcssimagelinear.c    |    4 +-
 gtk/gtkcssshadowvalue.c    |    8 +-
 gtk/gtkiconview.c          |    2 +
 gtk/gtkrenderbackground.c  |   10 +-
 gtk/gtkrenderborder.c      |    3 +-
 gtk/gtksnapshot.c          |   73 ++++----
 gtk/gtksnapshot.h          |    2 +
 gtk/gtksnapshotprivate.h   |    2 +
 gtk/gtkstack.c             |    8 +-
 16 files changed, 420 insertions(+), 373 deletions(-)
---
diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c
index bba0153..12c0486 100644
--- a/gsk/gskrenderer.c
+++ b/gsk/gskrenderer.c
@@ -688,38 +688,38 @@ gsk_renderer_render_texture (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 0873cf7..62f5adb 100644
--- a/gsk/gskrenderer.h
+++ b/gsk/gskrenderer.h
@@ -75,7 +75,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 ab14c15..dfbd92f 100644
--- a/gsk/gskrendernode.c
+++ b/gsk/gskrendernode.c
@@ -53,6 +53,113 @@
 
 #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)
+G_DEFINE_QUARK (gsk-serialization-error-quark, gsk_serialization_error)
+
+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,42 +172,34 @@ G_DEFINE_BOXED_TYPE (GskRenderNode, gsk_render_node,
                      gsk_render_node_ref,
                      gsk_render_node_unref)
 
-G_DEFINE_QUARK (gsk-serialization-error-quark, gsk_serialization_error)
-
-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);
-
-  self->node_class = node_class;
+  node = gsk_render_tree_allocate (self, node_class->struct_size + extra_size, 2*sizeof(gsize));
 
-  self->ref_count = 1;
+  node->node_class = node_class;
+  node->tree = self;
+  node->min_filter = GSK_SCALING_FILTER_NEAREST;
+  node->mag_filter = GSK_SCALING_FILTER_NEAREST;
 
-  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;
 }
 
 /**
@@ -108,6 +207,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
  *
@@ -116,9 +219,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;
 }
@@ -137,10 +243,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);
 }
 
 /**
@@ -209,10 +317,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;
 }
 
 /**
@@ -391,6 +505,7 @@ gsk_render_node_deserialize (GBytes  *bytes,
   guint32 version, node_type;
   GVariant *variant, *node_variant;
   GskRenderNode *node = NULL;
+  GskRenderTree *tree;
 
   variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("(suuv)"), bytes, FALSE);
 
@@ -410,7 +525,10 @@ gsk_render_node_deserialize (GBytes  *bytes,
       goto out;
     }
 
-  node = gsk_render_node_deserialize_node (node_type, node_variant, error);
+  tree = gsk_render_tree_new ();
+  node = gsk_render_node_deserialize_node (tree, node_type, node_variant, error);
+  gsk_render_node_ref (node);
+  g_object_unref (tree);
 
 out:
   g_free (id_string);
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index f46c283..3e1016e 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -28,12 +28,17 @@
 
 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)
 
 #define GSK_SERIALIZATION_ERROR       (gsk_serialization_error_quark ())
 
+typedef struct _GskRenderTree           GskRenderTree;
 typedef struct _GskRenderNode           GskRenderNode;
 typedef struct _GskColorStop            GskColorStop;
 typedef struct _GskShadow               GskShadow;
@@ -53,10 +58,11 @@ struct _GskShadow
 };
 
 GDK_AVAILABLE_IN_3_90
-GType                   gsk_render_node_get_type                (void) G_GNUC_CONST;
+GQuark                  gsk_serialization_error_quark           (void);
+GskRenderTree * gsk_render_tree_new (void);
 
 GDK_AVAILABLE_IN_3_90
-GQuark                  gsk_serialization_error_quark           (void);
+GType gsk_render_node_get_type (void) G_GNUC_CONST;
 
 GDK_AVAILABLE_IN_3_90
 GskRenderNode *         gsk_render_node_ref                     (GskRenderNode *node);
@@ -67,40 +73,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,
@@ -108,13 +121,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);
@@ -123,51 +138,60 @@ 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_color_matrix_node_new               (GskRenderNode            *child,
+GskRenderNode *         gsk_color_matrix_node_new               (GskRenderTree            *tree,
+                                                                 GskRenderNode            *child,
                                                                  const graphene_matrix_t  *color_matrix,
                                                                  const graphene_vec4_t    *color_offset);
 
 GDK_AVAILABLE_IN_3_90
-GskRenderNode *         gsk_repeat_node_new                     (const graphene_rect_t    *bounds,
+GskRenderNode *         gsk_repeat_node_new                     (GskRenderTree            *tree,
+                                                                 const graphene_rect_t    *bounds,
                                                                  GskRenderNode            *child,
                                                                  const graphene_rect_t    *child_bounds);
 
 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 af356d5..0791f54 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -54,11 +54,6 @@ struct _GskColorNode
 };
 
 static void
-gsk_color_node_finalize (GskRenderNode *node)
-{
-}
-
-static void
 gsk_color_node_draw (GskRenderNode *node,
                      cairo_t       *cr)
 {
@@ -87,7 +82,8 @@ gsk_color_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_color_node_deserialize (GVariant  *variant,
+gsk_color_node_deserialize (GskRenderTree *tree,
+                            GVariant  *variant,
                             GError   **error)
 {
   double x, y, w, h;
@@ -100,14 +96,13 @@ gsk_color_node_deserialize (GVariant  *variant,
                  &color.red, &color.green, &color.blue, &color.alpha,
                  &x, &y, &w, &h);
 
-  return gsk_color_node_new (&color, &GRAPHENE_RECT_INIT (x, y, w, h));
+  return gsk_color_node_new (tree, &color, &GRAPHENE_RECT_INIT (x, y, w, h));
 }
 
 static const GskRenderNodeClass GSK_COLOR_NODE_CLASS = {
   GSK_COLOR_NODE,
   sizeof (GskColorNode),
   "GskColorNode",
-  gsk_color_node_finalize,
   gsk_color_node_draw,
   gsk_color_node_serialize,
   gsk_color_node_deserialize,
@@ -134,7 +129,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;
@@ -142,7 +138,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);
@@ -166,11 +162,6 @@ struct _GskLinearGradientNode
 };
 
 static void
-gsk_linear_gradient_node_finalize (GskRenderNode *node)
-{
-}
-
-static void
 gsk_linear_gradient_node_draw (GskRenderNode *node,
                                cairo_t       *cr)
 {
@@ -230,7 +221,8 @@ gsk_linear_gradient_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_linear_gradient_node_real_deserialize (GVariant  *variant,
+gsk_linear_gradient_node_real_deserialize (GskRenderTree *tree,
+                                           GVariant  *variant,
                                            gboolean   repeating,
                                            GError   **error)
 {
@@ -260,7 +252,8 @@ gsk_linear_gradient_node_real_deserialize (GVariant  *variant,
   g_variant_iter_free (iter);
 
   return (repeating ? gsk_repeating_linear_gradient_node_new : gsk_linear_gradient_node_new)
-                      (&GRAPHENE_RECT_INIT (x, y, w, h),
+                      (tree,
+                       &GRAPHENE_RECT_INIT (x, y, w, h),
                        &GRAPHENE_POINT_INIT (start_x, start_y),
                        &GRAPHENE_POINT_INIT (end_x, end_y),
                        stops,
@@ -268,24 +261,25 @@ gsk_linear_gradient_node_real_deserialize (GVariant  *variant,
 }
 
 static GskRenderNode *
-gsk_linear_gradient_node_deserialize (GVariant  *variant,
+gsk_linear_gradient_node_deserialize (GskRenderTree *tree,
+                                      GVariant  *variant,
                                       GError   **error)
 {
-  return gsk_linear_gradient_node_real_deserialize (variant, FALSE, error);
+  return gsk_linear_gradient_node_real_deserialize (tree, variant, FALSE, error);
 }
 
 static GskRenderNode *
-gsk_repeating_linear_gradient_node_deserialize (GVariant  *variant,
+gsk_repeating_linear_gradient_node_deserialize (GskRenderTree *tree,
+                                                GVariant  *variant,
                                                 GError   **error)
 {
-  return gsk_linear_gradient_node_real_deserialize (variant, TRUE, error);
+  return gsk_linear_gradient_node_real_deserialize (tree, variant, TRUE, error);
 }
 
 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,
   gsk_linear_gradient_node_serialize,
   gsk_linear_gradient_node_deserialize,
@@ -295,7 +289,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,
   gsk_linear_gradient_node_serialize,
   gsk_repeating_linear_gradient_node_deserialize,
@@ -314,7 +307,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,
@@ -336,7 +330,7 @@ gsk_linear_gradient_node_new (const graphene_rect_t  *bounds,
     }
   g_return_val_if_fail (color_stops[n_color_stops - 1].offset <= 1, 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);
@@ -349,7 +343,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,
@@ -371,7 +366,7 @@ gsk_repeating_linear_gradient_node_new (const graphene_rect_t  *bounds,
     }
   g_return_val_if_fail (color_stops[n_color_stops - 1].offset <= 1, 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);
@@ -429,11 +424,6 @@ struct _GskBorderNode
 };
 
 static void
-gsk_border_node_finalize (GskRenderNode *node)
-{
-}
-
-static void
 gsk_border_node_draw (GskRenderNode *node,
                        cairo_t       *cr)
 {
@@ -543,7 +533,8 @@ gsk_border_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_border_node_deserialize (GVariant  *variant,
+gsk_border_node_deserialize (GskRenderTree *tree,
+                             GVariant  *variant,
                              GError   **error)
 {
   double doutline[12], dwidths[4];
@@ -562,7 +553,8 @@ gsk_border_node_deserialize (GVariant  *variant,
                  &colors[2].red, &colors[2].green, &colors[2].blue, &colors[2].alpha,
                  &colors[3].red, &colors[3].green, &colors[3].blue, &colors[3].alpha);
 
-  return gsk_border_node_new (&(GskRoundedRect) {
+  return gsk_border_node_new (tree,
+                              &(GskRoundedRect) {
                                   .bounds = GRAPHENE_RECT_INIT(doutline[0], doutline[1], doutline[2], 
doutline[3]),
                                   .corner = {
                                       GRAPHENE_SIZE_INIT (doutline[4], doutline[5]),
@@ -579,7 +571,6 @@ static const GskRenderNodeClass GSK_BORDER_NODE_CLASS = {
   GSK_BORDER_NODE,
   sizeof (GskBorderNode),
   "GskBorderNode",
-  gsk_border_node_finalize,
   gsk_border_node_draw,
   gsk_border_node_serialize,
   gsk_border_node_deserialize
@@ -627,7 +618,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])
 {
@@ -637,7 +629,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));
@@ -660,14 +652,6 @@ struct _GskTextureNode
 };
 
 static void
-gsk_texture_node_finalize (GskRenderNode *node)
-{
-  GskTextureNode *self = (GskTextureNode *) node;
-
-  g_object_unref (self->texture);
-}
-
-static void
 gsk_texture_node_draw (GskRenderNode *node,
                        cairo_t       *cr)
 {
@@ -721,7 +705,8 @@ gsk_texture_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_texture_node_deserialize (GVariant  *variant,
+gsk_texture_node_deserialize (GskRenderTree *tree,
+                              GVariant  *variant,
                               GError   **error)
 {
   GskRenderNode *node;
@@ -743,7 +728,7 @@ gsk_texture_node_deserialize (GVariant  *variant,
                                       width, height, width * 4);
   g_variant_unref (pixel_variant);
 
-  node = gsk_texture_node_new (texture, &GRAPHENE_RECT_INIT(bounds[0], bounds[1], bounds[2], bounds[3]));
+  node = gsk_texture_node_new (tree, texture, &GRAPHENE_RECT_INIT(bounds[0], bounds[1], bounds[2], 
bounds[3]));
 
   g_object_unref (texture);
 
@@ -754,7 +739,6 @@ static const GskRenderNodeClass GSK_TEXTURE_NODE_CLASS = {
   GSK_TEXTURE_NODE,
   sizeof (GskTextureNode),
   "GskTextureNode",
-  gsk_texture_node_finalize,
   gsk_texture_node_draw,
   gsk_texture_node_serialize,
   gsk_texture_node_deserialize
@@ -783,7 +767,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;
@@ -791,9 +776,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)g_object_unref, g_object_ref (texture));
 
-  self->texture = g_object_ref (texture);
+  self->texture = texture;
   graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
 
   return &self->render_node;
@@ -815,11 +802,6 @@ struct _GskInsetShadowNode
   float blur_radius;
 };
 
-static void
-gsk_inset_shadow_node_finalize (GskRenderNode *node)
-{
-}
-
 static gboolean
 has_empty_clip (cairo_t *cr)
 {
@@ -1224,7 +1206,8 @@ gsk_inset_shadow_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_inset_shadow_node_deserialize (GVariant  *variant,
+gsk_inset_shadow_node_deserialize (GskRenderTree *tree,
+                                   GVariant  *variant,
                                    GError   **error)
 {
   double doutline[12], dx, dy, spread, radius;
@@ -1240,7 +1223,8 @@ gsk_inset_shadow_node_deserialize (GVariant  *variant,
                  &color.red, &color.green, &color.blue, &color.alpha,
                  &dx, &dy, &spread, &radius);
 
-  return gsk_inset_shadow_node_new (&(GskRoundedRect) {
+  return gsk_inset_shadow_node_new (tree,
+                                    &(GskRoundedRect) {
                                         .bounds = GRAPHENE_RECT_INIT(doutline[0], doutline[1], doutline[2], 
doutline[3]),
                                         .corner = {
                                             GRAPHENE_SIZE_INIT (doutline[4], doutline[5]),
@@ -1256,7 +1240,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,
   gsk_inset_shadow_node_serialize,
   gsk_inset_shadow_node_deserialize
@@ -1279,7 +1262,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,
@@ -1291,7 +1275,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;
@@ -1322,11 +1306,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,
@@ -1467,7 +1446,8 @@ gsk_outset_shadow_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_outset_shadow_node_deserialize (GVariant  *variant,
+gsk_outset_shadow_node_deserialize (GskRenderTree *tree,
+                                    GVariant  *variant,
                                     GError   **error)
 {
   double doutline[12], dx, dy, spread, radius;
@@ -1483,7 +1463,8 @@ gsk_outset_shadow_node_deserialize (GVariant  *variant,
                  &color.red, &color.green, &color.blue, &color.alpha,
                  &dx, &dy, &spread, &radius);
 
-  return gsk_outset_shadow_node_new (&(GskRoundedRect) {
+  return gsk_outset_shadow_node_new (tree,
+                                     &(GskRoundedRect) {
                                          .bounds = GRAPHENE_RECT_INIT(doutline[0], doutline[1], doutline[2], 
doutline[3]),
                                          .corner = {
                                              GRAPHENE_SIZE_INIT (doutline[4], doutline[5]),
@@ -1499,7 +1480,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,
   gsk_outset_shadow_node_serialize,
   gsk_outset_shadow_node_deserialize
@@ -1522,7 +1502,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,
@@ -1535,7 +1516,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;
@@ -1568,15 +1549,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)
 {
@@ -1628,7 +1600,8 @@ gsk_cairo_node_serialize (GskRenderNode *node)
 const cairo_user_data_key_t gsk_surface_variant_key;
 
 static GskRenderNode *
-gsk_cairo_node_deserialize (GVariant  *variant,
+gsk_cairo_node_deserialize (GskRenderTree *tree,
+                            GVariant  *variant,
                             GError   **error)
 {
   GskRenderNode *result;
@@ -1649,7 +1622,7 @@ gsk_cairo_node_deserialize (GVariant  *variant,
   if (surface_width == 0 || surface_height == 0)
     {
       g_variant_unref (pixel_variant);
-      return gsk_cairo_node_new (&GRAPHENE_RECT_INIT (x, y, width, height));
+      return gsk_cairo_node_new (tree, &GRAPHENE_RECT_INIT (x, y, width, height));
     }
 
   /* XXX: Make this work without copying the data */
@@ -1661,7 +1634,7 @@ gsk_cairo_node_deserialize (GVariant  *variant,
                                pixel_variant,
                                (cairo_destroy_func_t) g_variant_unref);
 
-  result = gsk_cairo_node_new_for_surface (&GRAPHENE_RECT_INIT (x, y, width, height), surface);
+  result = gsk_cairo_node_new_for_surface (tree, &GRAPHENE_RECT_INIT (x, y, width, height), surface);
 
   cairo_surface_destroy (surface);
 
@@ -1672,7 +1645,6 @@ static const GskRenderNodeClass GSK_CAIRO_NODE_CLASS = {
   GSK_CAIRO_NODE,
   sizeof (GskCairoNode),
   "GskCairoNode",
-  gsk_cairo_node_finalize,
   gsk_cairo_node_draw,
   gsk_cairo_node_serialize,
   gsk_cairo_node_deserialize
@@ -1697,17 +1669,20 @@ gsk_cairo_node_get_surface (GskRenderNode *node)
 }
 
 GskRenderNode *
-gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds,
+gsk_cairo_node_new_for_surface (GskRenderTree         *tree,
+                                const graphene_rect_t *bounds,
                                 cairo_surface_t       *surface)
 {
   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);
+
   self->surface = cairo_surface_reference (surface);
+  gsk_render_tree_add_cleanup (tree, (GDestroyNotify)cairo_surface_destroy, self->surface);
 
   return &self->render_node;
 }
@@ -1725,13 +1700,14 @@ gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds,
  * 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);
 
@@ -1775,6 +1751,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,
@@ -1788,6 +1766,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
@@ -1835,16 +1814,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)
 {
@@ -1896,7 +1865,8 @@ gsk_container_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_container_node_deserialize (GVariant  *variant,
+gsk_container_node_deserialize (GskRenderTree *tree,
+                                GVariant  *variant,
                                 GError   **error)
 {
   GskRenderNode *result;
@@ -1914,7 +1884,7 @@ gsk_container_node_deserialize (GVariant  *variant,
 
   while (g_variant_iter_loop (&iter, "(uv)", &child_type, &child_variant))
     {
-      children[i] = gsk_render_node_deserialize_node (child_type, child_variant, error);
+      children[i] = gsk_render_node_deserialize_node (tree, child_type, child_variant, error);
       if (children[i] == NULL)
         {
           guint j;
@@ -1926,7 +1896,7 @@ gsk_container_node_deserialize (GVariant  *variant,
       i++;
     }
 
-  result = gsk_container_node_new (children, n_children);
+  result = gsk_container_node_new (tree, children, n_children);
 
   for (i = 0; i < n_children; i++)
     gsk_render_node_unref (children[i]);
@@ -1938,7 +1908,6 @@ static const GskRenderNodeClass GSK_CONTAINER_NODE_CLASS = {
   GSK_CONTAINER_NODE,
   sizeof (GskContainerNode),
   "GskContainerNode",
-  gsk_container_node_finalize,
   gsk_container_node_draw,
   gsk_container_node_serialize,
   gsk_container_node_deserialize
@@ -1957,18 +1926,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);
 
@@ -2020,14 +1990,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)
 {
@@ -2072,7 +2034,8 @@ gsk_transform_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_transform_node_deserialize (GVariant  *variant,
+gsk_transform_node_deserialize (GskRenderTree *tree,
+                                GVariant  *variant,
                                 GError   **error)
 {
   graphene_matrix_t transform;
@@ -2091,7 +2054,7 @@ gsk_transform_node_deserialize (GVariant  *variant,
                  &mat[12], &mat[13], &mat[14], &mat[15],
                  &child_type, &child_variant);
 
-  child = gsk_render_node_deserialize_node (child_type, child_variant, error);
+  child = gsk_render_node_deserialize_node (tree, child_type, child_variant, error);
   g_variant_unref (child_variant);
 
   if (child == NULL)
@@ -2105,7 +2068,7 @@ gsk_transform_node_deserialize (GVariant  *variant,
                                        mat[12], mat[13], mat[14], mat[15]
                                    });
                                     
-  result = gsk_transform_node_new (child, &transform);
+  result = gsk_transform_node_new (tree, child, &transform);
 
   gsk_render_node_unref (child);
 
@@ -2116,7 +2079,6 @@ static const GskRenderNodeClass GSK_TRANSFORM_NODE_CLASS = {
   GSK_TRANSFORM_NODE,
   sizeof (GskTransformNode),
   "GskTransformNode",
-  gsk_transform_node_finalize,
   gsk_transform_node_draw,
   gsk_transform_node_serialize,
   gsk_transform_node_deserialize
@@ -2135,7 +2097,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;
@@ -2143,9 +2106,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,
@@ -2196,14 +2159,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)
 {
@@ -2240,7 +2195,8 @@ gsk_opacity_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_opacity_node_deserialize (GVariant  *variant,
+gsk_opacity_node_deserialize (GskRenderTree *tree,
+                              GVariant  *variant,
                               GError   **error)
 {
   double opacity;
@@ -2255,13 +2211,13 @@ gsk_opacity_node_deserialize (GVariant  *variant,
                  &opacity,
                  &child_type, &child_variant);
 
-  child = gsk_render_node_deserialize_node (child_type, child_variant, error);
+  child = gsk_render_node_deserialize_node (tree, child_type, child_variant, error);
   g_variant_unref (child_variant);
 
   if (child == NULL)
     return NULL;
 
-  result = gsk_opacity_node_new (child, opacity);
+  result = gsk_opacity_node_new (tree, child, opacity);
 
   gsk_render_node_unref (child);
 
@@ -2272,7 +2228,6 @@ static const GskRenderNodeClass GSK_OPACITY_NODE_CLASS = {
   GSK_OPACITY_NODE,
   sizeof (GskOpacityNode),
   "GskOpacityNode",
-  gsk_opacity_node_finalize,
   gsk_opacity_node_draw,
   gsk_opacity_node_serialize,
   gsk_opacity_node_deserialize
@@ -2291,16 +2246,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);
@@ -2349,13 +2305,6 @@ struct _GskColorMatrixNode
   graphene_vec4_t color_offset;
 };
 
-static void
-gsk_color_matrix_node_finalize (GskRenderNode *node)
-{
-  GskColorMatrixNode *self = (GskColorMatrixNode *) node;
-
-  gsk_render_node_unref (self->child);
-}
 
 static void
 gsk_color_matrix_node_draw (GskRenderNode *node,
@@ -2461,7 +2410,8 @@ gsk_color_matrix_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_color_matrix_node_deserialize (GVariant  *variant,
+gsk_color_matrix_node_deserialize (GskRenderTree *tree,
+                                   GVariant  *variant,
                                    GError   **error)
 {
   double mat[16], vec[4];
@@ -2482,7 +2432,7 @@ gsk_color_matrix_node_deserialize (GVariant  *variant,
                  &vec[0], &vec[1], &vec[2], &vec[3],
                  &child_type, &child_variant);
 
-  child = gsk_render_node_deserialize_node (child_type, child_variant, error);
+  child = gsk_render_node_deserialize_node (tree, child_type, child_variant, error);
   g_variant_unref (child_variant);
 
   if (child == NULL)
@@ -2497,7 +2447,7 @@ gsk_color_matrix_node_deserialize (GVariant  *variant,
                                    });
   graphene_vec4_init (&offset, vec[0], vec[1], vec[2], vec[3]);
                                     
-  result = gsk_color_matrix_node_new (child, &matrix, &offset);
+  result = gsk_color_matrix_node_new (tree, child, &matrix, &offset);
 
   gsk_render_node_unref (child);
 
@@ -2508,7 +2458,6 @@ static const GskRenderNodeClass GSK_COLOR_MATRIX_NODE_CLASS = {
   GSK_COLOR_MATRIX_NODE,
   sizeof (GskColorMatrixNode),
   "GskColorMatrixNode",
-  gsk_color_matrix_node_finalize,
   gsk_color_matrix_node_draw,
   gsk_color_matrix_node_serialize,
   gsk_color_matrix_node_deserialize
@@ -2532,7 +2481,8 @@ static const GskRenderNodeClass GSK_COLOR_MATRIX_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_color_matrix_node_new (GskRenderNode           *child,
+gsk_color_matrix_node_new (GskRenderTree         *tree,
+                           GskRenderNode           *child,
                            const graphene_matrix_t *color_matrix,
                            const graphene_vec4_t   *color_offset)
 {
@@ -2540,9 +2490,9 @@ gsk_color_matrix_node_new (GskRenderNode           *child,
 
   g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
 
-  self = (GskColorMatrixNode *) gsk_render_node_new (&GSK_COLOR_MATRIX_NODE_CLASS, 0);
+  self = (GskColorMatrixNode *) gsk_render_tree_new_node (tree, &GSK_COLOR_MATRIX_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->color_matrix, color_matrix);
   graphene_vec4_init_from_vec4 (&self->color_offset, color_offset);
 
@@ -2594,14 +2544,6 @@ struct _GskRepeatNode
 };
 
 static void
-gsk_repeat_node_finalize (GskRenderNode *node)
-{
-  GskRepeatNode *self = (GskRepeatNode *) node;
-
-  gsk_render_node_unref (self->child);
-}
-
-static void
 gsk_repeat_node_draw (GskRenderNode *node,
                       cairo_t       *cr)
 {
@@ -2655,7 +2597,8 @@ gsk_repeat_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_repeat_node_deserialize (GVariant  *variant,
+gsk_repeat_node_deserialize (GskRenderTree *tree,
+                             GVariant  *variant,
                              GError   **error)
 {
   double x, y, width, height, child_x, child_y, child_width, child_height;
@@ -2671,13 +2614,14 @@ gsk_repeat_node_deserialize (GVariant  *variant,
                  &child_x, &child_y, &child_width, &child_height,
                  &child_type, &child_variant);
 
-  child = gsk_render_node_deserialize_node (child_type, child_variant, error);
+  child = gsk_render_node_deserialize_node (tree, child_type, child_variant, error);
   g_variant_unref (child_variant);
 
   if (child == NULL)
     return NULL;
 
-  result = gsk_repeat_node_new (&GRAPHENE_RECT_INIT (x, y, width, height),
+  result = gsk_repeat_node_new (tree,
+                                &GRAPHENE_RECT_INIT (x, y, width, height),
                                 child,
                                 &GRAPHENE_RECT_INIT (child_x, child_y, child_width, child_height));
 
@@ -2690,7 +2634,6 @@ static const GskRenderNodeClass GSK_REPEAT_NODE_CLASS = {
   GSK_REPEAT_NODE,
   sizeof (GskRepeatNode),
   "GskRepeatNode",
-  gsk_repeat_node_finalize,
   gsk_repeat_node_draw,
   gsk_repeat_node_serialize,
   gsk_repeat_node_deserialize
@@ -2711,7 +2654,8 @@ static const GskRenderNodeClass GSK_REPEAT_NODE_CLASS = {
  * Since: 3.90
  */
 GskRenderNode *
-gsk_repeat_node_new (const graphene_rect_t *bounds,
+gsk_repeat_node_new (GskRenderTree         *tree,
+                     const graphene_rect_t *bounds,
                      GskRenderNode         *child,
                      const graphene_rect_t *child_bounds)
 {
@@ -2720,10 +2664,10 @@ gsk_repeat_node_new (const graphene_rect_t *bounds,
   g_return_val_if_fail (bounds != NULL, NULL);
   g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
 
-  self = (GskRepeatNode *) gsk_render_node_new (&GSK_REPEAT_NODE_CLASS, 0);
+  self = (GskRepeatNode *) gsk_render_tree_new_node (tree, &GSK_REPEAT_NODE_CLASS, 0);
 
   graphene_rect_init_from_rect (&self->render_node.bounds, bounds);
-  self->child = gsk_render_node_ref (child);
+  self->child = gsk_render_tree_ref_foreign (tree, child);
   if (child_bounds)
     graphene_rect_init_from_rect (&self->child_bounds, child_bounds);
   else
@@ -2765,14 +2709,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)
 {
@@ -2805,7 +2741,8 @@ gsk_clip_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_clip_node_deserialize (GVariant  *variant,
+gsk_clip_node_deserialize (GskRenderTree *tree,
+                           GVariant  *variant,
                            GError   **error)
 {
   double x, y, width, height;
@@ -2820,13 +2757,13 @@ gsk_clip_node_deserialize (GVariant  *variant,
                  &x, &y, &width, &height,
                  &child_type, &child_variant);
 
-  child = gsk_render_node_deserialize_node (child_type, child_variant, error);
+  child = gsk_render_node_deserialize_node (tree, child_type, child_variant, error);
   g_variant_unref (child_variant);
 
   if (child == NULL)
     return NULL;
 
-  result = gsk_clip_node_new (child, &GRAPHENE_RECT_INIT(x, y, width, height));
+  result = gsk_clip_node_new (tree, child, &GRAPHENE_RECT_INIT(x, y, width, height));
 
   gsk_render_node_unref (child);
 
@@ -2837,7 +2774,6 @@ static const GskRenderNodeClass GSK_CLIP_NODE_CLASS = {
   GSK_CLIP_NODE,
   sizeof (GskClipNode),
   "GskClipNode",
-  gsk_clip_node_finalize,
   gsk_clip_node_draw,
   gsk_clip_node_serialize,
   gsk_clip_node_deserialize
@@ -2856,7 +2792,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;
@@ -2864,9 +2801,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);
@@ -2915,14 +2852,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)
 {
@@ -2957,7 +2886,8 @@ gsk_rounded_clip_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_rounded_clip_node_deserialize (GVariant  *variant,
+gsk_rounded_clip_node_deserialize (GskRenderTree *tree,
+                                   GVariant  *variant,
                                    GError   **error)
 {
   double doutline[12];
@@ -2974,13 +2904,13 @@ gsk_rounded_clip_node_deserialize (GVariant  *variant,
                  &doutline[8], &doutline[9], &doutline[10], &doutline[11],
                  &child_type, &child_variant);
 
-  child = gsk_render_node_deserialize_node (child_type, child_variant, error);
+  child = gsk_render_node_deserialize_node (tree, child_type, child_variant, error);
   g_variant_unref (child_variant);
 
   if (child == NULL)
     return NULL;
 
-  result = gsk_rounded_clip_node_new (child,
+  result = gsk_rounded_clip_node_new (tree, child,
                                       &(GskRoundedRect) {
                                           .bounds = GRAPHENE_RECT_INIT(doutline[0], doutline[1], 
doutline[2], doutline[3]),
                                           .corner = {
@@ -3000,7 +2930,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,
   gsk_rounded_clip_node_serialize,
   gsk_rounded_clip_node_deserialize
@@ -3019,7 +2948,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;
@@ -3027,9 +2957,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);
@@ -3080,14 +3010,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)
 {
@@ -3174,7 +3096,8 @@ gsk_shadow_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_shadow_node_deserialize (GVariant  *variant,
+gsk_shadow_node_deserialize (GskRenderTree *tree,
+                             GVariant  *variant,
                              GError   **error)
 {
   gsize n_shadows;
@@ -3190,7 +3113,7 @@ gsk_shadow_node_deserialize (GVariant  *variant,
   g_variant_get (variant, GSK_SHADOW_NODE_VARIANT_TYPE,
                  &child_type, &child_variant, &iter);
 
-  child = gsk_render_node_deserialize_node (child_type, child_variant, error);
+  child = gsk_render_node_deserialize_node (tree, child_type, child_variant, error);
   g_variant_unref (child_variant);
 
   if (child == NULL)
@@ -3214,7 +3137,7 @@ gsk_shadow_node_deserialize (GVariant  *variant,
     }
   g_variant_iter_free (iter);
 
-  result = gsk_shadow_node_new (child, shadows, n_shadows);
+  result = gsk_shadow_node_new (tree, child, shadows, n_shadows);
 
   gsk_render_node_unref (child);
 
@@ -3225,7 +3148,6 @@ static const GskRenderNodeClass GSK_SHADOW_NODE_CLASS = {
   GSK_SHADOW_NODE,
   sizeof (GskShadowNode),
   "GskShadowNode",
-  gsk_shadow_node_finalize,
   gsk_shadow_node_draw,
   gsk_shadow_node_serialize,
   gsk_shadow_node_deserialize
@@ -3245,7 +3167,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)
 {
@@ -3255,9 +3178,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;
 
@@ -3354,15 +3277,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)
 {
@@ -3398,7 +3312,8 @@ gsk_blend_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_blend_node_deserialize (GVariant  *variant,
+gsk_blend_node_deserialize (GskRenderTree *tree,
+                            GVariant  *variant,
                             GError   **error)
 {
   guint32 bottom_child_type, top_child_type, blend_mode;
@@ -3413,7 +3328,7 @@ gsk_blend_node_deserialize (GVariant  *variant,
                  &top_child_type, &top_child_variant,
                  &blend_mode);
 
-  bottom_child = gsk_render_node_deserialize_node (bottom_child_type, bottom_child_variant, error);
+  bottom_child = gsk_render_node_deserialize_node (tree, bottom_child_type, bottom_child_variant, error);
   g_variant_unref (bottom_child_variant);
   if (bottom_child == NULL)
     {
@@ -3421,7 +3336,7 @@ gsk_blend_node_deserialize (GVariant  *variant,
       return NULL;
     }
 
-  top_child = gsk_render_node_deserialize_node (top_child_type, top_child_variant, error);
+  top_child = gsk_render_node_deserialize_node (tree, top_child_type, top_child_variant, error);
   g_variant_unref (top_child_variant);
   if (top_child == NULL)
     {
@@ -3429,7 +3344,7 @@ gsk_blend_node_deserialize (GVariant  *variant,
       return NULL;
     }
 
-  result = gsk_blend_node_new (bottom_child, top_child, blend_mode);
+  result = gsk_blend_node_new (tree, bottom_child, top_child, blend_mode);
 
   gsk_render_node_unref (top_child);
   gsk_render_node_unref (bottom_child);
@@ -3441,7 +3356,6 @@ static const GskRenderNodeClass GSK_BLEND_NODE_CLASS = {
   GSK_BLEND_NODE,
   sizeof (GskBlendNode),
   "GskBlendNode",
-  gsk_blend_node_finalize,
   gsk_blend_node_draw,
   gsk_blend_node_serialize,
   gsk_blend_node_deserialize
@@ -3461,7 +3375,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)
 {
@@ -3470,10 +3385,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);
@@ -3525,15 +3440,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)
 {
@@ -3569,7 +3475,8 @@ gsk_cross_fade_node_serialize (GskRenderNode *node)
 }
 
 static GskRenderNode *
-gsk_cross_fade_node_deserialize (GVariant  *variant,
+gsk_cross_fade_node_deserialize (GskRenderTree *tree,
+                                 GVariant  *variant,
                                  GError   **error)
 {
   guint32 start_child_type, end_child_type;
@@ -3585,7 +3492,7 @@ gsk_cross_fade_node_deserialize (GVariant  *variant,
                  &end_child_type, &end_child_variant,
                  &progress);
 
-  start_child = gsk_render_node_deserialize_node (start_child_type, start_child_variant, error);
+  start_child = gsk_render_node_deserialize_node (tree, start_child_type, start_child_variant, error);
   g_variant_unref (start_child_variant);
   if (start_child == NULL)
     {
@@ -3593,7 +3500,7 @@ gsk_cross_fade_node_deserialize (GVariant  *variant,
       return NULL;
     }
 
-  end_child = gsk_render_node_deserialize_node (end_child_type, end_child_variant, error);
+  end_child = gsk_render_node_deserialize_node (tree, end_child_type, end_child_variant, error);
   g_variant_unref (end_child_variant);
   if (end_child == NULL)
     {
@@ -3601,7 +3508,7 @@ gsk_cross_fade_node_deserialize (GVariant  *variant,
       return NULL;
     }
 
-  result = gsk_cross_fade_node_new (start_child, end_child, progress);
+  result = gsk_cross_fade_node_new (tree, start_child, end_child, progress);
 
   gsk_render_node_unref (end_child);
   gsk_render_node_unref (start_child);
@@ -3613,7 +3520,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,
   gsk_cross_fade_node_serialize,
   gsk_cross_fade_node_deserialize
@@ -3633,7 +3539,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)
 {
@@ -3642,10 +3549,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);
@@ -3704,7 +3611,8 @@ static const GskRenderNodeClass *klasses[] = {
 };
 
 GskRenderNode *
-gsk_render_node_deserialize_node (GskRenderNodeType   type,
+gsk_render_node_deserialize_node (GskRenderTree *tree,
+                                  GskRenderNodeType   type,
                                   GVariant           *variant,
                                   GError            **error)
 {
@@ -3723,7 +3631,7 @@ gsk_render_node_deserialize_node (GskRenderNodeType   type,
       return NULL;
     }
 
-  result = klass->deserialize (variant, error);
+  result = klass->deserialize (tree, variant, error);
 
   return result;
 }
diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h
index 938c948..ebdfb53 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,19 +30,23 @@ struct _GskRenderNodeClass
   GskRenderNodeType node_type;
   gsize struct_size;
   const char *type_name;
-  void (* finalize) (GskRenderNode *node);
   void (* draw) (GskRenderNode *node,
                  cairo_t       *cr);
   GVariant * (* serialize) (GskRenderNode *node);
-  GskRenderNode * (* deserialize) (GVariant  *variant,
+  GskRenderNode * (* deserialize) (GskRenderTree *tree,
+                                   GVariant  *variant,
                                    GError   **error);
 };
 
-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);
 
 GVariant * gsk_render_node_serialize_node (GskRenderNode *node);
-GskRenderNode * gsk_render_node_deserialize_node (GskRenderNodeType type, GVariant *variant, GError **error);
+GskRenderNode * gsk_render_node_deserialize_node (GskRenderTree *tree, GskRenderNodeType type, GVariant 
*variant, GError **error);
 
+GskRenderTree *gsk_render_node_get_tree (GskRenderNode *self);
 double gsk_opacity_node_get_opacity (GskRenderNode *node);
 
 GskRenderNode * gsk_color_matrix_node_get_child (GskRenderNode *node);
@@ -62,7 +65,7 @@ const GskRoundedRect * gsk_border_node_peek_outline (GskRenderNode *node);
 float gsk_border_node_get_width (GskRenderNode *node, guint i);
 const GdkRGBA * gsk_border_node_peek_color (GskRenderNode *node, guint i);
 
-GskRenderNode *gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds, cairo_surface_t *surface);
+GskRenderNode *gsk_cairo_node_new_for_surface (GskRenderTree *tree, const graphene_rect_t *bounds, 
cairo_surface_t *surface);
 cairo_surface_t *gsk_cairo_node_get_surface (GskRenderNode *node);
 
 GskTexture *gsk_texture_node_get_texture (GskRenderNode *node);
diff --git a/gtk/gtkcssimagecrossfade.c b/gtk/gtkcssimagecrossfade.c
index 2b9aab1..ca4829b 100644
--- a/gtk/gtkcssimagecrossfade.c
+++ b/gtk/gtkcssimagecrossfade.c
@@ -139,29 +139,23 @@ 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);
 
           if (snapshot->record_names)
             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, 1.0 - 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, 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 7200c48..1536205 100644
--- a/gtk/gtkcssimagelinear.c
+++ b/gtk/gtkcssimagelinear.c
@@ -238,6 +238,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)),
@@ -247,6 +248,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)),
@@ -262,8 +264,6 @@ gtk_css_image_linear_snapshot (GtkCssImage        *image,
     }
 
   gtk_snapshot_append_node (snapshot, node);
-
-  gsk_render_node_unref (node);
 }
 
 
diff --git a/gtk/gtkcssshadowvalue.c b/gtk/gtkcssshadowvalue.c
index ed56504..ec37300 100644
--- a/gtk/gtkcssshadowvalue.c
+++ b/gtk/gtkcssshadowvalue.c
@@ -1051,7 +1051,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,
   if (snapshot->record_names)
     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),
@@ -1091,6 +1092,5 @@ gtk_css_shadow_value_snapshot_inset (const GtkCssValue   *shadow,
   if (snapshot->record_names)
     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 2cbc680..b431559 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 e52d1de..84f2949 100644
--- a/gtk/gtkrenderbackground.c
+++ b/gtk/gtkrenderbackground.c
@@ -676,20 +676,16 @@ 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);
               if (snapshot->record_names)
                 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 a42f74e..1201ab5 100644
--- a/gtk/gtkrenderborder.c
+++ b/gtk/gtkrenderborder.c
@@ -437,11 +437,10 @@ snapshot_frame_fill (GtkSnapshot          *snapshot,
   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);
   if (snapshot->record_names)
     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 08db8c5..703a3b0 100644
--- a/gtk/gtksnapshot.c
+++ b/gtk/gtksnapshot.c
@@ -62,11 +62,11 @@ gtk_snapshot_collect_default (GtkSnapshotState *state,
     }
   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 (state->tree, nodes, n_nodes);
       if (name)
         gsk_render_node_set_name (node, name);
     }
@@ -77,6 +77,7 @@ gtk_snapshot_collect_default (GtkSnapshotState *state,
 static GtkSnapshotState *
 gtk_snapshot_state_new (GtkSnapshotState       *parent,
                         char                   *name,
+                        GskRenderTree          *tree,
                         cairo_region_t         *clip,
                         int                     translate_x,
                         int                     translate_y,
@@ -92,11 +93,12 @@ gtk_snapshot_state_new (GtkSnapshotState       *parent,
   else
     {
       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;
@@ -137,6 +139,7 @@ gtk_snapshot_init (GtkSnapshot          *snapshot,
   snapshot->state = NULL;
   snapshot->record_names = record_names;
   snapshot->renderer = renderer;
+  snapshot->tree = gsk_render_tree_new ();
 
   if (name && record_names)
     {
@@ -151,6 +154,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);
@@ -160,7 +164,7 @@ GskRenderNode *
 gtk_snapshot_finish (GtkSnapshot *snapshot)
 {
   GskRenderNode *result;
-  
+
   result = gtk_snapshot_pop (snapshot);
 
   if (snapshot->state != NULL)
@@ -168,6 +172,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;
 }
 
@@ -208,6 +215,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,
@@ -217,6 +225,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);
@@ -235,12 +244,10 @@ gtk_snapshot_collect_transform (GtkSnapshotState *state,
   if (node == NULL)
     return NULL;
 
-  transform_node = gsk_transform_node_new (node, &state->data.transform.transform);
+  transform_node = gsk_transform_node_new (state->tree, node, &state->data.transform.transform);
   if (name)
     gsk_render_node_set_name (transform_node, name);
 
-  gsk_render_node_unref (node);
-
   return transform_node;
 }
 
@@ -267,6 +274,7 @@ gtk_snapshot_push_transform (GtkSnapshot             *snapshot,
 
   state = gtk_snapshot_state_new (snapshot->state,
                                   str,
+                                  snapshot->state->tree,
                                   NULL,
                                   0, 0,
                                   gtk_snapshot_collect_transform);
@@ -295,12 +303,10 @@ gtk_snapshot_collect_opacity (GtkSnapshotState *state,
   if (node == NULL)
     return NULL;
 
-  opacity_node = gsk_opacity_node_new (node, state->data.opacity.opacity);
+  opacity_node = gsk_opacity_node_new (state->tree, node, state->data.opacity.opacity);
   if (name)
     gsk_render_node_set_name (opacity_node, name);
 
-  gsk_render_node_unref (node);
-
   return opacity_node;
 }
 
@@ -326,6 +332,7 @@ gtk_snapshot_push_opacity (GtkSnapshot *snapshot,
 
   state = gtk_snapshot_state_new (snapshot->state,
                                   str,
+                                  snapshot->state->tree,
                                   snapshot->state->clip_region,
                                   snapshot->state->translate_x,
                                   snapshot->state->translate_y,
@@ -346,14 +353,12 @@ gtk_snapshot_collect_color_matrix (GtkSnapshotState *state,
   if (node == NULL)
     return NULL;
 
-  color_matrix_node = gsk_color_matrix_node_new (node,
+  color_matrix_node = gsk_color_matrix_node_new (state->tree, node,
                                                  &state->data.color_matrix.matrix,
                                                  &state->data.color_matrix.offset);
   if (name)
     gsk_render_node_set_name (color_matrix_node, name);
 
-  gsk_render_node_unref (node);
-
   return color_matrix_node;
 }
 
@@ -380,6 +385,7 @@ gtk_snapshot_push_color_matrix (GtkSnapshot             *snapshot,
 
   state = gtk_snapshot_state_new (snapshot->state,
                                   str,
+                                  snapshot->state->tree,
                                   snapshot->state->clip_region,
                                   snapshot->state->translate_x,
                                   snapshot->state->translate_y,
@@ -414,14 +420,12 @@ gtk_snapshot_collect_repeat (GtkSnapshotState *state,
   if (node == NULL)
     return NULL;
 
-  repeat_node = gsk_repeat_node_new (bounds,
+  repeat_node = gsk_repeat_node_new (state->tree, bounds,
                                      node,
                                      child_bounds->size.width > 0 ? child_bounds : NULL);
   if (name)
     gsk_render_node_set_name (repeat_node, name);
 
-  gsk_render_node_unref (node);
-
   return repeat_node;
 }
 
@@ -458,6 +462,7 @@ gtk_snapshot_push_repeat (GtkSnapshot           *snapshot,
 
   state = gtk_snapshot_state_new (snapshot->state,
                                   str,
+                                  snapshot->state->tree,
                                   clip,
                                   snapshot->state->translate_x,
                                   snapshot->state->translate_y,
@@ -484,12 +489,10 @@ gtk_snapshot_collect_clip (GtkSnapshotState *state,
   if (node == NULL)
     return NULL;
 
-  clip_node = gsk_clip_node_new (node, &state->data.clip.bounds);
+  clip_node = gsk_clip_node_new (state->tree, node, &state->data.clip.bounds);
   if (name)
     gsk_render_node_set_name (clip_node, name);
 
-  gsk_render_node_unref (node);
-
   return clip_node;
 }
 
@@ -530,6 +533,7 @@ gtk_snapshot_push_clip (GtkSnapshot           *snapshot,
     }
   state = gtk_snapshot_state_new (snapshot->state,
                                   str,
+                                  snapshot->state->tree,
                                   clip,
                                   snapshot->state->translate_x,
                                   snapshot->state->translate_y,
@@ -554,12 +558,10 @@ gtk_snapshot_collect_rounded_clip (GtkSnapshotState *state,
   if (node == NULL)
     return NULL;
 
-  clip_node = gsk_rounded_clip_node_new (node, &state->data.rounded_clip.bounds);
+  clip_node = gsk_rounded_clip_node_new (state->tree, node, &state->data.rounded_clip.bounds);
   if (name)
     gsk_render_node_set_name (clip_node, name);
 
-  gsk_render_node_unref (node);
-
   return clip_node;
 }
 
@@ -602,6 +604,7 @@ gtk_snapshot_push_rounded_clip (GtkSnapshot          *snapshot,
 
   state = gtk_snapshot_state_new (snapshot->state,
                                   str,
+                                  snapshot->state->tree,
                                   clip,
                                   snapshot->state->translate_x,
                                   snapshot->state->translate_y,
@@ -626,11 +629,10 @@ gtk_snapshot_collect_shadow (GtkSnapshotState *state,
   if (node == NULL)
     return NULL;
 
-  shadow_node = gsk_shadow_node_new (node, state->data.shadow.shadows, state->data.shadow.n_shadows);
+  shadow_node = gsk_shadow_node_new (state->tree, node, state->data.shadow.shadows, 
state->data.shadow.n_shadows);
   if (name)
     gsk_render_node_set_name (shadow_node, name);
 
-  gsk_render_node_unref (node);
   if (state->data.shadow.shadows != &state->data.shadow.a_shadow)
     g_free (state->data.shadow.shadows);
 
@@ -661,6 +663,7 @@ gtk_snapshot_push_shadow (GtkSnapshot            *snapshot,
 
   state = gtk_snapshot_state_new (snapshot->state,
                                   str,
+                                  snapshot->state->tree,
                                   snapshot->state->clip_region,
                                   snapshot->state->translate_x,
                                   snapshot->state->translate_y,
@@ -736,10 +739,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);
 }
 
 /**
@@ -807,6 +807,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
@@ -826,7 +832,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
     {
@@ -863,7 +869,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 && snapshot->record_names)
     {
@@ -880,7 +886,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);
 
@@ -915,7 +920,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 && snapshot->record_names)
     {
@@ -932,7 +937,6 @@ gtk_snapshot_append_texture_node (GtkSnapshot            *snapshot,
     }
 
   gtk_snapshot_append_node (snapshot, node);
-  gsk_render_node_unref (node);
 }
 
 /**
@@ -963,7 +967,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 && snapshot->record_names)
     {
@@ -980,7 +984,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 0b691c3..6f39144 100644
--- a/gtk/gtksnapshot.h
+++ b/gtk/gtksnapshot.h
@@ -92,6 +92,8 @@ GDK_AVAILABLE_IN_3_90
 void            gtk_snapshot_get_offset                 (GtkSnapshot            *snapshot,
                                                          int                    *x,
                                                          int                    *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 91d1b66..ea7663e 100644
--- a/gtk/gtksnapshotprivate.h
+++ b/gtk/gtksnapshotprivate.h
@@ -34,6 +34,7 @@ struct _GtkSnapshotState {
   GtkSnapshotState      *cached_state; /* A cleared state object we can (re)use */
 
   char                  *name;
+  GskRenderTree         *tree;
   GPtrArray             *nodes;
 
   cairo_region_t        *clip_region;
@@ -74,6 +75,7 @@ struct _GtkSnapshot {
   GtkSnapshotState      *state;
   gboolean               record_names;
   GskRenderer           *renderer;
+  GskRenderTree         *tree;
 };
 
 void            gtk_snapshot_init               (GtkSnapshot             *state,
diff --git a/gtk/gtkstack.c b/gtk/gtkstack.c
index d1f4767..dea41c8 100644
--- a/gtk/gtkstack.c
+++ b/gtk/gtkstack.c
@@ -1933,12 +1933,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);
     }
 
   if (snapshot->record_names)
@@ -1949,9 +1948,6 @@ gtk_stack_snapshot_crossfade (GtkWidget   *widget,
     }
 
   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]