clutter/actor: Add CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE
Which offscreens actor rendering only in cases where it hasn't changed for 2 frames or more. This avoids the performance penalty of offscreening an actor whose content is trying to animate at full frame rate. It will switch automatically. https://gitlab.gnome.org/GNOME/mutter/merge_requests/1069
This commit is contained in:
parent
c5d2fc856a
commit
282b09c17e
@ -3743,7 +3743,13 @@ needs_flatten_effect (ClutterActor *self)
|
||||
CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
|
||||
return FALSE;
|
||||
|
||||
if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS)
|
||||
/* We need to enable the effect immediately even in ON_IDLE because that can
|
||||
* only be implemented efficiently within the effect itself.
|
||||
* If it was implemented here using just priv->is_dirty then we would lose
|
||||
* the ability to animate opacity without repaints.
|
||||
*/
|
||||
if ((priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS) ||
|
||||
(priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE))
|
||||
return TRUE;
|
||||
else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
|
||||
{
|
||||
@ -4201,6 +4207,11 @@ clutter_actor_continue_paint (ClutterActor *self,
|
||||
run_flags |= CLUTTER_EFFECT_PAINT_ACTOR_DIRTY;
|
||||
}
|
||||
|
||||
if (priv->current_effect == priv->flatten_effect &&
|
||||
priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE &&
|
||||
run_flags & CLUTTER_EFFECT_PAINT_ACTOR_DIRTY)
|
||||
run_flags |= CLUTTER_EFFECT_PAINT_BYPASS_EFFECT;
|
||||
|
||||
_clutter_effect_paint (priv->current_effect, paint_context, run_flags);
|
||||
|
||||
priv->current_effect = old_current_effect;
|
||||
|
@ -538,6 +538,10 @@ typedef enum /*< prefix=CLUTTER_ACTOR >*/
|
||||
* virtual returns %TRUE.
|
||||
* @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS: Always redirect the actor to an
|
||||
* offscreen buffer even if it is fully opaque.
|
||||
* @CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE: Only redirect the actor if it is the
|
||||
* most efficient thing to do based on its recent repaint behaviour. That
|
||||
* means when its contents are changing less frequently than it's being used
|
||||
* on stage.
|
||||
*
|
||||
* Possible flags to pass to clutter_actor_set_offscreen_redirect().
|
||||
*
|
||||
@ -545,8 +549,9 @@ typedef enum /*< prefix=CLUTTER_ACTOR >*/
|
||||
*/
|
||||
typedef enum /*< prefix=CLUTTER_OFFSCREEN_REDIRECT >*/
|
||||
{
|
||||
CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY = 1<<0,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS = 1<<1
|
||||
CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY = 1 << 0,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS = 1 << 1,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE = 1 << 2
|
||||
} ClutterOffscreenRedirect;
|
||||
|
||||
/**
|
||||
@ -673,12 +678,15 @@ typedef enum /*< prefix=CLUTTER_BIND >*/
|
||||
* has queued a redraw before this paint. This implies that the effect
|
||||
* should call clutter_actor_continue_paint() to chain to the next
|
||||
* effect and can not cache any results from a previous paint.
|
||||
* @CLUTTER_EFFECT_PAINT_BYPASS_EFFECT: The effect should not be used
|
||||
* on this frame, but it will be asked to paint the actor still.
|
||||
*
|
||||
* Flags passed to the ‘paint’ or ‘pick’ method of #ClutterEffect.
|
||||
*/
|
||||
typedef enum /*< prefix=CLUTTER_EFFECT_PAINT >*/
|
||||
{
|
||||
CLUTTER_EFFECT_PAINT_ACTOR_DIRTY = (1 << 0)
|
||||
CLUTTER_EFFECT_PAINT_ACTOR_DIRTY = (1 << 0),
|
||||
CLUTTER_EFFECT_PAINT_BYPASS_EFFECT = (1 << 1)
|
||||
} ClutterEffectPaintFlags;
|
||||
|
||||
/**
|
||||
|
@ -469,6 +469,13 @@ clutter_offscreen_effect_paint (ClutterEffect *effect,
|
||||
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
|
||||
ClutterOffscreenEffectPrivate *priv = self->priv;
|
||||
|
||||
if (flags & CLUTTER_EFFECT_PAINT_BYPASS_EFFECT)
|
||||
{
|
||||
clutter_actor_continue_paint (priv->actor, paint_context);
|
||||
cogl_clear_object (&priv->offscreen);
|
||||
return;
|
||||
}
|
||||
|
||||
/* If we've already got a cached image and the actor hasn't been redrawn
|
||||
* then we can just use the cached image in the FBO.
|
||||
*/
|
||||
|
@ -193,6 +193,9 @@ verify_redraws (gpointer user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
|
||||
clutter_actor_set_offscreen_redirect (data->container,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS);
|
||||
|
||||
/* Queueing a redraw on the actor should cause a redraw */
|
||||
clutter_actor_queue_redraw (data->container);
|
||||
verify_redraw (data, 1);
|
||||
@ -220,6 +223,7 @@ static gboolean
|
||||
run_verify (gpointer user_data)
|
||||
{
|
||||
Data *data = user_data;
|
||||
int i;
|
||||
|
||||
group_has_overlaps = FALSE;
|
||||
|
||||
@ -313,6 +317,90 @@ run_verify (gpointer user_data)
|
||||
0,
|
||||
255);
|
||||
|
||||
/* ON_IDLE: Defer redirection through the FBO until it is deemed to be the
|
||||
* best performing option, which means when the actor's contents have
|
||||
* stopped changing.
|
||||
*/
|
||||
clutter_actor_set_offscreen_redirect (data->container,
|
||||
CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE);
|
||||
|
||||
/* Changing modes should not incur a redraw */
|
||||
verify_results (data,
|
||||
255, 0, 0,
|
||||
0,
|
||||
255);
|
||||
|
||||
/* These will incur a redraw because the actor is dirty: */
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
clutter_actor_queue_redraw (data->container);
|
||||
verify_results (data,
|
||||
255, 0, 0,
|
||||
1,
|
||||
255);
|
||||
}
|
||||
|
||||
/* The actor is not dirty, but also not yet cached so a redraw is expected */
|
||||
verify_results (data,
|
||||
255, 0, 0,
|
||||
1,
|
||||
255);
|
||||
|
||||
/* These will NOT incur a redraw because the actor is unchanged: */
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
verify_results (data,
|
||||
255, 0, 0,
|
||||
0,
|
||||
255);
|
||||
}
|
||||
|
||||
/* The first opacity change should require no redaw */
|
||||
clutter_actor_set_opacity (data->container, 64);
|
||||
verify_results (data,
|
||||
255, 191, 191,
|
||||
0,
|
||||
255);
|
||||
|
||||
/* The second opacity change should require no redaw */
|
||||
clutter_actor_set_opacity (data->container, 127);
|
||||
verify_results (data,
|
||||
255, 127, 127,
|
||||
0,
|
||||
255);
|
||||
|
||||
/* The third opacity change should require no redaw */
|
||||
clutter_actor_set_opacity (data->container, 255);
|
||||
verify_results (data,
|
||||
255, 0, 0,
|
||||
0,
|
||||
255);
|
||||
|
||||
/* Now several frames without the actor changing AND the FBO is populated.
|
||||
* Expect no internal repaints.
|
||||
*/
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
verify_results (data,
|
||||
255, 0, 0,
|
||||
0,
|
||||
255);
|
||||
}
|
||||
|
||||
/* Another opacity change, no redraw expected */
|
||||
clutter_actor_set_opacity (data->container, 127);
|
||||
verify_results (data,
|
||||
255, 127, 127,
|
||||
0,
|
||||
255);
|
||||
|
||||
/* Finally the actor's content changes so a redraw is expected */
|
||||
clutter_actor_queue_redraw (data->container);
|
||||
verify_results (data,
|
||||
255, 127, 127,
|
||||
1,
|
||||
127);
|
||||
|
||||
/* Check redraws */
|
||||
g_idle_add (verify_redraws, data);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user