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

Tomasz Figa tfiga at chromium.org
Mon Nov 21 06:50:02 UTC 2016


On Thu, Nov 10, 2016 at 5:48 PM, Tapani Pälli <tapani.palli at intel.com> wrote:
>
>
> 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 ..

Yeah, I agree that it's not very intuitive, however it does its job
pretty well without making Android depend on some DRM-specific stuff
(which I personally don't have anything against...). Since I'm only a
ChromeOS mortal, I can't really tell what we could do about it,
though. In any case, any change would only affect further Android
versions, so we still need to support the old API for current ones.

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

Anyway, I think we can commit this for the time being, so:

Gentle ping. :)

Thanks,
Tomasz

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