egl/android: Use gralloc::lock_ycbcr for resolving YUV formats (v2)
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. 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@chromium.org> Reviewed-by: Emil Velikov <emil.velikov@collabora.com> Reviewed-by: Tapani Pälli <tapani.palli@intel.com>
This commit is contained in:
parent
859d0b0121
commit
51727b1cf5
|
@ -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);
|
||||
}
|
||||
|
@ -541,35 +584,80 @@ droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
|
|||
}
|
||||
|
||||
static _EGLImage *
|
||||
droid_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
|
||||
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 (!dri2_dpy->gralloc->lock_ycbcr) {
|
||||
_eglLog(_EGL_WARNING, "Gralloc does not support lock_ycbcr");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* .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;
|
||||
|
||||
/* .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) {
|
||||
_eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
|
||||
_eglLog(_EGL_WARNING, "unsupported YUV format, native = %x, is_ycrcb = %d, chroma_step = %d",
|
||||
buf->format, is_ycrcb, ycbcr.chroma_step);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pitches[0] = buf->stride * get_format_bpp(buf->format);
|
||||
if (pitches[0] == 0) {
|
||||
_eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
|
||||
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
|
||||
};
|
||||
|
||||
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];
|
||||
|
||||
const EGLint attr_list_yv12[] = {
|
||||
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,
|
||||
|
@ -585,7 +673,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[] = {
|
||||
|
@ -593,7 +703,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
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue