mirror of
https://github.com/brl/mutter.git
synced 2024-12-23 11:32:04 +00:00
clutter/actor: Emit the queue-redraw signal right away
Since we now decoupled the "queue-redraw" signal from creating the stage clip, we can move signal emission into _clutter_actor_queue_redraw_full() and emit the signal right away when queueing a redraw on an actor. With that we now no longer have to accommodate for the stage pending_queue_redraws list changing while iterating over it. To ensure we don't emit the signal too often when multiple redraws are queued on one actor, use the propagated_one_redraw flag to limit the number of emissions to a single one for every update cycle. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1511>
This commit is contained in:
parent
9b16eff784
commit
ce4c297cea
@ -8023,8 +8023,6 @@ _clutter_actor_finish_queue_redraw (ClutterActor *self)
|
||||
later)
|
||||
*/
|
||||
priv->queue_redraw_entry = NULL;
|
||||
|
||||
_clutter_actor_propagate_queue_redraw (self, self);
|
||||
}
|
||||
|
||||
void
|
||||
@ -8041,63 +8039,26 @@ _clutter_actor_queue_redraw_full (ClutterActor *self,
|
||||
* wrapper for this function. Additionally, an effect can queue a
|
||||
* redraw by wrapping this function in clutter_effect_queue_repaint().
|
||||
*
|
||||
* This function will emit the "queue-redraw" signal for each actor
|
||||
* up the actor-tree, allowing to track redraws queued by children
|
||||
* or to queue a redraw of a different actor (like a clone) in
|
||||
* response to this one.
|
||||
*
|
||||
* This functions queues an entry in a list associated with the
|
||||
* stage which is a list of actors that queued a redraw while
|
||||
* updating the timelines, performing layouting and processing other
|
||||
* mainloop sources before the next paint starts.
|
||||
*
|
||||
* We aim to minimize the processing done at this point because
|
||||
* there is a good chance other events will happen while updating
|
||||
* the scenegraph that would invalidate any expensive work we might
|
||||
* otherwise try to do here. For example we don't try and resolve
|
||||
* the screen space bounding box of an actor at this stage so as to
|
||||
* minimize how much of the screen redraw because it's possible
|
||||
* something else will happen which will force a full redraw anyway.
|
||||
*
|
||||
* When all updates are complete and we come to paint the stage then
|
||||
* we iterate this list and actually emit the "queue-redraw" signals
|
||||
* for each of the listed actors which will bubble up to the stage
|
||||
* for each actor and at that point we will transform the actors
|
||||
* paint volume into screen coordinates to determine the clip region
|
||||
* for what needs to be redrawn in the next paint.
|
||||
* we iterate this list and build the redraw clip of the stage by
|
||||
* either using the clip that was supplied to
|
||||
* _clutter_actor_queue_redraw_full() or by asking the actor for its
|
||||
* redraw clip using clutter_actor_get_redraw_clip().
|
||||
*
|
||||
* Besides minimizing redundant work another reason for this
|
||||
* deferred design is that it's more likely we will be able to
|
||||
* determine the paint volume of an actor once we've finished
|
||||
* updating the scenegraph because its allocation should be up to
|
||||
* date. NB: If we can't determine an actors paint volume then we
|
||||
* can't automatically queue a clipped redraw which can make a big
|
||||
* difference to performance.
|
||||
*
|
||||
* So the control flow goes like this:
|
||||
* One of clutter_actor_queue_redraw(),
|
||||
* or clutter_effect_queue_repaint()
|
||||
*
|
||||
* then control moves to:
|
||||
* _clutter_stage_queue_actor_redraw()
|
||||
*
|
||||
* later during _clutter_stage_do_update(), once relayouting is done
|
||||
* and the scenegraph has been updated we will call:
|
||||
* clutter_stage_maybe_finish_queue_redraws().
|
||||
*
|
||||
* clutter_stage_maybe_finish_queue_redraws() will call
|
||||
* _clutter_actor_finish_queue_redraw() for each listed actor.
|
||||
*
|
||||
* Note: actors *are* allowed to queue further redraws during this
|
||||
* process (considering clone actors or texture_new_from_actor which
|
||||
* respond to their source queueing a redraw by queuing a redraw
|
||||
* themselves). We repeat the process until the list is empty.
|
||||
*
|
||||
* This will result in the "queue-redraw" signal being fired for
|
||||
* each actor which will pass control to the default signal handler:
|
||||
* clutter_actor_real_queue_redraw()
|
||||
*
|
||||
* This will bubble up to the stages handler:
|
||||
* clutter_stage_real_queue_redraw()
|
||||
*
|
||||
* clutter_stage_real_queue_redraw() will transform the actors paint
|
||||
* volume into screen space and add it as a clip region for the next
|
||||
* paint.
|
||||
* Doing this later during the stage update instead of now is an
|
||||
* important optimization, because later it's more likely we will be
|
||||
* able to determine the paint volume of an actor (its allocation
|
||||
* should be up to date).
|
||||
*/
|
||||
|
||||
/* ignore queueing a redraw for actors being destroyed */
|
||||
@ -8179,6 +8140,9 @@ _clutter_actor_queue_redraw_full (ClutterActor *self,
|
||||
}
|
||||
|
||||
priv->is_dirty = TRUE;
|
||||
|
||||
if (!priv->propagated_one_redraw)
|
||||
_clutter_actor_propagate_queue_redraw (self, self);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2882,6 +2882,7 @@ void
|
||||
clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage)
|
||||
{
|
||||
ClutterStagePrivate *priv = stage->priv;
|
||||
GList *l;
|
||||
|
||||
COGL_TRACE_BEGIN_SCOPED (ClutterStageFinishQueueRedraws, "FinishQueueRedraws");
|
||||
|
||||
@ -2890,68 +2891,50 @@ clutter_stage_maybe_finish_queue_redraws (ClutterStage *stage)
|
||||
|
||||
priv->pending_finish_queue_redraws = FALSE;
|
||||
|
||||
/* Note: we have to repeat until the pending_queue_redraws list is
|
||||
* empty because actors are allowed to queue redraws in response to
|
||||
* the queue-redraw signal. For example Clone actors or
|
||||
* texture_new_from_actor actors will have to queue a redraw if
|
||||
* their source queues a redraw.
|
||||
*/
|
||||
while (stage->priv->pending_queue_redraws)
|
||||
for (l = priv->pending_queue_redraws; l; l = l->next)
|
||||
{
|
||||
GList *l;
|
||||
/* XXX: we need to allow stage->priv->pending_queue_redraws to
|
||||
* be updated while we process the current entries in the list
|
||||
* so we steal the list pointer and then reset it to an empty
|
||||
* list before processing... */
|
||||
GList *stolen_list = stage->priv->pending_queue_redraws;
|
||||
stage->priv->pending_queue_redraws = NULL;
|
||||
ClutterStageQueueRedrawEntry *entry = l->data;
|
||||
|
||||
for (l = stolen_list; l; l = l->next)
|
||||
/* NB: Entries may be invalidated if the actor gets destroyed */
|
||||
if (G_LIKELY (entry->actor != NULL))
|
||||
{
|
||||
ClutterStageQueueRedrawEntry *entry = l->data;
|
||||
ClutterPaintVolume old_actor_pv, new_actor_pv;
|
||||
|
||||
/* NB: Entries may be invalidated if the actor gets destroyed */
|
||||
if (G_LIKELY (entry->actor != NULL))
|
||||
_clutter_paint_volume_init_static (&old_actor_pv, NULL);
|
||||
_clutter_paint_volume_init_static (&new_actor_pv, NULL);
|
||||
|
||||
if (entry->has_clip)
|
||||
{
|
||||
ClutterPaintVolume old_actor_pv, new_actor_pv;
|
||||
|
||||
_clutter_actor_finish_queue_redraw (entry->actor);
|
||||
|
||||
_clutter_paint_volume_init_static (&old_actor_pv, NULL);
|
||||
_clutter_paint_volume_init_static (&new_actor_pv, NULL);
|
||||
|
||||
if (entry->has_clip)
|
||||
{
|
||||
add_to_stage_clip (stage, &entry->clip);
|
||||
}
|
||||
else if (clutter_actor_get_redraw_clip (entry->actor,
|
||||
&old_actor_pv,
|
||||
&new_actor_pv))
|
||||
{
|
||||
/* Add both the old paint volume of the actor (which is
|
||||
* currently visible on the screen) and the new paint volume
|
||||
* (which will be visible on the screen after this redraw)
|
||||
* to the redraw clip.
|
||||
* The former we do to ensure the old texture on the screen
|
||||
* will be fully painted over in case the actor was moved.
|
||||
*/
|
||||
add_to_stage_clip (stage, &old_actor_pv);
|
||||
add_to_stage_clip (stage, &new_actor_pv);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If there's no clip we can use, we have to trigger an
|
||||
* unclipped full stage redraw.
|
||||
*/
|
||||
add_to_stage_clip (stage, NULL);
|
||||
}
|
||||
|
||||
add_to_stage_clip (stage, &entry->clip);
|
||||
}
|
||||
else if (clutter_actor_get_redraw_clip (entry->actor,
|
||||
&old_actor_pv,
|
||||
&new_actor_pv))
|
||||
{
|
||||
/* Add both the old paint volume of the actor (which is
|
||||
* currently visible on the screen) and the new paint volume
|
||||
* (which will be visible on the screen after this redraw)
|
||||
* to the redraw clip.
|
||||
* The former we do to ensure the old texture on the screen
|
||||
* will be fully painted over in case the actor was moved.
|
||||
*/
|
||||
add_to_stage_clip (stage, &old_actor_pv);
|
||||
add_to_stage_clip (stage, &new_actor_pv);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If there's no clip we can use, we have to trigger an
|
||||
* unclipped full stage redraw.
|
||||
*/
|
||||
add_to_stage_clip (stage, NULL);
|
||||
}
|
||||
|
||||
free_queue_redraw_entry (entry);
|
||||
}
|
||||
g_list_free (stolen_list);
|
||||
|
||||
free_queue_redraw_entry (entry);
|
||||
}
|
||||
|
||||
g_list_free (priv->pending_queue_redraws);
|
||||
priv->pending_queue_redraws = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user