clutter/frame-clock: Optimize latency for platforms missing TIMESTAMP_QUERY
Previously if we had no measurements then `compute_max_render_time_us` would pessimise its answer to ensure triple buffering could be reached: ``` if (frame_clock->state == CLUTTER_FRAME_CLOCK_STATE_DISPATCHED_ONE) ret += refresh_interval_us; ``` But that also meant entering triple buffering even when not required. Now we make `compute_max_render_time_us` more honest and return failure if the answer isn't known (or is disabled). This in turn allows us to optimize `calculate_next_update_time_us` for this special case, ensuring triple buffering can be used, but isn't blindly always used. This makes a visible difference to the latency when dragging windows in Xorg, but will also help Wayland sessions on platforms lacking TIMESTAMP_QUERY such as Raspberry Pi. (cherry picked from commit 7852451a9e93f5116fa853350020a318d31cb710) Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1441> Signed-off-by: Mingi Sung <sungmg@saltyming.net>
This commit is contained in:
parent
d7b8793f34
commit
f2290877be
1 changed files with 46 additions and 24 deletions
|
@ -563,25 +563,18 @@ clutter_frame_clock_notify_ready (ClutterFrameClock *frame_clock)
|
|||
}
|
||||
}
|
||||
|
||||
static int64_t
|
||||
clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
|
||||
static gboolean
|
||||
clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock,
|
||||
int64_t *max_render_time_us)
|
||||
{
|
||||
int64_t refresh_interval_us;
|
||||
int64_t max_render_time_us;
|
||||
|
||||
refresh_interval_us = frame_clock->refresh_interval_us;
|
||||
|
||||
if (!frame_clock->ever_got_measurements ||
|
||||
G_UNLIKELY (clutter_paint_debug_flags &
|
||||
CLUTTER_DEBUG_DISABLE_DYNAMIC_MAX_RENDER_TIME))
|
||||
{
|
||||
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;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
/* 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
|
||||
|
@ -595,15 +588,15 @@ clutter_frame_clock_compute_max_render_time_us (ClutterFrameClock *frame_clock)
|
|||
* - The duration of vertical blank.
|
||||
* - A constant to account for variations in the above estimates.
|
||||
*/
|
||||
max_render_time_us =
|
||||
*max_render_time_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;
|
||||
|
||||
max_render_time_us = CLAMP (max_render_time_us, 0, 2 * refresh_interval_us);
|
||||
*max_render_time_us = CLAMP (*max_render_time_us, 0, 2 * refresh_interval_us);
|
||||
|
||||
return max_render_time_us;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -621,6 +614,7 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
|
|||
int64_t next_presentation_time_us;
|
||||
int64_t next_smooth_presentation_time_us = 0;
|
||||
int64_t next_update_time_us;
|
||||
gboolean max_render_time_is_known;
|
||||
|
||||
now_us = g_get_monotonic_time ();
|
||||
|
||||
|
@ -642,10 +636,13 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
|
|||
}
|
||||
|
||||
min_render_time_allowed_us = refresh_interval_us / 2;
|
||||
max_render_time_allowed_us =
|
||||
clutter_frame_clock_compute_max_render_time_us (frame_clock);
|
||||
|
||||
if (min_render_time_allowed_us > max_render_time_allowed_us)
|
||||
max_render_time_is_known =
|
||||
clutter_frame_clock_compute_max_render_time_us (frame_clock,
|
||||
&max_render_time_allowed_us);
|
||||
|
||||
if (max_render_time_is_known &&
|
||||
min_render_time_allowed_us > max_render_time_allowed_us)
|
||||
min_render_time_allowed_us = max_render_time_allowed_us;
|
||||
|
||||
/*
|
||||
|
@ -767,6 +764,24 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
|
|||
}
|
||||
else
|
||||
{
|
||||
/* If the max render time isn't known then using the current value of
|
||||
* next_presentation_time_us is suboptimal. Targeting always one frame
|
||||
* prior to that we'd lose the ability to scale up to triple buffering
|
||||
* on late presentation. But targeting two frames prior we would be
|
||||
* always triple buffering even when not required.
|
||||
* So the algorithm for deciding when to scale up to triple buffering
|
||||
* in the absence of render time measurements is to simply target full
|
||||
* frame rate. If we're keeping up then we'll stay double buffering. If
|
||||
* we're not keeping up then this will switch us to triple buffering.
|
||||
*/
|
||||
if (!max_render_time_is_known)
|
||||
{
|
||||
max_render_time_allowed_us =
|
||||
(int64_t) (refresh_interval_us * SYNC_DELAY_FALLBACK_FRACTION);
|
||||
next_presentation_time_us =
|
||||
last_presentation_time_us + refresh_interval_us;
|
||||
}
|
||||
|
||||
while (next_presentation_time_us - min_render_time_allowed_us < now_us)
|
||||
next_presentation_time_us += refresh_interval_us;
|
||||
|
||||
|
@ -799,7 +814,10 @@ calculate_next_variable_update_time_us (ClutterFrameClock *frame_clock,
|
|||
|
||||
refresh_interval_us = frame_clock->refresh_interval_us;
|
||||
|
||||
if (!last_presentation || last_presentation->presentation_time_us == 0)
|
||||
if (!last_presentation ||
|
||||
last_presentation->presentation_time_us == 0 ||
|
||||
!clutter_frame_clock_compute_max_render_time_us (frame_clock,
|
||||
&max_render_time_allowed_us))
|
||||
{
|
||||
const Frame *last_dispatch = frame_clock->prev_dispatch;
|
||||
|
||||
|
@ -814,9 +832,6 @@ calculate_next_variable_update_time_us (ClutterFrameClock *frame_clock,
|
|||
return;
|
||||
}
|
||||
|
||||
max_render_time_allowed_us =
|
||||
clutter_frame_clock_compute_max_render_time_us (frame_clock);
|
||||
|
||||
last_presentation_time_us = last_presentation->presentation_time_us;
|
||||
next_presentation_time_us = last_presentation_time_us + refresh_interval_us;
|
||||
|
||||
|
@ -1316,12 +1331,19 @@ GString *
|
|||
clutter_frame_clock_get_max_render_time_debug_info (ClutterFrameClock *frame_clock)
|
||||
{
|
||||
const Frame *last_presentation = frame_clock->prev_presentation;
|
||||
int64_t max_render_time_us;
|
||||
int64_t max_update_duration_us;
|
||||
GString *string;
|
||||
|
||||
string = g_string_new (NULL);
|
||||
g_string_append_printf (string, "Max render time: %ld µs",
|
||||
clutter_frame_clock_compute_max_render_time_us (frame_clock));
|
||||
string = g_string_new ("Max render time: ");
|
||||
if (!clutter_frame_clock_compute_max_render_time_us (frame_clock,
|
||||
&max_render_time_us))
|
||||
{
|
||||
g_string_append (string, "unknown");
|
||||
return string;
|
||||
}
|
||||
|
||||
g_string_append_printf (string, "%ld µs", max_render_time_us);
|
||||
|
||||
if (last_presentation && last_presentation->got_measurements)
|
||||
g_string_append_printf (string, " =");
|
||||
|
|
Loading…
Reference in a new issue