| /* Copyright (c) 2012 - 2018, 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); |
| mC2DLibHandle = NULL; |
| } |
| if (mAdrenoUtilsHandle) { |
| dlclose(mAdrenoUtilsHandle); |
| mAdrenoUtilsHandle = NULL; |
| } |
| |
| } |
| |
| 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; |
| if (srcFormat == RGBA8888 && |
| #ifdef __LIBGBM__ |
| flags & GBM_BO_USAGE_UBWC_ALIGNED_QTI) { |
| #else |
| flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) { |
| #endif |
| mSrcFormat = RGBA8888_UBWC; |
| } else { |
| mSrcFormat = srcFormat; |
| } |
| mDstFormat = dstFormat; |
| mSrcSize = calcSize(mSrcFormat, srcWidth, srcHeight); |
| mDstSize = calcSize(dstFormat, dstWidth, dstHeight); |
| mSrcYSize = calcYSize(mSrcFormat, srcWidth, srcHeight); |
| mDstYSize = calcYSize(dstFormat, dstWidth, dstHeight); |
| |
| mFlags = flags; // can be used for rotation |
| |
| retval = getDummySurfaceDef(mSrcFormat, 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 FD (%d:%d) Data (%p:%p) Base (%p:%p)", |
| __FUNCTION__, srcFd, dstFd, srcData, dstData, srcBase, dstBase); |
| 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_512: |
| case NV12_128m: |
| case NV12_UBWC: |
| case TP10_UBWC: |
| case CbYCrY: |
| 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, isSource); |
| (*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 (mFlags & private_handle_t::PRIV_FLAGS_ITU_R_601_FR) { |
| (*surfaceYUVDef)->format |= C2D_FORMAT_BT601_FULLRANGE; |
| } |
| |
| 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, isSource); |
| |
| if (mFlags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED || |
| mFlags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED_PI) |
| (*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, bool isSource) |
| { |
| uint32_t C2DFormat; |
| switch (format) { |
| case RGB565: |
| return C2D_COLOR_FORMAT_565_RGB; |
| case RGBA8888: |
| C2DFormat = C2D_COLOR_FORMAT_8888_RGBA | C2D_FORMAT_SWAP_ENDIANNESS; |
| if (isSource) |
| C2DFormat |= C2D_FORMAT_PREMULTIPLIED; |
| return C2DFormat; |
| case RGBA8888_UBWC: |
| C2DFormat = C2D_COLOR_FORMAT_8888_RGBA | |
| C2D_FORMAT_SWAP_ENDIANNESS | |
| C2D_FORMAT_UBWC_COMPRESSED; |
| if (isSource) |
| C2DFormat |= C2D_FORMAT_PREMULTIPLIED; |
| return C2DFormat; |
| case YCbCr420Tile: |
| return (C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_MACROTILED); |
| case YCbCr420SP: |
| case NV12_2K: |
| case NV12_512: |
| 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; |
| case CbYCrY: |
| return C2D_COLOR_FORMAT_422_UYVY; |
| 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_512: |
| return ALIGN(width, ALIGN512); |
| 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); |
| case CbYCrY: |
| return ALIGN(width*2, ALIGN64); |
| case RGBA8888_UBWC: |
| return VENUS_RGB_STRIDE(COLOR_FMT_RGBA8888_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_512: |
| return ALIGN(width, ALIGN512) * ALIGN(height, ALIGN512); |
| 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_512: |
| alignedw = ALIGN(width, ALIGN512); |
| alignedh = ALIGN(height, ALIGN512); |
| size = ALIGN(alignedw * alignedh + (alignedw * ALIGN(height/2, ALIGN256)), ALIGN4K); |
| 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; |
| case CbYCrY: |
| size = ALIGN(ALIGN(width * 2, ALIGN64) * height, ALIGN4K); |
| break; |
| case RGBA8888_UBWC: |
| size = VENUS_BUFFER_SIZE(COLOR_FMT_RGBA8888_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_512: |
| return ALIGN512; |
| 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_512: |
| case NV12_128m: |
| case NV12_UBWC: |
| case TP10_UBWC: |
| case RGBA8888_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_512: |
| 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; |
| } |