blob: 258af91c1db7b35a5a43d21560f90b06470d60de [file] [log] [blame]
/* Copyright (c) 2012 - 2017, The Linux Foundation. All rights reserved.
*
* redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* this software is provided "as is" and any express or implied
* warranties, including, but not limited to, the implied warranties of
* merchantability, fitness for a particular purpose and non-infringement
* are disclaimed. in no event shall the copyright owner or contributors
* be liable for any direct, indirect, incidental, special, exemplary, or
* consequential damages (including, but not limited to, procurement of
* substitute goods or services; loss of use, data, or profits; or
* business interruption) however caused and on any theory of liability,
* whether in contract, strict liability, or tort (including negligence
* or otherwise) arising in any way out of the use of this software, even
* if advised of the possibility of such damage.
*
*/
#include <C2DColorConverter.h>
C2DColorConverter::C2DColorConverter()
: mC2DLibHandle(NULL),
mAdrenoUtilsHandle(NULL)
{
enabled = true;
mSrcSurface = 0;
mDstSurface = 0;
mSrcWidth = 0;
mSrcHeight = 0;
mSrcStride = 0;
mDstWidth = 0;
mDstHeight = 0;
mSrcFormat = NO_COLOR_FORMAT;
mDstFormat = NO_COLOR_FORMAT;
mSrcSurfaceDef = NULL;
mDstSurfaceDef = NULL;
mConversionNeeded = false;
pthread_mutex_init(&mLock, NULL);
mC2DLibHandle = dlopen("libC2D2.so", RTLD_NOW);
if (!mC2DLibHandle) {
ALOGE("%s: ERROR: could not dlopen libc2d2.so: %s. C2D is disabled.",
__FUNCTION__, dlerror());
enabled = false;
return;
}
mAdrenoUtilsHandle = dlopen("libadreno_utils.so", RTLD_NOW);
if (!mAdrenoUtilsHandle) {
ALOGE("%s: ERROR: could not dlopen libadreno_utils.so: %s.. C2D is disabled.",
__FUNCTION__, dlerror());
enabled = false;
return;
}
mC2DCreateSurface = (LINK_c2dCreateSurface)dlsym(mC2DLibHandle, "c2dCreateSurface");
mC2DUpdateSurface = (LINK_c2dUpdateSurface)dlsym(mC2DLibHandle, "c2dUpdateSurface");
mC2DReadSurface = (LINK_c2dReadSurface)dlsym(mC2DLibHandle, "c2dReadSurface");
mC2DDraw = (LINK_c2dDraw)dlsym(mC2DLibHandle, "c2dDraw");
mC2DFlush = (LINK_c2dFlush)dlsym(mC2DLibHandle, "c2dFlush");
mC2DFinish = (LINK_c2dFinish)dlsym(mC2DLibHandle, "c2dFinish");
mC2DWaitTimestamp = (LINK_c2dWaitTimestamp)dlsym(mC2DLibHandle, "c2dWaitTimestamp");
mC2DDestroySurface = (LINK_c2dDestroySurface)dlsym(mC2DLibHandle, "c2dDestroySurface");
mC2DMapAddr = (LINK_c2dMapAddr)dlsym(mC2DLibHandle, "c2dMapAddr");
mC2DUnMapAddr = (LINK_c2dUnMapAddr)dlsym(mC2DLibHandle, "c2dUnMapAddr");
if (!mC2DCreateSurface || !mC2DUpdateSurface || !mC2DReadSurface
|| !mC2DDraw || !mC2DFlush || !mC2DFinish || !mC2DWaitTimestamp
|| !mC2DDestroySurface || !mC2DMapAddr || !mC2DUnMapAddr) {
ALOGE("%s: dlsym ERROR. C2D is disabled. mC2DCreateSurface[%p] mC2DUpdateSurface[%p] "
"mC2DReadSurface[%p] mC2DDraw[%p] mC2DFlush[%p] mC2DFinish[%p] mC2DWaitTimestamp[%p] "
"mC2DDestroySurface[%p] mC2DMapAddr[%p] mC2DUnMapAddr[%p]", __FUNCTION__,
mC2DCreateSurface, mC2DUpdateSurface, mC2DReadSurface, mC2DDraw, mC2DFlush, mC2DFinish,
mC2DWaitTimestamp, mC2DDestroySurface, mC2DMapAddr, mC2DUnMapAddr);
enabled = false;
return;
}
mAdrenoComputeFmtAlignedWidthAndHeight = (LINK_adreno_compute_fmt_aligned_width_and_height)dlsym(mAdrenoUtilsHandle, "compute_fmt_aligned_width_and_height");
if (!mAdrenoComputeFmtAlignedWidthAndHeight) {
ALOGE("%s: dlsym compute_aligned_width_and_height ERROR. C2D is disabled.", __FUNCTION__);
enabled = false;
return;
}
}
C2DColorConverter::~C2DColorConverter()
{
if (enabled) {
if (mDstSurface) {
mC2DDestroySurface(mDstSurface);
mDstSurface = 0;
}
if (mSrcSurface) {
mC2DDestroySurface(mSrcSurface);
mSrcSurface = 0;
}
if (mSrcSurfaceDef) {
if (isYUVSurface(mSrcFormat)) {
delete ((C2D_YUV_SURFACE_DEF *)mSrcSurfaceDef);
} else {
delete ((C2D_RGB_SURFACE_DEF *)mSrcSurfaceDef);
}
}
if (mDstSurfaceDef) {
if (isYUVSurface(mDstFormat)) {
delete ((C2D_YUV_SURFACE_DEF *)mDstSurfaceDef);
} else {
delete ((C2D_RGB_SURFACE_DEF *)mDstSurfaceDef);
}
}
mSrcSurfaceDef = NULL;
mDstSurfaceDef = NULL;
}
if (mC2DLibHandle) {
dlclose(mC2DLibHandle);
}
if (mAdrenoUtilsHandle) {
dlclose(mAdrenoUtilsHandle);
}
}
bool C2DColorConverter::isPropChanged(size_t srcWidth, size_t srcHeight, size_t dstWidth,
size_t dstHeight, ColorConvertFormat srcFormat,
ColorConvertFormat dstFormat, int32_t flags,
size_t srcStride)
{
return (mSrcWidth != srcWidth ||
mSrcHeight != srcHeight ||
mDstWidth != dstWidth ||
mDstHeight != dstHeight ||
mSrcFormat != srcFormat ||
mDstFormat != dstFormat ||
mSrcStride != srcStride ||
(mFlags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) !=
(flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED));
}
bool C2DColorConverter::setResolution(size_t srcWidth, size_t srcHeight,
size_t dstWidth, size_t dstHeight,
ColorConvertFormat srcFormat,
ColorConvertFormat dstFormat,
int32_t flags, size_t srcStride)
{
int32_t retval = -1;
if (enabled) {
pthread_mutex_lock(&mLock);
mSrcWidth = srcWidth;
mSrcHeight = srcHeight;
mSrcStride = srcStride;
mDstWidth = dstWidth;
mDstHeight = dstHeight;
mSrcFormat = srcFormat;
mDstFormat = dstFormat;
mSrcSize = calcSize(srcFormat, srcWidth, srcHeight);
mDstSize = calcSize(dstFormat, dstWidth, dstHeight);
mSrcYSize = calcYSize(srcFormat, srcWidth, srcHeight);
mDstYSize = calcYSize(dstFormat, dstWidth, dstHeight);
mFlags = flags; // can be used for rotation
retval = getDummySurfaceDef(srcFormat, srcWidth, srcHeight, true);
retval |= getDummySurfaceDef(dstFormat, dstWidth, dstHeight, false);
if (retval == 0) {
memset((void*)&mBlit,0,sizeof(C2D_OBJECT));
mBlit.source_rect.x = 0 << 16;
mBlit.source_rect.y = 0 << 16;
mBlit.source_rect.width = srcWidth << 16;
mBlit.source_rect.height = srcHeight << 16;
mBlit.target_rect.x = 0 << 16;
mBlit.target_rect.y = 0 << 16;
mBlit.target_rect.width = dstWidth << 16;
mBlit.target_rect.height = dstHeight << 16;
mBlit.config_mask = C2D_ALPHA_BLEND_NONE |
C2D_NO_BILINEAR_BIT |
C2D_NO_ANTIALIASING_BIT |
C2D_TARGET_RECT_BIT;
mBlit.surface_id = mSrcSurface;
}
pthread_mutex_unlock(&mLock);
}
return retval == 0? true:false;
}
bool C2DColorConverter::convertC2D(int srcFd, void *srcBase, void * srcData,
int dstFd, void *dstBase, void * dstData)
{
C2D_STATUS ret;
uint8_t *srcMappedGpuAddr = nullptr;
uint8_t *dstMappedGpuAddr = nullptr;
bool status = false;
if (enabled) {
pthread_mutex_lock(&mLock);
if (srcFd < 0 || dstFd < 0
|| srcData == NULL || dstData == NULL
|| srcBase == NULL || dstBase == NULL) {
ALOGE("%s: Color conversion failed. Incorrect input parameters", __FUNCTION__);
status = false;
} else {
srcMappedGpuAddr = (uint8_t *)getMappedGPUAddr(srcFd, srcData, mSrcSize);
if (!srcMappedGpuAddr) {
pthread_mutex_unlock(&mLock);
return false;
}
if (isYUVSurface(mSrcFormat)) {
ret = updateYUVSurfaceDef(srcMappedGpuAddr, srcBase, srcData, true);
} else {
ret = updateRGBSurfaceDef(srcMappedGpuAddr, srcData, true);
}
if (ret == C2D_STATUS_OK) {
dstMappedGpuAddr = (uint8_t *)getMappedGPUAddr(dstFd, dstData, mDstSize);
if (!dstMappedGpuAddr) {
unmapGPUAddr((unsigned long)srcMappedGpuAddr);
pthread_mutex_unlock(&mLock);
return false;
}
if (isYUVSurface(mDstFormat)) {
ret = updateYUVSurfaceDef(dstMappedGpuAddr, dstBase, dstData, false);
} else {
ret = updateRGBSurfaceDef(dstMappedGpuAddr, dstData, false);
}
if (ret == C2D_STATUS_OK) {
mBlit.surface_id = mSrcSurface;
ret = mC2DDraw(mDstSurface, C2D_TARGET_ROTATE_0, 0, 0, 0, &mBlit, 1);
mC2DFinish(mDstSurface);
if (ret == C2D_STATUS_OK) {
bool unmappedSrcSuccess;
unmappedSrcSuccess = unmapGPUAddr((unsigned long)srcMappedGpuAddr);
bool unmappedDstSuccess;
unmappedDstSuccess = unmapGPUAddr((unsigned long)dstMappedGpuAddr);
if (!unmappedSrcSuccess || !unmappedDstSuccess) {
ALOGE("%s: unmapping GPU address failed (%d:%d)", __FUNCTION__,
unmappedSrcSuccess, unmappedDstSuccess);
status = false;
} else {
status = true;
}
} else {
ALOGE("%s: C2D Draw failed (%d)", __FUNCTION__, ret);
status = false;
}
} else {
ALOGE("%s: Update dst surface def failed (%d)", __FUNCTION__, ret);
unmapGPUAddr((unsigned long)srcMappedGpuAddr);
unmapGPUAddr((unsigned long)dstMappedGpuAddr);
status = false;
}
} else {
ALOGE("%s: Update src surface def failed (%d)", __FUNCTION__, ret);
unmapGPUAddr((unsigned long)srcMappedGpuAddr);
status = false;
}
}
pthread_mutex_unlock(&mLock);
}
return status;
}
bool C2DColorConverter::isYUVSurface(ColorConvertFormat format)
{
switch (format) {
case YCbCr420Tile:
case YCbCr420SP:
case YCbCr420P:
case YCrCb420P:
case NV12_2K:
case NV12_128m:
case NV12_UBWC:
case TP10_UBWC:
return true;
default:
return false;
}
}
int32_t C2DColorConverter::getDummySurfaceDef(ColorConvertFormat format,
size_t width, size_t height,
bool isSource)
{
void *surfaceDef = NULL;
C2D_SURFACE_TYPE hostSurfaceType;
C2D_STATUS ret;
if (isSource){
if (mSrcSurface) {
mC2DDestroySurface(mSrcSurface);
mSrcSurface = 0;
}
} else if (mDstSurface) {
mC2DDestroySurface(mDstSurface);
mDstSurface = 0;
}
if (isYUVSurface(format)) {
C2D_YUV_SURFACE_DEF **surfaceYUVDef = (C2D_YUV_SURFACE_DEF **)
(isSource ? &mSrcSurfaceDef : &mDstSurfaceDef);
if (*surfaceYUVDef == NULL) {
*surfaceYUVDef = (C2D_YUV_SURFACE_DEF *)
calloc(1, sizeof(C2D_YUV_SURFACE_DEF));
if (*surfaceYUVDef == NULL) {
ALOGE("%s: surfaceYUVDef allocation failed", __FUNCTION__);
return -1;
}
} else {
memset(*surfaceYUVDef, 0, sizeof(C2D_YUV_SURFACE_DEF));
}
(*surfaceYUVDef)->format = getC2DFormat(format);
(*surfaceYUVDef)->width = width;
(*surfaceYUVDef)->height = height;
(*surfaceYUVDef)->plane0 = (void *)0xaaaaaaaa;
(*surfaceYUVDef)->phys0 = (void *)0xaaaaaaaa;
(*surfaceYUVDef)->stride0 = calcStride(format, width);
(*surfaceYUVDef)->plane1 = (void *)0xaaaaaaaa;
(*surfaceYUVDef)->phys1 = (void *)0xaaaaaaaa;
(*surfaceYUVDef)->stride1 = calcStride(format, width);
(*surfaceYUVDef)->stride2 = calcStride(format, width);
(*surfaceYUVDef)->phys2 = NULL;
(*surfaceYUVDef)->plane2 = NULL;
if (format == YCbCr420P ||
format == YCrCb420P) {
ALOGI("%s: half stride for Cb Cr planes \n", __FUNCTION__);
(*surfaceYUVDef)->stride1 = calcStride(format, width) / 2;
(*surfaceYUVDef)->phys2 = (void *)0xaaaaaaaa;
(*surfaceYUVDef)->stride2 = calcStride(format, width) / 2;
}
surfaceDef = *surfaceYUVDef;
hostSurfaceType = C2D_SURFACE_YUV_HOST;
} else {
C2D_RGB_SURFACE_DEF **surfaceRGBDef = (C2D_RGB_SURFACE_DEF **)
(isSource ? &mSrcSurfaceDef : &mDstSurfaceDef);
if (*surfaceRGBDef == NULL) {
*surfaceRGBDef = (C2D_RGB_SURFACE_DEF *)
calloc(1, sizeof(C2D_RGB_SURFACE_DEF));
if (*surfaceRGBDef == NULL) {
ALOGE("%s: surfaceRGBDef allocation failed", __FUNCTION__);
return -1;
}
} else {
memset(*surfaceRGBDef, 0, sizeof(C2D_RGB_SURFACE_DEF));
}
(*surfaceRGBDef)->format = getC2DFormat(format);
if (mFlags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED)
(*surfaceRGBDef)->format |= C2D_FORMAT_UBWC_COMPRESSED;
(*surfaceRGBDef)->width = width;
(*surfaceRGBDef)->height = height;
(*surfaceRGBDef)->buffer = (void *)0xaaaaaaaa;
(*surfaceRGBDef)->phys = (void *)0xaaaaaaaa;
(*surfaceRGBDef)->stride = calcStride(format, width);
surfaceDef = *surfaceRGBDef;
hostSurfaceType = C2D_SURFACE_RGB_HOST;
}
ret = mC2DCreateSurface(isSource ? &mSrcSurface :
&mDstSurface,
isSource ? C2D_SOURCE : C2D_TARGET,
(C2D_SURFACE_TYPE)(hostSurfaceType
| C2D_SURFACE_WITH_PHYS
| C2D_SURFACE_WITH_PHYS_DUMMY),
surfaceDef);
return (int32_t) ret;
}
C2D_STATUS C2DColorConverter::updateYUVSurfaceDef(uint8_t *gpuAddr, void *base,
void *data, bool isSource)
{
if (isSource) {
C2D_YUV_SURFACE_DEF * srcSurfaceDef = (C2D_YUV_SURFACE_DEF *)mSrcSurfaceDef;
srcSurfaceDef->plane0 = data;
srcSurfaceDef->phys0 = gpuAddr + ((uint8_t *)data - (uint8_t *)base);
srcSurfaceDef->plane1 = (uint8_t *)data + mSrcYSize;
srcSurfaceDef->phys1 = (uint8_t *)srcSurfaceDef->phys0 + mSrcYSize;
if (srcSurfaceDef->format & C2D_COLOR_FORMAT_420_I420 ||
srcSurfaceDef->format & C2D_COLOR_FORMAT_420_YV12) {
srcSurfaceDef->plane2 = (uint8_t *)srcSurfaceDef->plane1 + mSrcYSize/4;
srcSurfaceDef->phys2 = (uint8_t *)srcSurfaceDef->phys1 + mSrcYSize/4;
}
return mC2DUpdateSurface(mSrcSurface, C2D_SOURCE,
(C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS),
&(*srcSurfaceDef));
} else {
C2D_YUV_SURFACE_DEF * dstSurfaceDef = (C2D_YUV_SURFACE_DEF *)mDstSurfaceDef;
dstSurfaceDef->plane0 = data;
dstSurfaceDef->phys0 = gpuAddr + ((uint8_t *)data - (uint8_t *)base);
dstSurfaceDef->plane1 = (uint8_t *)data + mDstYSize;
dstSurfaceDef->phys1 = (uint8_t *)dstSurfaceDef->phys0 + mDstYSize;
if (dstSurfaceDef->format & C2D_COLOR_FORMAT_420_I420 ||
dstSurfaceDef->format & C2D_COLOR_FORMAT_420_YV12) {
dstSurfaceDef->plane2 = (uint8_t *)dstSurfaceDef->plane1 + mDstYSize/4;
dstSurfaceDef->phys2 = (uint8_t *)dstSurfaceDef->phys1 + mDstYSize/4;
}
return mC2DUpdateSurface(mDstSurface, C2D_TARGET,
(C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS),
&(*dstSurfaceDef));
}
}
C2D_STATUS C2DColorConverter::updateRGBSurfaceDef(uint8_t *gpuAddr, void * data, bool isSource)
{
if (isSource) {
C2D_RGB_SURFACE_DEF * srcSurfaceDef = (C2D_RGB_SURFACE_DEF *)mSrcSurfaceDef;
srcSurfaceDef->buffer = data;
srcSurfaceDef->phys = gpuAddr;
return mC2DUpdateSurface(mSrcSurface, C2D_SOURCE,
(C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS),
&(*srcSurfaceDef));
} else {
C2D_RGB_SURFACE_DEF * dstSurfaceDef = (C2D_RGB_SURFACE_DEF *)mDstSurfaceDef;
dstSurfaceDef->buffer = data;
ALOGV("%s: dstSurfaceDef->buffer = %p", __FUNCTION__, data);
dstSurfaceDef->phys = gpuAddr;
return mC2DUpdateSurface(mDstSurface, C2D_TARGET,
(C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS),
&(*dstSurfaceDef));
}
}
uint32_t C2DColorConverter::getC2DFormat(ColorConvertFormat format)
{
switch (format) {
case RGB565:
return C2D_COLOR_FORMAT_565_RGB;
case RGBA8888:
return C2D_COLOR_FORMAT_8888_RGBA | C2D_FORMAT_SWAP_ENDIANNESS | C2D_FORMAT_PREMULTIPLIED;
case RGBA8888_UBWC:
return C2D_COLOR_FORMAT_8888_RGBA |
C2D_FORMAT_SWAP_ENDIANNESS |
C2D_FORMAT_PREMULTIPLIED |
C2D_FORMAT_UBWC_COMPRESSED;
case YCbCr420Tile:
return (C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_MACROTILED);
case YCbCr420SP:
case NV12_2K:
case NV12_128m:
return C2D_COLOR_FORMAT_420_NV12;
case YCbCr420P:
return C2D_COLOR_FORMAT_420_I420;
case YCrCb420P:
return C2D_COLOR_FORMAT_420_YV12;
case NV12_UBWC:
return C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_UBWC_COMPRESSED;
case TP10_UBWC:
return C2D_COLOR_FORMAT_420_TP10 | C2D_FORMAT_UBWC_COMPRESSED;
default:
ALOGW("%s: Format not supported , %d", __FUNCTION__, format);
return -1;
}
}
size_t C2DColorConverter::calcStride(ColorConvertFormat format, size_t width)
{
switch (format) {
case RGB565:
return ALIGN(width, ALIGN32) * 2; // RGB565 has width as twice
case RGBA8888:
if (mSrcStride)
return mSrcStride * 4;
else
return ALIGN(width, ALIGN32) * 4;
case YCbCr420Tile:
return ALIGN(width, ALIGN128);
case YCbCr420SP:
return ALIGN(width, ALIGN16);
case NV12_2K:
return ALIGN(width, ALIGN16);
case NV12_128m:
return ALIGN(width, ALIGN128);
case YCbCr420P:
return ALIGN(width, ALIGN16);
case YCrCb420P:
return ALIGN(width, ALIGN16);
case NV12_UBWC:
return VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width);
case TP10_UBWC:
return VENUS_Y_STRIDE(COLOR_FMT_NV12_BPP10_UBWC, width);
default:
ALOGW("%s: Format not supported , %d", __FUNCTION__, format);
return 0;
}
}
size_t C2DColorConverter::calcYSize(ColorConvertFormat format, size_t width, size_t height)
{
switch (format) {
case YCbCr420SP:
return (ALIGN(width, ALIGN16) * height);
case YCbCr420P:
return ALIGN(width, ALIGN16) * height;
case YCrCb420P:
return ALIGN(width, ALIGN16) * height;
case YCbCr420Tile:
return ALIGN(ALIGN(width, ALIGN128) * ALIGN(height, ALIGN32), ALIGN8K);
case NV12_2K: {
size_t alignedw = ALIGN(width, ALIGN16);
size_t lumaSize = ALIGN(alignedw * height, ALIGN2K);
return lumaSize;
}
case NV12_128m:
return ALIGN(width, ALIGN128) * ALIGN(height, ALIGN32);
case NV12_UBWC:
return ALIGN( VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width) *
VENUS_Y_SCANLINES(COLOR_FMT_NV12_UBWC, height), ALIGN4K) +
ALIGN( VENUS_Y_META_STRIDE(COLOR_FMT_NV12_UBWC, width) *
VENUS_Y_META_SCANLINES(COLOR_FMT_NV12_UBWC, height), ALIGN4K);
case TP10_UBWC:
return ALIGN( VENUS_Y_STRIDE(COLOR_FMT_NV12_BPP10_UBWC, width) *
VENUS_Y_SCANLINES(COLOR_FMT_NV12_BPP10_UBWC, height), ALIGN4K) +
ALIGN( VENUS_Y_META_STRIDE(COLOR_FMT_NV12_BPP10_UBWC, width) *
VENUS_Y_META_SCANLINES(COLOR_FMT_NV12_BPP10_UBWC, height), ALIGN4K);
default:
ALOGW("%s: Format not supported , %d", __FUNCTION__, format);
return 0;
}
}
size_t C2DColorConverter::calcSize(ColorConvertFormat format, size_t width, size_t height)
{
int32_t alignedw = 0;
int32_t alignedh = 0;
int32_t size = 0;
int32_t tile_mode = 0;
int32_t raster_mode = 0;
int32_t padding_threshold = 512; /* hardcode for RGB formats */
int32_t bpp = 0;
switch (format) {
case RGB565:
bpp = 2;
mAdrenoComputeFmtAlignedWidthAndHeight(width, height,
0, ADRENO_PIXELFORMAT_B5G6R5,
1, tile_mode, raster_mode,
padding_threshold,
&alignedw, &alignedh);
ALOGV("%s: alignedw %d alignedh %d", __FUNCTION__,alignedw, alignedh);
size = alignedw * alignedh * bpp;
size = ALIGN(size, ALIGN4K);
break;
case RGBA8888:
bpp = 4;
mAdrenoComputeFmtAlignedWidthAndHeight(width, height,
0, ADRENO_PIXELFORMAT_R8G8B8A8 ,
1, tile_mode, raster_mode,
padding_threshold,
&alignedw, &alignedh);
ALOGV("%s: alignedw %d alignedh %d", __FUNCTION__,alignedw, alignedh);
if (mSrcStride)
size = mSrcStride * alignedh * bpp;
else
size = alignedw * alignedh * bpp;
size = ALIGN(size, ALIGN4K);
break;
case YCbCr420SP:
alignedw = ALIGN(width, ALIGN16);
size = ALIGN((alignedw * height) + (ALIGN(width/2, ALIGN32) * (height/2) * 2), ALIGN4K);
break;
case YCbCr420P:
alignedw = ALIGN(width, ALIGN16);
size = ALIGN((alignedw * height) + (ALIGN(width/2, ALIGN16) * (height/2) * 2), ALIGN4K);
break;
case YCrCb420P:
alignedw = ALIGN(width, ALIGN16);
size = ALIGN((alignedw * height) + (ALIGN(width/2, ALIGN16) * (height/2) * 2), ALIGN4K);
break;
case YCbCr420Tile:
alignedw = ALIGN(width, ALIGN128);
alignedh = ALIGN(height, ALIGN32);
size = ALIGN(alignedw * alignedh, ALIGN8K) + ALIGN(alignedw * ALIGN(height/2, ALIGN32), ALIGN8K);
break;
case NV12_2K: {
alignedw = ALIGN(width, ALIGN16);
size_t lumaSize = ALIGN(alignedw * height, ALIGN2K);
size_t chromaSize = ALIGN((alignedw * height)/2, ALIGN2K);
size = ALIGN(lumaSize + chromaSize, ALIGN4K);
ALOGV("%s: NV12_2k, width = %zu, height = %zu, size = %d",
__FUNCTION__, width, height, size);
}
break;
case NV12_128m:
alignedw = ALIGN(width, ALIGN128);
alignedh = ALIGN(height, ALIGN32);
size = ALIGN(alignedw * alignedh + (alignedw * ALIGN(height/2, ALIGN16)), ALIGN4K);
break;
case NV12_UBWC:
size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
break;
case TP10_UBWC:
size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
break;
default:
ALOGW("%s: Format not supported , %d", __FUNCTION__, format);
break;
}
return size;
}
/*
* Tells GPU to map given buffer and returns a physical address of mapped buffer
*/
void * C2DColorConverter::getMappedGPUAddr(int bufFD, void *bufPtr, size_t bufLen)
{
C2D_STATUS status;
void *gpuaddr = NULL;
status = mC2DMapAddr(bufFD, bufPtr, bufLen, 0, KGSL_USER_MEM_TYPE_ION,
&gpuaddr);
if (status != C2D_STATUS_OK) {
ALOGE("%s: c2dMapAddr failed: status %d fd %d ptr %p len %zu flags %d",
__FUNCTION__, status, bufFD, bufPtr, bufLen, KGSL_USER_MEM_TYPE_ION);
return NULL;
}
ALOGV("%s: c2d mapping created: gpuaddr %p fd %d ptr %p len %zu",
__FUNCTION__, gpuaddr, bufFD, bufPtr, bufLen);
return gpuaddr;
}
bool C2DColorConverter::unmapGPUAddr(unsigned long gAddr)
{
C2D_STATUS status = mC2DUnMapAddr((void*)gAddr);
if (status != C2D_STATUS_OK)
ALOGE("%s: c2dUnMapAddr failed: status %d gpuaddr %08lx",
__FUNCTION__, status, gAddr);
return (status == C2D_STATUS_OK);
}
int32_t C2DColorConverter::getBuffSize(int32_t port)
{
if (enabled) {
if (port == C2D_INPUT) {
return calcSize(mSrcFormat, mSrcWidth, mSrcHeight);
} else if (port == C2D_OUTPUT) {
return calcSize(mDstFormat, mDstWidth, mDstHeight);
}
}
return 0;
}
bool C2DColorConverter::getBuffFilledLen(int32_t port, unsigned int &filled_length)
{
bool ret = false;
C2DBuffReq req;
if (enabled) {
ret = getBuffReq(port, &req);
if (ret && req.bpp.denominator > 0) {
filled_length = (req.stride * req.sliceHeight * req.bpp.numerator);
filled_length /= req.bpp.denominator;
}
}
return ret;
}
bool C2DColorConverter::getBuffReq(int32_t port, C2DBuffReq *req) {
if (!req
|| (port != C2D_INPUT
&& port != C2D_OUTPUT)) return false;
memset(req, 0, sizeof(C2DBuffReq));
if (port == C2D_INPUT) {
req->width = mSrcWidth;
req->height = mSrcHeight;
req->stride = calcStride(mSrcFormat, mSrcWidth);
req->sliceHeight = mSrcHeight;
req->lumaAlign = calcLumaAlign(mSrcFormat);
req->sizeAlign = calcSizeAlign(mSrcFormat);
req->size = calcSize(mSrcFormat, mSrcWidth, mSrcHeight);
req->bpp = calcBytesPerPixel(mSrcFormat);
ALOGV("%s: input req->size = %d", __FUNCTION__, req->size);
} else if (port == C2D_OUTPUT) {
req->width = mDstWidth;
req->height = mDstHeight;
req->stride = calcStride(mDstFormat, mDstWidth);
req->sliceHeight = mDstHeight;
req->lumaAlign = calcLumaAlign(mDstFormat);
req->sizeAlign = calcSizeAlign(mDstFormat);
req->size = calcSize(mDstFormat, mDstWidth, mDstHeight);
req->bpp = calcBytesPerPixel(mDstFormat);
ALOGV("%s: output req->size = %d", __FUNCTION__, req->size);
}
return true;
}
size_t C2DColorConverter::calcLumaAlign(ColorConvertFormat format) {
if (!isYUVSurface(format)) return 1; //no requirement
switch (format) {
case NV12_2K:
return ALIGN2K;
case NV12_128m:
return 1;
case NV12_UBWC:
case TP10_UBWC:
return ALIGN4K;
default:
ALOGW("%s: unknown format (%d) passed for luma alignment number.",
__FUNCTION__, format);
return 1;
}
}
size_t C2DColorConverter::calcSizeAlign(ColorConvertFormat format) {
if (!isYUVSurface(format)) return 1; //no requirement
switch (format) {
case YCbCr420SP: //OR NV12
case YCbCr420P:
case NV12_2K:
case NV12_128m:
case NV12_UBWC:
case TP10_UBWC:
return ALIGN4K;
default:
ALOGW("%s: unknown format (%d) passed for size alignment number",
__FUNCTION__, format);
return 1;
}
}
C2DBytesPerPixel C2DColorConverter::calcBytesPerPixel(ColorConvertFormat format) {
C2DBytesPerPixel bpp;
bpp.numerator = 0;
bpp.denominator = 1;
switch (format) {
case RGB565:
bpp.numerator = 2;
break;
case RGBA8888:
case RGBA8888_UBWC:
bpp.numerator = 4;
break;
case YCbCr420SP:
case YCbCr420P:
case YCrCb420P:
case YCbCr420Tile:
case NV12_2K:
case NV12_128m:
case NV12_UBWC:
case TP10_UBWC:
bpp.numerator = 3;
bpp.denominator = 2;
break;
default:
ALOGW("%s: unknown format (%d) passed.", __FUNCTION__, format);
break;
}
return bpp;
}
int32_t C2DColorConverter::dumpOutput(char * filename, char mode) {
int fd;
size_t stride, sliceHeight;
if (!filename) return -1;
int flags = O_RDWR | O_CREAT;
if (mode == 'a') {
flags |= O_APPEND;
}
if ((fd = open(filename, flags)) < 0) {
ALOGE("%s: open dump file failed w/ errno %s", __FUNCTION__, strerror(errno));
return -1;
}
int ret = 0;
if (isYUVSurface(mDstFormat)) {
C2D_YUV_SURFACE_DEF * dstSurfaceDef = (C2D_YUV_SURFACE_DEF *)mDstSurfaceDef;
uint8_t * base = (uint8_t *)dstSurfaceDef->plane0;
stride = dstSurfaceDef->stride0;
sliceHeight = dstSurfaceDef->height;
/* dump luma */
for (size_t i = 0; i < sliceHeight; i++) {
ret = write(fd, base, mDstWidth); //will work only for the 420 ones
if (ret < 0) goto cleanup;
base += stride;
}
if (mDstFormat == YCbCr420P ||
mDstFormat == YCrCb420P) {
ALOGI("%s: Dump Cb and Cr separately for Planar\n", __FUNCTION__);
//dump Cb/Cr
base = (uint8_t *)dstSurfaceDef->plane1;
stride = dstSurfaceDef->stride1;
for (size_t i = 0; i < sliceHeight/2;i++) { //will work only for the 420 ones
ret = write(fd, base, mDstWidth/2);
if (ret < 0) goto cleanup;
base += stride;
}
//dump Cr/Cb
base = (uint8_t *)dstSurfaceDef->plane2;
stride = dstSurfaceDef->stride2;
for (size_t i = 0; i < sliceHeight/2;i++) { //will work only for the 420 ones
ret = write(fd, base, mDstWidth/2);
if (ret < 0) goto cleanup;
base += stride;
}
} else {
/* dump chroma */
base = (uint8_t *)dstSurfaceDef->plane1;
stride = dstSurfaceDef->stride1;
for (size_t i = 0; i < sliceHeight/2;i++) { //will work only for the 420 ones
ret = write(fd, base, mDstWidth);
if (ret < 0) goto cleanup;
base += stride;
}
}
} else {
C2D_RGB_SURFACE_DEF * dstSurfaceDef = (C2D_RGB_SURFACE_DEF *)mDstSurfaceDef;
uint8_t * base = (uint8_t *)dstSurfaceDef->buffer;
stride = dstSurfaceDef->stride;
sliceHeight = dstSurfaceDef->height;
ALOGI("%s: rgb surface base is %p", __FUNCTION__, base);
ALOGI("%s: rgb surface dumpsslice height is %lu\n",
__FUNCTION__, (unsigned long)sliceHeight);
ALOGI("%s: rgb surface dump stride is %lu\n",
__FUNCTION__, (unsigned long)stride);
int bpp = 1; //bytes per pixel
if (mDstFormat == RGB565) {
bpp = 2;
} else if (mDstFormat == RGBA8888 || mDstFormat == RGBA8888_UBWC) {
bpp = 4;
}
int count = 0;
for (size_t i = 0; i < sliceHeight; i++) {
ret = write(fd, base, mDstWidth*bpp);
if (ret < 0) {
ALOGI("%s: write failed, count = %d\n", __FUNCTION__, count);
goto cleanup;
}
base += stride;
count += stride;
}
}
cleanup:
if (ret < 0) {
ALOGE("%s: file write failed w/ errno %s", __FUNCTION__, strerror(errno));
}
close(fd);
return ret < 0 ? ret : 0;
}