From b8a92dfa0eddca1283b08b17359bf628f25211dc Mon Sep 17 00:00:00 2001 From: Emmanuele Bassi Date: Wed, 29 Jun 2016 19:05:33 +0100 Subject: [PATCH] gsk: Turn GskRenderNode into a pure GTypeInstance Using GObject as the base type for a transient tree may prove to be too intensive, especially when creating a lot of node instances. Since we don't need properties or signals, and we don't need complex destruction semantics, we can use GTypeInstance directly as the base type for GskRenderNode. --- gsk/gskrenderer.c | 31 +---- gsk/gskrendernode.c | 264 +++++++++++++++++++++++++++++++++++-- gsk/gskrendernode.h | 17 +++ gsk/gskrendernodeprivate.h | 8 +- 4 files changed, 283 insertions(+), 37 deletions(-) diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c index 72717bbbdf..bcccb388f9 100644 --- a/gsk/gskrenderer.c +++ b/gsk/gskrenderer.c @@ -80,7 +80,6 @@ enum { PROP_USE_ALPHA, PROP_SCALE_FACTOR, PROP_WINDOW, - PROP_ROOT_NODE, PROP_DISPLAY, PROP_DRAWING_CONTEXT, @@ -228,10 +227,6 @@ gsk_renderer_get_property (GObject *gobject, g_value_set_object (value, priv->window); break; - case PROP_ROOT_NODE: - g_value_set_object (value, priv->root_node); - break; - case PROP_DRAWING_CONTEXT: g_value_set_object (value, priv->drawing_context); break; @@ -401,21 +396,6 @@ gsk_renderer_class_init (GskRendererClass *klass) G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); - /** - * GskRenderer:root-node: - * - * The root #GskRenderNode of the scene to be rendered. - * - * Since: 3.22 - */ - gsk_renderer_properties[PROP_ROOT_NODE] = - g_param_spec_object ("root-node", - "Root Node", - "The root render node to render", - GSK_TYPE_RENDER_NODE, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS); - /** * GskRenderer:display: * @@ -930,16 +910,17 @@ gsk_renderer_render (GskRenderer *renderer, g_return_if_fail (priv->is_realized); g_return_if_fail (GSK_IS_RENDER_NODE (root)); g_return_if_fail (GDK_IS_DRAWING_CONTEXT (context)); + g_return_if_fail (priv->drawing_context == NULL); + g_return_if_fail (priv->root_node == NULL); - g_set_object (&priv->root_node, root); - g_set_object (&priv->drawing_context, context); - - gsk_render_node_make_immutable (root); + priv->drawing_context = g_object_ref (context); + priv->root_node = gsk_render_node_ref (root); + gsk_render_node_make_immutable (priv->root_node); GSK_RENDERER_GET_CLASS (renderer)->render (renderer, root, context); - g_clear_object (&priv->root_node); g_clear_object (&priv->drawing_context); + g_clear_pointer (&priv->root_node, gsk_render_node_unref); } /** diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c index 95feb24147..4618c5a81b 100644 --- a/gsk/gskrendernode.c +++ b/gsk/gskrendernode.c @@ -33,32 +33,122 @@ #include -G_DEFINE_TYPE (GskRenderNode, gsk_render_node, G_TYPE_OBJECT) +#include static void -gsk_render_node_dispose (GObject *gobject) +value_render_node_init (GValue *value) +{ + value->data[0].v_pointer = NULL; +} + +static void +value_render_node_free (GValue *value) +{ + if (value->data[0].v_pointer != NULL) + gsk_render_node_unref (value->data[0].v_pointer); +} + +static void +value_render_node_copy (const GValue *src, + GValue *dst) +{ + if (src->data[0].v_pointer != NULL) + dst->data[0].v_pointer = gsk_render_node_ref (src->data[0].v_pointer); + else + dst->data[0].v_pointer = NULL; +} + +static gpointer +value_render_node_peek_pointer (const GValue *value) +{ + return value->data[0].v_pointer; +} + +static gchar * +value_render_node_collect_value (GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + GskRenderNode *node; + + node = collect_values[0].v_pointer; + + if (node == NULL) + { + value->data[0].v_pointer = NULL; + return NULL; + } + + if (node->parent_instance.g_class == NULL) + return g_strconcat ("invalid unclassed GskRenderNode pointer for " + "value type '", + G_VALUE_TYPE_NAME (value), + "'", + NULL); + + value->data[0].v_pointer = gsk_render_node_ref (node); + + return NULL; +} + +static gchar * +value_render_node_lcopy_value (const GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + GskRenderNode **node_p = collect_values[0].v_pointer; + + if (node_p == NULL) + return g_strconcat ("value location for '", + G_VALUE_TYPE_NAME (value), + "' passed as NULL", + NULL); + + if (value->data[0].v_pointer == NULL) + *node_p = NULL; + else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) + *node_p = value->data[0].v_pointer; + else + *node_p = gsk_render_node_ref (value->data[0].v_pointer); + + return NULL; +} + +static void +gsk_render_node_finalize (GskRenderNode *self) { - GskRenderNode *self = GSK_RENDER_NODE (gobject); GskRenderNodeIter iter; gsk_render_node_iter_init (&iter, self); while (gsk_render_node_iter_next (&iter, NULL)) gsk_render_node_iter_remove (&iter); - G_OBJECT_CLASS (gsk_render_node_parent_class)->dispose (gobject); + g_type_free_instance ((GTypeInstance *) self); +} + +static void +gsk_render_node_class_base_init (GskRenderNodeClass *klass) +{ +} + +static void +gsk_render_node_class_base_finalize (GskRenderNodeClass *klass) +{ } static void gsk_render_node_class_init (GskRenderNodeClass *klass) { - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - gobject_class->dispose = gsk_render_node_dispose; + klass->finalize = gsk_render_node_finalize; } static void gsk_render_node_init (GskRenderNode *self) { + self->ref_count = 1; + graphene_rect_init_from_rect (&self->bounds, graphene_rect_zero ()); graphene_matrix_init_identity (&self->transform); @@ -69,6 +159,54 @@ gsk_render_node_init (GskRenderNode *self) self->is_mutable = TRUE; } +GType +gsk_render_node_get_type (void) +{ + static volatile gsize gsk_render_node_type__volatile; + + if (g_once_init_enter (&gsk_render_node_type__volatile)) + { + static const GTypeFundamentalInfo finfo = { + (G_TYPE_FLAG_CLASSED | + G_TYPE_FLAG_INSTANTIATABLE | + G_TYPE_FLAG_DERIVABLE | + G_TYPE_FLAG_DEEP_DERIVABLE), + }; + static const GTypeValueTable render_node_value_table = { + value_render_node_init, + value_render_node_free, + value_render_node_copy, + value_render_node_peek_pointer, + "p", value_render_node_collect_value, + "p", value_render_node_lcopy_value, + }; + const GTypeInfo render_node_info = { + sizeof (GskRenderNodeClass), + + (GBaseInitFunc) gsk_render_node_class_base_init, + (GBaseFinalizeFunc) gsk_render_node_class_base_finalize, + (GClassInitFunc) gsk_render_node_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + sizeof (GskRenderNode), 16, + (GInstanceInitFunc) gsk_render_node_init, + + &render_node_value_table, + }; + GType gsk_render_node_type = + g_type_register_fundamental (g_type_fundamental_next (), + g_intern_static_string ("GskRenderNode"), + &render_node_info, + &finfo, + 0); + + g_once_init_leave (&gsk_render_node_type__volatile, gsk_render_node_type); + } + + return gsk_render_node_type__volatile; +} + /** * gsk_render_node_new: * @@ -81,7 +219,47 @@ gsk_render_node_init (GskRenderNode *self) GskRenderNode * gsk_render_node_new (void) { - return g_object_new (GSK_TYPE_RENDER_NODE, NULL); + return (GskRenderNode *) g_type_create_instance (GSK_TYPE_RENDER_NODE); +} + +/** + * gsk_render_node_ref: + * @node: a #GskRenderNode + * + * Acquires a reference on the given #GskRenderNode. + * + * Returns: (transfer none): the #GskRenderNode with an additional reference + * + * Since: 3.22 + */ +GskRenderNode * +gsk_render_node_ref (GskRenderNode *node) +{ + g_return_val_if_fail (GSK_IS_RENDER_NODE (node), NULL); + + g_atomic_int_inc (&node->ref_count); + + return node; +} + +/** + * gsk_render_node_unref: + * @node: a #GskRenderNode + * + * Releases a reference on the given #GskRenderNode. + * + * If the reference was the last, the resources associated to the @node are + * freed. + * + * Since: 3.22 + */ +void +gsk_render_node_unref (GskRenderNode *node) +{ + g_return_if_fail (GSK_IS_RENDER_NODE (node)); + + if (g_atomic_int_dec_and_test (&node->ref_count)) + GSK_RENDER_NODE_GET_CLASS (node)->finalize (node); } /** @@ -206,7 +384,7 @@ gsk_render_node_insert_child_internal (GskRenderNode *node, insert_func (node, child, insert_func_data); - g_object_ref (child); + gsk_render_node_ref (child); child->parent = node; child->age = 0; @@ -606,7 +784,7 @@ gsk_render_node_remove_child (GskRenderNode *node, if (node->last_child == child) node->last_child = prev_sibling; - g_object_unref (child); + gsk_render_node_unref (child); return node; } @@ -1098,3 +1276,69 @@ gsk_render_node_make_immutable (GskRenderNode *node) while (gsk_render_node_iter_next (&iter, &child)) gsk_render_node_make_immutable (child); } + +void +gsk_value_set_render_node (GValue *value, + GskRenderNode *node) +{ + GskRenderNode *old_node; + + g_return_if_fail (GSK_VALUE_HOLDS_RENDER_NODE (value)); + + old_node = value->data[0].v_pointer; + + if (node != NULL) + { + g_return_if_fail (GSK_IS_RENDER_NODE (node)); + + value->data[0].v_pointer = gsk_render_node_ref (node); + } + else + value->data[0].v_pointer = NULL; + + if (old_node != NULL) + gsk_render_node_unref (old_node); +} + +void +gsk_value_take_render_node (GValue *value, + GskRenderNode *node) +{ + GskRenderNode *old_node; + + g_return_if_fail (GSK_VALUE_HOLDS_RENDER_NODE (value)); + + old_node = value->data[0].v_pointer; + + if (node != NULL) + { + g_return_if_fail (GSK_IS_RENDER_NODE (node)); + + /* take over ownership */ + value->data[0].v_pointer = node; + } + else + value->data[0].v_pointer = NULL; + + if (old_node != NULL) + gsk_render_node_unref (old_node); +} + +GskRenderNode * +gsk_value_get_render_node (const GValue *value) +{ + g_return_val_if_fail (GSK_VALUE_HOLDS_RENDER_NODE (value), NULL); + + return value->data[0].v_pointer; +} + +GskRenderNode * +gsk_value_dup_render_node (const GValue *value) +{ + g_return_val_if_fail (GSK_VALUE_HOLDS_RENDER_NODE (value), NULL); + + if (value->data[0].v_pointer != NULL) + return gsk_render_node_ref (value->data[0].v_pointer); + + return NULL; +} diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index 18e56f728b..d8b57e29dd 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -40,6 +40,10 @@ GType gsk_render_node_get_type (void) G_GNUC_CONST; GDK_AVAILABLE_IN_3_22 GskRenderNode * gsk_render_node_new (void); +GDK_AVAILABLE_IN_3_22 +GskRenderNode * gsk_render_node_ref (GskRenderNode *node); +GDK_AVAILABLE_IN_3_22 +void gsk_render_node_unref (GskRenderNode *node); GDK_AVAILABLE_IN_3_22 GskRenderNode * gsk_render_node_get_parent (GskRenderNode *node); @@ -115,6 +119,19 @@ GDK_AVAILABLE_IN_3_22 void gsk_render_node_set_name (GskRenderNode *node, const char *name); +#define GSK_VALUE_HOLDS_RENDER_NODE(value) (G_VALUE_HOLDS (value, GSK_TYPE_RENDER_NODE)) + +GDK_AVAILABLE_IN_3_22 +void gsk_value_set_render_node (GValue *value, + GskRenderNode *node); +GDK_AVAILABLE_IN_3_22 +void gsk_value_take_render_node (GValue *value, + GskRenderNode *node); +GDK_AVAILABLE_IN_3_22 +GskRenderNode * gsk_value_get_render_node (const GValue *value); +GDK_AVAILABLE_IN_3_22 +GskRenderNode * gsk_value_dup_render_node (const GValue *value); + G_END_DECLS #endif /* __GSK_RENDER_NODE_H__ */ diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 9e9188fe8b..16b7cf9c64 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -12,7 +12,9 @@ G_BEGIN_DECLS struct _GskRenderNode { - GObject parent_instance; + GTypeInstance parent_instance; + + volatile int ref_count; /* The graph */ GskRenderNode *parent; @@ -58,7 +60,9 @@ struct _GskRenderNode struct _GskRenderNodeClass { - GObjectClass parent_class; + GTypeClass parent_class; + + void (* finalize) (GskRenderNode *node); }; void gsk_render_node_make_immutable (GskRenderNode *node);