On Tue, 18 Jul 2017 14:14:31 +0100 Daniel Stone <dani...@collabora.com> wrote:
> Change the type of cursor_plane from a weston_plane (base tracking > structure) to a drm_plane (wrapper containing additional DRM-specific > details), and make it a dynamically-allocated pointer. > > Using the standard drm_plane allows us to reuse code which already deals > with drm_planes, e.g. a common cleanup function. > > This patch introduces a 'special plane' helper, creating a drm_plane > either from a real KMS plane when using universal planes, or a fake plane > otherwise. Without universal planes, the cursor and primary planes are > hidden from us; this helper allows us to pretend otherwise. Hi, I found a couple of holes in the pretending: NULL dereference I think you're guaranteed to hit, and missing fake plane teardown. We are going to need a testing switch to make Weston believe universal planes are not available so we can test that path, or stop pretending. :-) But the universal plane path looks ok. > > Signed-off-by: Daniel Stone <dani...@collabora.com> > --- > libweston/compositor-drm.c | 395 > ++++++++++++++++++++++++++++++++++----------- > 1 file changed, 304 insertions(+), 91 deletions(-) > > diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c > index 6fdf31a7..2ede76b6 100644 > --- a/libweston/compositor-drm.c > +++ b/libweston/compositor-drm.c > @@ -2363,6 +2435,19 @@ drm_assign_planes(struct weston_output *output_base, > void *repaint_data) > pixman_region32_fini(&surface_overlap); > } > pixman_region32_fini(&overlap); > + > + /* We rely on ev->cursor_view being both an accurate reflection of the ev->cursor_view should be output->cursor_view. > + * cursor plane's state, but also being maintained across repaints to > + * avoid unnecessary damage uploads, per the comment in > + * drm_output_prepare_cursor_view. In the event that we go from having > + * a cursor view to not having a cursor view, we need to clear it. */ > + if (output->cursor_view) { > + plane_state = > + drm_output_state_get_existing_plane(state, > + > output->cursor_plane); > + if (!plane_state || !plane_state->fb) > + output->cursor_view = NULL; > + } > } > > /** > @@ -2628,19 +2713,30 @@ init_pixman(struct drm_backend *b) > * Creates one drm_plane structure for a hardware plane, and initialises its > * properties and formats. > * > + * In the absence of universal plane support, where KMS does not explicitly > + * expose the primary and cursor planes to userspace, this may also create > + * an 'internal' plane for internal management. > + * > * This function does not add the plane to the list of usable planes in > Weston > * itself; the caller is responsible for this. > * > * Call drm_plane_destroy to clean up the plane. > * > + * @sa drm_output_find_special_plane > * @param b DRM compositor backend > - * @param kplane DRM plane to create > + * @param kplane DRM plane to create, or NULL if creating internal plane > + * @param output Output to create internal plane for, or NULL > + * @param type Type to use when creating internal plane, or invalid > + * @param format Format to use for internal planes, or 0 > */ > static struct drm_plane * > -drm_plane_create(struct drm_backend *b, const drmModePlane *kplane) > +drm_plane_create(struct drm_backend *b, const drmModePlane *kplane, > + struct drm_output *output, enum wdrm_plane_type type, > + uint32_t format) > { > struct drm_plane *plane; > drmModeObjectProperties *props; > + int num_formats = (kplane) ? kplane->count_formats : 1; > > static struct drm_property_enum_info plane_type_enums[] = { > [WDRM_PLANE_TYPE_PRIMARY] = { > @@ -2661,21 +2757,38 @@ drm_plane_create(struct drm_backend *b, const > drmModePlane *kplane) > }, > }; > > - plane = zalloc(sizeof(*plane) + ((sizeof(uint32_t)) * > - kplane->count_formats)); > + /* With universal planes, everything is a DRM plane; without > + * universal planes, the only DRM planes are overlay planes. */ > + if (b->universal_planes) > + assert(b->universal_planes && kplane); > + else > + assert(!b->universal_planes && > + (type == WDRM_PLANE_TYPE_OVERLAY || (output && format))); Any reason for the redundancy of the 'if' condition in the asserts? > + > + plane = zalloc(sizeof(*plane) + > + (sizeof(uint32_t) * num_formats)); > if (!plane) { > weston_log("%s: out of memory\n", __func__); > return NULL; > } > > plane->backend = b; > - plane->possible_crtcs = kplane->possible_crtcs; > - plane->plane_id = kplane->plane_id; > - plane->count_formats = kplane->count_formats; > plane->state_cur = drm_plane_state_alloc(NULL, plane); > plane->state_cur->complete = true; > - memcpy(plane->formats, kplane->formats, > - kplane->count_formats * sizeof(kplane->formats[0])); > + > + if (kplane) { > + plane->possible_crtcs = kplane->possible_crtcs; > + plane->plane_id = kplane->plane_id; > + plane->count_formats = kplane->count_formats; > + memcpy(plane->formats, kplane->formats, > + kplane->count_formats * sizeof(kplane->formats[0])); > + } Remove line break here. > + else { > + plane->possible_crtcs = (1 << output->pipe); > + plane->plane_id = 0; > + plane->count_formats = 1; > + plane->formats[0] = format; > + } > > props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id, > DRM_MODE_OBJECT_PLANE); Does drmModeObjectGetProperties() actually work without universal planes for non-overlay planes? Should we simply set plane->type = type; and skip all the property stuff here? Oh, but this is even a NULL-dereference when kplane is NULL. Medic! :-) > @@ -2689,7 +2802,7 @@ drm_plane_create(struct drm_backend *b, const > drmModePlane *kplane) > plane->type = > drm_property_get_value(&plane->props[WDRM_PLANE_TYPE], > props, > - WDRM_PLANE_TYPE_OVERLAY); > + type); > drmModeFreeObjectProperties(props); > > weston_plane_init(&plane->base, b->compositor, 0, 0); > @@ -2699,6 +2812,88 @@ drm_plane_create(struct drm_backend *b, const > drmModePlane *kplane) > } > > /** > + * Find, or create, a special-purpose plane > + * > + * Primary and cursor planes are a special case, in that before universal > + * planes, they are driven by non-plane API calls. Without universal plane > + * support, the only way to configure a primary plane is via drmModeSetCrtc, > + * and the only way to configure a cursor plane is drmModeSetCursor2. > + * > + * Although they may actually be regular planes in the hardware, without > + * universal plane support, these planes are not actually exposed to > + * userspace in the regular plane list. > + * > + * However, for ease of internal tracking, we want to manage all planes > + * through the same drm_plane structures. Therefore, when we are running > + * without universal plane support, we create fake drm_plane structures > + * to track these planes. > + * > + * @param b DRM backend > + * @param output Output to use for plane > + * @param type Type of plane > + */ > +static struct drm_plane * > +drm_output_find_special_plane(struct drm_backend *b, struct drm_output > *output, > + enum wdrm_plane_type type) > +{ > + struct drm_plane *plane; > + > + if (!b->universal_planes) { > + uint32_t format; > + > + switch (type) { > + case WDRM_PLANE_TYPE_CURSOR: > + format = GBM_FORMAT_ARGB8888; > + break; > + case WDRM_PLANE_TYPE_PRIMARY: > + format = output->gbm_format; > + break; > + default: > + assert(!"invalid type in > drm_output_find_special_plane"); > + break; > + } > + > + return drm_plane_create(b, NULL, output, type, format); > + } > + > + wl_list_for_each(plane, &b->plane_list, link) { > + struct drm_output *tmp; > + bool found_elsewhere = false; > + > + if (plane->type != type) > + continue; > + if (!drm_plane_crtc_supported(output, plane)) > + continue; > + > + /* On some platforms, primary/cursor planes can roam > + * between different CRTCs, so make sure we don't claim the > + * same plane for two outputs. */ > + wl_list_for_each(tmp, &b->compositor->pending_output_list, > + base.link) { > + if (tmp->cursor_plane == plane) { > + found_elsewhere = true; > + break; > + } > + } > + wl_list_for_each(tmp, &b->compositor->output_list, > + base.link) { > + if (tmp->cursor_plane == plane) { > + found_elsewhere = true; > + break; > + } > + } > + > + if (found_elsewhere) > + continue; > + > + plane->possible_crtcs = (1 << output->pipe); I'm a little confused here. You smash the possible_crtcs and you have the search loops to see if the plane was already associated to some output. Why both, isn't one enough? > + return plane; > + } > + > + return NULL; > +} > + > +/** > * Destroy one DRM plane > * > * Destroy a DRM plane, removing it from screen and releasing its retained > @@ -3634,10 +3844,11 @@ drm_output_deinit(struct weston_output *base) > drm_output_fini_egl(output); > > weston_plane_release(&output->scanout_plane); > - weston_plane_release(&output->cursor_plane); > > - /* Turn off hardware cursor */ > - drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0); > + if (output->cursor_plane) { > + /* Turn off hardware cursor */ > + drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0); Are we not leaking the cursor plane if drm_output_find_special_plane() created it in the no-universal-planes case? Looks like drm_plane_destroy() would need a special path for the special fake planes. > + } > } > > static void > @@ -4040,7 +4251,9 @@ session_notify(struct wl_listener *listener, void *data) > > wl_list_for_each(output, &compositor->output_list, base.link) { > output->base.repaint_needed = false; > - drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0); > + if (output->cursor_plane) > + drmModeSetCursor(b->drm.fd, output->crtc_id, > + 0, 0, 0); > } > > output = container_of(compositor->output_list.next, Thanks, pq
pgpey30VnHV2h.pgp
Description: OpenPGP digital signature
_______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel