diff --git a/clutter/clutter/clutter-master-clock-default.c b/clutter/clutter/clutter-master-clock-default.c index 6779eb70b7404519b4ce4c251bd51040ea5d34e1..3197a32e3e4d1606847933c6229c88f2c414bee0 100644 --- a/clutter/clutter/clutter-master-clock-default.c +++ b/clutter/clutter/clutter-master-clock-default.c @@ -64,9 +64,6 @@ struct _ClutterMasterClockDefault /* the current state of the clock, in usecs */ gint64 cur_tick; - /* the previous state of the clock, in usecs, used to compute the delta */ - gint64 prev_tick; - #ifdef CLUTTER_ENABLE_DEBUG gint64 frame_budget; gint64 remaining_budget; @@ -77,12 +74,6 @@ struct _ClutterMasterClockDefault */ GSource *source; - /* If the master clock is idle that means it has - * fallen back to idle polling for timeline - * progressions and it may have been some time since - * the last real stage update. - */ - guint idle : 1; guint ensure_next_iteration : 1; guint paused : 1; @@ -275,78 +266,12 @@ master_clock_reschedule_stage_updates (ClutterMasterClockDefault *master_clock, static gint master_clock_next_frame_delay (ClutterMasterClockDefault *master_clock) { - gint64 now, next; - gint swap_delay; - if (!master_clock_is_running (master_clock)) return -1; /* If all of the stages are busy waiting for a swap-buffers to complete * then we wait for one to be ready.. */ - swap_delay = master_clock_get_swap_wait_time (master_clock); - if (swap_delay != 0) - return swap_delay; - - /* When we have sync-to-vblank, we count on swap-buffer requests (or - * swap-buffer-complete events if supported in the backend) to throttle our - * frame rate so no additional delay is needed to start the next frame. - * - * If the master-clock has become idle due to no timeline progression causing - * redraws then we can no longer rely on vblank synchronization because the - * last real stage update/redraw may have happened a long time ago and so we - * fallback to polling for timeline progressions every 1/frame_rate seconds. - * - * (NB: if there aren't even any timelines running then the master clock will - * be completely stopped in master_clock_is_running()) - */ - if (clutter_feature_available (CLUTTER_FEATURE_SWAP_THROTTLE) && - !master_clock->idle) - { - CLUTTER_NOTE (SCHEDULER, "swap throttling available and updated stages"); - return 0; - } - - if (master_clock->prev_tick == 0) - { - /* If we weren't previously running, then draw the next frame - * immediately - */ - CLUTTER_NOTE (SCHEDULER, "draw the first frame immediately"); - return 0; - } - - /* Otherwise, wait at least 1/frame_rate seconds since we last - * started a frame - */ - now = g_source_get_time (master_clock->source); - - next = master_clock->prev_tick; - - /* If time has gone backwards then there's no way of knowing how - long we should wait so let's just dispatch immediately */ - if (now <= next) - { - CLUTTER_NOTE (SCHEDULER, "Time has gone backwards"); - - return 0; - } - - next += (1000000L / clutter_get_default_frame_rate ()); - - if (next <= now) - { - CLUTTER_NOTE (SCHEDULER, "Less than %lu microsecs", - 1000000L / (gulong) clutter_get_default_frame_rate ()); - - return 0; - } - else - { - CLUTTER_NOTE (SCHEDULER, "Waiting %" G_GINT64_FORMAT " msecs", - (next - now) / 1000); - - return (next - now) / 1000; - } + return master_clock_get_swap_wait_time (master_clock); } static void @@ -530,7 +455,6 @@ clutter_clock_dispatch (GSource *source, { ClutterClockSource *clock_source = (ClutterClockSource *) source; ClutterMasterClockDefault *master_clock = clock_source->master_clock; - gboolean stages_updated = FALSE; GSList *stages; CLUTTER_NOTE (SCHEDULER, "Master clock [tick]"); @@ -550,8 +474,6 @@ clutter_clock_dispatch (GSource *source, */ stages = master_clock_list_ready_stages (master_clock); - master_clock->idle = FALSE; - /* Each frame is split into three separate phases: */ /* 1. process all the events; each stage goes through its events queue @@ -564,19 +486,12 @@ clutter_clock_dispatch (GSource *source, master_clock_advance_timelines (master_clock); /* 3. relayout and redraw the stages */ - stages_updated = master_clock_update_stages (master_clock, stages); - - /* The master clock goes idle if no stages were updated and falls back - * to polling for timeline progressions... */ - if (!stages_updated) - master_clock->idle = TRUE; + master_clock_update_stages (master_clock, stages); master_clock_reschedule_stage_updates (master_clock, stages); g_slist_free_full (stages, g_object_unref); - master_clock->prev_tick = master_clock->cur_tick; - _clutter_threads_release_lock (); return TRUE; @@ -608,7 +523,6 @@ clutter_master_clock_default_init (ClutterMasterClockDefault *self) source = clutter_clock_source_new (self); self->source = source; - self->idle = FALSE; self->ensure_next_iteration = FALSE; self->paused = FALSE; diff --git a/clutter/clutter/cogl/clutter-stage-cogl.c b/clutter/clutter/cogl/clutter-stage-cogl.c index e8ea80d7f85872a4946ee970ba58b5ea1608a03f..5b6eeb8bf45ac598ffb94baf5a06d6e0d5b81406 100644 --- a/clutter/clutter/cogl/clutter-stage-cogl.c +++ b/clutter/clutter/cogl/clutter-stage-cogl.c @@ -185,38 +185,56 @@ clutter_stage_cogl_schedule_update (ClutterStageWindow *stage_window, return; } - /* We only extrapolate presentation times for 150ms - this is somewhat - * arbitrary. The reasons it might not be accurate for larger times are - * that the refresh interval might be wrong or the vertical refresh - * might be downclocked if nothing is going on onscreen. - */ - if (stage_cogl->last_presentation_time == 0|| - stage_cogl->last_presentation_time < now - 150000) + refresh_rate = stage_cogl->refresh_rate; + if (refresh_rate <= 0.0) + refresh_rate = clutter_get_default_frame_rate (); + + refresh_interval = (gint64) (0.5 + G_USEC_PER_SEC / refresh_rate); + if (refresh_interval == 0) { stage_cogl->update_time = now; return; } - refresh_rate = stage_cogl->refresh_rate; - if (refresh_rate == 0.0) - refresh_rate = 60.0; - - refresh_interval = (gint64) (0.5 + 1000000 / refresh_rate); - if (refresh_interval == 0) - refresh_interval = 16667; /* 1/60th second */ - min_render_time_allowed = refresh_interval / 2; max_render_time_allowed = refresh_interval - 1000 * sync_delay; + /* Be robust in the case of incredibly bogus refresh rate */ + if (max_render_time_allowed <= 0) + { + g_warning ("Unsupported monitor refresh rate detected. " + "(Refresh rate: %.3f, refresh interval: %ld)", + refresh_rate, + refresh_interval); + stage_cogl->update_time = now; + return; + } + if (min_render_time_allowed > max_render_time_allowed) min_render_time_allowed = max_render_time_allowed; next_presentation_time = stage_cogl->last_presentation_time + refresh_interval; + /* Get next_presentation_time closer to its final value, to reduce + * the number of while iterations below. + */ + if (next_presentation_time < now) + { + int64_t last_virtual_presentation_time = now - now % refresh_interval; + int64_t hardware_clock_phase = + stage_cogl->last_presentation_time % refresh_interval; + + next_presentation_time = + last_virtual_presentation_time + hardware_clock_phase; + } + while (next_presentation_time < now + min_render_time_allowed) next_presentation_time += refresh_interval; stage_cogl->update_time = next_presentation_time - max_render_time_allowed; + + if (stage_cogl->update_time == stage_cogl->last_update_time) + stage_cogl->update_time = stage_cogl->last_update_time + refresh_interval; } static gint64 @@ -235,6 +253,7 @@ clutter_stage_cogl_clear_update_time (ClutterStageWindow *stage_window) { ClutterStageCogl *stage_cogl = CLUTTER_STAGE_COGL (stage_window); + stage_cogl->last_update_time = stage_cogl->update_time; stage_cogl->update_time = -1; } diff --git a/clutter/clutter/cogl/clutter-stage-cogl.h b/clutter/clutter/cogl/clutter-stage-cogl.h index aead9785e0be6b05b2b00d966115ed9dc00648c4..a69c424eb02f6f88aa2c114c24d326dbc4d1a963 100644 --- a/clutter/clutter/cogl/clutter-stage-cogl.h +++ b/clutter/clutter/cogl/clutter-stage-cogl.h @@ -53,6 +53,7 @@ struct _ClutterStageCogl gint64 last_presentation_time; gint64 update_time; + int64_t last_update_time; /* We only enable clipped redraws after 2 frames, since we've seen * a lot of drivers can struggle to get going and may output some