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:
parent
77cd4e2bc8
commit
89a8fd7755
@ -95,16 +95,17 @@ static GSourceFuncs clock_funcs = {
|
|||||||
G_DEFINE_TYPE (ClutterMasterClock, clutter_master_clock, G_TYPE_OBJECT);
|
G_DEFINE_TYPE (ClutterMasterClock, clutter_master_clock, G_TYPE_OBJECT);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* has_running_timeline:
|
* master_clock_is_running:
|
||||||
* @master_clock: a #ClutterMasterClock
|
* @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
|
* Return value: %TRUE if the #ClutterMasterClock has at least
|
||||||
* one running timeline
|
* one running timeline
|
||||||
*/
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
has_running_timeline (ClutterMasterClock *master_clock)
|
master_clock_is_running (ClutterMasterClock *master_clock)
|
||||||
{
|
{
|
||||||
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
|
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
|
||||||
const GSList *stages, *l;
|
const GSList *stages, *l;
|
||||||
@ -112,6 +113,11 @@ has_running_timeline (ClutterMasterClock *master_clock)
|
|||||||
if (master_clock->timelines)
|
if (master_clock->timelines)
|
||||||
return TRUE;
|
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;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,7 +154,7 @@ clutter_clock_prepare (GSource *source,
|
|||||||
/* just like an idle source, we are ready if nothing else is */
|
/* just like an idle source, we are ready if nothing else is */
|
||||||
*timeout = -1;
|
*timeout = -1;
|
||||||
|
|
||||||
retval = has_running_timeline (master_clock);
|
retval = master_clock_is_running (master_clock);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -160,7 +166,7 @@ clutter_clock_check (GSource *source)
|
|||||||
ClutterMasterClock *master_clock = clock_source->master_clock;
|
ClutterMasterClock *master_clock = clock_source->master_clock;
|
||||||
gboolean retval;
|
gboolean retval;
|
||||||
|
|
||||||
retval = has_running_timeline (master_clock);
|
retval = master_clock_is_running (master_clock);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -170,6 +176,8 @@ clutter_clock_dispatch (GSource *source,
|
|||||||
GSourceFunc callback,
|
GSourceFunc callback,
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
|
ClutterClockSource *clock_source = (ClutterClockSource *) source;
|
||||||
|
ClutterMasterClock *master_clock = clock_source->master_clock;
|
||||||
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
|
ClutterStageManager *stage_manager = clutter_stage_manager_get_default ();
|
||||||
const GSList *stages, *l;
|
const GSList *stages, *l;
|
||||||
|
|
||||||
@ -177,12 +185,13 @@ clutter_clock_dispatch (GSource *source,
|
|||||||
|
|
||||||
stages = clutter_stage_manager_peek_stages (stage_manager);
|
stages = clutter_stage_manager_peek_stages (stage_manager);
|
||||||
|
|
||||||
/* queue a redraw for each stage; this will advance each timeline
|
_clutter_master_clock_advance (master_clock);
|
||||||
* held by the master clock of the amount of milliseconds elapsed
|
|
||||||
* since the last redraw
|
/* Update any stage that needs redraw/relayout after the clock
|
||||||
|
* is advanced.
|
||||||
*/
|
*/
|
||||||
for (l = stages; l != NULL; l = l->next)
|
for (l = stages; l != NULL; l = l->next)
|
||||||
clutter_actor_queue_redraw (l->data);
|
_clutter_stage_do_update (l->data);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,8 @@ ClutterStageWindow *_clutter_stage_get_window (ClutterStage *sta
|
|||||||
ClutterStageWindow *_clutter_stage_get_default_window (void);
|
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);
|
||||||
|
void _clutter_stage_do_update (ClutterStage *stage);
|
||||||
|
|
||||||
/* vfuncs implemented by backend */
|
/* vfuncs implemented by backend */
|
||||||
GType _clutter_backend_impl_get_type (void);
|
GType _clutter_backend_impl_get_type (void);
|
||||||
|
@ -87,8 +87,7 @@ struct _ClutterStagePrivate
|
|||||||
gchar *title;
|
gchar *title;
|
||||||
ClutterActor *key_focused_actor;
|
ClutterActor *key_focused_actor;
|
||||||
|
|
||||||
guint update_idle; /* repaint idler id */
|
guint redraw_pending : 1;
|
||||||
|
|
||||||
guint is_fullscreen : 1;
|
guint is_fullscreen : 1;
|
||||||
guint is_offscreen : 1;
|
guint is_offscreen : 1;
|
||||||
guint is_cursor_visible : 1;
|
guint is_cursor_visible : 1;
|
||||||
@ -390,29 +389,43 @@ clutter_stage_real_fullscreen (ClutterStage *stage)
|
|||||||
CLUTTER_ALLOCATION_NONE);
|
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;
|
||||||
ClutterStagePrivate *priv = stage->priv;
|
|
||||||
ClutterMasterClock *master_clock;
|
|
||||||
|
|
||||||
/* before we redraw we advance the master clock of one tick; this means
|
g_return_val_if_fail (CLUTTER_IS_STAGE (stage), FALSE);
|
||||||
* 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);
|
|
||||||
|
|
||||||
/* run the (eventual) repaint functions; since those might end up queuing
|
priv = stage->priv;
|
||||||
* a relayout or a redraw we need to execute them before maybe_relayout()
|
|
||||||
*/
|
return priv->redraw_pending;
|
||||||
CLUTTER_NOTE (PAINT, "Repaint functions");
|
}
|
||||||
_clutter_run_repaint_functions ();
|
|
||||||
|
/**
|
||||||
|
* _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
|
/* 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
|
||||||
@ -422,12 +435,11 @@ redraw_update_idle (gpointer user_data)
|
|||||||
*/
|
*/
|
||||||
_clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
|
_clutter_stage_maybe_relayout (CLUTTER_ACTOR (stage));
|
||||||
|
|
||||||
/* redrawing will advance the master clock */
|
|
||||||
CLUTTER_NOTE (PAINT, "redrawing via idle for stage[%p]", stage);
|
CLUTTER_NOTE (PAINT, "redrawing via idle for stage[%p]", stage);
|
||||||
_clutter_do_redraw (stage);
|
_clutter_do_redraw (stage);
|
||||||
|
|
||||||
/* reset the guard, so that new redraws are possible */
|
/* reset the guard, so that new redraws are possible */
|
||||||
priv->update_idle = 0;
|
priv->redraw_pending = FALSE;
|
||||||
|
|
||||||
if (CLUTTER_CONTEXT ()->redraw_count > 0)
|
if (CLUTTER_CONTEXT ()->redraw_count > 0)
|
||||||
{
|
{
|
||||||
@ -436,8 +448,6 @@ redraw_update_idle (gpointer user_data)
|
|||||||
|
|
||||||
CLUTTER_CONTEXT ()->redraw_count = 0;
|
CLUTTER_CONTEXT ()->redraw_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -450,15 +460,15 @@ clutter_stage_real_queue_redraw (ClutterActor *actor,
|
|||||||
CLUTTER_NOTE (PAINT, "Redraw request number %lu",
|
CLUTTER_NOTE (PAINT, "Redraw request number %lu",
|
||||||
CLUTTER_CONTEXT ()->redraw_count + 1);
|
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 =
|
/* If called from a thread, we need to wake up the main loop
|
||||||
clutter_threads_add_idle_full (CLUTTER_PRIORITY_REDRAW,
|
* out of its sleep so the clock source notices that we have
|
||||||
redraw_update_idle,
|
* a redraw pending
|
||||||
stage,
|
*/
|
||||||
NULL);
|
g_main_context_wakeup (NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
CLUTTER_CONTEXT ()->redraw_count += 1;
|
CLUTTER_CONTEXT ()->redraw_count += 1;
|
||||||
@ -608,12 +618,6 @@ clutter_stage_dispose (GObject *object)
|
|||||||
|
|
||||||
clutter_actor_hide (CLUTTER_ACTOR (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);
|
_clutter_stage_manager_remove_stage (stage_manager, stage);
|
||||||
|
|
||||||
if (priv->impl)
|
if (priv->impl)
|
||||||
|
Loading…
Reference in New Issue
Block a user