summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerek Foreman <derek.foreman@collabora.com>2025-04-14 10:48:04 -0500
committerDaniel Stone <daniels@collabora.com>2025-06-27 14:51:49 +0100
commit5a48cedc7b8421d8342dd6a943705955217b0fd1 (patch)
treea233bb5db506f22c73ed0c0f0c645d4c3f64d171
parent2d34d3289386831147c78c866b0808cdac9b19b0 (diff)
drm: Improve VRR timing at start of repaint loopHEADmain
There was an old kernel bug where the drm driver could give us a stale timestamp. We worked around this by performing a page flip at the start of the repaint loop. Now that we support VRR, when we don't render our refresh rate drops to the display's lowest possible refresh rate. This leaves us with a race where the repaint loop could be started between the mode's refresh rate and the lowest possible VRR rate - which is indistinguishable from a stale timestamp. In this case we'd perform a needless page flip and potentially miss an opportunity to render. The kernel bug was introduced in v3.16 in commit 844b03f27739135 and later fixed in v4.1 in commit fdb68e09bbb1c98 Since the vrr_capable property was introduced in v4.20 in commit ba1b0f6c73d4ea1, any kernel that supports VRR is new enough not to give us stale timestamps, so we don't have to miss these opportunities. Signed-off-by: Derek Foreman <derek.foreman@collabora.com>
-rw-r--r--libweston/backend-drm/drm.c44
1 files changed, 33 insertions, 11 deletions
diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c
index 712eb61d..14fc0c16 100644
--- a/libweston/backend-drm/drm.c
+++ b/libweston/backend-drm/drm.c
@@ -916,8 +916,6 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
struct drm_backend *backend = device->backend;
struct weston_compositor *compositor = backend->compositor;
struct timespec ts, tnow;
- struct timespec vbl2now;
- int64_t refresh_nsec;
uint32_t flags = WP_PRESENTATION_FEEDBACK_INVALID;
int ret;
drmVBlank vbl = {
@@ -958,19 +956,43 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
/* Error ret or zero timestamp means failure to get valid timestamp */
if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
+ bool stale_timestamp = false;
+
ts.tv_sec = vbl.reply.tval_sec;
ts.tv_nsec = vbl.reply.tval_usec * 1000;
- /* Valid timestamp for most recent vblank - not stale?
- * Stale ts could happen on Linux 3.17+, so make sure it
- * is not older than 1 refresh duration since now.
+ /* Between Linux 3.16 and Linux 4.1 there was a bug that
+ * could result in a stale timestamp being returned. We
+ * can catch that by checking if the timestamp we have
+ * is older than 1 refresh duration since now, and use a
+ * page flip to start the repaint loop.
+ *
+ * However, if we're using VRR, the time since the last
+ * vblank could be the display's longest possible frame
+ * time, which is longer than rfresh_nsec. That looks
+ * exactly like the bug we need to work around here, and
+ * the page flip workaround would result in an unnecessary
+ * delay.
+ *
+ * We know that the kernel bug was fixed in v4.1, before the
+ * much later introduction of the vrr_capable property we
+ * use to detect VRR. So we only need the bug fix if we don't
+ * have VRR.
*/
- weston_compositor_read_presentation_clock(compositor,
- &tnow);
- timespec_sub(&vbl2now, &tnow, &ts);
- refresh_nsec =
- millihz_to_nsec(output->base.current_mode->refresh);
- if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
+ if (output->base.vrr_mode == WESTON_VRR_MODE_NONE) {
+ struct timespec vbl2now;
+ int64_t refresh_nsec;
+
+ weston_compositor_read_presentation_clock(compositor,
+ &tnow);
+ timespec_sub(&vbl2now, &tnow, &ts);
+ refresh_nsec =
+ millihz_to_nsec(output->base.current_mode->refresh);
+ if (timespec_to_nsec(&vbl2now) > refresh_nsec)
+ stale_timestamp = true;
+ }
+
+ if (!stale_timestamp) {
drm_output_update_msc(output, vbl.reply.sequence);
weston_output_finish_frame(output_base, &ts, flags);
return 0;