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
This commit is contained in:
Kenny Levinsen 2023-10-07 19:06:09 +02:00
parent fcc55ca1d0
commit 45ba35719e

View File

@ -68,6 +68,21 @@ static bool atomic_commit(struct atomic *atom,
} }
int ret = drmModeAtomicCommit(drm->fd, atom->req, flags, drm); 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) { if (ret != 0) {
wlr_drm_conn_log_errno(conn, wlr_drm_conn_log_errno(conn,
(flags & DRM_MODE_ATOMIC_TEST_ONLY) ? WLR_DEBUG : WLR_ERROR, (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) { if (modeset) {
flags |= DRM_MODE_ATOMIC_ALLOW_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 if (!test_only && conn->pending_page_flip_crtc == 0) {
// 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.
flags |= DRM_MODE_ATOMIC_NONBLOCK; flags |= DRM_MODE_ATOMIC_NONBLOCK;
} }