mirror of
https://github.com/brl/mutter.git
synced 2024-12-25 12:32:05 +00:00
clutter/frame-clock: Use single pair of maxima for render time estimate
Instead of separate pairs of short- and long-term maxima for each measured step of the frame update process. This should result in the render time estimate rising less often: Previously it did whenever the measurement of any of at least 3 out of 4 steps reached a new maximum, even if that didn't result in a new maximum for the whole update duration. Now it's only in the latter case. This should also result in a lower render time estimate (and thus input→output latency) in general, since the variability of measurements for each 3/4 steps doesn't always add up anymore. The flip side of this is that it might result in missing a display refresh cycle more often. v2: * Fix coding style in maybe_update_longterm_max_duration_us. (Robert Mader) Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3090>
This commit is contained in:
parent
c4c6d17649
commit
69afa7a142
@ -88,20 +88,12 @@ struct _ClutterFrameClock
|
|||||||
/* Last KMS buffer submission time. */
|
/* Last KMS buffer submission time. */
|
||||||
int64_t last_flip_time_us;
|
int64_t last_flip_time_us;
|
||||||
|
|
||||||
/* Last time we promoted short term durations to long term ones */
|
/* Last time we promoted short-term maximum to long-term one */
|
||||||
int64_t longterm_promotion_us;
|
int64_t longterm_promotion_us;
|
||||||
|
/* Long-term maximum update duration */
|
||||||
/* Short & long term maximum values */
|
int64_t longterm_max_update_duration_us;
|
||||||
struct {
|
/* Short-term maximum update duration */
|
||||||
/* Duration between desired and effective dispatch start. */
|
int64_t shortterm_max_update_duration_us;
|
||||||
int64_t max_dispatch_lateness_us;
|
|
||||||
/* Duration between dispatch start and buffer swap. */
|
|
||||||
int64_t max_dispatch_to_swap_us;
|
|
||||||
/* Duration between buffer swap and GPU rendering finish. */
|
|
||||||
int64_t max_swap_to_rendering_done_us;
|
|
||||||
/* Duration between buffer swap and KMS submission. */
|
|
||||||
int64_t max_swap_to_flip_us;
|
|
||||||
} shortterm, longterm;
|
|
||||||
|
|
||||||
/* If we got new measurements last frame. */
|
/* If we got new measurements last frame. */
|
||||||
gboolean got_measurements_last_frame;
|
gboolean got_measurements_last_frame;
|
||||||
@ -224,20 +216,33 @@ maybe_reschedule_update (ClutterFrameClock *frame_clock)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
update_longterm_max (int64_t *longterm_max,
|
maybe_update_longterm_max_duration_us (ClutterFrameClock *frame_clock,
|
||||||
int64_t *shortterm_max)
|
ClutterFrameInfo *frame_info)
|
||||||
{
|
{
|
||||||
/* Do not update long term max if there has been no measurement in over a second. */
|
/* Do not update long-term max if there has been no measurement */
|
||||||
if (!*shortterm_max)
|
if (!frame_clock->shortterm_max_update_duration_us)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (*longterm_max > *shortterm_max)
|
if ((frame_info->presentation_time - frame_clock->longterm_promotion_us) <
|
||||||
/* Exponential drop-off toward the short term max */
|
G_USEC_PER_SEC)
|
||||||
*longterm_max -= (*longterm_max - *shortterm_max) / 2;
|
return;
|
||||||
else
|
|
||||||
*longterm_max = *shortterm_max;
|
|
||||||
|
|
||||||
*shortterm_max = 0;
|
if (frame_clock->longterm_max_update_duration_us >
|
||||||
|
frame_clock->shortterm_max_update_duration_us)
|
||||||
|
{
|
||||||
|
/* Exponential drop-off toward the short-term max */
|
||||||
|
frame_clock->longterm_max_update_duration_us -=
|
||||||
|
(frame_clock->longterm_max_update_duration_us -
|
||||||
|
frame_clock->shortterm_max_update_duration_us) / 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
frame_clock->longterm_max_update_duration_us =
|
||||||
|
frame_clock->shortterm_max_update_duration_us;
|
||||||
|
}
|
||||||
|
|
||||||
|
frame_clock->shortterm_max_update_duration_us = 0;
|
||||||
|
frame_clock->longterm_promotion_us = frame_info->presentation_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -343,12 +348,12 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
|
|||||||
swap_to_rendering_done_us,
|
swap_to_rendering_done_us,
|
||||||
swap_to_flip_us);
|
swap_to_flip_us);
|
||||||
|
|
||||||
frame_clock->shortterm.max_dispatch_to_swap_us =
|
frame_clock->shortterm_max_update_duration_us =
|
||||||
MAX (frame_clock->shortterm.max_dispatch_to_swap_us, dispatch_to_swap_us);
|
MAX (frame_clock->shortterm_max_update_duration_us,
|
||||||
frame_clock->shortterm.max_swap_to_rendering_done_us =
|
frame_clock->last_dispatch_lateness_us + dispatch_to_swap_us +
|
||||||
MAX (frame_clock->shortterm.max_swap_to_rendering_done_us, swap_to_rendering_done_us);
|
MAX (swap_to_rendering_done_us, swap_to_flip_us));
|
||||||
frame_clock->shortterm.max_swap_to_flip_us =
|
|
||||||
MAX (frame_clock->shortterm.max_swap_to_flip_us, swap_to_flip_us);
|
maybe_update_longterm_max_duration_us (frame_clock, frame_info);
|
||||||
|
|
||||||
frame_clock->got_measurements_last_frame = TRUE;
|
frame_clock->got_measurements_last_frame = TRUE;
|
||||||
frame_clock->ever_got_measurements = TRUE;
|
frame_clock->ever_got_measurements = TRUE;
|
||||||
@ -359,20 +364,6 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
|
|||||||
frame_clock->last_dispatch_lateness_us);
|
frame_clock->last_dispatch_lateness_us);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame_info->presentation_time - frame_clock->longterm_promotion_us > G_USEC_PER_SEC)
|
|
||||||
{
|
|
||||||
update_longterm_max (&frame_clock->longterm.max_dispatch_lateness_us,
|
|
||||||
&frame_clock->shortterm.max_dispatch_lateness_us);
|
|
||||||
update_longterm_max (&frame_clock->longterm.max_dispatch_to_swap_us,
|
|
||||||
&frame_clock->shortterm.max_dispatch_to_swap_us);
|
|
||||||
update_longterm_max (&frame_clock->longterm.max_swap_to_rendering_done_us,
|
|
||||||
&frame_clock->shortterm.max_swap_to_rendering_done_us);
|
|
||||||
update_longterm_max (&frame_clock->longterm.max_swap_to_flip_us,
|
|
||||||
&frame_clock->shortterm.max_swap_to_flip_us);
|
|
||||||
|
|
||||||
frame_clock->longterm_promotion_us = frame_info->presentation_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (frame_info->refresh_rate > 1.0)
|
if (frame_info->refresh_rate > 1.0)
|
||||||
{
|
{
|
||||||
clutter_frame_clock_set_refresh_rate (frame_clock,
|
clutter_frame_clock_set_refresh_rate (frame_clock,
|
||||||
@ -418,10 +409,6 @@ static int64_t
|
|||||||
clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
|
clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
|
||||||
{
|
{
|
||||||
int64_t refresh_interval_us;
|
int64_t refresh_interval_us;
|
||||||
int64_t max_dispatch_lateness_us;
|
|
||||||
int64_t max_dispatch_to_swap_us;
|
|
||||||
int64_t max_swap_to_rendering_done_us;
|
|
||||||
int64_t max_swap_to_flip_us;
|
|
||||||
int64_t max_render_time_us;
|
int64_t max_render_time_us;
|
||||||
|
|
||||||
refresh_interval_us = frame_clock->refresh_interval_us;
|
refresh_interval_us = frame_clock->refresh_interval_us;
|
||||||
@ -431,34 +418,21 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
|
|||||||
CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME))
|
CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME))
|
||||||
return refresh_interval_us * SYNC_DELAY_FALLBACK_FRACTION;
|
return refresh_interval_us * SYNC_DELAY_FALLBACK_FRACTION;
|
||||||
|
|
||||||
max_dispatch_lateness_us =
|
|
||||||
MAX (frame_clock->longterm.max_dispatch_lateness_us,
|
|
||||||
frame_clock->shortterm.max_dispatch_lateness_us);
|
|
||||||
max_dispatch_to_swap_us =
|
|
||||||
MAX (frame_clock->longterm.max_dispatch_to_swap_us,
|
|
||||||
frame_clock->shortterm.max_dispatch_to_swap_us);
|
|
||||||
max_swap_to_rendering_done_us =
|
|
||||||
MAX (frame_clock->longterm.max_swap_to_rendering_done_us,
|
|
||||||
frame_clock->shortterm.max_swap_to_rendering_done_us);
|
|
||||||
max_swap_to_flip_us =
|
|
||||||
MAX (frame_clock->longterm.max_swap_to_flip_us,
|
|
||||||
frame_clock->shortterm.max_swap_to_flip_us);
|
|
||||||
|
|
||||||
/* 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 composed of:
|
* to make it to the predicted next presentation time. It is an estimate of
|
||||||
* - An estimate of dispatch start lateness.
|
* the total update duration, which is composed of:
|
||||||
* - An estimate of duration from dispatch start to buffer swap.
|
* - Dispatch start lateness.
|
||||||
* - Maximum between estimates of duration from buffer swap to GPU rendering
|
* - The duration from dispatch start to buffer swap.
|
||||||
* finish and duration from buffer swap to buffer submission to KMS. This
|
* - The maximum of duration from buffer swap to GPU rendering finish and
|
||||||
* is because both of these things need to happen before the vblank, and
|
* duration from buffer swap to buffer submission to KMS. This is because
|
||||||
* they are done in parallel.
|
* both of these things need to happen before the vblank, and they are done
|
||||||
* - Duration of the vblank.
|
* in parallel.
|
||||||
|
* - The duration of vertical blank.
|
||||||
* - A constant to account for variations in the above estimates.
|
* - A constant to account for variations in the above estimates.
|
||||||
*/
|
*/
|
||||||
max_render_time_us =
|
max_render_time_us =
|
||||||
max_dispatch_lateness_us +
|
MAX (frame_clock->longterm_max_update_duration_us,
|
||||||
max_dispatch_to_swap_us +
|
frame_clock->shortterm_max_update_duration_us) +
|
||||||
MAX (max_swap_to_rendering_done_us, max_swap_to_flip_us) +
|
|
||||||
frame_clock->vblank_duration_us +
|
frame_clock->vblank_duration_us +
|
||||||
clutter_max_render_time_constant_us;
|
clutter_max_render_time_constant_us;
|
||||||
|
|
||||||
@ -764,10 +738,6 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
|
|||||||
else
|
else
|
||||||
frame_clock->last_dispatch_lateness_us = lateness_us;
|
frame_clock->last_dispatch_lateness_us = lateness_us;
|
||||||
|
|
||||||
frame_clock->shortterm.max_dispatch_lateness_us =
|
|
||||||
MAX (frame_clock->shortterm.max_dispatch_lateness_us,
|
|
||||||
frame_clock->last_dispatch_lateness_us);
|
|
||||||
|
|
||||||
if (G_UNLIKELY (CLUTTER_HAS_DEBUG (FRAME_TIMINGS)))
|
if (G_UNLIKELY (CLUTTER_HAS_DEBUG (FRAME_TIMINGS)))
|
||||||
{
|
{
|
||||||
int64_t dispatch_interval_us, jitter_us;
|
int64_t dispatch_interval_us, jitter_us;
|
||||||
@ -873,10 +843,7 @@ clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock,
|
|||||||
GString *
|
GString *
|
||||||
clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock)
|
clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock)
|
||||||
{
|
{
|
||||||
int64_t max_dispatch_lateness_us;
|
int64_t max_update_duration_us;
|
||||||
int64_t max_dispatch_to_swap_us;
|
|
||||||
int64_t max_swap_to_rendering_done_us;
|
|
||||||
int64_t max_swap_to_flip_us;
|
|
||||||
GString *string;
|
GString *string;
|
||||||
|
|
||||||
string = g_string_new (NULL);
|
string = g_string_new (NULL);
|
||||||
@ -888,29 +855,14 @@ clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clo
|
|||||||
else
|
else
|
||||||
g_string_append_printf (string, " (no measurements last frame)");
|
g_string_append_printf (string, " (no measurements last frame)");
|
||||||
|
|
||||||
max_dispatch_lateness_us =
|
max_update_duration_us =
|
||||||
MAX (frame_clock->longterm.max_dispatch_lateness_us,
|
MAX (frame_clock->longterm_max_update_duration_us,
|
||||||
frame_clock->shortterm.max_dispatch_lateness_us);
|
frame_clock->shortterm_max_update_duration_us);
|
||||||
max_dispatch_to_swap_us =
|
|
||||||
MAX (frame_clock->longterm.max_dispatch_to_swap_us,
|
|
||||||
frame_clock->shortterm.max_dispatch_to_swap_us);
|
|
||||||
max_swap_to_rendering_done_us =
|
|
||||||
MAX (frame_clock->longterm.max_swap_to_rendering_done_us,
|
|
||||||
frame_clock->shortterm.max_swap_to_rendering_done_us);
|
|
||||||
max_swap_to_flip_us =
|
|
||||||
MAX (frame_clock->longterm.max_swap_to_flip_us,
|
|
||||||
frame_clock->shortterm.max_swap_to_flip_us);
|
|
||||||
|
|
||||||
g_string_append_printf (string, "\nVblank duration: %ld µs +",
|
g_string_append_printf (string, "\nVblank duration: %ld µs +",
|
||||||
frame_clock->vblank_duration_us);
|
frame_clock->vblank_duration_us);
|
||||||
g_string_append_printf (string, "\nDispatch lateness: %ld µs +",
|
g_string_append_printf (string, "\nUpdate duration: %ld µs +",
|
||||||
max_dispatch_lateness_us);
|
max_update_duration_us);
|
||||||
g_string_append_printf (string, "\nDispatch to swap: %ld µs +",
|
|
||||||
max_dispatch_to_swap_us);
|
|
||||||
g_string_append_printf (string, "\nmax(Swap to rendering done: %ld µs,",
|
|
||||||
max_swap_to_rendering_done_us);
|
|
||||||
g_string_append_printf (string, "\nSwap to flip: %ld µs) +",
|
|
||||||
max_swap_to_flip_us);
|
|
||||||
g_string_append_printf (string, "\nConstant: %d µs",
|
g_string_append_printf (string, "\nConstant: %d µs",
|
||||||
clutter_max_render_time_constant_us);
|
clutter_max_render_time_constant_us);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user