drm_hwcomposer: libdrm gralloc_handle: modifiers and YUV support
1. Import DRM modifier field from libdrm's gralloc_habdle.
2. Recently lock_ycrcb() was added to gbm_gralloc() [1], mesa3d uses
this function to obtain CrCb plane data (offsets, strides).
Use the same alhorythm in drm_hwcomposer. This allows GPU offloading
during video playback. (Tested using Gallery app and SkyTube).
[1] - https://github.com/robherring/gbm_gralloc/pull/15
[2] - 68957a8256/src/egl/drivers/dri2/platform_android.c (L202)
Signed-off-by: Roman Stratiienko <r.stratiienko@gmail.com>
Change-Id: I8ec177ac782f27174443cebcb6e773070c1505cc
This commit is contained in:
parent
cfc2b2e602
commit
fbf5c0ca45
2 changed files with 148 additions and 6 deletions
|
|
@ -73,6 +73,130 @@ int DrmGenericImporter::Init() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
enum chroma_order {
|
||||
YCbCr,
|
||||
YCrCb,
|
||||
};
|
||||
|
||||
struct droid_yuv_format {
|
||||
/* Lookup keys */
|
||||
int native; /* HAL_PIXEL_FORMAT_ */
|
||||
enum chroma_order chroma_order; /* chroma order is {Cb, Cr} or {Cr, Cb} */
|
||||
int chroma_step; /* Distance in bytes between subsequent chroma pixels. */
|
||||
|
||||
/* Result */
|
||||
int fourcc; /* DRM_FORMAT_ */
|
||||
};
|
||||
|
||||
/* 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, YCbCr, 2, DRM_FORMAT_NV12},
|
||||
{HAL_PIXEL_FORMAT_YCbCr_420_888, YCbCr, 1, DRM_FORMAT_YUV420},
|
||||
{HAL_PIXEL_FORMAT_YCbCr_420_888, YCrCb, 1, DRM_FORMAT_YVU420},
|
||||
{HAL_PIXEL_FORMAT_YV12, YCrCb, 1, DRM_FORMAT_YVU420},
|
||||
/* HACK: See droid_create_image_from_prime_fds() and
|
||||
* https://issuetracker.google.com/32077885. */
|
||||
{HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 2, DRM_FORMAT_NV12},
|
||||
{HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCbCr, 1, DRM_FORMAT_YUV420},
|
||||
{HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_YVU420},
|
||||
{HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_AYUV},
|
||||
{HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, YCrCb, 1, DRM_FORMAT_XYUV8888},
|
||||
};
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
static int get_fourcc_yuv(int native, enum chroma_order chroma_order,
|
||||
int chroma_step) {
|
||||
for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i)
|
||||
if (droid_yuv_formats[i].native == native &&
|
||||
droid_yuv_formats[i].chroma_order == chroma_order &&
|
||||
droid_yuv_formats[i].chroma_step == chroma_step)
|
||||
return droid_yuv_formats[i].fourcc;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static bool is_yuv(int native) {
|
||||
for (int i = 0; i < ARRAY_SIZE(droid_yuv_formats); ++i)
|
||||
if (droid_yuv_formats[i].native == native)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DrmGenericImporter::GetYuvPlaneInfo(int num_fds, buffer_handle_t handle,
|
||||
hwc_drm_bo_t *bo) {
|
||||
struct android_ycbcr ycbcr;
|
||||
enum chroma_order chroma_order;
|
||||
int ret;
|
||||
|
||||
if (!gralloc_->lock_ycbcr) {
|
||||
static std::once_flag once;
|
||||
std::call_once(once,
|
||||
[]() { ALOGW("Gralloc does not support lock_ycbcr()"); });
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&ycbcr, 0, sizeof(ycbcr));
|
||||
ret = gralloc_->lock_ycbcr(gralloc_, handle, 0, 0, 0, 0, 0, &ycbcr);
|
||||
if (ret) {
|
||||
ALOGW("gralloc->lock_ycbcr failed: %d", ret);
|
||||
return false;
|
||||
}
|
||||
gralloc_->unlock(gralloc_, 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. */
|
||||
bo->offsets[0] = (size_t)ycbcr.y;
|
||||
/* We assume here that all the planes are located in one DMA-buf. */
|
||||
if ((size_t)ycbcr.cr < (size_t)ycbcr.cb) {
|
||||
chroma_order = YCrCb;
|
||||
bo->offsets[1] = (size_t)ycbcr.cr;
|
||||
bo->offsets[2] = (size_t)ycbcr.cb;
|
||||
} else {
|
||||
chroma_order = YCbCr;
|
||||
bo->offsets[1] = (size_t)ycbcr.cb;
|
||||
bo->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. */
|
||||
bo->pitches[0] = ycbcr.ystride;
|
||||
bo->pitches[1] = bo->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. */
|
||||
bo->format = get_fourcc_yuv(bo->hal_format, chroma_order, ycbcr.chroma_step);
|
||||
if (bo->format == -1) {
|
||||
ALOGW(
|
||||
"unsupported YUV format, native = %x, chroma_order = %s, chroma_step = "
|
||||
"%d",
|
||||
bo->hal_format, chroma_order == YCbCr ? "YCbCr" : "YCrCb",
|
||||
(int)ycbcr.chroma_step);
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since this is EGL_NATIVE_BUFFER_ANDROID don't assume that
|
||||
* the single-fd case cannot happen. So handle eithe single
|
||||
* fd or fd-per-plane case:
|
||||
*/
|
||||
if (num_fds == 1) {
|
||||
bo->prime_fds[2] = bo->prime_fds[1] = bo->prime_fds[0];
|
||||
} else {
|
||||
int expected_planes = (ycbcr.chroma_step == 2) ? 2 : 3;
|
||||
if (num_fds != expected_planes)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t DrmGenericImporter::ConvertHalFormatToDrm(uint32_t hal_format) {
|
||||
switch (hal_format) {
|
||||
case HAL_PIXEL_FORMAT_RGB_888:
|
||||
|
|
@ -120,15 +244,32 @@ int DrmGenericImporter::ConvertBoInfo(buffer_handle_t handle,
|
|||
bo->width = gr_handle->width;
|
||||
bo->height = gr_handle->height;
|
||||
bo->hal_format = gr_handle->format;
|
||||
bo->format = ConvertHalFormatToDrm(gr_handle->format);
|
||||
if (bo->format == DRM_FORMAT_INVALID)
|
||||
return -EINVAL;
|
||||
|
||||
#if GRALLOC_HANDLE_VERSION < 4
|
||||
#warning libdrm >= v2.4.97 is required to support modifiers
|
||||
#endif
|
||||
#if GRALLOC_HANDLE_VERSION == 4
|
||||
bo->modifiers[0] = gr_handle->modifier;
|
||||
bo->with_modifiers = gr_handle->modifier != DRM_FORMAT_MOD_NONE &&
|
||||
gr_handle->modifier != DRM_FORMAT_MOD_INVALID;
|
||||
#endif
|
||||
|
||||
bo->usage = gr_handle->usage;
|
||||
bo->prime_fds[0] = gr_handle->prime_fd;
|
||||
|
||||
if (is_yuv(gr_handle->format)) {
|
||||
if (!GetYuvPlaneInfo(handle->numFds, handle, bo))
|
||||
return -EINVAL;
|
||||
} else {
|
||||
bo->pitches[0] = gr_handle->stride;
|
||||
bo->offsets[0] = 0;
|
||||
bo->format = ConvertHalFormatToDrm(gr_handle->format);
|
||||
if (bo->format == DRM_FORMAT_INVALID)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
bo->pixel_stride = (gr_handle->stride * 8) /
|
||||
DrmFormatToBitsPerPixel(bo->format);
|
||||
bo->prime_fds[0] = gr_handle->prime_fd;
|
||||
bo->pitches[0] = gr_handle->stride;
|
||||
bo->offsets[0] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ class DrmGenericImporter : public Importer {
|
|||
|
||||
uint32_t ConvertHalFormatToDrm(uint32_t hal_format);
|
||||
uint32_t DrmFormatToBitsPerPixel(uint32_t drm_format);
|
||||
bool GetYuvPlaneInfo(int num_fds, buffer_handle_t handle, hwc_drm_bo_t *bo);
|
||||
|
||||
protected:
|
||||
DrmDevice *drm_;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue