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))
|
CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT))
|
||||||
return FALSE;
|
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;
|
return TRUE;
|
||||||
else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY)
|
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;
|
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);
|
_clutter_effect_paint (priv->current_effect, paint_context, run_flags);
|
||||||
|
|
||||||
priv->current_effect = old_current_effect;
|
priv->current_effect = old_current_effect;
|
||||||
|
@ -538,6 +538,10 @@ typedef enum /*< prefix=CLUTTER_ACTOR >*/
|
|||||||
* virtual returns %TRUE.
|
* virtual returns %TRUE.
|
||||||
* @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS: Always redirect the actor to an
|
* @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS: Always redirect the actor to an
|
||||||
* offscreen buffer even if it is fully opaque.
|
* 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().
|
* 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 >*/
|
typedef enum /*< prefix=CLUTTER_OFFSCREEN_REDIRECT >*/
|
||||||
{
|
{
|
||||||
CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY = 1<<0,
|
CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY = 1 << 0,
|
||||||
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS = 1<<1
|
CLUTTER_OFFSCREEN_REDIRECT_ALWAYS = 1 << 1,
|
||||||
|
CLUTTER_OFFSCREEN_REDIRECT_ON_IDLE = 1 << 2
|
||||||
} ClutterOffscreenRedirect;
|
} ClutterOffscreenRedirect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -673,12 +678,15 @@ typedef enum /*< prefix=CLUTTER_BIND >*/
|
|||||||
* has queued a redraw before this paint. This implies that the effect
|
* has queued a redraw before this paint. This implies that the effect
|
||||||
* should call clutter_actor_continue_paint() to chain to the next
|
* should call clutter_actor_continue_paint() to chain to the next
|
||||||
* effect and can not cache any results from a previous paint.
|
* 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.
|
* Flags passed to the ‘paint’ or ‘pick’ method of #ClutterEffect.
|
||||||
*/
|
*/
|
||||||
typedef enum /*< prefix=CLUTTER_EFFECT_PAINT >*/
|
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;
|
} ClutterEffectPaintFlags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -469,6 +469,13 @@ clutter_offscreen_effect_paint (ClutterEffect *effect,
|
|||||||
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
|
ClutterOffscreenEffect *self = CLUTTER_OFFSCREEN_EFFECT (effect);
|
||||||
ClutterOffscreenEffectPrivate *priv = self->priv;
|
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
|
/* 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.
|
* then we can just use the cached image in the FBO.
|
||||||
*/
|
*/
|
||||||
|
@ -193,6 +193,9 @@ verify_redraws (gpointer user_data)
|
|||||||
{
|
{
|
||||||
Data *data = 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 */
|
/* Queueing a redraw on the actor should cause a redraw */
|
||||||
clutter_actor_queue_redraw (data->container);
|
clutter_actor_queue_redraw (data->container);
|
||||||
verify_redraw (data, 1);
|
verify_redraw (data, 1);
|
||||||
@ -220,6 +223,7 @@ static gboolean
|
|||||||
run_verify (gpointer user_data)
|
run_verify (gpointer user_data)
|
||||||
{
|
{
|
||||||
Data *data = user_data;
|
Data *data = user_data;
|
||||||
|
int i;
|
||||||
|
|
||||||
group_has_overlaps = FALSE;
|
group_has_overlaps = FALSE;
|
||||||
|
|
||||||
@ -313,6 +317,90 @@ run_verify (gpointer user_data)
|
|||||||
0,
|
0,
|
||||||
255);
|
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 */
|
/* Check redraws */
|
||||||
g_idle_add (verify_redraws, data);
|
g_idle_add (verify_redraws, data);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user