mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-18 06:47:31 -04:00
backend/drm: Refactor scan_drm_connectors
This separates GPU hot-plug handling and display hot-plug handling, thereby making it possible to reason about each of those in isolation.
This commit is contained in:
parent
303f23d7dd
commit
2822a40531
1 changed files with 116 additions and 86 deletions
|
|
@ -1500,49 +1500,47 @@ static bool connect_drm_connector(struct wlr_drm_connector *wlr_conn,
|
||||||
|
|
||||||
static void disconnect_drm_connector(struct wlr_drm_connector *conn);
|
static void disconnect_drm_connector(struct wlr_drm_connector *conn);
|
||||||
|
|
||||||
void scan_drm_connectors(struct wlr_drm_backend *drm,
|
static struct wlr_drm_connector *find_wlr_drm_connector(const struct wlr_drm_backend *drm, uint32_t id) {
|
||||||
struct wlr_device_hotplug_event *event) {
|
struct wlr_drm_connector *c;
|
||||||
if (event != NULL && event->connector_id != 0) {
|
wl_list_for_each(c, &drm->connectors, link) {
|
||||||
wlr_log(WLR_INFO, "Scanning DRM connector %"PRIu32" on %s",
|
if (c->id == id) {
|
||||||
event->connector_id, drm->name);
|
return c;
|
||||||
} else {
|
}
|
||||||
wlr_log(WLR_INFO, "Scanning DRM connectors on %s", drm->name);
|
}
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void update_drm_connector_list(struct wlr_drm_backend *drm) {
|
||||||
drmModeRes *res = drmModeGetResources(drm->fd);
|
drmModeRes *res = drmModeGetResources(drm->fd);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
wlr_log_errno(WLR_ERROR, "Failed to get DRM resources");
|
wlr_log_errno(WLR_ERROR, "Failed to get DRM resources");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t seen_len = wl_list_length(&drm->connectors);
|
// Removed:
|
||||||
// +1 so length can never be 0, which is undefined behaviour.
|
struct wlr_drm_connector *c, *tmp;
|
||||||
// Last element isn't used.
|
wl_list_for_each_safe(c, tmp, &drm->connectors, link) {
|
||||||
bool seen[seen_len + 1];
|
bool found = false;
|
||||||
memset(seen, false, sizeof(seen));
|
|
||||||
size_t new_outputs_len = 0;
|
|
||||||
struct wlr_drm_connector *new_outputs[res->count_connectors + 1];
|
|
||||||
|
|
||||||
for (int i = 0; i < res->count_connectors; ++i) {
|
for (int i = 0; i < res->count_connectors; ++i) {
|
||||||
uint32_t conn_id = res->connectors[i];
|
uint32_t conn_id = res->connectors[i];
|
||||||
|
if (conn_id == c->id) {
|
||||||
ssize_t index = -1;
|
found = true;
|
||||||
struct wlr_drm_connector *c, *wlr_conn = NULL;
|
|
||||||
wl_list_for_each(c, &drm->connectors, link) {
|
|
||||||
index++;
|
|
||||||
if (c->id == conn_id) {
|
|
||||||
wlr_conn = c;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the hotplug event contains a connector ID, ignore any other
|
if (found) {
|
||||||
// connector.
|
continue;
|
||||||
if (event != NULL && event->connector_id != 0 &&
|
|
||||||
event->connector_id != conn_id) {
|
|
||||||
if (wlr_conn != NULL) {
|
|
||||||
seen[index] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wlr_log(WLR_INFO, "'%s' disappeared", c->name);
|
||||||
|
destroy_drm_connector(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Added:
|
||||||
|
for (int i = 0; i < res->count_connectors; ++i) {
|
||||||
|
uint32_t conn_id = res->connectors[i];
|
||||||
|
if (find_wlr_drm_connector(drm, conn_id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1552,14 +1550,26 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_connector *wlr_conn = create_drm_connector(drm, drm_conn);
|
||||||
if (!wlr_conn) {
|
if (!wlr_conn) {
|
||||||
wlr_conn = create_drm_connector(drm, drm_conn);
|
wlr_log_errno(WLR_ERROR, "Failed to create new connector");
|
||||||
if (wlr_conn == NULL) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->name);
|
wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->name);
|
||||||
} else {
|
}
|
||||||
seen[index] = true;
|
|
||||||
|
drmModeFreeResources(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool scan_single_drm_connector(struct wlr_drm_backend *drm,
|
||||||
|
struct wlr_drm_connector *wlr_conn) {
|
||||||
|
bool r = false;
|
||||||
|
|
||||||
|
drmModeConnector *drm_conn = drmModeGetConnector(drm->fd, wlr_conn->id);
|
||||||
|
if (!drm_conn) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "Failed to get DRM connector");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This can only happen *after* hotplug, since we haven't read the
|
// This can only happen *after* hotplug, since we haven't read the
|
||||||
|
|
@ -1570,7 +1580,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
|
||||||
wlr_conn->props.link_status, &link_status)) {
|
wlr_conn->props.link_status, &link_status)) {
|
||||||
wlr_drm_conn_log(wlr_conn, WLR_ERROR,
|
wlr_drm_conn_log(wlr_conn, WLR_ERROR,
|
||||||
"Failed to get link status prop");
|
"Failed to get link status prop");
|
||||||
continue;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (link_status == DRM_MODE_LINK_STATUS_BAD) {
|
if (link_status == DRM_MODE_LINK_STATUS_BAD) {
|
||||||
|
|
@ -1583,34 +1593,54 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
|
||||||
if (wlr_conn->status == DRM_MODE_DISCONNECTED &&
|
if (wlr_conn->status == DRM_MODE_DISCONNECTED &&
|
||||||
drm_conn->connection == DRM_MODE_CONNECTED) {
|
drm_conn->connection == DRM_MODE_CONNECTED) {
|
||||||
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name);
|
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->name);
|
||||||
if (!connect_drm_connector(wlr_conn, drm_conn)) {
|
connect_drm_connector(wlr_conn, drm_conn);
|
||||||
wlr_drm_conn_log(wlr_conn, WLR_ERROR, "Failed to connect DRM connector");
|
r = true;
|
||||||
continue;
|
goto out;
|
||||||
}
|
}
|
||||||
new_outputs[new_outputs_len++] = wlr_conn;
|
|
||||||
} else if (wlr_conn->status == DRM_MODE_CONNECTED &&
|
if (wlr_conn->status == DRM_MODE_CONNECTED &&
|
||||||
drm_conn->connection != 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
drmModeFreeConnector(drm_conn);
|
drmModeFreeConnector(drm_conn);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
drmModeFreeResources(res);
|
void scan_drm_connectors(struct wlr_drm_backend *drm,
|
||||||
|
struct wlr_device_hotplug_event *event) {
|
||||||
// Iterate in reverse order because we'll remove items from the list and
|
if (event != NULL && event->connector_id != 0) {
|
||||||
// still want indices to remain correct.
|
wlr_log(WLR_INFO, "Scanning DRM connector %"PRIu32" on %s",
|
||||||
struct wlr_drm_connector *conn, *tmp_conn;
|
event->connector_id, drm->name);
|
||||||
size_t index = wl_list_length(&drm->connectors);
|
} else {
|
||||||
wl_list_for_each_reverse_safe(conn, tmp_conn, &drm->connectors, link) {
|
wlr_log(WLR_INFO, "Scanning DRM connectors on %s", drm->name);
|
||||||
index--;
|
|
||||||
if (index >= seen_len || seen[index]) {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_log(WLR_INFO, "'%s' disappeared", conn->name);
|
update_drm_connector_list(drm);
|
||||||
destroy_drm_connector(conn);
|
|
||||||
|
struct wlr_drm_connector *new_outputs[64];
|
||||||
|
size_t new_outputs_len = 0;
|
||||||
|
|
||||||
|
if (event && event->connector_id) {
|
||||||
|
struct wlr_drm_connector *c = find_wlr_drm_connector(drm, event->connector_id);
|
||||||
|
if (c) {
|
||||||
|
if (scan_single_drm_connector(drm, c)) {
|
||||||
|
assert(new_outputs_len < sizeof(new_outputs) / sizeof(new_outputs[0]));
|
||||||
|
new_outputs[new_outputs_len++] = c;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_ERROR, "Missing connector from hotplug event");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct wlr_drm_connector *c;
|
||||||
|
wl_list_for_each(c, &drm->connectors, link) {
|
||||||
|
if (scan_single_drm_connector(drm, c)) {
|
||||||
|
assert(new_outputs_len < sizeof(new_outputs) / sizeof(new_outputs[0]));
|
||||||
|
new_outputs[new_outputs_len++] = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
realloc_crtcs(drm, NULL);
|
realloc_crtcs(drm, NULL);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue