diff options
author | Emmanuele Bassi <ebassi@gnome.org> | 2016-07-05 17:41:01 +0100 |
---|---|---|
committer | Emmanuele Bassi <ebassi@gnome.org> | 2016-07-05 17:41:01 +0100 |
commit | c4bf786e42360735cb947bf76333df781c8670e7 (patch) | |
tree | e04617076165f134e7f007ffe34e41e77b220454 | |
parent | 4470d7d26949c96599a998b86ba92f07022524d4 (diff) | |
download | gtk+-wip/ebassi/gsk-render-node-pool.tar.gz |
gsk: Use GskRenderer to create render nodeswip/ebassi/gsk-render-node-pool
Instead of letting users create their own GskRenderNode instances we
should cache render nodes inside GskRenderer. As rendering may end up
resulting in thousands or more render nodes per frame, the memory
pressure on the slice allocator may end up degrading our performance.
By having render nodes cached and handed out from a pool we can recycle
instances at every frame.
-rw-r--r-- | gsk/gskrenderer.c | 50 | ||||
-rw-r--r-- | gsk/gskrenderer.h | 3 | ||||
-rw-r--r-- | gsk/gskrendernode.c | 39 | ||||
-rw-r--r-- | gsk/gskrendernode.h | 2 | ||||
-rw-r--r-- | gsk/gskrendernodeprivate.h | 4 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 4 |
6 files changed, 95 insertions, 7 deletions
diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c index f9a9fedccb..f5ea2d9092 100644 --- a/gsk/gskrenderer.c +++ b/gsk/gskrenderer.c @@ -72,6 +72,9 @@ typedef struct int scale_factor; + GPtrArray *render_nodes; + int last_render_node; + gboolean is_realized : 1; gboolean auto_clear : 1; gboolean use_alpha : 1; @@ -867,6 +870,11 @@ gsk_renderer_realize (GskRenderer *renderer) return TRUE; priv->is_realized = GSK_RENDERER_GET_CLASS (renderer)->realize (renderer); + if (priv->is_realized) + { + priv->render_nodes = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref); + priv->last_render_node = 0; + } return priv->is_realized; } @@ -891,6 +899,9 @@ gsk_renderer_unrealize (GskRenderer *renderer) GSK_RENDERER_GET_CLASS (renderer)->unrealize (renderer); + g_clear_pointer (&priv->render_nodes, g_ptr_array_unref); + priv->last_render_node = 0; + priv->is_realized = FALSE; } @@ -930,6 +941,7 @@ gsk_renderer_render (GskRenderer *renderer, g_clear_object (&priv->drawing_context); g_clear_pointer (&priv->root_node, gsk_render_node_unref); + priv->last_render_node = 0; } /** @@ -1081,3 +1093,41 @@ gsk_renderer_get_for_display (GdkDisplay *display) return g_object_new (renderer_type, "display", display, NULL); } + +/** + * gsk_renderer_create_render_node: + * @renderer: a #GskRenderer + * + * Creates a new #GskRenderNode. + * + * Returns: (transfer full): the newly created #GskRenderNode + * + * Since: 3.22 + */ +GskRenderNode * +gsk_renderer_create_render_node (GskRenderer *renderer) +{ + GskRendererPrivate *priv = gsk_renderer_get_instance_private (renderer); + GskRenderNode *res; + + g_return_val_if_fail (GSK_IS_RENDERER (renderer), NULL); + + if (priv->last_render_node < priv->render_nodes->len) + { + int idx = priv->last_render_node; + + priv->last_render_node += 1; + + res = g_ptr_array_index (priv->render_nodes, idx); + gsk_render_node_clear (res); + } + else + { + res = gsk_render_node_new (); + g_ptr_array_add (priv->render_nodes, res); + + priv->last_render_node = priv->render_nodes->len - 1; + } + + return gsk_render_node_ref (res); +} diff --git a/gsk/gskrenderer.h b/gsk/gskrenderer.h index ec1d3aacc2..b8cf446f9e 100644 --- a/gsk/gskrenderer.h +++ b/gsk/gskrenderer.h @@ -101,6 +101,9 @@ void gsk_renderer_render (GskRenderer GskRenderNode *root, GdkDrawingContext *context); +GDK_AVAILABLE_IN_3_22 +GskRenderNode * gsk_renderer_create_render_node (GskRenderer *renderer); + G_END_DECLS #endif /* __GSK_RENDERER_H__ */ diff --git a/gsk/gskrendernode.c b/gsk/gskrendernode.c index 9fe76d64f7..04f2bbdc66 100644 --- a/gsk/gskrendernode.c +++ b/gsk/gskrendernode.c @@ -144,10 +144,15 @@ gsk_render_node_finalize (GskRenderNode *self) { GskRenderNodeIter iter; + /* We need to drop the reference on each child + * before clearing the node + */ gsk_render_node_iter_init (&iter, self); while (gsk_render_node_iter_next (&iter, NULL)) gsk_render_node_iter_remove (&iter); + gsk_render_node_clear (self); + g_type_free_instance ((GTypeInstance *) self); } @@ -231,14 +236,12 @@ gsk_render_node_get_type (void) return gsk_render_node_type__volatile; } -/** +/*< private > * gsk_render_node_new: * * Creates a new #GskRenderNode, to be used with #GskRenderer. * * Returns: (transfer full): the newly created #GskRenderNode - * - * Since: 3.22 */ GskRenderNode * gsk_render_node_new (void) @@ -246,6 +249,36 @@ gsk_render_node_new (void) return (GskRenderNode *) g_type_create_instance (GSK_TYPE_RENDER_NODE); } +void +gsk_render_node_clear (GskRenderNode *self) +{ + graphene_rect_init_from_rect (&self->bounds, graphene_rect_zero ()); + + graphene_matrix_init_identity (&self->transform); + graphene_matrix_init_identity (&self->child_transform); + + self->opacity = 1.0; + + self->is_mutable = TRUE; + self->opaque = FALSE; + self->hidden = FALSE; + self->needs_world_matrix_update = TRUE; + + self->parent = NULL; + self->first_child = NULL; + self->last_child = NULL; + self->prev_sibling = NULL; + self->next_sibling = NULL; + self->n_children = 0; + + self->age = 0; + + g_free (self->name); + self->name = NULL; + + g_clear_pointer (&self->surface, cairo_surface_destroy); +} + /** * gsk_render_node_ref: * @node: a #GskRenderNode diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h index a4709ff453..8cbd243497 100644 --- a/gsk/gskrendernode.h +++ b/gsk/gskrendernode.h @@ -39,8 +39,6 @@ GDK_AVAILABLE_IN_3_22 GType gsk_render_node_get_type (void) G_GNUC_CONST; GDK_AVAILABLE_IN_3_22 -GskRenderNode * gsk_render_node_new (void); -GDK_AVAILABLE_IN_3_22 GskRenderNode * gsk_render_node_ref (GskRenderNode *node); GDK_AVAILABLE_IN_3_22 void gsk_render_node_unref (GskRenderNode *node); diff --git a/gsk/gskrendernodeprivate.h b/gsk/gskrendernodeprivate.h index 9893f962c1..e1b796416f 100644 --- a/gsk/gskrendernodeprivate.h +++ b/gsk/gskrendernodeprivate.h @@ -86,6 +86,10 @@ void gsk_render_node_update_world_matrix (GskRenderNode *node, void gsk_render_node_get_world_matrix (GskRenderNode *node, graphene_matrix_t *mv); +GskRenderNode *gsk_render_node_new (void); + +void gsk_render_node_clear (GskRenderNode *node); + int gsk_render_node_get_size (GskRenderNode *root); G_END_DECLS diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 90e0f2616e..fd3c728718 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -17479,7 +17479,7 @@ gtk_widget_get_render_node (GtkWidget *widget, GskRenderNode *tmp; cairo_t *cr; - tmp = gsk_render_node_new (); + tmp = gsk_renderer_create_render_node (renderer); gsk_render_node_set_bounds (tmp, &bounds); gsk_render_node_set_transform (tmp, &m); cr = gsk_render_node_get_draw_context (tmp); @@ -17501,7 +17501,7 @@ gtk_widget_get_render_node (GtkWidget *widget, gboolean result; cairo_t *cr; - tmp = gsk_render_node_new (); + tmp = gsk_renderer_create_render_node (renderer); gsk_render_node_set_bounds (tmp, &bounds); gsk_render_node_set_transform (tmp, &m); cr = gsk_render_node_get_draw_context (tmp); |