From 4579e86330282101abc10ce6b97fe0437229a5f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Dre=C3=9Fler?= Date: Mon, 17 Oct 2022 18:22:30 +0200 Subject: [PATCH] clutter/actor: Avoid always traversing actor tree on finish_layout With commit 5a565b42586abb0c851888b827ffabc0cce38b75, we changed clutter_actor_finish_layout() to be not only about updating stage views, but also take care of updating the visible_paint_volume, for that we started doing a full tree traversal of all mapped actors. This can be quite a performance issue, apparently especially on certain ARM devices, where the simple tree traversal can take as long as 2ms. This is precious time we need to paint our next frame, so lets do a bit more work to avoid those useless traversals. Fixes https://gitlab.gnome.org/GNOME/mutter/-/issues/2459 Part-of: --- clutter/clutter/clutter-actor.c | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 4908c425c..331c61cad 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -850,6 +850,7 @@ struct _ClutterActorPrivate guint needs_update_stage_views : 1; guint clear_stage_views_needs_stage_views_changed : 1; guint needs_redraw : 1; + guint needs_finish_layout : 1; }; enum @@ -1511,6 +1512,7 @@ queue_update_paint_volume (ClutterActor *actor) { actor->priv->needs_paint_volume_update = TRUE; actor->priv->needs_visible_paint_volume_update = TRUE; + actor->priv->needs_finish_layout = TRUE; actor = actor->priv->parent; } } @@ -1530,6 +1532,19 @@ clutter_actor_real_map (ClutterActor *self) if (priv->unmapped_paint_branch_counter == 0) { + /* Invariant that needs_finish_layout is set all the way up to the stage + * needs to be met. + */ + if (priv->needs_finish_layout) + { + iter = priv->parent; + while (iter && !iter->priv->needs_finish_layout) + { + iter->priv->needs_finish_layout = TRUE; + iter = iter->priv->parent; + } + } + /* Avoid the early return in clutter_actor_queue_relayout() */ priv->needs_width_request = FALSE; priv->needs_height_request = FALSE; @@ -2479,6 +2494,11 @@ absolute_geometry_changed (ClutterActor *actor) { actor->priv->needs_update_stage_views = TRUE; actor->priv->needs_visible_paint_volume_update = TRUE; + + actor->priv->needs_finish_layout = TRUE; + /* needs_finish_layout is already TRUE on the whole parent tree thanks + * to queue_update_paint_volume() that was called by transform_changed(). + */ } static ClutterActorTraverseVisitFlags @@ -7566,6 +7586,7 @@ clutter_actor_init (ClutterActor *self) priv->needs_paint_volume_update = TRUE; priv->needs_visible_paint_volume_update = TRUE; priv->needs_update_stage_views = TRUE; + priv->needs_finish_layout = TRUE; priv->cached_width_age = 1; priv->cached_height_age = 1; @@ -7700,9 +7721,17 @@ _clutter_actor_queue_redraw_full (ClutterActor *self, { if (!priv->needs_redraw) { + ClutterActor *iter = self; + priv->needs_redraw = TRUE; clutter_stage_schedule_update (CLUTTER_STAGE (stage)); + + while (iter && !iter->priv->needs_finish_layout) + { + iter->priv->needs_finish_layout = TRUE; + iter = iter->priv->parent; + } } if (volume) @@ -15230,6 +15259,7 @@ clear_stage_views_cb (ClutterActor *actor, _clutter_actor_stop_transitions (actor); actor->priv->needs_update_stage_views = TRUE; + actor->priv->needs_finish_layout = TRUE; old_stage_views = g_steal_pointer (&actor->priv->stage_views); @@ -15506,6 +15536,9 @@ clutter_actor_finish_layout (ClutterActor *self, gboolean old_visible_paint_volume_valid = FALSE; ClutterPaintVolume old_visible_paint_volume; + if (!priv->needs_finish_layout) + return; + if ((!CLUTTER_ACTOR_IS_MAPPED (self) && !clutter_actor_has_mapped_clones (self)) || CLUTTER_ACTOR_IN_DESTRUCTION (self)) @@ -15547,6 +15580,8 @@ clutter_actor_finish_layout (ClutterActor *self, priv->needs_redraw = FALSE; } + priv->needs_finish_layout = FALSE; + for (child = priv->first_child; child; child = child->priv->next_sibling) clutter_actor_finish_layout (child, use_max_scale); }