[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