From f4456221db312f326dc0f16a306686d8c2f3c999 Mon Sep 17 00:00:00 2001 From: Sergi Granell Date: Thu, 12 Jan 2017 17:17:32 +0000 Subject: compositor-drm: Support plane IN_FORMATS The per-plane IN_FORMATS KMS property describes the format/modifier combinations supported for display on this plane. Read and parse this format, storing the data in each plane, so we can know which combinations might work, and which combinations definitely will not work. Similarly to f11ec02cad40 ("compositor-drm: Extract overlay FB import to helper"), we now use this when considering promoting a view to overlay planes. If the framebuffer's modifier is definitely not supported by the plane, we do not attempt to use that plane for that view. This will also be used in a follow-patch, passing the list of modifiers to GBM surface allocation to allow it to allocate more optimal buffers. Signed-off-by: Sergi Granell Reviewed-by: Daniel Stone Reviewed-by: Pekka Paalanen Tested-by: Emre Ucan --- configure.ac | 3 + libweston/compositor-drm.c | 134 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 128 insertions(+), 9 deletions(-) diff --git a/configure.ac b/configure.ac index ef55ace3..c550198a 100644 --- a/configure.ac +++ b/configure.ac @@ -212,6 +212,9 @@ if test x$enable_drm_compositor = xyes; then PKG_CHECK_MODULES(DRM_COMPOSITOR_ATOMIC, [libdrm >= 2.4.78], [AC_DEFINE([HAVE_DRM_ATOMIC], 1, [libdrm supports atomic API])], [AC_MSG_WARN([libdrm does not support atomic modesetting, will omit that capability])]) + PKG_CHECK_MODULES(DRM_COMPOSITOR_FORMATS_BLOB, [libdrm >= 2.4.83], + [AC_DEFINE([HAVE_DRM_FORMATS_BLOB], 1, [libdrm supports modifier advertisement])], + [AC_MSG_WARN([libdrm does not support modifier advertisement])]) PKG_CHECK_MODULES(DRM_COMPOSITOR_GBM, [gbm >= 17.2], [AC_DEFINE([HAVE_GBM_FD_IMPORT], 1, [gbm supports import with modifiers])], [AC_MSG_WARN([GBM does not support dmabuf import, will omit that capability])]) diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c index 87e3e5d2..907a62b3 100644 --- a/libweston/compositor-drm.c +++ b/libweston/compositor-drm.c @@ -144,6 +144,7 @@ enum wdrm_plane_property { WDRM_PLANE_CRTC_H, WDRM_PLANE_FB_ID, WDRM_PLANE_CRTC_ID, + WDRM_PLANE_IN_FORMATS, WDRM_PLANE__COUNT }; @@ -185,6 +186,7 @@ static const struct drm_property_info plane_props[] = { [WDRM_PLANE_CRTC_H] = { .name = "CRTC_H", }, [WDRM_PLANE_FB_ID] = { .name = "FB_ID", }, [WDRM_PLANE_CRTC_ID] = { .name = "CRTC_ID", }, + [WDRM_PLANE_IN_FORMATS] = { .name = "IN_FORMATS" }, }; /** @@ -448,7 +450,11 @@ struct drm_plane { struct wl_list link; - uint32_t formats[]; + struct { + uint32_t format; + uint32_t count_modifiers; + uint64_t *modifiers; + } formats[]; }; struct drm_head { @@ -3002,7 +3008,19 @@ drm_output_prepare_overlay_view(struct drm_output_state *output_state, /* Check whether the format is supported */ for (i = 0; i < p->count_formats; i++) { - if (p->formats[i] == fb->format->format) + unsigned int j; + + if (p->formats[i].format != fb->format->format) + continue; + + if (fb->modifier == DRM_FORMAT_MOD_INVALID) + break; + + for (j = 0; j < p->formats[i].count_modifiers; j++) { + if (p->formats[i].modifiers[j] == fb->modifier) + break; + } + if (j != p->formats[i].count_modifiers) break; } if (i == p->count_formats) @@ -3647,6 +3665,100 @@ init_pixman(struct drm_backend *b) return pixman_renderer_init(b->compositor); } +#ifdef HAVE_DRM_FORMATS_BLOB +static inline uint32_t * +formats_ptr(struct drm_format_modifier_blob *blob) +{ + return (uint32_t *)(((char *)blob) + blob->formats_offset); +} + +static inline struct drm_format_modifier * +modifiers_ptr(struct drm_format_modifier_blob *blob) +{ + return (struct drm_format_modifier *) + (((char *)blob) + blob->modifiers_offset); +} +#endif + +/** + * Populates the plane's formats array, using either the IN_FORMATS blob + * property (if available), or the plane's format list if not. + */ +static int +drm_plane_populate_formats(struct drm_plane *plane, const drmModePlane *kplane, + const drmModeObjectProperties *props) +{ + unsigned i; +#ifdef HAVE_DRM_FORMATS_BLOB + drmModePropertyBlobRes *blob; + struct drm_format_modifier_blob *fmt_mod_blob; + struct drm_format_modifier *blob_modifiers; + uint32_t *blob_formats; + uint32_t blob_id; + + blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS], + props, + 0); + if (blob_id == 0) + goto fallback; + + blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id); + if (!blob) + goto fallback; + + fmt_mod_blob = blob->data; + blob_formats = formats_ptr(fmt_mod_blob); + blob_modifiers = modifiers_ptr(fmt_mod_blob); + + if (plane->count_formats != fmt_mod_blob->count_formats) { + weston_log("DRM backend: format count differs between " + "plane (%d) and IN_FORMATS (%d)\n", + plane->count_formats, + fmt_mod_blob->count_formats); + weston_log("This represents a kernel bug; Weston is " + "unable to continue.\n"); + abort(); + } + + for (i = 0; i < fmt_mod_blob->count_formats; i++) { + uint32_t count_modifiers = 0; + uint64_t *modifiers = NULL; + unsigned j; + + for (j = 0; j < fmt_mod_blob->count_modifiers; j++) { + struct drm_format_modifier *mod = &blob_modifiers[j]; + + if ((i < mod->offset) || (i > mod->offset + 63)) + continue; + if (!(mod->formats & (1 << (i - mod->offset)))) + continue; + + modifiers = realloc(modifiers, + (count_modifiers + 1) * + sizeof(modifiers[0])); + assert(modifiers); + modifiers[count_modifiers++] = mod->modifier; + } + + plane->formats[i].format = blob_formats[i]; + plane->formats[i].modifiers = modifiers; + plane->formats[i].count_modifiers = count_modifiers; + } + + drmModeFreePropertyBlob(blob); + + return 0; + +fallback: +#endif + /* No IN_FORMATS blob available, so just use the old. */ + assert(plane->count_formats == kplane->count_formats); + for (i = 0; i < kplane->count_formats; i++) + plane->formats[i].format = kplane->formats[i]; + + return 0; +} + /** * Create a drm_plane for a hardware plane * @@ -3676,25 +3788,23 @@ drm_plane_create(struct drm_backend *b, const drmModePlane *kplane, { struct drm_plane *plane; drmModeObjectProperties *props; - int num_formats = (kplane) ? kplane->count_formats : 1; + uint32_t num_formats = (kplane) ? kplane->count_formats : 1; plane = zalloc(sizeof(*plane) + - (sizeof(uint32_t) * num_formats)); + (sizeof(plane->formats[0]) * num_formats)); if (!plane) { weston_log("%s: out of memory\n", __func__); return NULL; } plane->backend = b; + plane->count_formats = num_formats; plane->state_cur = drm_plane_state_alloc(NULL, plane); plane->state_cur->complete = true; 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])); props = drmModeObjectGetProperties(b->drm.fd, kplane->plane_id, DRM_MODE_OBJECT_PLANE); @@ -3708,13 +3818,19 @@ drm_plane_create(struct drm_backend *b, const drmModePlane *kplane, drm_property_get_value(&plane->props[WDRM_PLANE_TYPE], props, WDRM_PLANE_TYPE__COUNT); + + if (drm_plane_populate_formats(plane, kplane, props) < 0) { + drmModeFreeObjectProperties(props); + goto err; + } + drmModeFreeObjectProperties(props); } else { plane->possible_crtcs = (1 << output->pipe); plane->plane_id = 0; plane->count_formats = 1; - plane->formats[0] = format; + plane->formats[0].format = format; plane->type = type; } @@ -4990,7 +5106,7 @@ drm_output_set_gbm_format(struct weston_output *base, * supported by the primary plane; we just hope that the GBM format * works. */ if (!b->universal_planes) - output->scanout_plane->formats[0] = output->gbm_format; + output->scanout_plane->formats[0].format = output->gbm_format; } static void -- cgit v1.2.1