aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorKenny Levinsen <kl@kl.wtf>2023-10-07 19:06:09 +0200
committerKenny Levinsen <kl@kl.wtf>2023-10-10 12:44:59 +0000
commit45ba35719e874f7e8651e088c0582fe50301e731 (patch)
treef4ef77beadac1d336466ba4b7f45e0eb6dc114d2 /backend
parentfcc55ca1d0fabd9e7c29f2daeedbc9c7782f09ff (diff)
backend/drm: Automatic non-blocking commits
We currently only perform non-blocking commits for non-modeset commits with a buffer attached. Perform non-blocking commits whenever there is no pending pageflip event. If a non-blocking modeset commit fails, which can happen if the driver implicitly added more CRTCs to the commit that we did not know we had to wait for, retry with a blocking commit. References: https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/2239
Diffstat (limited to 'backend')
-rw-r--r--backend/drm/atomic.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c
index 4715c6f0..255da7ea 100644
--- a/backend/drm/atomic.c
+++ b/backend/drm/atomic.c
@@ -68,6 +68,21 @@ static bool atomic_commit(struct atomic *atom,
}
int ret = drmModeAtomicCommit(drm->fd, atom->req, flags, drm);
+
+ // A non-blocking commit will fail with EBUSY if a commit is already in
+ // progress for the affected CRTCs, and the caller is responsible for
+ // waiting for page_flip events before queuing more non-blocking commits.
+ //
+ // The driver may implicitly add more CRTCs to our commit for e.g. resource
+ // reallocation, and in that case we have no chance of waiting for the
+ // right page_flip events. Retry with a blocking commit when this happens.
+ if (ret == -EBUSY &&
+ (flags & DRM_MODE_ATOMIC_NONBLOCK) &&
+ (flags & DRM_MODE_ATOMIC_ALLOW_MODESET)) {
+ flags &= ~DRM_MODE_ATOMIC_NONBLOCK;
+ ret = drmModeAtomicCommit(drm->fd, atom->req, flags, drm);
+ }
+
if (ret != 0) {
wlr_drm_conn_log_errno(conn,
(flags & DRM_MODE_ATOMIC_TEST_ONLY) ? WLR_DEBUG : WLR_ERROR,
@@ -314,12 +329,8 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn,
}
if (modeset) {
flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
- } else if (!test_only && (state->base->committed & WLR_OUTPUT_STATE_BUFFER)) {
- // The wlr_output API requires non-modeset commits with a new buffer to
- // wait for the frame event. However compositors often perform
- // non-modesets commits without a new buffer without waiting for the
- // frame event. In that case we need to make the KMS commit blocking,
- // otherwise the kernel will error out with EBUSY.
+ }
+ if (!test_only && conn->pending_page_flip_crtc == 0) {
flags |= DRM_MODE_ATOMIC_NONBLOCK;
}