From b00d1a2efb215524739a5238466f86c90bb1bb33 Mon Sep 17 00:00:00 2001 From: Leandro Ribeiro Date: Thu, 13 Aug 2020 14:12:28 -0300 Subject: [PATCH] drm-backend: move CRTC data from struct drm_output to new struct drm_crtc There are no 'struct drm_output' for CRTCs that are not active. Also, CRTC data lives in 'struct drm_output'. This is causing us some trouble, as the DRM-backend needs to program those unnactive CRTCs to be off. If the DRM-backend had the reference for every CRTC (being active or not), it would make certain functions (e.g. drm_pending_state_apply_atomic()) more simple and efficient. Move CRTC data from 'struct drm_output' to 'struct drm_crtc', as this is the first step to allow the DRM-backend to have references for every CRTC. Also, add list of CRTCs to DRM-backend object. Now the DRM-backend is responsible for allocating/deallocating the CRTC objects. The outputs will only reference, init and fini the CRTCs in this list. Signed-off-by: Leandro Ribeiro --- libweston/backend-drm/drm-internal.h | 21 +- libweston/backend-drm/drm-virtual.c | 51 +++++ libweston/backend-drm/drm.c | 319 ++++++++++++++++----------- libweston/backend-drm/kms.c | 56 +++-- 4 files changed, 289 insertions(+), 158 deletions(-) diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index 06f952f2..b0c5af86 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -275,6 +275,9 @@ struct drm_backend { bool state_invalid; + /* drm_crtc::link */ + struct wl_list crtc_list; + /* CRTC IDs not used by any enabled output. */ struct wl_array unused_crtcs; @@ -483,15 +486,25 @@ struct drm_head { uint32_t inherited_crtc_id; /**< Original CRTC assignment */ }; -struct drm_output { - struct weston_output base; +struct drm_crtc { + /* drm_backend::crtc_list */ + struct wl_list link; struct drm_backend *backend; + /* The output driven by the CRTC */ + struct drm_output *output; + uint32_t crtc_id; /* object ID to pass to DRM functions */ int pipe; /* index of CRTC in resource array / bitmasks */ /* Holds the properties for the CRTC */ struct drm_property_info props_crtc[WDRM_CRTC__COUNT]; +}; + +struct drm_output { + struct weston_output base; + struct drm_backend *backend; + struct drm_crtc *crtc; bool page_flip_pending; bool atomic_complete_pending; @@ -573,8 +586,8 @@ drm_output_get_plane_type_name(struct drm_plane *p) } } -struct drm_output * -drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id); +struct drm_crtc * +drm_crtc_find(struct drm_backend *b, uint32_t crtc_id); struct drm_head * drm_head_find_by_connector(struct drm_backend *backend, uint32_t connector_id); diff --git a/libweston/backend-drm/drm-virtual.c b/libweston/backend-drm/drm-virtual.c index ebebbbd2..5ef5f8a7 100644 --- a/libweston/backend-drm/drm-virtual.c +++ b/libweston/backend-drm/drm-virtual.c @@ -38,6 +38,49 @@ #include "drm-internal.h" #include "renderer-gl/gl-renderer.h" +#define POISON_PTR ((void *)8) + +/** + * Create a drm_crtc for virtual output + * + * It will leave its ID and pipe zeroed, as virtual outputs should not use real + * CRTC's. Also, as this is a fake CRTC, it will not try to populate props. + */ +static struct drm_crtc * +drm_virtual_crtc_create(struct drm_backend *b, struct drm_output *output) +{ + struct drm_crtc *crtc; + + crtc = zalloc(sizeof(*crtc)); + if (!crtc) + return NULL; + + crtc->backend = b; + crtc->output = output; + + crtc->crtc_id = 0; + crtc->pipe = 0; + + /* Poisoning the pointers as CRTC's of virtual outputs should not be + * added to the DRM-backend CRTC list. With this we can assure (in + * function drm_virtual_crtc_destroy()) that this did not happen. */ + crtc->link.prev = POISON_PTR; + crtc->link.next = POISON_PTR; + + return crtc; +} + +/** + * Destroy drm_crtc created by drm_virtual_crtc_create() + */ +static void +drm_virtual_crtc_destroy(struct drm_crtc *crtc) +{ + assert(crtc->link.prev == POISON_PTR); + assert(crtc->link.next == POISON_PTR); + free(crtc); +} + /** * Create a drm_plane for virtual output * @@ -184,6 +227,7 @@ drm_virtual_output_deinit(struct weston_output *base) drm_output_fini_egl(output); drm_virtual_plane_destroy(output->scanout_plane); + drm_virtual_crtc_destroy(output->crtc); } static void @@ -267,11 +311,18 @@ static struct weston_output * drm_virtual_output_create(struct weston_compositor *c, char *name) { struct drm_output *output; + struct drm_backend *b = to_drm_backend(c); output = zalloc(sizeof *output); if (!output) return NULL; + output->crtc = drm_virtual_crtc_create(b, output); + if (!output->crtc) { + free(output); + return NULL; + } + output->virtual = true; output->gbm_bo_flags = GBM_BO_USE_LINEAR | GBM_BO_USE_RENDERING; diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index 2780f3bd..cd4639e8 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -208,17 +208,17 @@ drm_plane_is_available(struct drm_plane *plane, struct drm_output *output) /* Check whether the plane can be used with this CRTC; possible_crtcs * is a bitmask of CRTC indices (pipe), rather than CRTC object ID. */ - return !!(plane->possible_crtcs & (1 << output->pipe)); + return !!(plane->possible_crtcs & (1 << output->crtc->pipe)); } -struct drm_output * -drm_output_find_by_crtc(struct drm_backend *b, uint32_t crtc_id) +struct drm_crtc * +drm_crtc_find(struct drm_backend *b, uint32_t crtc_id) { - struct drm_output *output; + struct drm_crtc *crtc; - wl_list_for_each(output, &b->compositor->output_list, base.link) { - if (output->crtc_id == crtc_id) - return output; + wl_list_for_each(crtc, &b->crtc_list, link) { + if (crtc->crtc_id == crtc_id) + return crtc; } return NULL; @@ -506,12 +506,12 @@ err: * using DRM_BLANK_HIGH_CRTC_MASK. */ static unsigned int -drm_waitvblank_pipe(struct drm_output *output) +drm_waitvblank_pipe(struct drm_crtc *crtc) { - if (output->pipe > 1) - return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) & + if (crtc->pipe > 1) + return (crtc->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) & DRM_VBLANK_HIGH_CRTC_MASK; - else if (output->pipe > 0) + else if (crtc->pipe > 0) return DRM_VBLANK_SECONDARY; else return 0; @@ -552,7 +552,7 @@ drm_output_start_repaint_loop(struct weston_output *output_base) assert(scanout_plane->state_cur->output == output); /* Try to get current msc and timestamp via instant query */ - vbl.request.type |= drm_waitvblank_pipe(output); + vbl.request.type |= drm_waitvblank_pipe(output->crtc); ret = drmWaitVBlank(backend->drm.fd, &vbl); /* Error ret or zero timestamp means failure to get valid timestamp */ @@ -818,7 +818,7 @@ drm_plane_create(struct drm_backend *b, const drmModePlane *kplane, drmModeFreeObjectProperties(props); } else { - plane->possible_crtcs = (1 << output->pipe); + plane->possible_crtcs = (1 << output->crtc->pipe); plane->plane_id = 0; plane->count_formats = 1; plane->formats[0].format = format; @@ -929,7 +929,7 @@ drm_output_find_special_plane(struct drm_backend *b, struct drm_output *output, if (found_elsewhere) continue; - plane->possible_crtcs = (1 << output->pipe); + plane->possible_crtcs = (1 << output->crtc->pipe); return plane; } @@ -1435,8 +1435,8 @@ drm_output_init_gamma_size(struct drm_output *output) drmModeCrtc *crtc; assert(output->base.compositor); - assert(output->crtc_id != 0); - crtc = drmModeGetCrtc(backend->drm.fd, output->crtc_id); + assert(output->crtc); + crtc = drmModeGetCrtc(backend->drm.fd, output->crtc->crtc_id); if (!crtc) return -1; @@ -1467,39 +1467,25 @@ drm_head_get_possible_crtcs_mask(struct drm_head *head) return possible_crtcs; } -static int -drm_crtc_get_index(drmModeRes *resources, uint32_t crtc_id) -{ - int i; - - for (i = 0; i < resources->count_crtcs; i++) { - if (resources->crtcs[i] == crtc_id) - return i; - } - - assert(0 && "unknown crtc id"); - return -1; -} - /** Pick a CRTC that might be able to drive all attached connectors * * @param output The output whose attached heads to include. - * @param resources The DRM KMS resources. - * @return CRTC index, or -1 on failure or not found. + * @return CRTC object to pick, or NULL on failure or not found. */ -static int -drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources) +static struct drm_crtc * +drm_output_pick_crtc(struct drm_output *output) { struct drm_backend *backend; struct weston_head *base; struct drm_head *head; + struct drm_crtc *crtc; + struct drm_crtc *best_crtc = NULL; + struct drm_crtc *fallback_crtc = NULL; + struct drm_crtc *existing_crtc[32]; uint32_t possible_crtcs = 0xffffffff; - int existing_crtc[32]; - unsigned j, n = 0; + unsigned n = 0; uint32_t crtc_id; - int best_crtc_index = -1; - int fallback_crtc_index = -1; - int i; + unsigned int i; bool match; backend = to_drm_backend(output->base.compositor); @@ -1515,30 +1501,28 @@ drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources) crtc_id = head->inherited_crtc_id; if (crtc_id > 0 && n < ARRAY_LENGTH(existing_crtc)) - existing_crtc[n++] = drm_crtc_get_index(resources, - crtc_id); + existing_crtc[n++] = drm_crtc_find(backend, crtc_id); } /* Find a crtc that could drive each connector individually at least, * and prefer existing routings. */ - for (i = 0; i < resources->count_crtcs; i++) { - crtc_id = resources->crtcs[i]; + wl_list_for_each(crtc, &backend->crtc_list, link) { /* Could the crtc not drive each connector? */ - if (!(possible_crtcs & (1 << i))) + if (!(possible_crtcs & (1 << crtc->pipe))) continue; /* Is the crtc already in use? */ - if (drm_output_find_by_crtc(backend, crtc_id)) + if (crtc->output) continue; /* Try to preserve the existing CRTC -> connector routing; * it makes initialisation faster, and also since we have a * very dumb picking algorithm, may preserve a better * choice. */ - for (j = 0; j < n; j++) { - if (existing_crtc[j] == i) - return i; + for (i = 0; i < n; i++) { + if (existing_crtc[i] == crtc) + return crtc; } /* Check if any other head had existing routing to this CRTC. @@ -1555,22 +1539,22 @@ drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources) if (weston_head_is_enabled(&head->base)) continue; - if (head->inherited_crtc_id == crtc_id) { + if (head->inherited_crtc_id == crtc->crtc_id) { match = true; break; } } if (!match) - best_crtc_index = i; + best_crtc = crtc; - fallback_crtc_index = i; + fallback_crtc = crtc; } - if (best_crtc_index != -1) - return best_crtc_index; + if (best_crtc) + return best_crtc; - if (fallback_crtc_index != -1) - return fallback_crtc_index; + if (fallback_crtc) + return fallback_crtc; /* Likely possible_crtcs was empty due to asking for clones, * but since the DRM documentation says the kernel lies, let's @@ -1578,72 +1562,142 @@ drm_output_pick_crtc(struct drm_output *output, drmModeRes *resources) * be sure if something doesn't work. */ /* First pick any existing assignment. */ - for (j = 0; j < n; j++) { - crtc_id = resources->crtcs[existing_crtc[j]]; - if (!drm_output_find_by_crtc(backend, crtc_id)) - return existing_crtc[j]; + for (i = 0; i < n; i++) { + crtc = existing_crtc[i]; + if (!crtc->output) + return crtc; } /* Otherwise pick any available crtc. */ - for (i = 0; i < resources->count_crtcs; i++) { - crtc_id = resources->crtcs[i]; + wl_list_for_each(crtc, &backend->crtc_list, link) { + if (!crtc->output) + return crtc; + } - if (!drm_output_find_by_crtc(backend, crtc_id)) - return i; + return NULL; +} + +/** Create an "empty" drm_crtc. It will only set its ID, pipe and props. After + * all, it adds the object to the DRM-backend CRTC list. + */ +static struct drm_crtc * +drm_crtc_create(struct drm_backend *b, uint32_t crtc_id, uint32_t pipe) +{ + struct drm_crtc *crtc; + drmModeObjectPropertiesPtr props; + + props = drmModeObjectGetProperties(b->drm.fd, crtc_id, + DRM_MODE_OBJECT_CRTC); + if (!props) { + weston_log("failed to get CRTC properties\n"); + return NULL; } - return -1; + crtc = zalloc(sizeof(*crtc)); + if (!crtc) + goto ret; + + drm_property_info_populate(b, crtc_props, crtc->props_crtc, + WDRM_CRTC__COUNT, props); + crtc->backend = b; + crtc->crtc_id = crtc_id; + crtc->pipe = pipe; + crtc->output = NULL; + + /* Add it to the last position of the DRM-backend CRTC list */ + wl_list_insert(b->crtc_list.prev, &crtc->link); + +ret: + drmModeFreeObjectProperties(props); + return crtc; } -/** Allocate a CRTC for the output - * - * @param output The output with no allocated CRTC. - * @param resources DRM KMS resources. - * @return 0 on success, -1 on failure. +/** Destroy a drm_crtc object that was created with drm_crtc_create(). It will + * also remove it from the DRM-backend CRTC list. + */ +static void +drm_crtc_destroy(struct drm_crtc *crtc) +{ + /* TODO: address the issue below to be able to remove the comment + * from the assert. + * + * https://gitlab.freedesktop.org/wayland/weston/-/issues/421 + */ + + //assert(!crtc->output); + + wl_list_remove(&crtc->link); + drm_property_info_free(crtc->props_crtc, WDRM_CRTC__COUNT); + free(crtc); +} + +/** Find all CRTCs of the fd and create drm_crtc objects for them. * - * Finds a free CRTC that might drive the attached connectors, reserves the CRTC - * for the output, and loads the CRTC properties. + * The CRTCs are saved in a list of the drm_backend and will keep there until + * the fd gets closed. * - * Populates the cursor and scanout planes. + * @param b The DRM-backend structure. + * @return 0 on success (at least one CRTC in the list), -1 on failure. + */ +static int +drm_backend_create_crtc_list(struct drm_backend *b) +{ + drmModeRes *resources; + struct drm_crtc *crtc, *crtc_tmp; + int i; + + resources = drmModeGetResources(b->drm.fd); + if (!resources) { + weston_log("drmModeGetResources failed\n"); + return -1; + } + + /* Iterate through all CRTCs */ + for (i = 0; i < resources->count_crtcs; i++) { + + /* Let's create an object for the CRTC and add it to the list */ + crtc = drm_crtc_create(b, resources->crtcs[i], i); + if (!crtc) + goto err; + } + + drmModeFreeResources(resources); + return 0; + +err: + wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link) + drm_crtc_destroy(crtc); + drmModeFreeResources(resources); + return -1; +} + +/** Pick a CRTC and reserve it for the output. * * On failure, the output remains without a CRTC. + * + * @param output The output with no CRTC associated. + * @return 0 on success, -1 on failure. */ static int -drm_output_init_crtc(struct drm_output *output, drmModeRes *resources) +drm_output_attach_crtc(struct drm_output *output) { struct drm_backend *b = to_drm_backend(output->base.compositor); - drmModeObjectPropertiesPtr props; - int i; - - assert(output->crtc_id == 0); - i = drm_output_pick_crtc(output, resources); - if (i < 0) { + output->crtc = drm_output_pick_crtc(output); + if (!output->crtc) { weston_log("Output '%s': No available CRTCs.\n", output->base.name); return -1; } - output->crtc_id = resources->crtcs[i]; - output->pipe = i; - - props = drmModeObjectGetProperties(b->drm.fd, output->crtc_id, - DRM_MODE_OBJECT_CRTC); - if (!props) { - weston_log("failed to get CRTC properties\n"); - goto err_crtc; - } - drm_property_info_populate(b, crtc_props, output->props_crtc, - WDRM_CRTC__COUNT, props); - drmModeFreeObjectProperties(props); - output->scanout_plane = drm_output_find_special_plane(b, output, WDRM_PLANE_TYPE_PRIMARY); if (!output->scanout_plane) { weston_log("Failed to find primary plane for output %s\n", output->base.name); - goto err_crtc; + output->crtc = NULL; + return -1; } /* Without universal planes, we can't discover which formats are @@ -1658,27 +1712,24 @@ drm_output_init_crtc(struct drm_output *output, drmModeRes *resources) drm_output_find_special_plane(b, output, WDRM_PLANE_TYPE_CURSOR); - wl_array_remove_uint32(&b->unused_crtcs, output->crtc_id); + /* Reserve the CRTC for the output */ + output->crtc->output = output; + wl_array_remove_uint32(&b->unused_crtcs, output->crtc->crtc_id); return 0; - -err_crtc: - output->crtc_id = 0; - output->pipe = 0; - - return -1; } -/** Free the CRTC from the output +/** Release reservation of the CRTC. * - * @param output The output whose CRTC to deallocate. + * Make the CRTC free to be reserved and used by another output. * - * The CRTC reserved for the given output becomes free to use again. + * @param output The output that will release its CRTC. */ static void -drm_output_fini_crtc(struct drm_output *output) +drm_output_detach_crtc(struct drm_output *output) { struct drm_backend *b = to_drm_backend(output->base.compositor); + struct drm_crtc *crtc = output->crtc; uint32_t *unused; /* If the compositor is already shutting down, the planes have already @@ -1706,17 +1757,15 @@ drm_output_fini_crtc(struct drm_output *output) } } - drm_property_info_free(output->props_crtc, WDRM_CRTC__COUNT); - - assert(output->crtc_id != 0); - unused = wl_array_add(&b->unused_crtcs, sizeof(*unused)); - *unused = output->crtc_id; + *unused = crtc->crtc_id; /* Force resetting unused CRTCs */ b->state_invalid = true; - output->crtc_id = 0; + crtc->output = NULL; + output->crtc = NULL; + output->cursor_plane = NULL; output->scanout_plane = NULL; } @@ -1726,18 +1775,11 @@ drm_output_enable(struct weston_output *base) { struct drm_output *output = to_drm_output(base); struct drm_backend *b = to_drm_backend(base->compositor); - drmModeRes *resources; int ret; assert(!output->virtual); - resources = drmModeGetResources(b->drm.fd); - if (!resources) { - weston_log("drmModeGetResources failed\n"); - return -1; - } - ret = drm_output_init_crtc(output, resources); - drmModeFreeResources(resources); + ret = drm_output_attach_crtc(output); if (ret < 0) return -1; @@ -1778,14 +1820,13 @@ drm_output_enable(struct weston_output *base) &b->compositor->primary_plane); weston_log("Output %s (crtc %d) video modes:\n", - output->base.name, output->crtc_id); + output->base.name, output->crtc->crtc_id); drm_output_print_modes(output); return 0; err: - drm_output_fini_crtc(output); - + drm_output_detach_crtc(output); return -1; } @@ -1812,11 +1853,11 @@ drm_output_deinit(struct weston_output *base) wl_list_remove(&output->cursor_plane->base.link); wl_list_init(&output->cursor_plane->base.link); /* Turn off hardware cursor */ - drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0); + drmModeSetCursor(b->drm.fd, output->crtc->crtc_id, 0, 0, 0); } } - drm_output_fini_crtc(output); + drm_output_detach_crtc(output); } static void @@ -1891,10 +1932,14 @@ drm_backend_update_unused_outputs(struct drm_backend *b, drmModeRes *resources) wl_array_init(&b->unused_crtcs); for (i = 0; i < resources->count_crtcs; i++) { - struct drm_output *output; + struct drm_output *output = NULL; + struct drm_crtc *crtc; uint32_t *crtc_id; - output = drm_output_find_by_crtc(b, resources->crtcs[i]); + crtc = drm_crtc_find(b, resources->crtcs[i]); + if (crtc) + output = crtc->output; + if (output && output->base.enabled) continue; @@ -2177,6 +2222,8 @@ drm_output_create(struct weston_compositor *compositor, const char *name) return NULL; output->backend = b; + output->crtc = NULL; + #ifdef BUILD_DRM_GBM output->gbm_bo_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING; #endif @@ -2410,6 +2457,7 @@ drm_destroy(struct weston_compositor *ec) { struct drm_backend *b = to_drm_backend(ec); struct weston_head *base, *next; + struct drm_crtc *crtc, *crtc_tmp; udev_input_destroy(&b->input); @@ -2424,6 +2472,9 @@ drm_destroy(struct weston_compositor *ec) b->debug = NULL; weston_compositor_shutdown(ec); + wl_list_for_each_safe(crtc, crtc_tmp, &b->crtc_list, link) + drm_crtc_destroy(crtc); + wl_list_for_each_safe(base, next, &ec->head_list, compositor_link) drm_head_destroy(to_drm_head(base)); @@ -2451,6 +2502,7 @@ session_notify(struct wl_listener *listener, void *data) struct drm_backend *b = to_drm_backend(compositor); struct drm_plane *plane; struct drm_output *output; + struct drm_crtc *crtc; if (compositor->session_active) { weston_log("activating session\n"); @@ -2473,23 +2525,22 @@ session_notify(struct wl_listener *listener, void *data) * pending frame callbacks. */ wl_list_for_each(output, &compositor->output_list, base.link) { + crtc = output->crtc; output->base.repaint_needed = false; if (output->cursor_plane) - drmModeSetCursor(b->drm.fd, output->crtc_id, + drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0); } output = container_of(compositor->output_list.next, struct drm_output, base.link); + crtc = output->crtc; wl_list_for_each(plane, &b->plane_list, link) { if (plane->type != WDRM_PLANE_TYPE_OVERLAY) continue; - - drmModeSetPlane(b->drm.fd, - plane->plane_id, - output->crtc_id, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0); + drmModeSetPlane(b->drm.fd, plane->plane_id, crtc->crtc_id, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); } } } @@ -2923,6 +2974,12 @@ drm_backend_create(struct weston_compositor *compositor, weston_setup_vt_switch_bindings(compositor); + wl_list_init(&b->crtc_list); + if (drm_backend_create_crtc_list(b) == -1) { + weston_log("Failed to create CRTC list for DRM-backend\n"); + goto err_udev_dev; + } + wl_list_init(&b->plane_list); create_sprites(b); diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index c91e3810..0d0fed61 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -533,7 +533,7 @@ drm_output_set_gamma(struct weston_output *output_base, return; rc = drmModeCrtcSetGamma(backend->drm.fd, - output->crtc_id, + output->crtc->crtc_id, size, r, g, b); if (rc) weston_log("set gamma failed: %s\n", strerror(errno)); @@ -568,7 +568,8 @@ drm_output_assign_state(struct drm_output_state *state, output->state_cur = state; if (b->atomic_modeset && mode == DRM_STATE_APPLY_ASYNC) { - drm_debug(b, "\t[CRTC:%u] setting pending flip\n", output->crtc_id); + drm_debug(b, "\t[CRTC:%u] setting pending flip\n", + output->crtc->crtc_id); output->atomic_complete_pending = true; } @@ -608,6 +609,7 @@ drm_output_set_cursor(struct drm_output_state *output_state) { struct drm_output *output = output_state->output; struct drm_backend *b = to_drm_backend(output->base.compositor); + struct drm_crtc *crtc = output->crtc; struct drm_plane *plane = output->cursor_plane; struct drm_plane_state *state; uint32_t handle; @@ -622,7 +624,7 @@ drm_output_set_cursor(struct drm_output_state *output_state) if (!state->fb) { pixman_region32_fini(&plane->base.damage); pixman_region32_init(&plane->base.damage); - drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0); + drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0); return; } @@ -631,7 +633,7 @@ drm_output_set_cursor(struct drm_output_state *output_state) handle = output->gbm_cursor_handle[output->current_cursor]; if (plane->state_cur->fb != state->fb) { - if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle, + if (drmModeSetCursor(b->drm.fd, crtc->crtc_id, handle, b->cursor_width, b->cursor_height)) { weston_log("failed to set cursor: %s\n", strerror(errno)); @@ -642,7 +644,7 @@ drm_output_set_cursor(struct drm_output_state *output_state) pixman_region32_fini(&plane->base.damage); pixman_region32_init(&plane->base.damage); - if (drmModeMoveCursor(b->drm.fd, output->crtc_id, + if (drmModeMoveCursor(b->drm.fd, crtc->crtc_id, state->dest_x, state->dest_y)) { weston_log("failed to move cursor: %s\n", strerror(errno)); goto err; @@ -652,7 +654,7 @@ drm_output_set_cursor(struct drm_output_state *output_state) err: b->cursors_are_broken = true; - drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0); + drmModeSetCursor(b->drm.fd, crtc->crtc_id, 0, 0, 0); } static int @@ -661,6 +663,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state) struct drm_output *output = state->output; struct drm_backend *backend = to_drm_backend(output->base.compositor); struct drm_plane *scanout_plane = output->scanout_plane; + struct drm_crtc *crtc = output->crtc; struct drm_property_info *dpms_prop; struct drm_plane_state *scanout_state; struct drm_mode *mode; @@ -690,14 +693,14 @@ drm_output_apply_state_legacy(struct drm_output_state *state) if (state->dpms != WESTON_DPMS_ON) { if (output->cursor_plane) { - ret = drmModeSetCursor(backend->drm.fd, output->crtc_id, + ret = drmModeSetCursor(backend->drm.fd, crtc->crtc_id, 0, 0, 0); if (ret) weston_log("drmModeSetCursor failed disable: %s\n", strerror(errno)); } - ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, 0, 0, 0, + ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id, 0, 0, 0, NULL, 0, NULL); if (ret) weston_log("drmModeSetCrtc failed disabling: %s\n", @@ -736,7 +739,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state) scanout_plane->state_cur->fb->strides[0] != scanout_state->fb->strides[0]) { - ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id, + ret = drmModeSetCrtc(backend->drm.fd, crtc->crtc_id, scanout_state->fb->fb_id, 0, 0, connectors, n_conn, @@ -749,10 +752,10 @@ drm_output_apply_state_legacy(struct drm_output_state *state) pinfo = scanout_state->fb->format; drm_debug(backend, "\t[CRTC:%u, PLANE:%u] FORMAT: %s\n", - output->crtc_id, scanout_state->plane->plane_id, + crtc->crtc_id, scanout_state->plane->plane_id, pinfo ? pinfo->drm_format_name : "UNKNOWN"); - if (drmModePageFlip(backend->drm.fd, output->crtc_id, + if (drmModePageFlip(backend->drm.fd, crtc->crtc_id, scanout_state->fb->fb_id, DRM_MODE_PAGE_FLIP_EVENT, output) < 0) { weston_log("queueing pageflip failed: %s\n", strerror(errno)); @@ -795,19 +798,19 @@ err: } static int -crtc_add_prop(drmModeAtomicReq *req, struct drm_output *output, +crtc_add_prop(drmModeAtomicReq *req, struct drm_crtc *crtc, enum wdrm_crtc_property prop, uint64_t val) { - struct drm_property_info *info = &output->props_crtc[prop]; + struct drm_property_info *info = &crtc->props_crtc[prop]; int ret; if (info->prop_id == 0) return -1; - ret = drmModeAtomicAddProperty(req, output->crtc_id, info->prop_id, + ret = drmModeAtomicAddProperty(req, crtc->crtc_id, info->prop_id, val); - drm_debug(output->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n", - (unsigned long) output->crtc_id, + drm_debug(crtc->backend, "\t\t\t[CRTC:%lu] %lu (%s) -> %llu (0x%llx)\n", + (unsigned long) crtc->crtc_id, (unsigned long) info->prop_id, info->name, (unsigned long long) val, (unsigned long long) val); return (ret <= 0) ? -1 : 0; @@ -939,6 +942,7 @@ drm_output_apply_state_atomic(struct drm_output_state *state, { struct drm_output *output = state->output; struct drm_backend *b = to_drm_backend(output->base.compositor); + struct drm_crtc *crtc = output->crtc; struct drm_plane_state *plane_state; struct drm_mode *current_mode = to_drm_mode(output->base.current_mode); struct drm_head *head; @@ -958,19 +962,19 @@ drm_output_apply_state_atomic(struct drm_output_state *state, if (ret != 0) return ret; - ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, + ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, current_mode->blob_id); - ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 1); + ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 1); /* No need for the DPMS property, since it is implicit in * routing and CRTC activity. */ wl_list_for_each(head, &output->base.head_list, base.output_link) { ret |= connector_add_prop(req, head, WDRM_CONNECTOR_CRTC_ID, - output->crtc_id); + crtc->crtc_id); } } else { - ret |= crtc_add_prop(req, output, WDRM_CRTC_MODE_ID, 0); - ret |= crtc_add_prop(req, output, WDRM_CRTC_ACTIVE, 0); + ret |= crtc_add_prop(req, crtc, WDRM_CRTC_MODE_ID, 0); + ret |= crtc_add_prop(req, crtc, WDRM_CRTC_ACTIVE, 0); /* No need for the DPMS property, since it is implicit in * routing and CRTC activity. */ @@ -993,7 +997,7 @@ drm_output_apply_state_atomic(struct drm_output_state *state, ret |= plane_add_prop(req, plane, WDRM_PLANE_FB_ID, plane_state->fb ? plane_state->fb->fb_id : 0); ret |= plane_add_prop(req, plane, WDRM_PLANE_CRTC_ID, - plane_state->fb ? output->crtc_id : 0); + plane_state->fb ? crtc->crtc_id : 0); ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_X, plane_state->src_x); ret |= plane_add_prop(req, plane, WDRM_PLANE_SRC_Y, @@ -1391,11 +1395,17 @@ atomic_flip_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, unsigned int crtc_id, void *data) { struct drm_backend *b = data; - struct drm_output *output = drm_output_find_by_crtc(b, crtc_id); + struct drm_crtc *crtc; + struct drm_output *output; uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC | WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION | WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK; + crtc = drm_crtc_find(b, crtc_id); + assert(crtc); + + output = crtc->output; + /* During the initial modeset, we can disable CRTCs which we don't * actually handle during normal operation; this will give us events * for unknown outputs. Ignore them. */