[Mesa-dev] [PATCH v2 2/2] egl/android: Use gralloc::lock_ycbcr for resolving YUV formats (v2)

Tapani Pälli tapani.palli at intel.com
Thu Nov 10 08:48:21 UTC 2016



On 11/10/2016 09:55 AM, Tomasz Figa wrote:
> There is an interface that can be used to query YUV buffers for their
> internal format. Specifically, if gralloc:lock_ycbcr() is given no SW
> usage flags, it's supposed to return plane offsets instead of pointers.
> Let's use this interface to implement support for YUV formats in Android
> EGL backend.

IMO lock_ycbcr() is not very intuitive API (read: is horrible) to query 
surface information, would be nice to have something generic along the 
lines of 'resolve_format' or 'query_format' but I don't know how 
feasible it would be to push for such new interface ..

both of these patches look good to me;
Reviewed-by: Tapani Pälli <tapani.palli at intel.com>

> v2: Fixes from Emil's review:
>  a) Added comments for parts that might be not clear,
>  b) Changed get_fourcc_yuv() to return -1 on failure,
>  c) Changed is_yuv() to use bool.
>
> Signed-off-by: Tomasz Figa <tfiga at chromium.org>
> Reviewed-by: Emil Velikov <emil.velikov at collabora.com>
> ---
>  src/egl/drivers/dri2/platform_android.c | 162 +++++++++++++++++++++++++++-----
>  1 file changed, 136 insertions(+), 26 deletions(-)
>
> diff --git a/src/egl/drivers/dri2/platform_android.c b/src/egl/drivers/dri2/platform_android.c
> index 3f5e2de..e70896e 100644
> --- a/src/egl/drivers/dri2/platform_android.c
> +++ b/src/egl/drivers/dri2/platform_android.c
> @@ -31,6 +31,7 @@
>  #include <dlfcn.h>
>  #include <fcntl.h>
>  #include <xf86drm.h>
> +#include <stdbool.h>
>
>  #if ANDROID_VERSION >= 0x402
>  #include <sync/sync.h>
> @@ -43,6 +44,52 @@
>
>  #define ALIGN(val, align)	(((val) + (align) - 1) & ~((align) - 1))
>
> +struct droid_yuv_format {
> +   /* Lookup keys */
> +   int native; /* HAL_PIXEL_FORMAT_ */
> +   int is_ycrcb; /* 0 if chroma order is {Cb, Cr}, 1 if {Cr, Cb} */
> +   int chroma_step; /* Distance in bytes between subsequent chroma pixels. */
> +
> +   /* Result */
> +   int fourcc; /* __DRI_IMAGE_FOURCC_ */
> +};
> +
> +/* The following table is used to look up a DRI image FourCC based
> + * on native format and information contained in android_ycbcr struct. */
> +static const struct droid_yuv_format droid_yuv_formats[] = {
> +   /* Native format, YCrCb, Chroma step, DRI image FourCC */
> +   { HAL_PIXEL_FORMAT_YCbCr_420_888,   0, 2, __DRI_IMAGE_FOURCC_NV12 },
> +   { HAL_PIXEL_FORMAT_YCbCr_420_888,   0, 1, __DRI_IMAGE_FOURCC_YUV420 },
> +   { HAL_PIXEL_FORMAT_YCbCr_420_888,   1, 1, __DRI_IMAGE_FOURCC_YVU420 },
> +   { HAL_PIXEL_FORMAT_YV12,            1, 1, __DRI_IMAGE_FOURCC_YVU420 },
> +};
> +
> +static int
> +get_fourcc_yuv(int native, int is_ycrcb, int chroma_step)
> +{
> +   int i;
> +
> +   for (i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i)
> +      if (droid_yuv_formats[i].native == native &&
> +          droid_yuv_formats[i].is_ycrcb == is_ycrcb &&
> +          droid_yuv_formats[i].chroma_step == chroma_step)
> +         return droid_yuv_formats[i].fourcc;
> +
> +   return -1;
> +}
> +
> +static bool
> +is_yuv(int native)
> +{
> +   int i;
> +
> +   for (i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i)
> +      if (droid_yuv_formats[i].native == native)
> +         return true;
> +
> +   return false;
> +}
> +
>  static int
>  get_format_bpp(int native)
>  {
> @@ -57,9 +104,6 @@ get_format_bpp(int native)
>     case HAL_PIXEL_FORMAT_RGB_565:
>        bpp = 2;
>        break;
> -   case HAL_PIXEL_FORMAT_YV12:
> -      bpp = 1;
> -      break;
>     default:
>        bpp = 0;
>        break;
> @@ -76,7 +120,6 @@ static int get_fourcc(int native)
>     case HAL_PIXEL_FORMAT_BGRA_8888: return __DRI_IMAGE_FOURCC_ARGB8888;
>     case HAL_PIXEL_FORMAT_RGBA_8888: return __DRI_IMAGE_FOURCC_ABGR8888;
>     case HAL_PIXEL_FORMAT_RGBX_8888: return __DRI_IMAGE_FOURCC_XBGR8888;
> -   case HAL_PIXEL_FORMAT_YV12:      return __DRI_IMAGE_FOURCC_YVU420;
>     default:
>        _eglLog(_EGL_WARNING, "unsupported native buffer format 0x%x", native);
>     }
> @@ -479,35 +522,80 @@ droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
>  }
>
>  static _EGLImage *
> -droid_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
> -                                 struct ANativeWindowBuffer *buf, int fd)
> +droid_create_image_from_prime_fd_yuv(_EGLDisplay *disp, _EGLContext *ctx,
> +                                     struct ANativeWindowBuffer *buf, int fd)
>  {
> -   unsigned int offsets[3] = { 0, 0, 0 };
> -   unsigned int pitches[3] = { 0, 0, 0 };
> +   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
> +   struct android_ycbcr ycbcr;
> +   size_t offsets[3];
> +   size_t pitches[3];
> +   int is_ycrcb;
> +   int fourcc;
> +   int ret;
>
> -   const int fourcc = get_fourcc(buf->format);
> -   if (fourcc == -1) {
> -      _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
> +   if (!dri2_dpy->gralloc->lock_ycbcr) {
> +      _eglLog(_EGL_WARNING, "Gralloc does not support lock_ycbcr");
>        return NULL;
>     }
>
> -   pitches[0] = buf->stride * get_format_bpp(buf->format);
> -   if (pitches[0] == 0) {
> -      _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
> +   memset(&ycbcr, 0, sizeof(ycbcr));
> +   ret = dri2_dpy->gralloc->lock_ycbcr(dri2_dpy->gralloc, buf->handle,
> +                                       0, 0, 0, 0, 0, &ycbcr);
> +   if (ret) {
> +      _eglLog(_EGL_WARNING, "gralloc->lock_ycbcr failed: %d", ret);
>        return NULL;
>     }
> +   dri2_dpy->gralloc->unlock(dri2_dpy->gralloc, buf->handle);
> +
> +   /* When lock_ycbcr's usage argument contains no SW_READ/WRITE flags
> +    * it will return the .y/.cb/.cr pointers based on a NULL pointer,
> +    * so they can be interpreted as offsets. */
> +   offsets[0] = (size_t)ycbcr.y;
> +   /* We assume here that all the planes are located in one DMA-buf. */
> +   is_ycrcb = (size_t)ycbcr.cb < (size_t)ycbcr.cr;
> +   if (is_ycrcb) {
> +      offsets[1] = (size_t)ycbcr.cr;
> +      offsets[2] = (size_t)ycbcr.cb;
> +   } else {
> +      offsets[1] = (size_t)ycbcr.cb;
> +      offsets[2] = (size_t)ycbcr.cr;
> +   }
>
> -   switch (buf->format) {
> -   case HAL_PIXEL_FORMAT_YV12:
> -      /* Y plane is assumed to be at offset 0. */
> -      /* Cr plane is located after Y plane */
> -      offsets[1] = offsets[0] + pitches[0] * buf->height;
> -      pitches[1] = ALIGN(pitches[0] / 2, 16);
> -      /* Cb plane is located after Cr plane */
> -      offsets[2] = offsets[1] + pitches[1] * buf->height / 2;
> -      pitches[2] = pitches[1];
> +   /* .ystride is the line length (in bytes) of the Y plane,
> +    * .cstride is the line length (in bytes) of any of the remaining
> +    * Cb/Cr/CbCr planes, assumed to be the same for Cb and Cr for fully
> +    * planar formats. */
> +   pitches[0] = ycbcr.ystride;
> +   pitches[1] = pitches[2] = ycbcr.cstride;
>
> -      const EGLint attr_list_yv12[] = {
> +   /* .chroma_step is the byte distance between the same chroma channel
> +    * values of subsequent pixels, assumed to be the same for Cb and Cr. */
> +   fourcc = get_fourcc_yuv(buf->format, is_ycrcb, ycbcr.chroma_step);
> +   if (fourcc == -1) {
> +      _eglLog(_EGL_WARNING, "unsupported YUV format, native = %x, is_ycrcb = %d, chroma_step = %d",
> +              buf->format, is_ycrcb, ycbcr.chroma_step);
> +      return NULL;
> +   }
> +
> +   if (ycbcr.chroma_step == 2) {
> +      /* Semi-planar Y + CbCr or Y + CbCr format. */
> +      const EGLint attr_list_2plane[] = {
> +         EGL_WIDTH, buf->width,
> +         EGL_HEIGHT, buf->height,
> +         EGL_LINUX_DRM_FOURCC_EXT, fourcc,
> +         EGL_DMA_BUF_PLANE0_FD_EXT, fd,
> +         EGL_DMA_BUF_PLANE0_PITCH_EXT, pitches[0],
> +         EGL_DMA_BUF_PLANE0_OFFSET_EXT, offsets[0],
> +         EGL_DMA_BUF_PLANE1_FD_EXT, fd,
> +         EGL_DMA_BUF_PLANE1_PITCH_EXT, pitches[1],
> +         EGL_DMA_BUF_PLANE1_OFFSET_EXT, offsets[1],
> +         EGL_NONE, 0
> +      };
> +
> +      return dri2_create_image_dma_buf(disp, ctx, NULL, attr_list_2plane);
> +   } else {
> +      /* Fully planar Y + Cb + Cr or Y + Cr + Cb format. */
> +      const EGLint attr_list_3plane[] = {
>           EGL_WIDTH, buf->width,
>           EGL_HEIGHT, buf->height,
>           EGL_LINUX_DRM_FOURCC_EXT, fourcc,
> @@ -523,7 +611,29 @@ droid_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
>           EGL_NONE, 0
>        };
>
> -      return dri2_create_image_dma_buf(disp, ctx, NULL, attr_list_yv12);
> +      return dri2_create_image_dma_buf(disp, ctx, NULL, attr_list_3plane);
> +   }
> +}
> +
> +static _EGLImage *
> +droid_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
> +                                 struct ANativeWindowBuffer *buf, int fd)
> +{
> +   unsigned int pitch;
> +
> +   if (is_yuv(buf->format))
> +      return droid_create_image_from_prime_fd_yuv(disp, ctx, buf, fd);
> +
> +   const int fourcc = get_fourcc(buf->format);
> +   if (fourcc == -1) {
> +      _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
> +      return NULL;
> +   }
> +
> +   pitch = buf->stride * get_format_bpp(buf->format);
> +   if (pitch == 0) {
> +      _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
> +      return NULL;
>     }
>
>     const EGLint attr_list[] = {
> @@ -531,7 +641,7 @@ droid_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
>        EGL_HEIGHT, buf->height,
>        EGL_LINUX_DRM_FOURCC_EXT, fourcc,
>        EGL_DMA_BUF_PLANE0_FD_EXT, fd,
> -      EGL_DMA_BUF_PLANE0_PITCH_EXT, pitches[0],
> +      EGL_DMA_BUF_PLANE0_PITCH_EXT, pitch,
>        EGL_DMA_BUF_PLANE0_OFFSET_EXT, 0,
>        EGL_NONE, 0
>     };
>


More information about the mesa-dev mailing list