[PATCH v14 40/41] compositor-drm: Support plane IN_FORMATS

Daniel Stone daniels at collabora.com
Wed Dec 20 12:26:57 UTC 2017


From: Sergi Granell <xerpi.g.12 at gmail.com>

The per-plane IN_FORMATS property adds information about format
modifiers; we can use these to both feed GBM with the set of modifiers
we want to use for rendering, and also as an early-out test when we're
trying to see if a FB will go on a particular plane.

Signed-off-by: Sergi Granell <xerpi.g.12 at gmail.com>
Reviewed-by: Daniel Stone <daniels at collabora.com>
Signed-off-by: Daniel Stone <daniels at collabora.com>
---
 configure.ac               |   3 ++
 libweston/compositor-drm.c | 128 +++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 122 insertions(+), 9 deletions(-)

diff --git a/configure.ac b/configure.ac
index 8d0d6582a..bc6fefc1e 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 cb1c23b03..ba2217fc0 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -83,6 +83,20 @@
 #define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
 #endif
 
+#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
+
 /**
  * Represents the values of an enum-type KMS property
  */
@@ -127,6 +141,7 @@ enum wdrm_plane_property {
 	WDRM_PLANE_CRTC_H,
 	WDRM_PLANE_FB_ID,
 	WDRM_PLANE_CRTC_ID,
+	WDRM_PLANE_IN_FORMATS,
 	WDRM_PLANE__COUNT
 };
 
@@ -168,6 +183,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" },
 };
 
 /**
@@ -403,7 +419,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_output {
@@ -2879,7 +2899,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)
@@ -3635,6 +3667,61 @@ init_pixman(struct drm_backend *b)
 	return pixman_renderer_init(b->compositor);
 }
 
+/**
+ * Populates the formats array, and the modifiers of each format for a drm_plane.
+ */
+#ifdef HAVE_DRM_FORMATS_BLOB
+static bool
+populate_format_modifiers(struct drm_plane *plane, const drmModePlane *kplane,
+			  uint32_t blob_id)
+{
+	unsigned i, j;
+	drmModePropertyBlobRes *blob;
+	struct drm_format_modifier_blob *fmt_mod_blob;
+	uint32_t *blob_formats;
+	struct drm_format_modifier *blob_modifiers;
+
+	blob = drmModeGetPropertyBlob(plane->backend->drm.fd, blob_id);
+	if (!blob)
+		return false;
+
+	fmt_mod_blob = blob->data;
+	blob_formats = formats_ptr(fmt_mod_blob);
+	blob_modifiers = modifiers_ptr(fmt_mod_blob);
+
+	assert(plane->count_formats == fmt_mod_blob->count_formats);
+
+	for (i = 0; i < fmt_mod_blob->count_formats; i++) {
+		uint32_t count_modifiers = 0;
+		uint64_t *modifiers = NULL;
+
+		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]));
+			if (!modifiers) {
+				drmModeFreePropertyBlob(blob);
+				return false;
+			}
+			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 true;
+}
+#endif
+
 /**
  * Create a drm_plane for a hardware plane
  *
@@ -3664,25 +3751,27 @@ 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) {
+#ifdef HAVE_DRM_FORMATS_BLOB
+		uint32_t blob_id;
+#endif
+
 		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);
@@ -3696,13 +3785,34 @@ drm_plane_create(struct drm_backend *b, const drmModePlane *kplane,
 			drm_property_get_value(&plane->props[WDRM_PLANE_TYPE],
 					       props,
 					       WDRM_PLANE_TYPE__COUNT);
+
+#ifdef HAVE_DRM_FORMATS_BLOB
+		blob_id = drm_property_get_value(&plane->props[WDRM_PLANE_IN_FORMATS],
+					         props,
+					         0);
+		if (blob_id) {
+			if (!populate_format_modifiers(plane, kplane, blob_id)) {
+				weston_log("%s: out of memory\n", __func__);
+				drm_property_info_free(plane->props, WDRM_PLANE__COUNT);
+				drmModeFreeObjectProperties(props);
+				free(plane);
+				return NULL;
+			}
+		} else
+#endif
+		{
+			uint32_t i;
+			for (i = 0; i < kplane->count_formats; i++)
+				plane->formats[i].format = kplane->formats[i];
+		}
+
 		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;
 	}
 
@@ -4768,7 +4878,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
-- 
2.14.3



More information about the wayland-devel mailing list