clutter/frame-clock: Add triple buffering support
This replaces the DISPATCHED state with new sub-states that are possible with triple buffering: DISPATCHED_ONE: Double buffering DISPATCHED_ONE_AND_SCHEDULED: Scheduled switch to triple buffering DISPATCHED_ONE_AND_SCHEDULED_NOW: Scheduled switch to triple buffering DISPATCHED_ONE_AND_SCHEDULED_LATER: Scheduled switch to triple buffering DISPATCHED_TWO: Triple buffering Triple buffering is currently disabled until the test cases get updated to handle it in the next commit. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1441>
This commit is contained in:
parent
9d2ab85f74
commit
394bf5ab24
@ -76,7 +76,11 @@ typedef enum _ClutterFrameClockState
|
|||||||
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED,
|
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED,
|
||||||
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW,
|
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW,
|
||||||
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER,
|
CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER,
|
||||||
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED,
|
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE,
|
||||||
|
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED,
|
||||||
|
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW,
|
||||||
|
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER,
|
||||||
|
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO,
|
||||||
} ClutterFrameClockState;
|
} ClutterFrameClockState;
|
||||||
|
|
||||||
typedef struct _Frame
|
typedef struct _Frame
|
||||||
@ -112,9 +116,10 @@ struct _ClutterFrameClock
|
|||||||
|
|
||||||
int64_t next_update_time_us;
|
int64_t next_update_time_us;
|
||||||
|
|
||||||
Frame frame_pool[2];
|
Frame frame_pool[3];
|
||||||
Frame *prev_dispatch;
|
Frame *prev_dispatch;
|
||||||
Frame *next_presentation;
|
Frame *next_presentation;
|
||||||
|
Frame *next_next_presentation;
|
||||||
Frame *prev_presentation;
|
Frame *prev_presentation;
|
||||||
|
|
||||||
gboolean is_next_presentation_time_valid;
|
gboolean is_next_presentation_time_valid;
|
||||||
@ -379,6 +384,11 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
|
|||||||
ClutterFrameInfo *frame_info)
|
ClutterFrameInfo *frame_info)
|
||||||
{
|
{
|
||||||
Frame *presented_frame;
|
Frame *presented_frame;
|
||||||
|
#ifdef CLUTTER_ENABLE_DEBUG
|
||||||
|
const char *debug_state =
|
||||||
|
frame_clock->state == CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO ?
|
||||||
|
"Triple buffering" : "Double buffering";
|
||||||
|
#endif
|
||||||
|
|
||||||
COGL_TRACE_BEGIN_SCOPED (ClutterFrameClockNotifyPresented,
|
COGL_TRACE_BEGIN_SCOPED (ClutterFrameClockNotifyPresented,
|
||||||
"Clutter::FrameClock::presented()");
|
"Clutter::FrameClock::presented()");
|
||||||
@ -389,6 +399,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
|
|||||||
clear_frame (&frame_clock->prev_presentation);
|
clear_frame (&frame_clock->prev_presentation);
|
||||||
presented_frame = frame_clock->prev_presentation =
|
presented_frame = frame_clock->prev_presentation =
|
||||||
g_steal_pointer (&frame_clock->next_presentation);
|
g_steal_pointer (&frame_clock->next_presentation);
|
||||||
|
frame_clock->next_presentation =
|
||||||
|
g_steal_pointer (&frame_clock->next_next_presentation);
|
||||||
|
|
||||||
presented_frame->next_presentation_time_us =
|
presented_frame->next_presentation_time_us =
|
||||||
frame_clock->next_presentation_time_us;
|
frame_clock->next_presentation_time_us;
|
||||||
@ -478,18 +490,21 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
|
|||||||
frame_info->has_valid_gpu_rendering_duration)
|
frame_info->has_valid_gpu_rendering_duration)
|
||||||
{
|
{
|
||||||
int64_t dispatch_to_swap_us, swap_to_rendering_done_us, swap_to_flip_us;
|
int64_t dispatch_to_swap_us, swap_to_rendering_done_us, swap_to_flip_us;
|
||||||
|
int64_t dispatch_time_us = presented_frame->dispatch_time_us;
|
||||||
|
int64_t flip_time_us = presented_frame->flip_time_us;
|
||||||
|
|
||||||
dispatch_to_swap_us =
|
dispatch_to_swap_us =
|
||||||
frame_info->cpu_time_before_buffer_swap_us -
|
frame_info->cpu_time_before_buffer_swap_us -
|
||||||
presented_frame->dispatch_time_us;
|
dispatch_time_us;
|
||||||
swap_to_rendering_done_us =
|
swap_to_rendering_done_us =
|
||||||
frame_info->gpu_rendering_duration_ns / 1000;
|
frame_info->gpu_rendering_duration_ns / 1000;
|
||||||
swap_to_flip_us =
|
swap_to_flip_us =
|
||||||
presented_frame->flip_time_us -
|
flip_time_us -
|
||||||
frame_info->cpu_time_before_buffer_swap_us;
|
frame_info->cpu_time_before_buffer_swap_us;
|
||||||
|
|
||||||
CLUTTER_NOTE (FRAME_TIMINGS,
|
CLUTTER_NOTE (FRAME_TIMINGS,
|
||||||
"update2dispatch %ld µs, dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs",
|
"%s: update2dispatch %ld µs, dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs",
|
||||||
|
debug_state,
|
||||||
presented_frame->dispatch_lateness_us,
|
presented_frame->dispatch_lateness_us,
|
||||||
dispatch_to_swap_us,
|
dispatch_to_swap_us,
|
||||||
swap_to_rendering_done_us,
|
swap_to_rendering_done_us,
|
||||||
@ -500,7 +515,7 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
|
|||||||
MAX (swap_to_rendering_done_us, swap_to_flip_us) +
|
MAX (swap_to_rendering_done_us, swap_to_flip_us) +
|
||||||
frame_clock->deadline_evasion_us,
|
frame_clock->deadline_evasion_us,
|
||||||
frame_clock->shortterm_max_update_duration_us,
|
frame_clock->shortterm_max_update_duration_us,
|
||||||
frame_clock->refresh_interval_us);
|
2 * frame_clock->refresh_interval_us);
|
||||||
|
|
||||||
maybe_update_longterm_max_duration_us (frame_clock, frame_info);
|
maybe_update_longterm_max_duration_us (frame_clock, frame_info);
|
||||||
|
|
||||||
@ -509,7 +524,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CLUTTER_NOTE (FRAME_TIMINGS, "update2dispatch %ld µs",
|
CLUTTER_NOTE (FRAME_TIMINGS, "%s: update2dispatch %ld µs",
|
||||||
|
debug_state,
|
||||||
presented_frame->dispatch_lateness_us);
|
presented_frame->dispatch_lateness_us);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,10 +544,26 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
|
|||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
||||||
g_warn_if_reached ();
|
g_warn_if_reached ();
|
||||||
break;
|
break;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED:
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
|
||||||
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
|
||||||
maybe_reschedule_update (frame_clock);
|
maybe_reschedule_update (frame_clock);
|
||||||
break;
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
|
||||||
|
maybe_reschedule_update (frame_clock);
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW;
|
||||||
|
maybe_reschedule_update (frame_clock);
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER;
|
||||||
|
maybe_reschedule_update (frame_clock);
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
|
||||||
|
maybe_reschedule_update (frame_clock);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,6 +573,9 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock)
|
|||||||
COGL_TRACE_BEGIN_SCOPED (ClutterFrameClockNotifyReady, "Clutter::FrameClock::ready()");
|
COGL_TRACE_BEGIN_SCOPED (ClutterFrameClockNotifyReady, "Clutter::FrameClock::ready()");
|
||||||
COGL_TRACE_DESCRIBE (ClutterFrameClockNotifyReady, frame_clock->output_name);
|
COGL_TRACE_DESCRIBE (ClutterFrameClockNotifyReady, frame_clock->output_name);
|
||||||
|
|
||||||
|
if (frame_clock->next_next_presentation)
|
||||||
|
clear_frame (&frame_clock->next_next_presentation);
|
||||||
|
else
|
||||||
clear_frame (&frame_clock->next_presentation);
|
clear_frame (&frame_clock->next_presentation);
|
||||||
|
|
||||||
switch (frame_clock->state)
|
switch (frame_clock->state)
|
||||||
@ -552,10 +587,26 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock)
|
|||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
||||||
g_warn_if_reached ();
|
g_warn_if_reached ();
|
||||||
break;
|
break;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED:
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
|
||||||
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
|
||||||
maybe_reschedule_update (frame_clock);
|
maybe_reschedule_update (frame_clock);
|
||||||
break;
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
|
||||||
|
maybe_reschedule_update (frame_clock);
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW;
|
||||||
|
maybe_reschedule_update (frame_clock);
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW;
|
||||||
|
maybe_reschedule_update (frame_clock);
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
|
||||||
|
maybe_reschedule_update (frame_clock);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,7 +621,14 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
|
|||||||
if (!frame_clock->ever_got_measurements ||
|
if (!frame_clock->ever_got_measurements ||
|
||||||
G_UNLIKELY (clutter_paint_debug_flags &
|
G_UNLIKELY (clutter_paint_debug_flags &
|
||||||
CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME))
|
CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME))
|
||||||
return (int64_t) (refresh_interval_us * SYNC_DELAY_FALLBACK_FRACTION);
|
{
|
||||||
|
int64_t ret = (int64_t) (refresh_interval_us * SYNC_DELAY_FALLBACK_FRACTION);
|
||||||
|
|
||||||
|
if (frame_clock->state >= CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE)
|
||||||
|
ret += refresh_interval_us;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* Max render time shows how early the frame clock needs to be dispatched
|
/* Max render time shows how early the frame clock needs to be dispatched
|
||||||
* to make it to the predicted next presentation time. It is an estimate of
|
* to make it to the predicted next presentation time. It is an estimate of
|
||||||
@ -590,7 +648,7 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
|
|||||||
frame_clock->vblank_duration_us +
|
frame_clock->vblank_duration_us +
|
||||||
clutter_max_render_time_constant_us;
|
clutter_max_render_time_constant_us;
|
||||||
|
|
||||||
max_render_time_us = CLAMP (max_render_time_us, 0, refresh_interval_us);
|
max_render_time_us = CLAMP (max_render_time_us, 0, 2 * refresh_interval_us);
|
||||||
|
|
||||||
return max_render_time_us;
|
return max_render_time_us;
|
||||||
}
|
}
|
||||||
@ -608,6 +666,7 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
|
|||||||
int64_t min_render_time_allowed_us;
|
int64_t min_render_time_allowed_us;
|
||||||
int64_t max_render_time_allowed_us;
|
int64_t max_render_time_allowed_us;
|
||||||
int64_t next_presentation_time_us;
|
int64_t next_presentation_time_us;
|
||||||
|
int64_t next_smooth_presentation_time_us = 0;
|
||||||
int64_t next_update_time_us;
|
int64_t next_update_time_us;
|
||||||
|
|
||||||
now_us = g_get_monotonic_time ();
|
now_us = g_get_monotonic_time ();
|
||||||
@ -654,7 +713,31 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
last_presentation_time_us = last_presentation->presentation_time_us;
|
last_presentation_time_us = last_presentation->presentation_time_us;
|
||||||
next_presentation_time_us = last_presentation_time_us + refresh_interval_us;
|
switch (frame_clock->state)
|
||||||
|
{
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_INIT:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
||||||
|
next_smooth_presentation_time_us = last_presentation_time_us +
|
||||||
|
refresh_interval_us;
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER:
|
||||||
|
next_smooth_presentation_time_us = last_presentation_time_us +
|
||||||
|
2 * refresh_interval_us;
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
|
||||||
|
g_warn_if_reached (); /* quad buffering would be a bug */
|
||||||
|
next_smooth_presentation_time_us = last_presentation_time_us +
|
||||||
|
3 * refresh_interval_us;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_presentation_time_us = next_smooth_presentation_time_us;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* However, the last presentation could have happened more than a frame ago.
|
* However, the last presentation could have happened more than a frame ago.
|
||||||
@ -721,7 +804,7 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (last_presentation->presentation_flags & CLUTTER_FRAME_INFO_FLAG_VSYNC &&
|
if (last_presentation->presentation_flags & CLUTTER_FRAME_INFO_FLAG_VSYNC &&
|
||||||
next_presentation_time_us != last_presentation_time_us + refresh_interval_us)
|
next_presentation_time_us != next_smooth_presentation_time_us)
|
||||||
{
|
{
|
||||||
/* There was an idle period since the last presentation, so there seems
|
/* There was an idle period since the last presentation, so there seems
|
||||||
* be no constantly updating actor. In this case it's best to start
|
* be no constantly updating actor. In this case it's best to start
|
||||||
@ -858,7 +941,21 @@ clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock)
|
|||||||
frame_clock->pending_reschedule_now = TRUE;
|
frame_clock->pending_reschedule_now = TRUE;
|
||||||
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
|
||||||
break;
|
break;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED:
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
|
||||||
|
frame_clock->pending_reschedule = TRUE;
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW:
|
||||||
|
frame_clock->pending_reschedule = TRUE;
|
||||||
|
frame_clock->pending_reschedule_now = TRUE;
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER:
|
||||||
|
frame_clock->pending_reschedule = TRUE;
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -877,6 +974,13 @@ clutter_frame_clock_uninhibit (ClutterFrameClock *frame_clock)
|
|||||||
maybe_reschedule_update (frame_clock);
|
maybe_reschedule_update (frame_clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
want_triple_buffering (ClutterFrameClock *frame_clock)
|
||||||
|
{
|
||||||
|
/* disabled until test cases are updated */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
|
clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
|
||||||
{
|
{
|
||||||
@ -895,10 +999,25 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
|
|||||||
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW;
|
||||||
break;
|
break;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW:
|
||||||
return;
|
return;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED:
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER:
|
||||||
|
frame_clock->state =
|
||||||
|
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW;
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
|
||||||
|
if (want_triple_buffering (frame_clock))
|
||||||
|
{
|
||||||
|
frame_clock->state =
|
||||||
|
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
G_GNUC_FALLTHROUGH;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
|
||||||
frame_clock->pending_reschedule = TRUE;
|
frame_clock->pending_reschedule = TRUE;
|
||||||
frame_clock->pending_reschedule_now = TRUE;
|
frame_clock->pending_reschedule_now = TRUE;
|
||||||
return;
|
return;
|
||||||
@ -927,7 +1046,6 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
|
|||||||
|
|
||||||
frame_clock->next_update_time_us = next_update_time_us;
|
frame_clock->next_update_time_us = next_update_time_us;
|
||||||
g_source_set_ready_time (frame_clock->source, next_update_time_us);
|
g_source_set_ready_time (frame_clock->source, next_update_time_us);
|
||||||
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -949,12 +1067,24 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
|
|||||||
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
|
||||||
return;
|
return;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
|
||||||
break;
|
break;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER:
|
||||||
return;
|
return;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED:
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
|
||||||
|
if (want_triple_buffering (frame_clock))
|
||||||
|
{
|
||||||
|
frame_clock->state =
|
||||||
|
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
G_GNUC_FALLTHROUGH;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
|
||||||
frame_clock->pending_reschedule = TRUE;
|
frame_clock->pending_reschedule = TRUE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -983,7 +1113,6 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
|
|||||||
|
|
||||||
frame_clock->next_update_time_us = next_update_time_us;
|
frame_clock->next_update_time_us = next_update_time_us;
|
||||||
g_source_set_ready_time (frame_clock->source, next_update_time_us);
|
g_source_set_ready_time (frame_clock->source, next_update_time_us);
|
||||||
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -996,6 +1125,7 @@ clutter_frame_clock_schedule_update_later (ClutterFrameClock *frame_clock,
|
|||||||
int64_t ready_time_us = 0, extrapolated_presentation_time_us;
|
int64_t ready_time_us = 0, extrapolated_presentation_time_us;
|
||||||
int64_t max_render_time_us;
|
int64_t max_render_time_us;
|
||||||
int64_t cycles;
|
int64_t cycles;
|
||||||
|
ClutterFrameClockState next_state = frame_clock->state;
|
||||||
|
|
||||||
if (frame_clock->inhibit_count > 0)
|
if (frame_clock->inhibit_count > 0)
|
||||||
{
|
{
|
||||||
@ -1008,11 +1138,24 @@ clutter_frame_clock_schedule_update_later (ClutterFrameClock *frame_clock,
|
|||||||
case CLUTTER_FRAME_CLOCK_STATE_INIT:
|
case CLUTTER_FRAME_CLOCK_STATE_INIT:
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
||||||
|
next_state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER;
|
||||||
break;
|
break;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW:
|
||||||
return;
|
return;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED:
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER:
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
|
||||||
|
if (want_triple_buffering (frame_clock))
|
||||||
|
{
|
||||||
|
next_state =
|
||||||
|
CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
G_GNUC_FALLTHROUGH;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
|
||||||
frame_clock->pending_reschedule = TRUE;
|
frame_clock->pending_reschedule = TRUE;
|
||||||
frame_clock->pending_reschedule_now = TRUE;
|
frame_clock->pending_reschedule_now = TRUE;
|
||||||
return;
|
return;
|
||||||
@ -1063,7 +1206,7 @@ clutter_frame_clock_schedule_update_later (ClutterFrameClock *frame_clock,
|
|||||||
|
|
||||||
g_source_set_ready_time (frame_clock->source, ready_time_us);
|
g_source_set_ready_time (frame_clock->source, ready_time_us);
|
||||||
frame_clock->pending_reschedule = TRUE;
|
frame_clock->pending_reschedule = TRUE;
|
||||||
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER;
|
frame_clock->state = next_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1105,6 +1248,8 @@ clutter_frame_clock_set_mode (ClutterFrameClock *frame_clock,
|
|||||||
{
|
{
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_INIT:
|
case CLUTTER_FRAME_CLOCK_STATE_INIT:
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
|
||||||
break;
|
break;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
||||||
@ -1116,7 +1261,15 @@ clutter_frame_clock_set_mode (ClutterFrameClock *frame_clock,
|
|||||||
frame_clock->pending_reschedule_now = TRUE;
|
frame_clock->pending_reschedule_now = TRUE;
|
||||||
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
|
||||||
break;
|
break;
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED:
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER:
|
||||||
|
frame_clock->pending_reschedule = TRUE;
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW:
|
||||||
|
frame_clock->pending_reschedule = TRUE;
|
||||||
|
frame_clock->pending_reschedule_now = TRUE;
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1162,9 +1315,16 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
|
|||||||
this_dispatch = frame_clock->prev_dispatch =
|
this_dispatch = frame_clock->prev_dispatch =
|
||||||
clutter_frame_clock_new_frame (frame_clock);
|
clutter_frame_clock_new_frame (frame_clock);
|
||||||
|
|
||||||
/* This will need changing for triple buffering */
|
if (frame_clock->next_presentation == NULL)
|
||||||
g_warn_if_fail (frame_clock->next_presentation == NULL);
|
{
|
||||||
frame_clock->next_presentation = ref_frame (this_dispatch);
|
frame_clock->next_presentation = ref_frame (this_dispatch);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_warn_if_fail (frame_clock->next_next_presentation == NULL);
|
||||||
|
frame_clock->next_next_presentation =
|
||||||
|
ref_frame (this_dispatch);
|
||||||
|
}
|
||||||
|
|
||||||
ideal_dispatch_time_us = frame_clock->next_update_time_us;
|
ideal_dispatch_time_us = frame_clock->next_update_time_us;
|
||||||
|
|
||||||
@ -1198,7 +1358,25 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
|
|||||||
this_dispatch->dispatch_time_us = time_us;
|
this_dispatch->dispatch_time_us = time_us;
|
||||||
g_source_set_ready_time (frame_clock->source, -1);
|
g_source_set_ready_time (frame_clock->source, -1);
|
||||||
|
|
||||||
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED;
|
switch (frame_clock->state)
|
||||||
|
{
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_INIT:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO:
|
||||||
|
g_warn_if_reached ();
|
||||||
|
return;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE;
|
||||||
|
break;
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_NOW:
|
||||||
|
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE_AND_SCHEDULED_LATER:
|
||||||
|
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_TWO;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
frame_count = frame_clock->frame_count++;
|
frame_count = frame_clock->frame_count++;
|
||||||
|
|
||||||
@ -1229,18 +1407,6 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
|
|||||||
result = iface->frame (frame_clock, frame, frame_clock->listener.user_data);
|
result = iface->frame (frame_clock, frame, frame_clock->listener.user_data);
|
||||||
COGL_TRACE_END (ClutterFrameClockFrame);
|
COGL_TRACE_END (ClutterFrameClockFrame);
|
||||||
|
|
||||||
switch (frame_clock->state)
|
|
||||||
{
|
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_INIT:
|
|
||||||
g_warn_if_reached ();
|
|
||||||
break;
|
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_IDLE:
|
|
||||||
/* Presentation completed synchronously in the above listener */
|
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
|
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_NOW:
|
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED_LATER:
|
|
||||||
break;
|
|
||||||
case CLUTTER_FRAME_CLOCK_STATE_DISPATCHED:
|
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
case CLUTTER_FRAME_RESULT_PENDING_PRESENTED:
|
case CLUTTER_FRAME_RESULT_PENDING_PRESENTED:
|
||||||
@ -1250,8 +1416,6 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
|
|||||||
clutter_frame_clock_notify_ready (frame_clock);
|
clutter_frame_clock_notify_ready (frame_clock);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_PROFILER
|
#ifdef HAVE_PROFILER
|
||||||
if (this_dispatch_ready_time_us != -1 &&
|
if (this_dispatch_ready_time_us != -1 &&
|
||||||
|
@ -8,6 +8,11 @@ stateDiagram
|
|||||||
IDLE --> SCHEDULED* : next frame scheduled
|
IDLE --> SCHEDULED* : next frame scheduled
|
||||||
SCHEDULED* --> IDLE : frame clock inhibited or mode changed
|
SCHEDULED* --> IDLE : frame clock inhibited or mode changed
|
||||||
SCHEDULED* --> SCHEDULED* : schedule upgraded to SCHEDULED_NOW
|
SCHEDULED* --> SCHEDULED* : schedule upgraded to SCHEDULED_NOW
|
||||||
SCHEDULED* --> DISPATCHED : begin an update
|
SCHEDULED* --> DISPATCHED_ONE : begin an update
|
||||||
DISPATCHED --> IDLE : frame was either presented or aborted with nothing to draw
|
DISPATCHED_ONE --> IDLE : frame was either presented or aborted with nothing to draw
|
||||||
|
DISPATCHED_ONE --> DISPATCHED_ONE_AND_SCHEDULED* : entering triple buffering
|
||||||
|
DISPATCHED_ONE_AND_SCHEDULED* --> SCHEDULED* : frame was either presented or aborted with nothing to draw
|
||||||
|
DISPATCHED_ONE_AND_SCHEDULED* --> DISPATCHED_ONE : frame clock inhibited or mode changed
|
||||||
|
DISPATCHED_ONE_AND_SCHEDULED* --> DISPATCHED_TWO : start a second concurrent frame
|
||||||
|
DISPATCHED_TWO --> DISPATCHED_ONE : leaving triple buffering
|
||||||
```
|
```
|
||||||
|
Loading…
x
Reference in New Issue
Block a user