From f8056a0350ba3d13bdcc9168740c11b9356f626d Mon Sep 17 00:00:00 2001 From: emersion Date: Sun, 9 Dec 2018 10:05:03 +0100 Subject: [PATCH 1/3] backend/drm: fix disappeared output indices This commit changes `scan_drm_connectors` to add new outputs to the end of the list. That way, it's easier to understand what's going on with indices. When we need to destroy outputs, we now walk the list in reverse order. This ensures indices remain correct while iterating and removing items from the list. We now also make outputs without a CRTC disappear (those are in WLR_DRM_CONN_NEEDS_MODESET state). --- backend/drm/drm.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 97028dc7..f14e3bb0 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1050,7 +1050,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { drmModeEncoder *curr_enc = drmModeGetEncoder(drm->fd, drm_conn->encoder_id); - int index = -1; + ssize_t index = -1; struct wlr_drm_connector *c, *wlr_conn = NULL; wl_list_for_each(c, &drm->outputs, link) { index++; @@ -1086,7 +1086,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_conn->old_crtc = drmModeGetCrtc(drm->fd, curr_enc->crtc_id); } - wl_list_insert(&drm->outputs, &wlr_conn->link); + wl_list_insert(drm->outputs.prev, &wlr_conn->link); wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->output.name); } else { seen[index] = true; @@ -1178,7 +1178,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wlr_conn->state = WLR_DRM_CONN_NEEDS_MODESET; new_outputs[new_outputs_len++] = wlr_conn; - } else if (wlr_conn->state == WLR_DRM_CONN_CONNECTED && + } else if ((wlr_conn->state == WLR_DRM_CONN_CONNECTED || + wlr_conn->state == WLR_DRM_CONN_NEEDS_MODESET) && drm_conn->connection != DRM_MODE_CONNECTED) { wlr_log(WLR_INFO, "'%s' disconnected", wlr_conn->output.name); @@ -1191,9 +1192,11 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { drmModeFreeResources(res); + // Iterate in reverse order because we'll remove items from the list and + // still want indices to remain correct. struct wlr_drm_connector *conn, *tmp_conn; size_t index = wl_list_length(&drm->outputs); - wl_list_for_each_safe(conn, tmp_conn, &drm->outputs, link) { + wl_list_for_each_reverse_safe(conn, tmp_conn, &drm->outputs, link) { index--; if (index >= seen_len || seen[index]) { continue; From efdd4d6ea275ff4a0a22f8a348abca5847a9e65e Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sun, 9 Dec 2018 22:48:00 +1300 Subject: [PATCH 2/3] backend/drm: Improve encoder logic This fixes an issue that can occur with DP MST connectors not reporting any encoders. --- backend/drm/drm.c | 55 +++++++++++++++++++------------- backend/drm/properties.c | 1 + include/backend/drm/properties.h | 1 + 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index f14e3bb0..14f1254f 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -991,36 +991,44 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { } } -static uint32_t get_possible_crtcs(int fd, uint32_t conn_id) { - drmModeConnector *conn = drmModeGetConnector(fd, conn_id); - if (!conn) { - wlr_log_errno(WLR_ERROR, "Failed to get DRM connector"); - return 0; - } +static uint32_t get_possible_crtcs(int fd, drmModeRes *res, + drmModeConnector *conn, bool is_mst) { + drmModeEncoder *enc; + uint32_t ret = 0; - if (conn->connection != DRM_MODE_CONNECTED || conn->count_modes == 0) { - wlr_log(WLR_ERROR, "Output is not connected"); - goto error_conn; - } - - drmModeEncoder *enc = NULL; for (int i = 0; !enc && i < conn->count_encoders; ++i) { enc = drmModeGetEncoder(fd, conn->encoders[i]); + if (!enc) { + continue; + } + + ret |= enc->possible_crtcs; + + drmModeFreeEncoder(enc); } - if (!enc) { - wlr_log(WLR_ERROR, "Failed to get DRM encoder"); - goto error_conn; + // Sometimes DP MST connectors report no encoders, so we'll loop though + // all of the encoders of the MST type instead. + // TODO: See if there is a better solution. + + if (!is_mst || ret) { + return ret; + } + + for (int i = 0; i < res->count_encoders; ++i) { + enc = drmModeGetEncoder(fd, res->encoders[i]); + if (!enc) { + continue; + } + + if (enc->encoder_type == DRM_MODE_ENCODER_DPMST) { + ret |= enc->possible_crtcs; + } + + drmModeFreeEncoder(enc); } - uint32_t ret = enc->possible_crtcs; - drmModeFreeEncoder(enc); - drmModeFreeConnector(conn); return ret; - -error_conn: - drmModeFreeConnector(conn); - return 0; } void scan_drm_connectors(struct wlr_drm_backend *drm) { @@ -1167,7 +1175,8 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { wl_list_insert(&wlr_conn->output.modes, &mode->wlr_mode.link); } - wlr_conn->possible_crtc = get_possible_crtcs(drm->fd, wlr_conn->id); + wlr_conn->possible_crtc = get_possible_crtcs(drm->fd, res, drm_conn, + wlr_conn->props.path != 0); if (wlr_conn->possible_crtc == 0) { wlr_log(WLR_ERROR, "No CRTC possible for connector '%s'", wlr_conn->output.name); diff --git a/backend/drm/properties.c b/backend/drm/properties.c index 5ca4c8ac..5541d1be 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -22,6 +22,7 @@ static const struct prop_info connector_info[] = { { "CRTC_ID", INDEX(crtc_id) }, { "DPMS", INDEX(dpms) }, { "EDID", INDEX(edid) }, + { "PATH", INDEX(path) }, { "link-status", INDEX(link_status) }, #undef INDEX }; diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h index 321b4492..b4d43bdd 100644 --- a/include/backend/drm/properties.h +++ b/include/backend/drm/properties.h @@ -15,6 +15,7 @@ union wlr_drm_connector_props { uint32_t edid; uint32_t dpms; uint32_t link_status; // not guaranteed to exist + uint32_t path; // atomic-modesetting only From fec88770dd1cbc42601b5cead8957dcb0b300fb0 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sun, 9 Dec 2018 22:55:53 +1300 Subject: [PATCH 3/3] backend/drm: Fix uninitialized variable --- backend/drm/drm.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 14f1254f..0acb0324 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -993,11 +993,10 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { static uint32_t get_possible_crtcs(int fd, drmModeRes *res, drmModeConnector *conn, bool is_mst) { - drmModeEncoder *enc; uint32_t ret = 0; - for (int i = 0; !enc && i < conn->count_encoders; ++i) { - enc = drmModeGetEncoder(fd, conn->encoders[i]); + for (int i = 0; i < conn->count_encoders; ++i) { + drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoders[i]); if (!enc) { continue; } @@ -1016,7 +1015,7 @@ static uint32_t get_possible_crtcs(int fd, drmModeRes *res, } for (int i = 0; i < res->count_encoders; ++i) { - enc = drmModeGetEncoder(fd, res->encoders[i]); + drmModeEncoder *enc = drmModeGetEncoder(fd, res->encoders[i]); if (!enc) { continue; }