actor: Skip transitions on invisible actors

If an actor has not been painted yet, or it's not going to be painted,
we can ignore transitions queued on it.

By ignoring transitions on actors that have not been painted yet, we can
avoid doing work during the set up phase of the scene graph, as well as
avoiding actors "flying in" from nowhere.

Obviously, we have to take into account potential clones, so we need to
check that the actor is not part of a cloned branch of the scene graph,
as well as checking if the actor has mapped clones.
This commit is contained in:
Emmanuele Bassi 2013-03-07 19:33:59 +00:00
parent 20c0985869
commit 8f032d5952

View File

@ -816,6 +816,7 @@ struct _ClutterActorPrivate
guint needs_compute_expand : 1; guint needs_compute_expand : 1;
guint needs_x_expand : 1; guint needs_x_expand : 1;
guint needs_y_expand : 1; guint needs_y_expand : 1;
guint was_painted : 1;
}; };
enum enum
@ -1487,6 +1488,12 @@ clutter_actor_real_map (ClutterActor *self)
stage = _clutter_actor_get_stage_internal (self); stage = _clutter_actor_get_stage_internal (self);
priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self); priv->pick_id = _clutter_stage_acquire_pick_id (CLUTTER_STAGE (stage), self);
/* reset the was_painted flag here: unmapped actors are not going to
* be painted in any case, and this allows us to catch the case of
* cloned actors.
*/
priv->was_painted = FALSE;
CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'", CLUTTER_NOTE (ACTOR, "Pick id '%d' for actor '%s'",
priv->pick_id, priv->pick_id,
_clutter_actor_get_debug_name (self)); _clutter_actor_get_debug_name (self));
@ -3892,6 +3899,9 @@ clutter_actor_continue_paint (ClutterActor *self)
/* XXX:2.0 - Call the paint() virtual directly */ /* XXX:2.0 - Call the paint() virtual directly */
g_signal_emit (self, actor_signals[PAINT], 0); g_signal_emit (self, actor_signals[PAINT], 0);
/* the actor was painted at least once */
priv->was_painted = TRUE;
} }
else else
{ {
@ -8611,14 +8621,26 @@ _clutter_actor_queue_redraw_full (ClutterActor *self,
return; return;
/* we can ignore unmapped actors, unless they have at least one /* we can ignore unmapped actors, unless they have at least one
* mapped clone, as unmapped actors will simply be left unpainted; * mapped clone or they are inside a cloned branch of the scene
* graph, as unmapped actors will simply be left unpainted.
*
* this allows us to ignore redraws queued on leaf nodes when one * this allows us to ignore redraws queued on leaf nodes when one
* of their parents has been hidden * of their parents has been hidden
*/ */
if (!CLUTTER_ACTOR_IS_MAPPED (self) && if (!CLUTTER_ACTOR_IS_MAPPED (self) &&
!clutter_actor_has_mapped_clones (self) && self->priv->in_cloned_branch == 0 &&
self->priv->in_cloned_branch == 0) !clutter_actor_has_mapped_clones (self))
{
CLUTTER_NOTE (PAINT,
"Skipping queue_redraw('%s'): mapped=%s, "
"mapped_clones=%s, "
"in_cloned_branch=%s\n",
_clutter_actor_get_debug_name (self),
CLUTTER_ACTOR_IS_MAPPED (self) ? "yes" : "no",
clutter_actor_has_mapped_clones (self) ? "yes" : "no",
self->priv->in_cloned_branch != 0 ? "yes" : "no");
return; return;
}
/* given the check above we could end up queueing a redraw on an /* given the check above we could end up queueing a redraw on an
* unmapped actor with mapped clones, so we cannot assume that * unmapped actor with mapped clones, so we cannot assume that
@ -18761,15 +18783,21 @@ _clutter_actor_create_transition (ClutterActor *actor,
goto out; goto out;
} }
/* if the current easing state has a duration of 0, then we don't if (info->cur_state->easing_duration == 0 ||
* bother to create the transition, and we just set the final value !actor->priv->was_painted ||
* directly on the actor; we don't go through the Animatable (!CLUTTER_ACTOR_IS_MAPPED (actor) &&
* interface because we know we got here through an animatable actor->priv->in_cloned_branch == 0 &&
* property. !clutter_actor_has_mapped_clones (actor)))
*/
if (info->cur_state->easing_duration == 0)
{ {
CLUTTER_NOTE (ANIMATION, "Easing duration=0, immediate set for '%s::%s'", /* don't bother creating the transition if one is not necessary
* because the actor doesn't want one, or if the actor is not
* visible: we just set the final value directly on the actor.
*
* we also don't go through the Animatable interface because we
* already know we got here through an animatable property.
*/
CLUTTER_NOTE (ANIMATION, "Easing duration=0 was_painted=%s, immediate set for '%s::%s'",
actor->priv->was_painted ? "yes" : "no",
_clutter_actor_get_debug_name (actor), _clutter_actor_get_debug_name (actor),
pspec->name); pspec->name);