1/* Copyright (c) 2012 - 2015, The Linux Foundation. All rights reserved. 2 * 3 * redistribution and use in source and binary forms, with or without 4 * modification, are permitted provided that the following conditions are 5 * met: 6 * * redistributions of source code must retain the above copyright 7 * notice, this list of conditions and the following disclaimer. 8 * * redistributions in binary form must reproduce the above 9 * copyright notice, this list of conditions and the following 10 * disclaimer in the documentation and/or other materials provided 11 * with the distribution. 12 * * neither the name of The Linux Foundation nor the names of its 13 * contributors may be used to endorse or promote products derived 14 * from this software without specific prior written permission. 15 * 16 * this software is provided "as is" and any express or implied 17 * warranties, including, but not limited to, the implied warranties of 18 * merchantability, fitness for a particular purpose and non-infringement 19 * are disclaimed. in no event shall the copyright owner or contributors 20 * be liable for any direct, indirect, incidental, special, exemplary, or 21 * consequential damages (including, but not limited to, procurement of 22 * substitute goods or services; loss of use, data, or profits; or 23 * business interruption) however caused and on any theory of liability, 24 * whether in contract, strict liability, or tort (including negligence 25 * or otherwise) arising in any way out of the use of this software, even 26 * if advised of the possibility of such damage. 27 * 28 */ 29 30#include <C2DColorConverter.h> 31#include <stdlib.h> 32#include <fcntl.h> 33#include <linux/msm_kgsl.h> 34#include <sys/ioctl.h> 35#include <utils/Log.h> 36#include <dlfcn.h> 37#include <string.h> 38#include <errno.h> 39#include <media/msm_media_info.h> 40 41#undef LOG_TAG 42#define LOG_TAG "C2DColorConvert" 43#define ALIGN( num, to ) (((num) + (to-1)) & (~(to-1))) 44#define ALIGN8K 8192 45#define ALIGN4K 4096 46#define ALIGN2K 2048 47#define ALIGN128 128 48#define ALIGN32 32 49#define ALIGN16 16 50 51//----------------------------------------------------- 52namespace android { 53 54class C2DColorConverter : public C2DColorConverterBase { 55 56public: 57 C2DColorConverter(size_t srcWidth, size_t srcHeight, size_t dstWidth, size_t dstHeight, ColorConvertFormat srcFormat, ColorConvertFormat dstFormat, int32_t flags,size_t srcStride); 58 int32_t getBuffReq(int32_t port, C2DBuffReq *req); 59 int32_t dumpOutput(char * filename, char mode); 60protected: 61 virtual ~C2DColorConverter(); 62 virtual int convertC2D(int srcFd, void *srcBase, void * srcData, int dstFd, void *dstBase, void * dstData); 63 64private: 65 bool isYUVSurface(ColorConvertFormat format); 66 void *getDummySurfaceDef(ColorConvertFormat format, size_t width, size_t height, bool isSource); 67 C2D_STATUS updateYUVSurfaceDef(int fd, void *base, void * data, bool isSource); 68 C2D_STATUS updateRGBSurfaceDef(int fd, void * data, bool isSource); 69 uint32_t getC2DFormat(ColorConvertFormat format); 70 size_t calcStride(ColorConvertFormat format, size_t width); 71 size_t calcYSize(ColorConvertFormat format, size_t width, size_t height); 72 size_t calcSize(ColorConvertFormat format, size_t width, size_t height); 73 void *getMappedGPUAddr(int bufFD, void *bufPtr, size_t bufLen); 74 bool unmapGPUAddr(unsigned long gAddr); 75 size_t calcLumaAlign(ColorConvertFormat format); 76 size_t calcSizeAlign(ColorConvertFormat format); 77 C2DBytesPerPixel calcBytesPerPixel(ColorConvertFormat format); 78 79 void *mC2DLibHandle; 80 LINK_c2dCreateSurface mC2DCreateSurface; 81 LINK_c2dUpdateSurface mC2DUpdateSurface; 82 LINK_c2dReadSurface mC2DReadSurface; 83 LINK_c2dDraw mC2DDraw; 84 LINK_c2dFlush mC2DFlush; 85 LINK_c2dFinish mC2DFinish; 86 LINK_c2dWaitTimestamp mC2DWaitTimestamp; 87 LINK_c2dDestroySurface mC2DDestroySurface; 88 LINK_c2dMapAddr mC2DMapAddr; 89 LINK_c2dUnMapAddr mC2DUnMapAddr; 90 91 void *mAdrenoUtilsHandle; 92 LINK_AdrenoComputeAlignedWidthAndHeight mAdrenoComputeAlignedWidthAndHeight; 93 94 uint32_t mSrcSurface, mDstSurface; 95 void * mSrcSurfaceDef; 96 void * mDstSurfaceDef; 97 98 C2D_OBJECT mBlit; 99 size_t mSrcWidth; 100 size_t mSrcHeight; 101 size_t mSrcStride; 102 size_t mDstWidth; 103 size_t mDstHeight; 104 size_t mSrcSize; 105 size_t mDstSize; 106 size_t mSrcYSize; 107 size_t mDstYSize; 108 enum ColorConvertFormat mSrcFormat; 109 enum ColorConvertFormat mDstFormat; 110 int32_t mFlags; 111 112 int mError; 113}; 114 115C2DColorConverter::C2DColorConverter(size_t srcWidth, size_t srcHeight, size_t dstWidth, size_t dstHeight, ColorConvertFormat srcFormat, ColorConvertFormat dstFormat, int32_t flags, size_t srcStride) 116{ 117 mError = 0; 118 if (NV12_UBWC == dstFormat) { 119 ALOGE("%s: FATAL ERROR: could not support UBWC output formats ", __FUNCTION__); 120 mError = -1; 121 return; 122 } 123 mC2DLibHandle = dlopen("libC2D2.so", RTLD_NOW); 124 if (!mC2DLibHandle) { 125 ALOGE("FATAL ERROR: could not dlopen libc2d2.so: %s", dlerror()); 126 mError = -1; 127 return; 128 } 129 mC2DCreateSurface = (LINK_c2dCreateSurface)dlsym(mC2DLibHandle, "c2dCreateSurface"); 130 mC2DUpdateSurface = (LINK_c2dUpdateSurface)dlsym(mC2DLibHandle, "c2dUpdateSurface"); 131 mC2DReadSurface = (LINK_c2dReadSurface)dlsym(mC2DLibHandle, "c2dReadSurface"); 132 mC2DDraw = (LINK_c2dDraw)dlsym(mC2DLibHandle, "c2dDraw"); 133 mC2DFlush = (LINK_c2dFlush)dlsym(mC2DLibHandle, "c2dFlush"); 134 mC2DFinish = (LINK_c2dFinish)dlsym(mC2DLibHandle, "c2dFinish"); 135 mC2DWaitTimestamp = (LINK_c2dWaitTimestamp)dlsym(mC2DLibHandle, "c2dWaitTimestamp"); 136 mC2DDestroySurface = (LINK_c2dDestroySurface)dlsym(mC2DLibHandle, "c2dDestroySurface"); 137 mC2DMapAddr = (LINK_c2dMapAddr)dlsym(mC2DLibHandle, "c2dMapAddr"); 138 mC2DUnMapAddr = (LINK_c2dUnMapAddr)dlsym(mC2DLibHandle, "c2dUnMapAddr"); 139 140 if (!mC2DCreateSurface || !mC2DUpdateSurface || !mC2DReadSurface 141 || !mC2DDraw || !mC2DFlush || !mC2DFinish || !mC2DWaitTimestamp 142 || !mC2DDestroySurface || !mC2DMapAddr || !mC2DUnMapAddr) { 143 ALOGE("%s: dlsym ERROR", __FUNCTION__); 144 mError = -1; 145 return; 146 } 147 148 mAdrenoUtilsHandle = dlopen("libadreno_utils.so", RTLD_NOW); 149 if (!mAdrenoUtilsHandle) { 150 ALOGE("FATAL ERROR: could not dlopen libadreno_utils.so: %s", dlerror()); 151 mError = -1; 152 return; 153 } 154 155 mAdrenoComputeAlignedWidthAndHeight = (LINK_AdrenoComputeAlignedWidthAndHeight)dlsym(mAdrenoUtilsHandle, "compute_aligned_width_and_height"); 156 if (!mAdrenoComputeAlignedWidthAndHeight) { 157 ALOGE("%s: dlsym ERROR", __FUNCTION__); 158 mError = -1; 159 return; 160 } 161 162 mSrcWidth = srcWidth; 163 mSrcHeight = srcHeight; 164 mSrcStride = srcStride;; 165 mDstWidth = dstWidth; 166 mDstHeight = dstHeight; 167 mSrcFormat = srcFormat; 168 mDstFormat = dstFormat; 169 mSrcSize = calcSize(srcFormat, srcWidth, srcHeight); 170 mDstSize = calcSize(dstFormat, dstWidth, dstHeight); 171 mSrcYSize = calcYSize(srcFormat, srcWidth, srcHeight); 172 mDstYSize = calcYSize(dstFormat, dstWidth, dstHeight); 173 174 mFlags = flags; // can be used for rotation 175 176 mSrcSurfaceDef = getDummySurfaceDef(srcFormat, srcWidth, srcHeight, true); 177 mDstSurfaceDef = getDummySurfaceDef(dstFormat, dstWidth, dstHeight, false); 178 179 memset((void*)&mBlit,0,sizeof(C2D_OBJECT)); 180 mBlit.source_rect.x = 0 << 16; 181 mBlit.source_rect.y = 0 << 16; 182 mBlit.source_rect.width = srcWidth << 16; 183 mBlit.source_rect.height = srcHeight << 16; 184 mBlit.target_rect.x = 0 << 16; 185 mBlit.target_rect.y = 0 << 16; 186 mBlit.target_rect.width = dstWidth << 16; 187 mBlit.target_rect.height = dstHeight << 16; 188 mBlit.config_mask = C2D_ALPHA_BLEND_NONE | C2D_NO_BILINEAR_BIT | C2D_NO_ANTIALIASING_BIT | C2D_TARGET_RECT_BIT; 189 mBlit.surface_id = mSrcSurface; 190} 191 192C2DColorConverter::~C2DColorConverter() 193{ 194 if (mError) { 195 if (mC2DLibHandle) { 196 dlclose(mC2DLibHandle); 197 } 198 return; 199 } 200 201 mC2DDestroySurface(mDstSurface); 202 mC2DDestroySurface(mSrcSurface); 203 if (isYUVSurface(mSrcFormat)) { 204 delete ((C2D_YUV_SURFACE_DEF *)mSrcSurfaceDef); 205 } else { 206 delete ((C2D_RGB_SURFACE_DEF *)mSrcSurfaceDef); 207 } 208 209 if (isYUVSurface(mDstFormat)) { 210 delete ((C2D_YUV_SURFACE_DEF *)mDstSurfaceDef); 211 } else { 212 delete ((C2D_RGB_SURFACE_DEF *)mDstSurfaceDef); 213 } 214 215 dlclose(mC2DLibHandle); 216} 217 218int C2DColorConverter::convertC2D(int srcFd, void *srcBase, void * srcData, int dstFd, void *dstBase, void * dstData) 219{ 220 C2D_STATUS ret; 221 222 if (mError) { 223 ALOGE("C2D library initialization failed\n"); 224 return mError; 225 } 226 227 if ((srcFd < 0) || (dstFd < 0) || (srcData == NULL) || (dstData == NULL)) { 228 ALOGE("Incorrect input parameters\n"); 229 return -1; 230 } 231 232 if (isYUVSurface(mSrcFormat)) { 233 ret = updateYUVSurfaceDef(srcFd, srcBase, srcData, true); 234 } else { 235 ret = updateRGBSurfaceDef(srcFd, srcData, true); 236 } 237 238 if (ret != C2D_STATUS_OK) { 239 ALOGE("Update src surface def failed\n"); 240 return -ret; 241 } 242 243 if (isYUVSurface(mDstFormat)) { 244 ret = updateYUVSurfaceDef(dstFd, dstBase, dstData, false); 245 } else { 246 ret = updateRGBSurfaceDef(dstFd, dstData, false); 247 } 248 249 if (ret != C2D_STATUS_OK) { 250 ALOGE("Update dst surface def failed\n"); 251 return -ret; 252 } 253 254 mBlit.surface_id = mSrcSurface; 255 ret = mC2DDraw(mDstSurface, C2D_TARGET_ROTATE_0, 0, 0, 0, &mBlit, 1); 256 mC2DFinish(mDstSurface); 257 258 bool unmappedSrcSuccess; 259 if (isYUVSurface(mSrcFormat)) { 260 unmappedSrcSuccess = unmapGPUAddr((unsigned long)((C2D_YUV_SURFACE_DEF *)mSrcSurfaceDef)->phys0); 261 } else { 262 unmappedSrcSuccess = unmapGPUAddr((unsigned long)((C2D_RGB_SURFACE_DEF *)mSrcSurfaceDef)->phys); 263 } 264 265 bool unmappedDstSuccess; 266 if (isYUVSurface(mDstFormat)) { 267 unmappedDstSuccess = unmapGPUAddr((unsigned long)((C2D_YUV_SURFACE_DEF *)mDstSurfaceDef)->phys0); 268 } else { 269 unmappedDstSuccess = unmapGPUAddr((unsigned long)((C2D_RGB_SURFACE_DEF *)mDstSurfaceDef)->phys); 270 } 271 272 if (ret != C2D_STATUS_OK) { 273 ALOGE("C2D Draw failed\n"); 274 return -ret; //c2d err values are positive 275 } else { 276 if (!unmappedSrcSuccess || !unmappedDstSuccess) { 277 ALOGE("unmapping GPU address failed\n"); 278 return -1; 279 } 280 return ret; 281 } 282} 283 284bool C2DColorConverter::isYUVSurface(ColorConvertFormat format) 285{ 286 switch (format) { 287 case YCbCr420Tile: 288 case YCbCr420SP: 289 case YCbCr420P: 290 case YCrCb420P: 291 case NV12_2K: 292 case NV12_128m: 293 case NV12_UBWC: 294 return true; 295 case RGB565: 296 case RGBA8888: 297 default: 298 return false; 299 } 300} 301 302void* C2DColorConverter::getDummySurfaceDef(ColorConvertFormat format, size_t width, size_t height, bool isSource) 303{ 304 if (isYUVSurface(format)) { 305 C2D_YUV_SURFACE_DEF * surfaceDef = new C2D_YUV_SURFACE_DEF; 306 surfaceDef->format = getC2DFormat(format); 307 surfaceDef->width = width; 308 surfaceDef->height = height; 309 surfaceDef->plane0 = (void *)0xaaaaaaaa; 310 surfaceDef->phys0 = (void *)0xaaaaaaaa; 311 surfaceDef->stride0 = calcStride(format, width); 312 surfaceDef->plane1 = (void *)0xaaaaaaaa; 313 surfaceDef->phys1 = (void *)0xaaaaaaaa; 314 surfaceDef->stride1 = calcStride(format, width); 315 surfaceDef->phys2 = NULL; 316 surfaceDef->plane2 = NULL; 317 318 if (format == YCbCr420P || 319 format == YCrCb420P) { 320 printf("half stride for Cb Cr planes \n"); 321 surfaceDef->stride1 = calcStride(format, width) / 2; 322 surfaceDef->phys2 = (void *)0xaaaaaaaa; 323 surfaceDef->stride2 = calcStride(format, width) / 2; 324 } 325 mC2DCreateSurface(isSource ? &mSrcSurface : &mDstSurface, isSource ? C2D_SOURCE : C2D_TARGET, 326 (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY), 327 &(*surfaceDef)); 328 return ((void *)surfaceDef); 329 } else { 330 C2D_RGB_SURFACE_DEF * surfaceDef = new C2D_RGB_SURFACE_DEF; 331 surfaceDef->format = getC2DFormat(format); 332 surfaceDef->width = width; 333 surfaceDef->height = height; 334 surfaceDef->buffer = (void *)0xaaaaaaaa; 335 surfaceDef->phys = (void *)0xaaaaaaaa; 336 surfaceDef->stride = calcStride(format, width); 337 mC2DCreateSurface(isSource ? &mSrcSurface : &mDstSurface, isSource ? C2D_SOURCE : C2D_TARGET, 338 (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY), 339 &(*surfaceDef)); 340 return ((void *)surfaceDef); 341 } 342} 343 344C2D_STATUS C2DColorConverter::updateYUVSurfaceDef(int fd, void *base, void *data, bool isSource) 345{ 346 if (isSource) { 347 C2D_YUV_SURFACE_DEF * srcSurfaceDef = (C2D_YUV_SURFACE_DEF *)mSrcSurfaceDef; 348 srcSurfaceDef->plane0 = data; 349 srcSurfaceDef->phys0 = (uint8_t *)getMappedGPUAddr(fd, data, mSrcSize) + ((uint8_t *)data - (uint8_t *)base); 350 srcSurfaceDef->plane1 = (uint8_t *)data + mSrcYSize; 351 srcSurfaceDef->phys1 = (uint8_t *)srcSurfaceDef->phys0 + mSrcYSize; 352 if (srcSurfaceDef->format & C2D_COLOR_FORMAT_420_I420 || 353 srcSurfaceDef->format & C2D_COLOR_FORMAT_420_YV12) { 354 srcSurfaceDef->plane2 = (uint8_t *)srcSurfaceDef->plane1 + mSrcYSize/4; 355 srcSurfaceDef->phys2 = (uint8_t *)srcSurfaceDef->phys1 + mSrcYSize/4; 356 } 357 return mC2DUpdateSurface(mSrcSurface, C2D_SOURCE, 358 (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS), 359 &(*srcSurfaceDef)); 360 } else { 361 C2D_YUV_SURFACE_DEF * dstSurfaceDef = (C2D_YUV_SURFACE_DEF *)mDstSurfaceDef; 362 dstSurfaceDef->plane0 = data; 363 dstSurfaceDef->phys0 = (uint8_t *)getMappedGPUAddr(fd, data, mDstSize) + ((uint8_t *)data - (uint8_t *)base); 364 dstSurfaceDef->plane1 = (uint8_t *)data + mDstYSize; 365 dstSurfaceDef->phys1 = (uint8_t *)dstSurfaceDef->phys0 + mDstYSize; 366 if (dstSurfaceDef->format & C2D_COLOR_FORMAT_420_I420 || 367 dstSurfaceDef->format & C2D_COLOR_FORMAT_420_YV12) { 368 dstSurfaceDef->plane2 = (uint8_t *)dstSurfaceDef->plane1 + mDstYSize/4; 369 dstSurfaceDef->phys2 = (uint8_t *)dstSurfaceDef->phys1 + mDstYSize/4; 370 } 371 372 return mC2DUpdateSurface(mDstSurface, C2D_TARGET, 373 (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS), 374 &(*dstSurfaceDef)); 375 } 376} 377 378C2D_STATUS C2DColorConverter::updateRGBSurfaceDef(int fd, void * data, bool isSource) 379{ 380 if (isSource) { 381 C2D_RGB_SURFACE_DEF * srcSurfaceDef = (C2D_RGB_SURFACE_DEF *)mSrcSurfaceDef; 382 srcSurfaceDef->buffer = data; 383 srcSurfaceDef->phys = getMappedGPUAddr(fd, data, mSrcSize); 384 return mC2DUpdateSurface(mSrcSurface, C2D_SOURCE, 385 (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS), 386 &(*srcSurfaceDef)); 387 } else { 388 C2D_RGB_SURFACE_DEF * dstSurfaceDef = (C2D_RGB_SURFACE_DEF *)mDstSurfaceDef; 389 dstSurfaceDef->buffer = data; 390 ALOGV("dstSurfaceDef->buffer = %p\n", data); 391 dstSurfaceDef->phys = getMappedGPUAddr(fd, data, mDstSize); 392 return mC2DUpdateSurface(mDstSurface, C2D_TARGET, 393 (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS), 394 &(*dstSurfaceDef)); 395 } 396} 397 398uint32_t C2DColorConverter::getC2DFormat(ColorConvertFormat format) 399{ 400 switch (format) { 401 case RGB565: 402 return C2D_COLOR_FORMAT_565_RGB; 403 case RGBA8888: 404 return C2D_COLOR_FORMAT_8888_RGBA | C2D_FORMAT_SWAP_ENDIANNESS | C2D_FORMAT_PREMULTIPLIED; 405 case YCbCr420Tile: 406 return (C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_MACROTILED); 407 case YCbCr420SP: 408 case NV12_2K: 409 case NV12_128m: 410 return C2D_COLOR_FORMAT_420_NV12; 411 case YCbCr420P: 412 return C2D_COLOR_FORMAT_420_I420; 413 case YCrCb420P: 414 return C2D_COLOR_FORMAT_420_YV12; 415 case NV12_UBWC: 416 return C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_UBWC_COMPRESSED; 417 default: 418 ALOGE("Format not supported , %d\n", format); 419 return -1; 420 } 421} 422 423size_t C2DColorConverter::calcStride(ColorConvertFormat format, size_t width) 424{ 425 switch (format) { 426 case RGB565: 427 return ALIGN(width, ALIGN32) * 2; // RGB565 has width as twice 428 case RGBA8888: 429 if (mSrcStride) 430 return mSrcStride * 4; 431 else 432 return ALIGN(width, ALIGN32) * 4; 433 case YCbCr420Tile: 434 return ALIGN(width, ALIGN128); 435 case YCbCr420SP: 436 return ALIGN(width, ALIGN16); 437 case NV12_2K: 438 return ALIGN(width, ALIGN16); 439 case NV12_128m: 440 return ALIGN(width, ALIGN128); 441 case YCbCr420P: 442 return ALIGN(width, ALIGN16); 443 case YCrCb420P: 444 return ALIGN(width, ALIGN16); 445 case NV12_UBWC: 446 return VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width); 447 default: 448 return 0; 449 } 450} 451 452size_t C2DColorConverter::calcYSize(ColorConvertFormat format, size_t width, size_t height) 453{ 454 switch (format) { 455 case YCbCr420SP: 456 return (ALIGN(width, ALIGN16) * height); 457 case YCbCr420P: 458 return ALIGN(width, ALIGN16) * height; 459 case YCrCb420P: 460 return ALIGN(width, ALIGN16) * height; 461 case YCbCr420Tile: 462 return ALIGN(ALIGN(width, ALIGN128) * ALIGN(height, ALIGN32), ALIGN8K); 463 case NV12_2K: { 464 size_t alignedw = ALIGN(width, ALIGN16); 465 size_t lumaSize = ALIGN(alignedw * height, ALIGN2K); 466 return lumaSize; 467 } 468 case NV12_128m: 469 return ALIGN(width, ALIGN128) * ALIGN(height, ALIGN32); 470 case NV12_UBWC: 471 return ALIGN( VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width) * 472 VENUS_Y_SCANLINES(COLOR_FMT_NV12_UBWC, height), ALIGN4K) + 473 ALIGN( VENUS_Y_META_STRIDE(COLOR_FMT_NV12_UBWC, width) * 474 VENUS_Y_META_SCANLINES(COLOR_FMT_NV12_UBWC, height), ALIGN4K); 475 default: 476 return 0; 477 } 478} 479 480size_t C2DColorConverter::calcSize(ColorConvertFormat format, size_t width, size_t height) 481{ 482 int32_t alignedw = 0; 483 int32_t alignedh = 0; 484 int32_t size = 0; 485 int32_t tile_mode = 0; 486 int32_t raster_mode = 0; 487 int32_t padding_threshold = 512; /* hardcode for RGB formats */ 488 int32_t bpp = 0; 489 490 switch (format) { 491 case RGB565: 492 bpp = 2; 493 mAdrenoComputeAlignedWidthAndHeight(width, height, bpp, tile_mode, raster_mode, padding_threshold, 494 &alignedw, &alignedh); 495 size = alignedw * alignedh * bpp; 496 size = ALIGN(size, ALIGN4K); 497 break; 498 case RGBA8888: 499 bpp = 4; 500 mAdrenoComputeAlignedWidthAndHeight(width, height, bpp, tile_mode, raster_mode, padding_threshold, 501 &alignedw, &alignedh); 502 if (mSrcStride) 503 size = mSrcStride * alignedh * bpp; 504 else 505 size = alignedw * alignedh * bpp; 506 size = ALIGN(size, ALIGN4K); 507 break; 508 case YCbCr420SP: 509 alignedw = ALIGN(width, ALIGN16); 510 size = ALIGN((alignedw * height) + (ALIGN(width/2, ALIGN32) * (height/2) * 2), ALIGN4K); 511 break; 512 case YCbCr420P: 513 alignedw = ALIGN(width, ALIGN16); 514 size = ALIGN((alignedw * height) + (ALIGN(width/2, ALIGN16) * (height/2) * 2), ALIGN4K); 515 break; 516 case YCrCb420P: 517 alignedw = ALIGN(width, ALIGN16); 518 size = ALIGN((alignedw * height) + (ALIGN(width/2, ALIGN16) * (height/2) * 2), ALIGN4K); 519 break; 520 case YCbCr420Tile: 521 alignedw = ALIGN(width, ALIGN128); 522 alignedh = ALIGN(height, ALIGN32); 523 size = ALIGN(alignedw * alignedh, ALIGN8K) + ALIGN(alignedw * ALIGN(height/2, ALIGN32), ALIGN8K); 524 break; 525 case NV12_2K: { 526 alignedw = ALIGN(width, ALIGN16); 527 size_t lumaSize = ALIGN(alignedw * height, ALIGN2K); 528 size_t chromaSize = ALIGN((alignedw * height)/2, ALIGN2K); 529 size = ALIGN(lumaSize + chromaSize, ALIGN4K); 530 ALOGV("NV12_2k, width = %d, height = %d, size = %d", width, height, size); 531 } 532 break; 533 case NV12_128m: 534 alignedw = ALIGN(width, ALIGN128); 535 alignedh = ALIGN(height, ALIGN32); 536 size = ALIGN(alignedw * alignedh + (alignedw * ALIGN(height/2, ALIGN16)), ALIGN4K); 537 break; 538 case NV12_UBWC: 539 size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height); 540 default: 541 break; 542 } 543 return size; 544} 545/* 546 * Tells GPU to map given buffer and returns a physical address of mapped buffer 547 */ 548void * C2DColorConverter::getMappedGPUAddr(int bufFD, void *bufPtr, size_t bufLen) 549{ 550 C2D_STATUS status; 551 void *gpuaddr = NULL; 552 553 status = mC2DMapAddr(bufFD, bufPtr, bufLen, 0, KGSL_USER_MEM_TYPE_ION, 554 &gpuaddr); 555 if (status != C2D_STATUS_OK) { 556 ALOGE("c2dMapAddr failed: status %d fd %d ptr %p len %d flags %d\n", 557 status, bufFD, bufPtr, bufLen, KGSL_USER_MEM_TYPE_ION); 558 return NULL; 559 } 560 ALOGV("c2d mapping created: gpuaddr %p fd %d ptr %p len %d\n", 561 gpuaddr, bufFD, bufPtr, bufLen); 562 563 return gpuaddr; 564} 565 566bool C2DColorConverter::unmapGPUAddr(unsigned long gAddr) 567{ 568 569 C2D_STATUS status = mC2DUnMapAddr((void*)gAddr); 570 571 if (status != C2D_STATUS_OK) 572 ALOGE("c2dUnMapAddr failed: status %d gpuaddr %08lx\n", status, gAddr); 573 574 return (status == C2D_STATUS_OK); 575} 576 577int32_t C2DColorConverter::getBuffReq(int32_t port, C2DBuffReq *req) { 578 if (!req) return -1; 579 580 if (port != C2D_INPUT && port != C2D_OUTPUT) return -1; 581 582 memset(req, 0, sizeof(C2DBuffReq)); 583 if (port == C2D_INPUT) { 584 req->width = mSrcWidth; 585 req->height = mSrcHeight; 586 req->stride = calcStride(mSrcFormat, mSrcWidth); 587 req->sliceHeight = mSrcHeight; 588 req->lumaAlign = calcLumaAlign(mSrcFormat); 589 req->sizeAlign = calcSizeAlign(mSrcFormat); 590 req->size = calcSize(mSrcFormat, mSrcWidth, mSrcHeight); 591 req->bpp = calcBytesPerPixel(mSrcFormat); 592 ALOGV("input req->size = %d\n", req->size); 593 } else if (port == C2D_OUTPUT) { 594 req->width = mDstWidth; 595 req->height = mDstHeight; 596 req->stride = calcStride(mDstFormat, mDstWidth); 597 req->sliceHeight = mDstHeight; 598 req->lumaAlign = calcLumaAlign(mDstFormat); 599 req->sizeAlign = calcSizeAlign(mDstFormat); 600 req->size = calcSize(mDstFormat, mDstWidth, mDstHeight); 601 req->bpp = calcBytesPerPixel(mDstFormat); 602 ALOGV("output req->size = %d\n", req->size); 603 } 604 return 0; 605} 606 607size_t C2DColorConverter::calcLumaAlign(ColorConvertFormat format) { 608 if (!isYUVSurface(format)) return 1; //no requirement 609 610 switch (format) { 611 case NV12_2K: 612 return ALIGN2K; 613 case NV12_128m: 614 return 1; 615 case NV12_UBWC: 616 return ALIGN4K; 617 default: 618 ALOGE("unknown format passed for luma alignment number"); 619 return 1; 620 } 621} 622 623size_t C2DColorConverter::calcSizeAlign(ColorConvertFormat format) { 624 if (!isYUVSurface(format)) return 1; //no requirement 625 626 switch (format) { 627 case YCbCr420SP: //OR NV12 628 case YCbCr420P: 629 case NV12_2K: 630 case NV12_128m: 631 case NV12_UBWC: 632 return ALIGN4K; 633 default: 634 ALOGE("unknown format passed for size alignment number"); 635 return 1; 636 } 637} 638 639C2DBytesPerPixel C2DColorConverter::calcBytesPerPixel(ColorConvertFormat format) { 640 C2DBytesPerPixel bpp; 641 bpp.numerator = 0; 642 bpp.denominator = 1; 643 644 switch (format) { 645 case RGB565: 646 bpp.numerator = 2; 647 break; 648 case RGBA8888: 649 bpp.numerator = 4; 650 break; 651 case YCbCr420SP: 652 case YCbCr420P: 653 case YCrCb420P: 654 case YCbCr420Tile: 655 case NV12_2K: 656 case NV12_128m: 657 case NV12_UBWC: 658 bpp.numerator = 3; 659 bpp.denominator = 2; 660 break; 661 default: 662 break; 663 } 664 return bpp; 665} 666 667int32_t C2DColorConverter::dumpOutput(char * filename, char mode) { 668 int fd; 669 size_t stride, sliceHeight; 670 if (!filename) return -1; 671 672 int flags = O_RDWR | O_CREAT; 673 if (mode == 'a') { 674 flags |= O_APPEND; 675 } 676 677 if ((fd = open(filename, flags)) < 0) { 678 ALOGE("open dump file failed w/ errno %s", strerror(errno)); 679 return -1; 680 } 681 682 int ret = 0; 683 if (isYUVSurface(mDstFormat)) { 684 C2D_YUV_SURFACE_DEF * dstSurfaceDef = (C2D_YUV_SURFACE_DEF *)mDstSurfaceDef; 685 uint8_t * base = (uint8_t *)dstSurfaceDef->plane0; 686 stride = dstSurfaceDef->stride0; 687 sliceHeight = dstSurfaceDef->height; 688 /* dump luma */ 689 for (size_t i = 0; i < sliceHeight; i++) { 690 ret = write(fd, base, mDstWidth); //will work only for the 420 ones 691 if (ret < 0) goto cleanup; 692 base += stride; 693 } 694 695 if (mDstFormat == YCbCr420P || 696 mDstFormat == YCrCb420P) { 697 printf("Dump Cb and Cr separately for Planar\n"); 698 //dump Cb/Cr 699 base = (uint8_t *)dstSurfaceDef->plane1; 700 stride = dstSurfaceDef->stride1; 701 for (size_t i = 0; i < sliceHeight/2;i++) { //will work only for the 420 ones 702 ret = write(fd, base, mDstWidth/2); 703 if (ret < 0) goto cleanup; 704 base += stride; 705 } 706 707 //dump Cr/Cb 708 base = (uint8_t *)dstSurfaceDef->plane2; 709 stride = dstSurfaceDef->stride2; 710 711 for (size_t i = 0; i < sliceHeight/2;i++) { //will work only for the 420 ones 712 ret = write(fd, base, mDstWidth/2); 713 if (ret < 0) goto cleanup; 714 base += stride; 715 } 716 717 } else { 718 /* dump chroma */ 719 base = (uint8_t *)dstSurfaceDef->plane1; 720 stride = dstSurfaceDef->stride1; 721 for (size_t i = 0; i < sliceHeight/2;i++) { //will work only for the 420 ones 722 ret = write(fd, base, mDstWidth); 723 if (ret < 0) goto cleanup; 724 base += stride; 725 } 726 } 727 } else { 728 C2D_RGB_SURFACE_DEF * dstSurfaceDef = (C2D_RGB_SURFACE_DEF *)mDstSurfaceDef; 729 uint8_t * base = (uint8_t *)dstSurfaceDef->buffer; 730 stride = dstSurfaceDef->stride; 731 sliceHeight = dstSurfaceDef->height; 732 733 printf("rgb surface base is %p", base); 734 printf("rgb surface dumpsslice height is %lu\n", (unsigned long)sliceHeight); 735 printf("rgb surface dump stride is %lu\n", (unsigned long)stride); 736 737 int bpp = 1; //bytes per pixel 738 if (mDstFormat == RGB565) { 739 bpp = 2; 740 } else if (mDstFormat == RGBA8888) { 741 bpp = 4; 742 } 743 744 int count = 0; 745 for (size_t i = 0; i < sliceHeight; i++) { 746 ret = write(fd, base, mDstWidth*bpp); 747 if (ret < 0) { 748 printf("write failed, count = %d\n", count); 749 goto cleanup; 750 } 751 base += stride; 752 count += stride; 753 } 754 } 755 cleanup: 756 if (ret < 0) { 757 ALOGE("file write failed w/ errno %s", strerror(errno)); 758 } 759 close(fd); 760 return ret < 0 ? ret : 0; 761} 762 763extern "C" C2DColorConverterBase* createC2DColorConverter(size_t srcWidth, size_t srcHeight, size_t dstWidth, size_t dstHeight, ColorConvertFormat srcFormat, ColorConvertFormat dstFormat, int32_t flags, size_t srcStride) 764{ 765 return new C2DColorConverter(srcWidth, srcHeight, dstWidth, dstHeight, srcFormat, dstFormat, flags, srcStride); 766} 767 768extern "C" void destroyC2DColorConverter(C2DColorConverterBase* C2DCC) 769{ 770 delete C2DCC; 771} 772 773} 774