backend/drm: implement KMS state snapshot/restore

Following ideas from [1], snapshot the entire KMS state when the VT
is switched away, and restore it when the VT is switched back.

> Well the neat trick is that userspace doesn’t need to be able to
> understand properties to save and restore them - the actual property
> value transport between kernel and userspace is fully generic.

That way, even if another DRM master changes a property we don't
understand like CTM or HDR_OUTPUT_METADATA, we can switch it back
and avoid getting garbage on screen.

[1]: https://blog.ffwll.ch/2016/01/vt-switching-with-atomic-modeset.html
This commit is contained in:
Simon Ser 2022-10-18 18:23:55 +02:00
parent e0b2bf2a6b
commit f0bb53c4ab
7 changed files with 155 additions and 20 deletions

View file

@ -342,6 +342,33 @@ static bool atomic_crtc_commit(struct wlr_drm_connector *conn,
return ok;
}
static bool atomic_snapshot_state(struct wlr_drm_backend *drm) {
drmModeAtomicFree(drm->atomic_snapshot);
drm->atomic_snapshot = snapshot_drm_state(drm->fd);
return drm->atomic_snapshot != NULL;
}
static bool atomic_restore_state(struct wlr_drm_backend *drm) {
if (drm->atomic_snapshot == NULL) {
wlr_log(WLR_DEBUG, "No atomic snapshot, falling back to legacy state restoration");
return legacy_restore_state(drm);
}
uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
int ret = drmModeAtomicCommit(drm->fd, drm->atomic_snapshot, flags, NULL);
if (ret != 0) {
wlr_log_errno(WLR_ERROR, "drmModeAtomicCommit failed");
return false;
}
drmModeAtomicFree(drm->atomic_snapshot);
drm->atomic_snapshot = NULL;
return true;
}
const struct wlr_drm_interface atomic_iface = {
.crtc_commit = atomic_crtc_commit,
.snapshot_state = atomic_snapshot_state,
.restore_state = atomic_restore_state,
};