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. */
|
||||
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;
|
||||
|
||||
/* Short & long term maximum values */
|
||||
struct {
|
||||
/* Duration between desired and effective dispatch start. */
|
||||
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;
|
||||
/* Long-term maximum update duration */
|
||||
int64_t longterm_max_update_duration_us;
|
||||
/* Short-term maximum update duration */
|
||||
int64_t shortterm_max_update_duration_us;
|
||||
|
||||
/* If we got new measurements last frame. */
|
||||
gboolean got_measurements_last_frame;
|
||||
@ -224,20 +216,33 @@ maybe_reschedule_update (ClutterFrameClock *frame_clock)
|
||||
}
|
||||
|
||||
static void
|
||||
update_longterm_max (int64_t *longterm_max,
|
||||
int64_t *shortterm_max)
|
||||
maybe_update_longterm_max_duration_us (ClutterFrameClock *frame_clock,
|
||||
ClutterFrameInfo *frame_info)
|
||||
{
|
||||
/* Do not update long term max if there has been no measurement in over a second. */
|
||||
if (!*shortterm_max)
|
||||
/* Do not update long-term max if there has been no measurement */
|
||||
if (!frame_clock->shortterm_max_update_duration_us)
|
||||
return;
|
||||
|
||||
if (*longterm_max > *shortterm_max)
|
||||
/* Exponential drop-off toward the short term max */
|
||||
*longterm_max -= (*longterm_max - *shortterm_max) / 2;
|
||||
else
|
||||
*longterm_max = *shortterm_max;
|
||||
if ((frame_info->presentation_time - frame_clock->longterm_promotion_us) <
|
||||
G_USEC_PER_SEC)
|
||||
return;
|
||||
|
||||
*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
|
||||
@ -343,12 +348,12 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
|
||||
swap_to_rendering_done_us,
|
||||
swap_to_flip_us);
|
||||
|
||||
frame_clock->shortterm.max_dispatch_to_swap_us =
|
||||
MAX (frame_clock->shortterm.max_dispatch_to_swap_us, dispatch_to_swap_us);
|
||||
frame_clock->shortterm.max_swap_to_rendering_done_us =
|
||||
MAX (frame_clock->shortterm.max_swap_to_rendering_done_us, swap_to_rendering_done_us);
|
||||
frame_clock->shortterm.max_swap_to_flip_us =
|
||||
MAX (frame_clock->shortterm.max_swap_to_flip_us, swap_to_flip_us);
|
||||
frame_clock->shortterm_max_update_duration_us =
|
||||
MAX (frame_clock->shortterm_max_update_duration_us,
|
||||
frame_clock->last_dispatch_lateness_us + dispatch_to_swap_us +
|
||||
MAX (swap_to_rendering_done_us, swap_to_flip_us));
|
||||
|
||||
maybe_update_longterm_max_duration_us (frame_clock, frame_info);
|
||||
|
||||
frame_clock->got_measurements_last_frame = 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
||||
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))
|
||||
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
|
||||
* to make it to the predicted next presentation time. It is composed of:
|
||||
* - An estimate of dispatch start lateness.
|
||||
* - An estimate of duration from dispatch start to buffer swap.
|
||||
* - Maximum between estimates of duration from buffer swap to GPU rendering
|
||||
* finish and duration from buffer swap to buffer submission to KMS. This
|
||||
* is because both of these things need to happen before the vblank, and
|
||||
* they are done in parallel.
|
||||
* - Duration of the vblank.
|
||||
* to make it to the predicted next presentation time. It is an estimate of
|
||||
* the total update duration, which is composed of:
|
||||
* - Dispatch start lateness.
|
||||
* - The duration from dispatch start to buffer swap.
|
||||
* - The maximum of duration from buffer swap to GPU rendering finish and
|
||||
* duration from buffer swap to buffer submission to KMS. This is because
|
||||
* both of these things need to happen before the vblank, and they are done
|
||||
* in parallel.
|
||||
* - The duration of vertical blank.
|
||||
* - A constant to account for variations in the above estimates.
|
||||
*/
|
||||
max_render_time_us =
|
||||
max_dispatch_lateness_us +
|
||||
max_dispatch_to_swap_us +
|
||||
MAX (max_swap_to_rendering_done_us, max_swap_to_flip_us) +
|
||||
MAX (frame_clock->longterm_max_update_duration_us,
|
||||
frame_clock->shortterm_max_update_duration_us) +
|
||||
frame_clock->vblank_duration_us +
|
||||
clutter_max_render_time_constant_us;
|
||||
|
||||
@ -764,10 +738,6 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
|
||||
else
|
||||
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)))
|
||||
{
|
||||
int64_t dispatch_interval_us, jitter_us;
|
||||
@ -873,10 +843,7 @@ clutter_frame_clock_record_flip_time (ClutterFrameClock *frame_clock,
|
||||
GString *
|
||||
clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock)
|
||||
{
|
||||
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_update_duration_us;
|
||||
GString *string;
|
||||
|
||||
string = g_string_new (NULL);
|
||||
@ -888,29 +855,14 @@ clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clo
|
||||
else
|
||||
g_string_append_printf (string, " (no measurements last frame)");
|
||||
|
||||
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_update_duration_us =
|
||||
MAX (frame_clock->longterm_max_update_duration_us,
|
||||
frame_clock->shortterm_max_update_duration_us);
|
||||
|
||||
g_string_append_printf (string, "\nVblank duration: %ld µs +",
|
||||
frame_clock->vblank_duration_us);
|
||||
g_string_append_printf (string, "\nDispatch lateness: %ld µs +",
|
||||
max_dispatch_lateness_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, "\nUpdate duration: %ld µs +",
|
||||
max_update_duration_us);
|
||||
g_string_append_printf (string, "\nConstant: %d µs",
|
||||
clutter_max_render_time_constant_us);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user