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 f11ec02cad ("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>
dev
Sergi Granell 8 years ago committed by Daniel Stone
parent f522e22611
commit f4456221db
  1. 3
      configure.ac
  2. 134
      libweston/compositor-drm.c

@ -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])])

@ -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

Loading…
Cancel
Save