summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichel Dänzer <mdaenzer@redhat.com>2022-07-04 15:15:59 +0200
committerMarge Bot <marge-bot@gnome.org>2022-12-17 23:45:19 +0000
commit99850f46459f5371a1edd0889b90b55d2c588f21 (patch)
treea3037942e0c399b171687ddd199713724daca518
parentca988951854ec30cdf92e631261079f9ae4ecc8c (diff)
downloadmutter-99850f46459f5371a1edd0889b90b55d2c588f21.tar.gz
clutter/frame-clock: Use dispatch lateness for dynamic max render time
Dispatch lateness is the difference between when we wanted frame clock dispatch to run and when it actually started running. This can be up to 1ms even under normal circumstances due to process scheduling granularity, or even higher under load. This keeps track of dispatch lateness of the last 16 frame clock dispatches, and incorporates the maximum into the dynamic render time estimate. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2500>
-rw-r--r--clutter/clutter/clutter-frame-clock.c38
1 files changed, 34 insertions, 4 deletions
diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c
index 4d441c364..4361df704 100644
--- a/clutter/clutter/clutter-frame-clock.c
+++ b/clutter/clutter/clutter-frame-clock.c
@@ -85,6 +85,7 @@ struct _ClutterFrameClock
int64_t last_dispatch_time_us;
int64_t last_dispatch_lateness_us;
int64_t last_presentation_time_us;
+ int64_t next_update_time_us;
gboolean is_next_presentation_time_valid;
int64_t next_presentation_time_us;
@@ -96,6 +97,8 @@ struct _ClutterFrameClock
/* Last KMS buffer submission time. */
int64_t last_flip_time_us;
+ /* Last few durations between desired and effective dispatch start. */
+ EstimateQueue dispatch_lateness_us;
/* Last few durations between dispatch start and buffer swap. */
EstimateQueue dispatch_to_swap_us;
/* Last few durations between buffer swap and GPU rendering finish. */
@@ -273,6 +276,9 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
if (frame_info->presentation_time > 0)
frame_clock->last_presentation_time_us = frame_info->presentation_time;
+ estimate_queue_add_value (&frame_clock->dispatch_lateness_us,
+ frame_clock->last_dispatch_lateness_us);
+
frame_clock->got_measurements_last_frame = FALSE;
if (frame_info->cpu_time_before_buffer_swap_us != 0 &&
@@ -290,7 +296,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
frame_info->cpu_time_before_buffer_swap_us;
CLUTTER_NOTE (FRAME_TIMINGS,
- "dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs",
+ "update2dispatch %ld µs, dispatch2swap %ld µs, swap2render %ld µs, swap2flip %ld µs",
+ frame_clock->last_dispatch_lateness_us,
dispatch_to_swap_us,
swap_to_rendering_done_us,
swap_to_flip_us);
@@ -304,6 +311,11 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
frame_clock->got_measurements_last_frame = TRUE;
}
+ else
+ {
+ CLUTTER_NOTE (FRAME_TIMINGS, "update2dispatch %ld µs",
+ frame_clock->last_dispatch_lateness_us);
+ }
if (frame_info->refresh_rate > 1.0)
{
@@ -350,6 +362,7 @@ 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 = 0;
int64_t max_dispatch_to_swap_us = 0;
int64_t max_swap_to_rendering_done_us = 0;
int64_t max_swap_to_flip_us = 0;
@@ -365,6 +378,9 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
for (i = 0; i < ESTIMATE_QUEUE_LENGTH; ++i)
{
+ max_dispatch_lateness_us =
+ MAX (max_dispatch_lateness_us,
+ frame_clock->dispatch_lateness_us.values[i]);
max_dispatch_to_swap_us =
MAX (max_dispatch_to_swap_us,
frame_clock->dispatch_to_swap_us.values[i]);
@@ -378,6 +394,7 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
/* 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
@@ -387,6 +404,7 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
* - 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) +
frame_clock->vblank_duration_us +
@@ -612,6 +630,7 @@ clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
g_warn_if_fail (next_update_time_us != -1);
+ frame_clock->next_update_time_us = next_update_time_us;
g_source_set_ready_time (frame_clock->source, next_update_time_us);
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
frame_clock->is_next_presentation_time_valid = FALSE;
@@ -650,6 +669,7 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
g_warn_if_fail (next_update_time_us != -1);
+ frame_clock->next_update_time_us = next_update_time_us;
g_source_set_ready_time (frame_clock->source, next_update_time_us);
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_SCHEDULED;
}
@@ -672,9 +692,13 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
this_dispatch_time_us = time_us;
#endif
- ideal_dispatch_time_us = (frame_clock->last_dispatch_time_us -
- frame_clock->last_dispatch_lateness_us) +
- frame_clock->refresh_interval_us;
+
+ ideal_dispatch_time_us = frame_clock->next_update_time_us;
+
+ if (ideal_dispatch_time_us <= 0)
+ ideal_dispatch_time_us = (frame_clock->last_dispatch_time_us -
+ frame_clock->last_dispatch_lateness_us) +
+ frame_clock->refresh_interval_us;
lateness_us = time_us - ideal_dispatch_time_us;
if (lateness_us < 0 || lateness_us >= frame_clock->refresh_interval_us)
@@ -770,6 +794,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 = 0;
int64_t max_dispatch_to_swap_us = 0;
int64_t max_swap_to_rendering_done_us = 0;
int64_t max_swap_to_flip_us = 0;
@@ -787,6 +812,9 @@ clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clo
for (i = 0; i < ESTIMATE_QUEUE_LENGTH; ++i)
{
+ max_dispatch_lateness_us =
+ MAX (max_dispatch_lateness_us,
+ frame_clock->dispatch_lateness_us.values[i]);
max_dispatch_to_swap_us =
MAX (max_dispatch_to_swap_us,
frame_clock->dispatch_to_swap_us.values[i]);
@@ -800,6 +828,8 @@ clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clo
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,",