backend/drm: Recreate output on EDID change

Some displays change their EDID while connected. The EDID can also
change if the user overrides it. With this change, a new EDID will take
effect immedately after it changes.
This commit is contained in:
Andri Yngvason 2023-10-11 18:38:13 +00:00
parent 2822a40531
commit 52d0d4a773
2 changed files with 29 additions and 8 deletions

View file

@ -1471,7 +1471,9 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
uint8_t *edid = get_drm_prop_blob(drm->fd, uint8_t *edid = get_drm_prop_blob(drm->fd,
wlr_conn->id, wlr_conn->props.edid, &edid_len); wlr_conn->id, wlr_conn->props.edid, &edid_len);
parse_edid(wlr_conn, edid_len, edid); parse_edid(wlr_conn, edid_len, edid);
free(edid);
wlr_conn->edid = edid;
wlr_conn->edid_len = edid_len;
char *subconnector = NULL; char *subconnector = NULL;
if (wlr_conn->props.subconnector) { if (wlr_conn->props.subconnector) {
@ -1590,18 +1592,29 @@ static bool scan_single_drm_connector(struct wlr_drm_backend *drm,
} }
} }
if (wlr_conn->status == DRM_MODE_DISCONNECTED && bool is_connected = drm_conn->connection == DRM_MODE_CONNECTED;
drm_conn->connection == DRM_MODE_CONNECTED) { bool was_connected = wlr_conn->status == DRM_MODE_CONNECTED;
if (!was_connected && is_connected) {
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name); wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name);
connect_drm_connector(wlr_conn, drm_conn); connect_drm_connector(wlr_conn, drm_conn);
r = true; r = true;
goto out; } else if (was_connected && !is_connected) {
}
if (wlr_conn->status == DRM_MODE_CONNECTED &&
drm_conn->connection != DRM_MODE_CONNECTED) {
wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->name); wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->name);
disconnect_drm_connector(wlr_conn); disconnect_drm_connector(wlr_conn);
} else if (was_connected && is_connected) {
size_t edid_len = 0;
uint8_t *edid = get_drm_prop_blob(drm->fd,
wlr_conn->id, wlr_conn->props.edid, &edid_len);
if (edid_len != wlr_conn->edid_len || memcmp(edid, wlr_conn->edid, edid_len) != 0) {
wlr_log(WLR_INFO, "EDID changed on '%s'", wlr_conn->name);
disconnect_drm_connector(wlr_conn);
connect_drm_connector(wlr_conn, drm_conn);
r = true;
}
free(edid);
} }
out: out:
@ -1782,6 +1795,10 @@ static void disconnect_drm_connector(struct wlr_drm_connector *conn) {
// our wlr_drm_connector. // our wlr_drm_connector.
wlr_output_destroy(&conn->output); wlr_output_destroy(&conn->output);
free(conn->edid);
conn->edid = NULL;
conn->edid_len = 0;
assert(conn->status == DRM_MODE_DISCONNECTED); assert(conn->status == DRM_MODE_DISCONNECTED);
} }
@ -1789,6 +1806,7 @@ void destroy_drm_connector(struct wlr_drm_connector *conn) {
disconnect_drm_connector(conn); disconnect_drm_connector(conn);
wl_list_remove(&conn->link); wl_list_remove(&conn->link);
free(conn->edid);
free(conn); free(conn);
} }

View file

@ -161,6 +161,9 @@ struct wlr_drm_connector {
* they're sent. * they're sent.
*/ */
uint32_t pending_page_flip_crtc; uint32_t pending_page_flip_crtc;
uint8_t *edid;
size_t edid_len;
}; };
struct wlr_drm_backend *get_drm_backend_from_backend( struct wlr_drm_backend *get_drm_backend_from_backend(