From 087ddf04e2f9065f4c3cd17f6baac9e9d8047d20 Mon Sep 17 00:00:00 2001 From: Daniel Stone Date: Tue, 14 Feb 2017 17:51:30 +0000 Subject: [PATCH] compositor-drm: Track unused connectors and CRTCs Rather than a more piecemeal approach at backend creation, explicitly track connectors and CRTCs we do not intend to use, so we can ensure they are disabled where appropriate. When we have an updated list of connector and CRTC IDs, we add any which are not owned by an enabled drm_output to the list. We remove them from the list when drm_output_repaint() is called for that output, and re-add them when the output is disabled or destroyed. Signed-off-by: Daniel Stone Reviewed-by: Pekka Paalanen --- libweston/compositor-drm.c | 89 +++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c index fe59bf52..f2d99b97 100644 --- a/libweston/compositor-drm.c +++ b/libweston/compositor-drm.c @@ -188,6 +188,10 @@ struct drm_backend { void *repaint_data; + /* Connector and CRTC IDs not used by any enabled output. */ + struct wl_array unused_connectors; + struct wl_array unused_crtcs; + int cursors_are_broken; bool universal_planes; @@ -386,6 +390,26 @@ static struct gl_renderer_interface *gl_renderer; static const char default_seat[] = "seat0"; +static void +wl_array_remove_uint32(struct wl_array *array, uint32_t elm) +{ + uint32_t *pos, *end; + + end = (uint32_t *) ((char *) array->data + array->size); + + wl_array_for_each(pos, array) { + if (*pos != elm) + continue; + + array->size -= sizeof(*pos); + if (pos + 1 == end) + break; + + memmove(pos, pos + 1, (char *) end - (char *) (pos + 1)); + break; + } +} + static inline struct drm_output * to_drm_output(struct weston_output *base) { @@ -1694,7 +1718,6 @@ drm_output_repaint(struct weston_output *output_base, pending_state, DRM_OUTPUT_STATE_CLEAR_PLANES); - /* If disable_planes is set then assign_planes() wasn't * called for this render, so we could still have a stale * cursor plane set up. @@ -1710,6 +1733,10 @@ drm_output_repaint(struct weston_output *output_base, if (!scanout_state || !scanout_state->fb) goto err; + wl_array_remove_uint32(&backend->unused_connectors, + output->connector_id); + wl_array_remove_uint32(&backend->unused_crtcs, output->crtc_id); + /* The legacy SetCrtc API doesn't allow us to do scaling, and the * legacy PageFlip API doesn't allow us to do clipping either. */ assert(scanout_state->src_x == 0); @@ -3989,6 +4016,7 @@ drm_output_deinit(struct weston_output *base) { struct drm_output *output = to_drm_output(base); struct drm_backend *b = to_drm_backend(base->compositor); + uint32_t *unused; if (b->use_pixman) drm_output_fini_pixman(output); @@ -4010,6 +4038,11 @@ drm_output_deinit(struct weston_output *base) drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0); } } + + unused = wl_array_add(&b->unused_connectors, sizeof(*unused)); + *unused = output->connector_id; + unused = wl_array_add(&b->unused_crtcs, sizeof(*unused)); + *unused = output->crtc_id; } static void @@ -4105,6 +4138,51 @@ drm_output_disable(struct weston_output *base) return 0; } +/** + * Update the list of unused connectors and CRTCs + * + * This keeps the unused_connectors and unused_crtcs arrays up to date. + * + * @param b Weston backend structure + * @param resources DRM resources for this device + */ +static void +drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources) +{ + int i; + + wl_array_release(&b->unused_connectors); + wl_array_init(&b->unused_connectors); + + for (i = 0; i < resources->count_connectors; i++) { + struct drm_output *output; + uint32_t *connector_id; + + output = drm_output_find_by_connector(b, resources->connectors[i]); + if (output && output->base.enabled) + continue; + + connector_id = wl_array_add(&b->unused_connectors, + sizeof(*connector_id)); + *connector_id = resources->connectors[i]; + } + + wl_array_release(&b->unused_crtcs); + wl_array_init(&b->unused_crtcs); + + for (i = 0; i < resources->count_crtcs; i++) { + struct drm_output *output; + uint32_t *crtc_id; + + output = drm_output_find_by_crtc(b, resources->crtcs[i]); + if (output && output->base.enabled) + continue; + + crtc_id = wl_array_add(&b->unused_crtcs, sizeof(*crtc_id)); + *crtc_id = resources->crtcs[i]; + } +} + /** * Create a Weston output structure * @@ -4265,6 +4343,8 @@ create_outputs(struct drm_backend *b, struct udev_device *drm_device) } } + drm_backend_update_unused_outputs(b, resources); + if (wl_list_empty(&b->compositor->output_list) && wl_list_empty(&b->compositor->pending_output_list)) weston_log("No currently active connector found.\n"); @@ -4356,6 +4436,8 @@ update_outputs(struct drm_backend *b, struct udev_device *drm_device) drm_output_destroy(&output->base); } + drm_backend_update_unused_outputs(b, resources); + free(connected); drmModeFreeResources(resources); } @@ -4422,6 +4504,9 @@ drm_destroy(struct weston_compositor *ec) weston_launcher_destroy(ec->launcher); + wl_array_release(&b->unused_crtcs); + wl_array_release(&b->unused_connectors); + close(b->drm.fd); free(b); } @@ -4854,6 +4939,8 @@ drm_backend_create(struct weston_compositor *compositor, return NULL; b->drm.fd = -1; + wl_array_init(&b->unused_crtcs); + wl_array_init(&b->unused_connectors); /* * KMS support for hardware planes cannot properly synchronize