diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index bbb4857bf..b45e6add6 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -261,6 +261,9 @@ struct drm_backend { struct wl_event_source *pageflip_timer_counter; bool timer_armed; } perf_page_flips_stats; + + /* True if we need a workaround for some very old kernels */ + bool stale_timestamp_workaround; }; struct drm_mode { diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index c4cd19dcc..13b78c8a6 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -992,17 +992,22 @@ drm_output_start_repaint_loop(struct weston_output *output_base) * * 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 + * time, which is longer than refresh_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. + * The workaround can cause other unexpected delays when + * starting the repaint loop. + * + * We keep the workaround in place, based on the presence of + * DRM_CAP_CRTC_IN_VBLANK_EVENT, which was introduced in + * Linux 4.12, to keep things working for Very Old Kernels. + * + * Anyone needing precise frame timings is encouraged to + * upgrade. */ - if (output->base.vrr_mode == WESTON_VRR_MODE_NONE) { + if (output->backend->stale_timestamp_workaround) { struct timespec vbl2now; int64_t refresh_nsec; diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index ef00ed47d..40eef7ceb 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -1994,10 +1994,29 @@ init_kms_caps(struct drm_device *device) return -1; } + ret = drmGetCap(device->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap); + if (ret != 0) + cap = 0; + + /* Between Linux 3.16 and Linux 4.1 there was a bug that + * could result in a stale timestamp being returned. + * + * The workaround for this has can make it impossible + * to display images with precise timing. + * + * It's somewhat difficult to determine whether we need + * that workaround or not, but we know that the + * DRM_CAP_CRTC_IN_VBLANK_EVENT drm cap exists in 4.12 + * and on. We'll use its presence to gate the workaround. + */ + if (!cap) { + weston_log("DRM Warning: stale timestamp workaround for Kernel older than 4.12\n"); + device->backend->stale_timestamp_workaround = true; + } else { + device->backend->stale_timestamp_workaround = false; + } + if (!getenv("WESTON_DISABLE_ATOMIC")) { - ret = drmGetCap(device->drm.fd, DRM_CAP_CRTC_IN_VBLANK_EVENT, &cap); - if (ret != 0) - cap = 0; ret = drmSetClientCap(device->drm.fd, DRM_CLIENT_CAP_ATOMIC, 1); device->atomic_modeset = ((ret == 0) && (cap == 1)); }