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. So when TIMESTAMP_QUERY support is missing we now take the same path as if presentation timestamps are missing (introduced in 56fc09151d and improved in 0555a5bbc1), which has the benefit of naturally switching from double to triple buffering as required without actually having to measure render times. 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. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1441>
This commit is contained in:
parent
2dbca5ff39
commit
f06913a2d1
@ -616,25 +616,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
|
||||
@ -648,15 +641,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
|
||||
@ -674,12 +667,19 @@ 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 ();
|
||||
|
||||
refresh_interval_us = frame_clock->refresh_interval_us;
|
||||
|
||||
if (!last_presentation || last_presentation->presentation_time_us == 0)
|
||||
max_render_time_is_known =
|
||||
clutter_frame_clock_compute_max_render_time_us (frame_clock,
|
||||
&max_render_time_allowed_us);
|
||||
|
||||
if (!last_presentation ||
|
||||
!max_render_time_is_known ||
|
||||
last_presentation->presentation_time_us == 0)
|
||||
{
|
||||
const Frame *last_dispatch = frame_clock->prev_dispatch;
|
||||
|
||||
@ -695,8 +695,6 @@ 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)
|
||||
min_render_time_allowed_us = max_render_time_allowed_us;
|
||||
@ -854,7 +852,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;
|
||||
|
||||
@ -869,9 +870,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;
|
||||
|
||||
@ -1203,8 +1201,12 @@ clutter_frame_clock_schedule_update_later (ClutterFrameClock *frame_clock,
|
||||
ready_time_us = extrapolated_presentation_time_us - max_render_time_us;
|
||||
break;
|
||||
case CLUTTER_FRAME_CLOCK_MODE_VARIABLE:
|
||||
max_render_time_us =
|
||||
clutter_frame_clock_compute_max_render_time_us (frame_clock);
|
||||
if (!clutter_frame_clock_compute_max_render_time_us (frame_clock,
|
||||
&max_render_time_us))
|
||||
{
|
||||
max_render_time_us = (int64_t) (frame_clock->refresh_interval_us *
|
||||
SYNC_DELAY_FALLBACK_FRACTION);
|
||||
}
|
||||
ready_time_us = target_us - max_render_time_us;
|
||||
break;
|
||||
}
|
||||
@ -1462,12 +1464,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…
x
Reference in New Issue
Block a user