diff options
author | Simon Ser <contact@emersion.fr> | 2022-12-06 19:01:24 +0100 |
---|---|---|
committer | Simon Zeni <simon@bl4ckb0ne.ca> | 2022-12-13 19:15:09 +0000 |
commit | bde68b1df79cef058a75d28c52a1544044bf3f70 (patch) | |
tree | 499f9ecb619accb59f2d418303b0892ab4a910d3 | |
parent | 99fb2fefc340278b29c3af9a53a319059599c8c7 (diff) |
backend/drm: refuse to switch CRTC for enabled connector
match_obj() might return a configuration where the CRTC for an
enabled connector is switched to another one.
We don't support this correctly: the wlr_output common code would
need to query again the supported formats, re-allocate the
swapchain, etc.
What's more, the kernel doesn't even support this [1]: it
requires planes to be disabled to change their CRTC, it rejects
commits directly switching the CRTC used by a plane.
[1]: https://cgit.freedesktop.org/drm/drm-misc/tree/drivers/gpu/drm/drm_atomic.c?h=6e90293618ed476d6b11f82ce724efbb9e9a071b#n697
-rw-r--r-- | backend/drm/drm.c | 40 |
1 files changed, 18 insertions, 22 deletions
diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 919d9821..380e5629 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1087,47 +1087,43 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, } } - /* - * In the case that we add a new connector (hotplug) and we fail to - * match everything, we prefer to fail the new connector and keep all - * of the old mappings instead. - */ + // Refuse to remove a CRTC from an enabled connector, and refuse to + // change the CRTC of an enabled connector. for (size_t i = 0; i < num_connectors; ++i) { struct wlr_drm_connector *conn = connectors[i]; - if (conn->status == DRM_MODE_CONNECTED && conn->output.enabled && - connector_match[i] == -1) { + if (conn->status != DRM_MODE_CONNECTED || !conn->output.enabled) { + continue; + } + if (connector_match[i] == -1) { wlr_log(WLR_DEBUG, "Could not match a CRTC for previously connected output; " - "keeping old configuration"); + "keeping old configuration"); + return; + } + assert(conn->crtc != NULL); + if (connector_match[i] != conn->crtc - drm->crtcs) { + wlr_log(WLR_DEBUG, "Cannot switch CRTC for enabled output; " + "keeping old configuration"); return; } } - wlr_log(WLR_DEBUG, "State after reallocation:"); // Apply new configuration + wlr_log(WLR_DEBUG, "State after reallocation:"); for (size_t i = 0; i < num_connectors; ++i) { struct wlr_drm_connector *conn = connectors[i]; - bool prev_enabled = conn->crtc; wlr_log(WLR_DEBUG, " '%s': crtc=%zd", conn->name, connector_match[i]); - // We don't need to change anything. - if (prev_enabled && connector_match[i] == conn->crtc - drm->crtcs) { + if (conn->crtc != NULL && connector_match[i] == conn->crtc - drm->crtcs) { + // We don't need to change anything continue; } dealloc_crtc(conn); - - if (connector_match[i] == -1) { - if (prev_enabled) { - wlr_drm_conn_log(conn, WLR_DEBUG, "Output has lost its CRTC"); - wlr_output_update_enabled(&conn->output, false); - wlr_output_update_mode(&conn->output, NULL); - } - continue; + if (connector_match[i] >= 0) { + conn->crtc = &drm->crtcs[connector_match[i]]; } - - conn->crtc = &drm->crtcs[connector_match[i]]; } } |