diff options
author | Kenny Levinsen <kl@kl.wtf> | 2023-10-07 19:06:09 +0200 |
---|---|---|
committer | Kenny Levinsen <kl@kl.wtf> | 2023-10-10 12:44:59 +0000 |
commit | 45ba35719e874f7e8651e088c0582fe50301e731 (patch) | |
tree | f4ef77beadac1d336466ba4b7f45e0eb6dc114d2 | |
parent | fcc55ca1d0fabd9e7c29f2daeedbc9c7782f09ff (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
-rw-r--r-- | backend/drm/atomic.c | 23 |
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; } |