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

Pekka Paalanen ppaalanen at gmail.com
Mon Jan 29 15:01:03 UTC 2018


On Wed, 20 Dec 2017 12:26:57 +0000
Daniel Stone <daniels at collabora.com> wrote:

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

Hi,

I wonder, we are getting more and more of these "libdrm has ..."
feature checks. How about merging some to produce fewer build types?
Just a general idea, not specifically for this patch.

> 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);
> +}

These two functions are unlikely to be used anywhere else than
populate_format_modifiers(), so they might as well be in the same #ifdef
block. If even functions at all. A long line.

> +#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)

I think this should be:

static int
drm_plane_populate_format_modifiers(...

I believe we tend to use int for success/failure returns, where
negative is a failure. Boolean return values are more used for
functions that return a truth value, like drm_device_is_kms().

> +{
> +	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;

Should we not check that fmt_mod_blob.version == 1?

> +	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]));

Split line, please.

> +			if (!modifiers) {

Realloc is a bit inconvenient in that if it fails, the original
allocation stays. Here I think it's such an unlikely occurrence that I
don't mind the leak. Everything would be failing anyway.

Either handle the original allocation staying, or don't bother handling
failure at all.

> +				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];
> +		}
> +

I wonder if it would be more readable to have the above hunk in a
function

static int
drm_plane_populate_formats(struct drm_plane *plane,
			   const drmModePlane *kplane,
			   const drmModeObjectProperties *props);

That way the #ifdefs would be inside a smaller function, there would be
fewer clean-up paths, and more room in line length.

>  		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

The code seems correct to me, mostly style'ish issues.


Thanks,
pq
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://lists.freedesktop.org/archives/wayland-devel/attachments/20180129/30307734/attachment-0001.sig>


More information about the wayland-devel mailing list