[master clock] Avoid excessive redraws

Currently, the clock source spins a redraw every time there is at
least a timeline running. If the timelines were not advanced in
the previous frame, though, because their interval is larger than
the vblanking interval then this will lead to excessive redraws of
the scenegraph even if nothing has changed.

To avoid this a simple guard should be set by the MasterClock::advance
method in case no timeline was effectively advanced, and checked
before dispatching the stage redraws.
This commit is contained in:
Emmanuele Bassi 2009-06-03 12:02:56 +01:00
parent b6f1322e07
commit 762873e79e
3 changed files with 28 additions and 5 deletions

View File

@ -68,6 +68,11 @@ struct _ClutterMasterClock
* after the last timeline has been completed
*/
guint last_advance : 1;
/* a guard, so that we dispatch the redraws only if
* any timeline did advance
*/
guint has_advanced : 1;
};
struct _ClutterMasterClockClass
@ -208,6 +213,17 @@ clutter_clock_dispatch (GSource *source,
CLUTTER_NOTE (SCHEDULER, "Master clock [tick]");
/* do not force a redraw if no timeline has advanced; this might
* happen if we only have timelines with intervals smaller than
* the vblank interval
*/
if (master_clock->has_advanced)
{
master_clock->has_advanced = FALSE;
return TRUE;
}
stages = clutter_stage_manager_peek_stages (stage_manager);
/* queue a redraw for each stage; this will advance each timeline
@ -438,6 +454,7 @@ void
_clutter_master_clock_advance (ClutterMasterClock *master_clock)
{
GTimeVal cur_tick = { 0, };
gboolean has_advanced;
gulong msecs;
GSList *l;
@ -461,12 +478,13 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock)
g_slist_length (master_clock->timelines),
msecs);
has_advanced = FALSE;
for (l = master_clock->timelines; l != NULL; l = l->next)
{
ClutterTimeline *timeline = l->data;
if (clutter_timeline_is_playing (timeline))
clutter_timeline_advance_delta (timeline, msecs);
has_advanced = clutter_timeline_advance_delta (timeline, msecs);
}
/* store the previous state so that we can use
@ -474,4 +492,5 @@ _clutter_master_clock_advance (ClutterMasterClock *master_clock)
*/
master_clock->msecs_delta = msecs;
master_clock->prev_tick = cur_tick;
master_clock->has_advanced = has_advanced;
}

View File

@ -1381,21 +1381,23 @@ clutter_timeline_get_delta (ClutterTimeline *timeline,
* elapsed since the last redraw operation. The @timeline will use this
* interval to emit the #ClutterTimeline::new-frame signal and eventually
* skip frames.
*
* Return value: %TRUE if the timeline advanced
*/
void
gboolean
clutter_timeline_advance_delta (ClutterTimeline *timeline,
guint msecs)
{
ClutterTimelinePrivate *priv;
g_return_if_fail (CLUTTER_IS_TIMELINE (timeline));
g_return_val_if_fail (CLUTTER_IS_TIMELINE (timeline), FALSE);
priv = timeline->priv;
priv->msecs_delta += msecs;
if (priv->msecs_delta < priv->frame_interval)
return;
return FALSE;
else
{
clutter_timeline_advance_internal (timeline);
@ -1403,6 +1405,8 @@ clutter_timeline_advance_delta (ClutterTimeline *timeline,
/* Keep the remainder of the frame time so that it will be
counted towards the next time if the delta is short */
priv->msecs_delta %= priv->frame_interval;
return TRUE;
}
}

View File

@ -167,7 +167,7 @@ void clutter_timeline_advance_to_marker (ClutterTimeline *timeli
const gchar *marker_name);
/*< private >*/
void clutter_timeline_advance_delta (ClutterTimeline *timeline,
gboolean clutter_timeline_advance_delta (ClutterTimeline *timeline,
guint msecs);
G_END_DECLS