Remove stage update idle and do updates from the master clock

When a redraw is queued on a stage, simply set a flag; then in
the check/prepare functions of the master clock source, check
for stages that need redrawing.

This avoids the complexity of having multiple competing sources
at the same priority and makes the update ordering more reliable and
understandable.

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

Signed-off-by: Emmanuele Bassi <ebassi@linux.intel.com>
This commit is contained in:
Owen W. Taylor 2009-06-06 18:22:51 -04:00 committed by Emmanuele Bassi
parent 77cd4e2bc8
commit 89a8fd7755
3 changed files with 63 additions and 48 deletions

View File

@ -95,16 +95,17 @@ static GSourceFuncs clock_funcs = {
G_DEFINE_TYPE (ClutterMasterClock, clutter_master_clock, G_TYPE_OBJECT);
/*
* has_running_timeline:
* master_clock_is_running:
* @master_clock: a #ClutterMasterClock
*
* Checks if @master_clock has any running timeline.
* Checks if we should currently be advancing timelines or redrawing
* stages.
*
* Return value: %TRUE if the #ClutterMasterClock has at least
* one running timeline
*/
static gboolean
has_running_timeline (ClutterMasterClock *master_clock)
master_clock_is_running (ClutterMasterClock *master_clock)
{
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
@ -112,6 +113,11 @@ has_running_timeline (ClutterMasterClock *master_clock)
if (master_clock->timelines)
return TRUE;
stages = clutter_stage_manager_peek_stages (stage_manager);
for (l = stages; l; l = l->next)
if (_clutter_stage_needs_update (l->data))
return TRUE;
return FALSE;
}
@ -148,7 +154,7 @@ clutter_clock_prepare (GSource *source,
/* just like an idle source, we are ready if nothing else is */
*timeout = -1;
retval = has_running_timeline (master_clock);
retval = master_clock_is_running (master_clock);
return retval;
}
@ -160,7 +166,7 @@ clutter_clock_check (GSource *source)
ClutterMasterClock *master_clock = clock_source->master_clock;
gboolean retval;
retval = has_running_timeline (master_clock);
retval = master_clock_is_running (master_clock);
return retval;
}
@ -170,6 +176,8 @@ clutter_clock_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
ClutterClockSource *clock_source = (ClutterClockSource *) source;
ClutterMasterClock *master_clock = clock_source->master_clock;
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
const GSList *stages, *l;
@ -177,12 +185,13 @@ clutter_clock_dispatch (GSource *source,
stages = clutter_stage_manager_peek_stages (stage_manager);
/* queue a redraw for each stage; this will advance each timeline
* held by the master clock of the amount of milliseconds elapsed
* since the last redraw
_clutter_master_clock_advance (master_clock);
/* Update any stage that needs redraw/relayout after the clock
* is advanced.
*/
for (l = stages; l != NULL; l = l->next)
clutter_actor_queue_redraw (l->data);
_clutter_stage_do_update (l->data);
return TRUE;
}

View File

@ -175,6 +175,8 @@ ClutterStageWindow *_clutter_stage_get_window (ClutterStage *sta
ClutterStageWindow *_clutter_stage_get_default_window (void);
void _clutter_stage_maybe_setup_viewport (ClutterStage *stage);
void _clutter_stage_maybe_relayout (ClutterActor *stage);
gboolean _clutter_stage_needs_update (ClutterStage *stage);
void _clutter_stage_do_update (ClutterStage *stage);
/* vfuncs implemented by backend */
GType _clutter_backend_impl_get_type (void);

View File

@ -87,8 +87,7 @@ struct _ClutterStagePrivate
gchar *title;
ClutterActor *key_focused_actor;
guint update_idle; /* repaint idler id */
guint redraw_pending : 1;
guint is_fullscreen : 1;
guint is_offscreen : 1;
guint is_cursor_visible : 1;
@ -390,29 +389,43 @@ clutter_stage_real_fullscreen (ClutterStage *stage)
CLUTTER_ALLOCATION_NONE);
}
static gboolean
redraw_update_idle (gpointer user_data)
/**
* _clutter_stage_needs_update:
* @stage: A #ClutterStage
*
* Determines if _clutter_stage_do_update() needs to be called.
*
* Return value: %TRUE if the stages need layout or painting
*/
gboolean
_clutter_stage_needs_update (ClutterStage *stage)
{
ClutterStage *stage = user_data;
ClutterStagePrivate *priv = stage->priv;
ClutterMasterClock *master_clock;
ClutterStagePrivate *priv;
/* before we redraw we advance the master clock of one tick; this means
* that all the timelines that need advancing will be advanced by one
* frame. this will cause multiple redraw requests, so we do this before
* we ask for a relayout and before we do the actual redraw. this ensures
* that we paint the most updated scenegraph state and that all animations
* are in sync with the paint process.
*/
CLUTTER_NOTE (PAINT, "Avdancing master clock");
master_clock = _clutter_master_clock_get_default ();
_clutter_master_clock_advance (master_clock);
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
/* run the (eventual) repaint functions; since those might end up queuing
* a relayout or a redraw we need to execute them before maybe_relayout()
*/
CLUTTER_NOTE (PAINT, "Repaint functions");
_clutter_run_repaint_functions ();
priv = stage->priv;
return priv->redraw_pending;
}
/**
* _clutter_stage_do_update:
* @stage: A #ClutterStage
*
* Handles per-frame layout and repaint for the stage.
*/
void
_clutter_stage_do_update (ClutterStage *stage)
{
ClutterStagePrivate *priv;
g_return_if_fail (CLUTTER_IS_STAGE (stage));
priv = stage->priv;
if (!priv->redraw_pending)
return;
/* 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
@ -422,12 +435,11 @@ redraw_update_idle (gpointer user_data)
*/
_clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
/* redrawing will advance the master clock */
CLUTTER_NOTE (PAINT, "redrawing via idle for stage[%p]", stage);
_clutter_do_redraw (stage);
/* reset the guard, so that new redraws are possible */
priv->update_idle = 0;
priv->redraw_pending = FALSE;
if (CLUTTER_CONTEXT ()->redraw_count > 0)
{
@ -436,8 +448,6 @@ redraw_update_idle (gpointer user_data)
CLUTTER_CONTEXT ()->redraw_count = 0;
}
return FALSE;
}
static void
@ -450,15 +460,15 @@ clutter_stage_real_queue_redraw (ClutterActor *actor,
CLUTTER_NOTE (PAINT, "Redraw request number %lu",
CLUTTER_CONTEXT ()->redraw_count + 1);
if (priv->update_idle == 0)
if (!priv->redraw_pending)
{
CLUTTER_NOTE (PAINT, "Adding idle source for stage: %p", stage);
priv->redraw_pending = TRUE;
priv->update_idle =
clutter_threads_add_idle_full (CLUTTER_PRIORITY_REDRAW,
redraw_update_idle,
stage,
NULL);
/* If called from a thread, we need to wake up the main loop
* out of its sleep so the clock source notices that we have
* a redraw pending
*/
g_main_context_wakeup (NULL);
}
else
CLUTTER_CONTEXT ()->redraw_count += 1;
@ -608,12 +618,6 @@ clutter_stage_dispose (GObject *object)
clutter_actor_hide (CLUTTER_ACTOR (object));
if (priv->update_idle)
{
g_source_remove (priv->update_idle);
priv->update_idle = 0;
}
_clutter_stage_manager_remove_stage (stage_manager, stage);
if (priv->impl)