diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 7f93e7550..f758eb6ed 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -117,11 +117,18 @@ static void handle_session_active(struct wl_listener *listener, void *data) { wlr_log(WLR_INFO, "DRM FD %s", session->active ? "resumed" : "paused"); if (!session->active) { + // Disconnect any active connectors so that the client will modeset and + // rerender when the session is activated again. + struct wlr_drm_connector *conn; + wl_list_for_each(conn, &drm->connectors, link) { + if (conn->status == DRM_MODE_CONNECTED) { + wlr_output_destroy(&conn->output); + } + } return; } scan_drm_connectors(drm, NULL); - restore_drm_device(drm); } static void handle_dev_change(struct wl_listener *listener, void *data) { diff --git a/backend/drm/drm.c b/backend/drm/drm.c index d70492af1..dcd9f3af1 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1851,108 +1851,6 @@ void scan_drm_leases(struct wlr_drm_backend *drm) { drmFree(list); } -static void build_current_connector_state(struct wlr_output_state *state, - struct wlr_drm_connector *conn) { - bool enabled = conn->status != DRM_MODE_DISCONNECTED && conn->output.enabled; - - wlr_output_state_init(state); - wlr_output_state_set_enabled(state, enabled); - if (!enabled) { - return; - } - - if (conn->output.current_mode != NULL) { - wlr_output_state_set_mode(state, conn->output.current_mode); - } else { - wlr_output_state_set_custom_mode(state, - conn->output.width, conn->output.height, conn->output.refresh); - } -} - -/** - * Check whether we need to perform a full reset after a VT switch. - * - * If any connector or plane has a different CRTC, we need to perform a full - * reset to restore our mapping. We couldn't avoid a full reset even if we - * used a single KMS atomic commit to apply our state: the kernel rejects - * commits which migrate a plane from one CRTC to another without going through - * an intermediate state where the plane is disabled. - */ -static bool skip_reset_for_restore(struct wlr_drm_backend *drm) { - struct wlr_drm_connector *conn; - wl_list_for_each(conn, &drm->connectors, link) { - drmModeConnector *drm_conn = drmModeGetConnectorCurrent(drm->fd, conn->id); - if (drm_conn == NULL) { - return false; - } - struct wlr_drm_crtc *crtc = connector_get_current_crtc(conn, drm_conn); - drmModeFreeConnector(drm_conn); - - if (crtc != NULL && conn->crtc != crtc) { - return false; - } - } - - for (size_t i = 0; i < drm->num_planes; i++) { - struct wlr_drm_plane *plane = &drm->planes[i]; - - drmModePlane *drm_plane = drmModeGetPlane(drm->fd, plane->id); - if (drm_plane == NULL) { - return false; - } - uint32_t crtc_id = drm_plane->crtc_id; - drmModeFreePlane(drm_plane); - - struct wlr_drm_crtc *crtc = NULL; - for (size_t i = 0; i < drm->num_crtcs; i++) { - if (drm->crtcs[i].id == crtc_id) { - crtc = &drm->crtcs[i]; - break; - } - } - if (crtc == NULL) { - continue; - } - - bool ok = false; - switch (plane->type) { - case DRM_PLANE_TYPE_PRIMARY: - ok = crtc->primary == plane; - break; - case DRM_PLANE_TYPE_CURSOR: - ok = crtc->cursor == plane; - break; - } - if (!ok) { - return false; - } - } - - return true; -} - -void restore_drm_device(struct wlr_drm_backend *drm) { - // The previous DRM master leaves KMS in an undefined state. We need - // to restore our own state, but be careful to avoid invalid - // 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: better use the atomic API to improve restoration after a VT switch - if (!skip_reset_for_restore(drm) && !drm->iface->reset(drm)) { - wlr_log(WLR_ERROR, "Failed to reset state after VT switch"); - } - - struct wlr_drm_connector *conn; - wl_list_for_each(conn, &drm->connectors, link) { - struct wlr_output_state state; - build_current_connector_state(&state, conn); - if (!drm_connector_commit_state(conn, &state, false)) { - wlr_drm_conn_log(conn, WLR_ERROR, "Failed to restore state after VT switch"); - } - wlr_output_state_finish(&state); - } -} - bool commit_drm_device(struct wlr_drm_backend *drm, const struct wlr_backend_output_state *output_states, size_t output_states_len, bool test_only) { diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 3ef83e3e0..9d3d62272 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -225,7 +225,6 @@ void scan_drm_connectors(struct wlr_drm_backend *state, void scan_drm_leases(struct wlr_drm_backend *drm); bool commit_drm_device(struct wlr_drm_backend *drm, const struct wlr_backend_output_state *states, size_t states_len, bool test_only); -void restore_drm_device(struct wlr_drm_backend *drm); int handle_drm_event(int fd, uint32_t mask, void *data); void destroy_drm_connector(struct wlr_drm_connector *conn); bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn);