[master-clock] Throttle if no redraw was performed

A flag in the master clock is now set whenever the dispatch caused an
actual redraw of a stage. If this flag is not set during the prepare
and check functions then it will resort to limiting the redraw
attempts to the default frame rate as if vblank syncing was
disabled. Otherwise if a timeline is running that does not cause the
scene to change then it would busy-wait with 100% CPU until the next
frame.

This fix was suggested by Owen Taylor in:

  http://bugzilla.openedhand.com/show_bug.cgi?id=1637

Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
This commit is contained in:
Neil Roberts 2009-06-10 15:50:27 +01:00 committed by Emmanuele Bassi
parent 7c08f554bc
commit acf7722a41
3 changed files with 18 additions and 7 deletions

View File

@ -66,6 +66,8 @@ struct _ClutterMasterClock
* a redraw on the stage and drive the animations * a redraw on the stage and drive the animations
*/ */
GSource *source; GSource *source;
guint updated_stages : 1;
}; };
struct _ClutterMasterClockClass struct _ClutterMasterClockClass
@ -144,7 +146,8 @@ master_clock_next_frame_delay (ClutterMasterClock *master_clock)
if (!master_clock_is_running (master_clock)) if (!master_clock_is_running (master_clock))
return -1; return -1;
if (clutter_feature_available (CLUTTER_FEATURE_SYNC_TO_VBLANK)) if (clutter_feature_available (CLUTTER_FEATURE_SYNC_TO_VBLANK) &&
master_clock->updated_stages)
{ {
/* When we have sync-to-vblank, we count on that to throttle /* When we have sync-to-vblank, we count on that to throttle
* our frame rate, and otherwise draw frames as fast as possible. * our frame rate, and otherwise draw frames as fast as possible.
@ -250,6 +253,8 @@ clutter_clock_dispatch (GSource *source,
stages = clutter_stage_manager_list_stages (stage_manager); stages = clutter_stage_manager_list_stages (stage_manager);
g_slist_foreach (stages, (GFunc)g_object_ref, NULL); g_slist_foreach (stages, (GFunc)g_object_ref, NULL);
master_clock->updated_stages = FALSE;
/* Process queued events /* Process queued events
*/ */
for (l = stages; l != NULL; l = l->next) for (l = stages; l != NULL; l = l->next)
@ -262,7 +267,7 @@ clutter_clock_dispatch (GSource *source,
* is advanced. * is advanced.
*/ */
for (l = stages; l != NULL; l = l->next) for (l = stages; l != NULL; l = l->next)
_clutter_stage_do_update (l->data); master_clock->updated_stages |= _clutter_stage_do_update (l->data);
g_slist_foreach (stages, (GFunc)g_object_unref, NULL); g_slist_foreach (stages, (GFunc)g_object_unref, NULL);
g_slist_free (stages); g_slist_free (stages);
@ -298,6 +303,8 @@ clutter_master_clock_init (ClutterMasterClock *self)
source = clutter_clock_source_new (self); source = clutter_clock_source_new (self);
self->source = source; self->source = source;
self->updated_stages = TRUE;
g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW); g_source_set_priority (source, CLUTTER_PRIORITY_REDRAW);
g_source_set_can_recurse (source, FALSE); g_source_set_can_recurse (source, FALSE);
g_source_attach (source, NULL); g_source_attach (source, NULL);

View File

@ -174,7 +174,7 @@ ClutterStageWindow *_clutter_stage_get_default_window (void);
void _clutter_stage_maybe_setup_viewport (ClutterStage *stage); void _clutter_stage_maybe_setup_viewport (ClutterStage *stage);
void _clutter_stage_maybe_relayout (ClutterActor *stage); void _clutter_stage_maybe_relayout (ClutterActor *stage);
gboolean _clutter_stage_needs_update (ClutterStage *stage); gboolean _clutter_stage_needs_update (ClutterStage *stage);
void _clutter_stage_do_update (ClutterStage *stage); gboolean _clutter_stage_do_update (ClutterStage *stage);
void _clutter_stage_queue_event (ClutterStage *stage, void _clutter_stage_queue_event (ClutterStage *stage,
ClutterEvent *event); ClutterEvent *event);

View File

@ -486,7 +486,7 @@ _clutter_stage_process_queued_events (ClutterStage *stage)
* *
* Determines if _clutter_stage_do_update() needs to be called. * Determines if _clutter_stage_do_update() needs to be called.
* *
* Return value: %TRUE if the stages need layout or painting * Return value: %TRUE if the stage need layout or painting
*/ */
gboolean gboolean
_clutter_stage_needs_update (ClutterStage *stage) _clutter_stage_needs_update (ClutterStage *stage)
@ -505,18 +505,20 @@ _clutter_stage_needs_update (ClutterStage *stage)
* @stage: A #ClutterStage * @stage: A #ClutterStage
* *
* Handles per-frame layout and repaint for the stage. * Handles per-frame layout and repaint for the stage.
*
* Return value: %TRUE if the stage was updated
*/ */
void gboolean
_clutter_stage_do_update (ClutterStage *stage) _clutter_stage_do_update (ClutterStage *stage)
{ {
ClutterStagePrivate *priv; ClutterStagePrivate *priv;
g_return_if_fail (CLUTTER_IS_STAGE (stage)); g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
priv = stage->priv; priv = stage->priv;
if (!priv->redraw_pending) if (!priv->redraw_pending)
return; return FALSE;
/* clutter_do_redraw() will also call maybe_relayout(), but since a relayout /* clutter_do_redraw() will also call maybe_relayout(), but since a relayout
* can queue a redraw, we want to do the relayout before we clear the * can queue a redraw, we want to do the relayout before we clear the
@ -539,6 +541,8 @@ _clutter_stage_do_update (ClutterStage *stage)
CLUTTER_CONTEXT ()->redraw_count = 0; CLUTTER_CONTEXT ()->redraw_count = 0;
} }
return TRUE;
} }
static void static void