From 505175e56f42700649158bfd4ad622860ceaa80b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Wed, 14 Feb 2024 18:54:01 +0100 Subject: [PATCH] backend/drm: atomically reset state after VT switch Allows the KMS driver to parallelize the modesets, so should be faster than going through each CRTC one by one. --- backend/drm/atomic.c | 46 ++++++++++++++++++++++++++++++++----- backend/drm/backend.c | 11 +++------ backend/drm/legacy.c | 14 +++++++++++ backend/drm/libliftoff.c | 1 + include/backend/drm/iface.h | 3 +++ 5 files changed, 61 insertions(+), 14 deletions(-) diff --git a/backend/drm/atomic.c b/backend/drm/atomic.c index dcad7d3d..6588bdc0 100644 --- a/backend/drm/atomic.c +++ b/backend/drm/atomic.c @@ -61,19 +61,26 @@ static void atomic_begin(struct atomic *atom) { } } -static bool atomic_commit(struct atomic *atom, +static bool atomic_commit(struct atomic *atom, struct wlr_drm_backend *drm, struct wlr_drm_connector *conn, struct wlr_drm_page_flip *page_flip, uint32_t flags) { - struct wlr_drm_backend *drm = conn->backend; if (atom->failed) { return false; } int ret = drmModeAtomicCommit(drm->fd, atom->req, flags, page_flip); if (ret != 0) { - wlr_drm_conn_log_errno(conn, - (flags & DRM_MODE_ATOMIC_TEST_ONLY) ? WLR_DEBUG : WLR_ERROR, - "Atomic commit failed"); + enum wlr_log_importance log_level = WLR_ERROR; + if (flags & DRM_MODE_ATOMIC_TEST_ONLY) { + log_level = WLR_DEBUG; + } + + if (conn != NULL) { + wlr_drm_conn_log_errno(conn, log_level, "Atomic commit failed"); + } else { + wlr_log_errno(log_level, "Atomic commit failed"); + } + char *flags_str = atomic_commit_flags_str(flags); wlr_log(WLR_DEBUG, "(Atomic commit flags: %s)", flags_str ? flags_str : ""); @@ -369,7 +376,7 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, } } - bool ok = atomic_commit(&atom, conn, page_flip, flags); + bool ok = atomic_commit(&atom, drm, conn, page_flip, flags); atomic_finish(&atom); if (ok && !test_only) { @@ -392,6 +399,33 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn, return ok; } +bool drm_atomic_reset(struct wlr_drm_backend *drm) { + struct atomic atom; + atomic_begin(&atom); + + for (size_t i = 0; i < drm->num_crtcs; i++) { + struct wlr_drm_crtc *crtc = &drm->crtcs[i]; + atomic_add(&atom, crtc->id, crtc->props.mode_id, 0); + atomic_add(&atom, crtc->id, crtc->props.active, 0); + } + + struct wlr_drm_connector *conn; + wl_list_for_each(conn, &drm->connectors, link) { + atomic_add(&atom, conn->id, conn->props.crtc_id, 0); + } + + for (size_t i = 0; i < drm->num_planes; i++) { + plane_disable(&atom, &drm->planes[i]); + } + + uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET; + bool ok = atomic_commit(&atom, drm, NULL, NULL, flags); + atomic_finish(&atom); + + return ok; +} + const struct wlr_drm_interface atomic_iface = { .crtc_commit = atomic_crtc_commit, + .reset = drm_atomic_reset, }; diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 84ae3738..43bfd9da 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -131,14 +131,9 @@ static void handle_session_active(struct wl_listener *listener, void *data) { // configurations. The connector/CRTC mapping may have changed, so // first disable all CRTCs, then light up the ones we were using // before the VT switch. - // TODO: use the atomic API to improve restoration after a VT switch - for (size_t i = 0; i < drm->num_crtcs; i++) { - struct wlr_drm_crtc *crtc = &drm->crtcs[i]; - - if (drmModeSetCrtc(drm->fd, crtc->id, 0, 0, 0, NULL, 0, NULL) != 0) { - wlr_log_errno(WLR_ERROR, "Failed to disable CRTC %"PRIu32" after VT switch", - crtc->id); - } + // TODO: better use the atomic API to improve restoration after a VT switch + if (!drm->iface->reset(drm)) { + wlr_log(WLR_ERROR, "Failed to reset state after VT switch"); } struct wlr_drm_connector *conn; diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c index 1c9ff46d..1e62f61f 100644 --- a/backend/drm/legacy.c +++ b/backend/drm/legacy.c @@ -227,6 +227,20 @@ bool drm_legacy_crtc_set_gamma(struct wlr_drm_backend *drm, return true; } +static bool legacy_reset(struct wlr_drm_backend *drm) { + bool ok = true; + for (size_t i = 0; i < drm->num_crtcs; i++) { + struct wlr_drm_crtc *crtc = &drm->crtcs[i]; + if (drmModeSetCrtc(drm->fd, crtc->id, 0, 0, 0, NULL, 0, NULL) != 0) { + wlr_log_errno(WLR_ERROR, "Failed to disable CRTC %"PRIu32, + crtc->id); + ok = false; + } + } + return ok; +} + const struct wlr_drm_interface legacy_iface = { .crtc_commit = legacy_crtc_commit, + .reset = legacy_reset, }; diff --git a/backend/drm/libliftoff.c b/backend/drm/libliftoff.c index a39f2493..534e5ef2 100644 --- a/backend/drm/libliftoff.c +++ b/backend/drm/libliftoff.c @@ -506,4 +506,5 @@ const struct wlr_drm_interface liftoff_iface = { .init = init, .finish = finish, .crtc_commit = crtc_commit, + .reset = drm_atomic_reset, }; diff --git a/include/backend/drm/iface.h b/include/backend/drm/iface.h index 2a90c4b5..6408c440 100644 --- a/include/backend/drm/iface.h +++ b/include/backend/drm/iface.h @@ -22,6 +22,8 @@ struct wlr_drm_interface { bool (*crtc_commit)(struct wlr_drm_connector *conn, const struct wlr_drm_connector_state *state, struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only); + // Turn off everything + bool (*reset)(struct wlr_drm_backend *drm); }; extern const struct wlr_drm_interface atomic_iface; @@ -37,5 +39,6 @@ bool create_gamma_lut_blob(struct wlr_drm_backend *drm, size_t size, const uint16_t *lut, uint32_t *blob_id); bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm, int width, int height, const pixman_region32_t *damage, uint32_t *blob_id); +bool drm_atomic_reset(struct wlr_drm_backend *drm); #endif