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.
This commit is contained in:
Simon Ser 2024-02-14 18:54:01 +01:00
parent 836cb820d0
commit 505175e56f
5 changed files with 61 additions and 14 deletions

View file

@ -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 : "<error>");
@ -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,
};

View file

@ -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;

View file

@ -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,
};

View file

@ -506,4 +506,5 @@ const struct wlr_drm_interface liftoff_iface = {
.init = init,
.finish = finish,
.crtc_commit = crtc_commit,
.reset = drm_atomic_reset,
};

View file

@ -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