diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 769a4a5c5..73e57bfa0 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -4,6 +4,8 @@ #include #include +#include + #include "backend/drm/backend.h" #include "backend/drm/drm.h" #include "backend/drm/session.h" @@ -18,10 +20,16 @@ struct wlr_drm_backend *wlr_drm_backend_init(void) return NULL; } + backend->displays = list_create(); + if (!backend->displays) { + wlr_log(L_ERROR, "Failed to allocate list"); + goto error_backend; + } + backend->event_loop = wl_event_loop_create(); if (!backend->event_loop) { wlr_log(L_ERROR, "Failed to create event loop"); - goto error_backend; + goto error_list; } if (!wlr_session_start(&backend->session)) { @@ -61,19 +69,25 @@ error_session: wlr_session_end(&backend->session); error_loop: wl_event_loop_destroy(backend->event_loop); +error_list: + list_free(backend->displays); error_backend: free(backend); return NULL; } +static void free_display(void *item) +{ + struct wlr_drm_display *disp = item; + wlr_drm_display_free(disp, true); +} + void wlr_drm_backend_free(struct wlr_drm_backend *backend) { if (!backend) return; - for (size_t i = 0; i < backend->display_len; ++i) { - wlr_drm_display_free(&backend->displays[i], true); - } + list_foreach(backend->displays, free_display); wlr_drm_renderer_free(&backend->renderer); wlr_udev_free(&backend->udev); @@ -83,7 +97,7 @@ void wlr_drm_backend_free(struct wlr_drm_backend *backend) wl_event_source_remove(backend->event_src.drm); wl_event_loop_destroy(backend->event_loop); - free(backend->displays); + list_free(backend->displays); free(backend); } diff --git a/backend/drm/drm.c b/backend/drm/drm.c index d1d682248..226c79fbf 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -240,6 +240,19 @@ void wlr_drm_renderer_free(struct wlr_drm_renderer *renderer) gbm_device_destroy(renderer->gbm); } +static int find_id(const void *item, const void *cmp_to) +{ + const struct wlr_drm_display *disp = item; + const uint32_t *id = cmp_to; + + if (disp->connector < *id) + return -1; + else if (disp->connector > *id) + return 1; + else + return 0; +} + void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) { drmModeRes *res = drmModeGetResources(backend->fd); @@ -248,39 +261,35 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) return; } - // I don't know if this needs to be allocated with realloc like this, - // as it may not even be possible for the number of connectors to change. - // I'll just have to see how DisplayPort MST works with DRM. - if ((size_t)res->count_connectors > backend->display_len) { - struct wlr_drm_display *new = realloc(backend->displays, sizeof *new * res->count_connectors); - if (!new) { - wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); - goto error; - } - - for (int i = backend->display_len; i < res->count_connectors; ++i) { - new[i] = (struct wlr_drm_display) { - .state = DRM_DISP_INVALID, - .renderer = &backend->renderer, - }; - } - - backend->display_len = res->count_connectors; - backend->displays = new; - } - for (int i = 0; i < res->count_connectors; ++i) { - struct wlr_drm_display *disp = &backend->displays[i]; - drmModeConnector *conn = drmModeGetConnector(backend->fd, res->connectors[i]); - if (!conn) - continue; + uint32_t id = res->connectors[i]; + + drmModeConnector *conn = drmModeGetConnector(backend->fd, id); + if (!conn) { + wlr_log(L_ERROR, "Failed to get DRM connector"); + continue; + } + + struct wlr_drm_display *disp; + int index = list_seq_find(backend->displays, find_id, &id); + + if (index == -1) { + disp = calloc(1, sizeof *disp); + if (!disp) { + wlr_log(L_ERROR, "Allocation failed: %s", strerror(errno)); + drmModeFreeConnector(conn); + continue; + } - if (backend->displays[i].state == DRM_DISP_INVALID) { disp->state = DRM_DISP_DISCONNECTED; disp->connector = res->connectors[i]; snprintf(disp->name, sizeof disp->name, "%s-%"PRIu32, conn_name[conn->connector_type], conn->connector_type_id); + + list_add(backend->displays, disp); + } else { + disp = backend->displays->items[index]; } if (disp->state == DRM_DISP_DISCONNECTED && @@ -298,7 +307,6 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) drmModeFreeConnector(conn); } -error: drmModeFreeResources(res); } diff --git a/include/backend/drm/backend.h b/include/backend/drm/backend.h index 25a42c375..87471fbbc 100644 --- a/include/backend/drm/backend.h +++ b/include/backend/drm/backend.h @@ -8,6 +8,8 @@ #include #include +#include + #include "session.h" #include "udev.h" #include "event.h" @@ -30,8 +32,7 @@ struct wlr_drm_backend { struct wl_signal display_render; } signals; - size_t display_len; - struct wlr_drm_display *displays; + list_t *displays; uint32_t taken_crtcs;