summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergi Granell <xerpi.g.12@gmail.com>2017-01-12 17:17:32 +0000
committerDaniel Stone <daniels@collabora.com>2018-07-09 15:39:32 +0100
commitf4456221db312f326dc0f16a306686d8c2f3c999 (patch)
tree16b57822c6bf262be893998a57b0a37d154e0447
parentf522e2261131eb9ed9f83157420f114540cfcbf1 (diff)
downloadweston-f4456221db312f326dc0f16a306686d8c2f3c999.tar.gz
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 <xerpi.g.12@gmail.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Reviewed-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk> Tested-by: Emre Ucan <eucan@de.adit-jv.com>
-rw-r--r--configure.ac3
-rw-r--r--libweston/compositor-drm.c134
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