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.
master
Simon Ser 9 months ago
parent 836cb820d0
commit 505175e56f

@ -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, struct wlr_drm_connector *conn, struct wlr_drm_page_flip *page_flip,
uint32_t flags) { uint32_t flags) {
struct wlr_drm_backend *drm = conn->backend;
if (atom->failed) { if (atom->failed) {
return false; return false;
} }
int ret = drmModeAtomicCommit(drm->fd, atom->req, flags, page_flip); int ret = drmModeAtomicCommit(drm->fd, atom->req, flags, page_flip);
if (ret != 0) { if (ret != 0) {
wlr_drm_conn_log_errno(conn, enum wlr_log_importance log_level = WLR_ERROR;
(flags & DRM_MODE_ATOMIC_TEST_ONLY) ? WLR_DEBUG : WLR_ERROR, if (flags & DRM_MODE_ATOMIC_TEST_ONLY) {
"Atomic commit failed"); 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); char *flags_str = atomic_commit_flags_str(flags);
wlr_log(WLR_DEBUG, "(Atomic commit flags: %s)", wlr_log(WLR_DEBUG, "(Atomic commit flags: %s)",
flags_str ? flags_str : "<error>"); 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); atomic_finish(&atom);
if (ok && !test_only) { if (ok && !test_only) {
@ -392,6 +399,33 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn,
return ok; 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 = { const struct wlr_drm_interface atomic_iface = {
.crtc_commit = atomic_crtc_commit, .crtc_commit = atomic_crtc_commit,
.reset = drm_atomic_reset,
}; };

@ -131,14 +131,9 @@ static void handle_session_active(struct wl_listener *listener, void *data) {
// configurations. The connector/CRTC mapping may have changed, so // configurations. The connector/CRTC mapping may have changed, so
// first disable all CRTCs, then light up the ones we were using // first disable all CRTCs, then light up the ones we were using
// before the VT switch. // before the VT switch.
// TODO: use the atomic API to improve restoration after a VT switch // TODO: better use the atomic API to improve restoration after a VT switch
for (size_t i = 0; i < drm->num_crtcs; i++) { if (!drm->iface->reset(drm)) {
struct wlr_drm_crtc *crtc = &drm->crtcs[i]; wlr_log(WLR_ERROR, "Failed to reset state after VT switch");
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);
}
} }
struct wlr_drm_connector *conn; struct wlr_drm_connector *conn;

@ -227,6 +227,20 @@ bool drm_legacy_crtc_set_gamma(struct wlr_drm_backend *drm,
return true; 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 = { const struct wlr_drm_interface legacy_iface = {
.crtc_commit = legacy_crtc_commit, .crtc_commit = legacy_crtc_commit,
.reset = legacy_reset,
}; };

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

@ -22,6 +22,8 @@ struct wlr_drm_interface {
bool (*crtc_commit)(struct wlr_drm_connector *conn, bool (*crtc_commit)(struct wlr_drm_connector *conn,
const struct wlr_drm_connector_state *state, const struct wlr_drm_connector_state *state,
struct wlr_drm_page_flip *page_flip, uint32_t flags, bool test_only); 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; 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); size_t size, const uint16_t *lut, uint32_t *blob_id);
bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm, bool create_fb_damage_clips_blob(struct wlr_drm_backend *drm,
int width, int height, const pixman_region32_t *damage, uint32_t *blob_id); int width, int height, const pixman_region32_t *damage, uint32_t *blob_id);
bool drm_atomic_reset(struct wlr_drm_backend *drm);
#endif #endif

Loading…
Cancel
Save