1 /* Copyright (c) 2012 - 2017, 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 //----------------------------------------------------- 52 namespace android { 53 54 class C2DColorConverter : public C2DColorConverterBase { 55 56 public: 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); 60 protected: 61 virtual ~C2DColorConverter(); 62 virtual int convertC2D(int srcFd, void *srcBase, void * srcData, int dstFd, void *dstBase, void * dstData); 63 64 private: 65 bool isYUVSurface(ColorConvertFormat format); 66 void *getDummySurfaceDef(ColorConvertFormat format, size_t width, size_t height, bool isSource); 67 C2D_STATUS updateYUVSurfaceDef(uint8_t *addr, void *base, void * data, bool isSource); 68 C2D_STATUS updateRGBSurfaceDef(uint8_t *addr, 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 115 C2DColorConverter::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 192 C2DColorConverter::~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 218 int C2DColorConverter::convertC2D(int srcFd, void *srcBase, void * srcData, int dstFd, void *dstBase, void * dstData) 219 { 220 C2D_STATUS ret; 221 uint8_t *srcMappedGpuAddr = nullptr; 222 uint8_t *dstMappedGpuAddr = nullptr; 223 224 if (mError) { 225 ALOGE("C2D library initialization failed\n"); 226 return mError; 227 } 228 229 if ((srcFd < 0) || (dstFd < 0) || (srcData == NULL) || (dstData == NULL)) { 230 ALOGE("Incorrect input parameters\n"); 231 return -1; 232 } 233 234 srcMappedGpuAddr = (uint8_t *)getMappedGPUAddr(srcFd, srcData, mSrcSize); 235 if (!srcMappedGpuAddr) 236 return -1; 237 238 if (isYUVSurface(mSrcFormat)) { 239 ret = updateYUVSurfaceDef(srcMappedGpuAddr, srcBase, srcData, true); 240 } else { 241 ret = updateRGBSurfaceDef(srcMappedGpuAddr, srcData, true); 242 } 243 244 if (ret != C2D_STATUS_OK) { 245 ALOGE("Update src surface def failed\n"); 246 unmapGPUAddr((unsigned long)srcMappedGpuAddr); 247 return -ret; 248 } 249 250 dstMappedGpuAddr = (uint8_t *)getMappedGPUAddr(dstFd, dstData, mDstSize); 251 if (!dstMappedGpuAddr) { 252 unmapGPUAddr((unsigned long)srcMappedGpuAddr); 253 return -1; 254 } 255 256 if (isYUVSurface(mDstFormat)) { 257 ret = updateYUVSurfaceDef(dstMappedGpuAddr, dstBase, dstData, false); 258 } else { 259 ret = updateRGBSurfaceDef(dstMappedGpuAddr, dstData, false); 260 } 261 262 if (ret != C2D_STATUS_OK) { 263 ALOGE("Update dst surface def failed\n"); 264 unmapGPUAddr((unsigned long)srcMappedGpuAddr); 265 unmapGPUAddr((unsigned long)dstMappedGpuAddr); 266 return -ret; 267 } 268 269 mBlit.surface_id = mSrcSurface; 270 ret = mC2DDraw(mDstSurface, C2D_TARGET_ROTATE_0, 0, 0, 0, &mBlit, 1); 271 mC2DFinish(mDstSurface); 272 273 bool unmappedSrcSuccess; 274 unmappedSrcSuccess = unmapGPUAddr((unsigned long)srcMappedGpuAddr); 275 276 bool unmappedDstSuccess; 277 unmappedDstSuccess = unmapGPUAddr((unsigned long)dstMappedGpuAddr); 278 279 if (ret != C2D_STATUS_OK) { 280 ALOGE("C2D Draw failed\n"); 281 return -ret; //c2d err values are positive 282 } else { 283 if (!unmappedSrcSuccess || !unmappedDstSuccess) { 284 ALOGE("unmapping GPU address failed\n"); 285 return -1; 286 } 287 return ret; 288 } 289 } 290 291 bool C2DColorConverter::isYUVSurface(ColorConvertFormat format) 292 { 293 switch (format) { 294 case YCbCr420Tile: 295 case YCbCr420SP: 296 case YCbCr420P: 297 case YCrCb420P: 298 case NV12_2K: 299 case NV12_128m: 300 case NV12_UBWC: 301 return true; 302 case RGB565: 303 case RGBA8888: 304 default: 305 return false; 306 } 307 } 308 309 void* C2DColorConverter::getDummySurfaceDef(ColorConvertFormat format, size_t width, size_t height, bool isSource) 310 { 311 if (isYUVSurface(format)) { 312 C2D_YUV_SURFACE_DEF * surfaceDef = new C2D_YUV_SURFACE_DEF; 313 surfaceDef->format = getC2DFormat(format); 314 surfaceDef->width = width; 315 surfaceDef->height = height; 316 surfaceDef->plane0 = (void *)0xaaaaaaaa; 317 surfaceDef->phys0 = (void *)0xaaaaaaaa; 318 surfaceDef->stride0 = calcStride(format, width); 319 surfaceDef->plane1 = (void *)0xaaaaaaaa; 320 surfaceDef->phys1 = (void *)0xaaaaaaaa; 321 surfaceDef->stride1 = calcStride(format, width); 322 surfaceDef->phys2 = NULL; 323 surfaceDef->plane2 = NULL; 324 325 if (format == YCbCr420P || 326 format == YCrCb420P) { 327 printf("half stride for Cb Cr planes \n"); 328 surfaceDef->stride1 = calcStride(format, width) / 2; 329 surfaceDef->phys2 = (void *)0xaaaaaaaa; 330 surfaceDef->stride2 = calcStride(format, width) / 2; 331 } 332 mC2DCreateSurface(isSource ? &mSrcSurface : &mDstSurface, isSource ? C2D_SOURCE : C2D_TARGET, 333 (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY), 334 &(*surfaceDef)); 335 return ((void *)surfaceDef); 336 } else { 337 C2D_RGB_SURFACE_DEF * surfaceDef = new C2D_RGB_SURFACE_DEF; 338 surfaceDef->format = getC2DFormat(format); 339 surfaceDef->width = width; 340 surfaceDef->height = height; 341 surfaceDef->buffer = (void *)0xaaaaaaaa; 342 surfaceDef->phys = (void *)0xaaaaaaaa; 343 surfaceDef->stride = calcStride(format, width); 344 mC2DCreateSurface(isSource ? &mSrcSurface : &mDstSurface, isSource ? C2D_SOURCE : C2D_TARGET, 345 (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS | C2D_SURFACE_WITH_PHYS_DUMMY), 346 &(*surfaceDef)); 347 return ((void *)surfaceDef); 348 } 349 } 350 351 C2D_STATUS C2DColorConverter::updateYUVSurfaceDef(uint8_t *gpuAddr, void *base, void *data, bool isSource) 352 { 353 if (isSource) { 354 C2D_YUV_SURFACE_DEF * srcSurfaceDef = (C2D_YUV_SURFACE_DEF *)mSrcSurfaceDef; 355 srcSurfaceDef->plane0 = data; 356 srcSurfaceDef->phys0 = gpuAddr + ((uint8_t *)data - (uint8_t *)base); 357 srcSurfaceDef->plane1 = (uint8_t *)data + mSrcYSize; 358 srcSurfaceDef->phys1 = (uint8_t *)srcSurfaceDef->phys0 + mSrcYSize; 359 if (srcSurfaceDef->format & C2D_COLOR_FORMAT_420_I420 || 360 srcSurfaceDef->format & C2D_COLOR_FORMAT_420_YV12) { 361 srcSurfaceDef->plane2 = (uint8_t *)srcSurfaceDef->plane1 + mSrcYSize/4; 362 srcSurfaceDef->phys2 = (uint8_t *)srcSurfaceDef->phys1 + mSrcYSize/4; 363 } 364 return mC2DUpdateSurface(mSrcSurface, C2D_SOURCE, 365 (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS), 366 &(*srcSurfaceDef)); 367 } else { 368 C2D_YUV_SURFACE_DEF * dstSurfaceDef = (C2D_YUV_SURFACE_DEF *)mDstSurfaceDef; 369 dstSurfaceDef->plane0 = data; 370 dstSurfaceDef->phys0 = gpuAddr + ((uint8_t *)data - (uint8_t *)base); 371 dstSurfaceDef->plane1 = (uint8_t *)data + mDstYSize; 372 dstSurfaceDef->phys1 = (uint8_t *)dstSurfaceDef->phys0 + mDstYSize; 373 if (dstSurfaceDef->format & C2D_COLOR_FORMAT_420_I420 || 374 dstSurfaceDef->format & C2D_COLOR_FORMAT_420_YV12) { 375 dstSurfaceDef->plane2 = (uint8_t *)dstSurfaceDef->plane1 + mDstYSize/4; 376 dstSurfaceDef->phys2 = (uint8_t *)dstSurfaceDef->phys1 + mDstYSize/4; 377 } 378 379 return mC2DUpdateSurface(mDstSurface, C2D_TARGET, 380 (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS), 381 &(*dstSurfaceDef)); 382 } 383 } 384 385 C2D_STATUS C2DColorConverter::updateRGBSurfaceDef(uint8_t *gpuAddr, void * data, bool isSource) 386 { 387 if (isSource) { 388 C2D_RGB_SURFACE_DEF * srcSurfaceDef = (C2D_RGB_SURFACE_DEF *)mSrcSurfaceDef; 389 srcSurfaceDef->buffer = data; 390 srcSurfaceDef->phys = gpuAddr; 391 return mC2DUpdateSurface(mSrcSurface, C2D_SOURCE, 392 (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS), 393 &(*srcSurfaceDef)); 394 } else { 395 C2D_RGB_SURFACE_DEF * dstSurfaceDef = (C2D_RGB_SURFACE_DEF *)mDstSurfaceDef; 396 dstSurfaceDef->buffer = data; 397 ALOGV("dstSurfaceDef->buffer = %p\n", data); 398 dstSurfaceDef->phys = gpuAddr; 399 return mC2DUpdateSurface(mDstSurface, C2D_TARGET, 400 (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS), 401 &(*dstSurfaceDef)); 402 } 403 } 404 405 uint32_t C2DColorConverter::getC2DFormat(ColorConvertFormat format) 406 { 407 switch (format) { 408 case RGB565: 409 return C2D_COLOR_FORMAT_565_RGB; 410 case RGBA8888: 411 return C2D_COLOR_FORMAT_8888_RGBA | C2D_FORMAT_SWAP_ENDIANNESS | C2D_FORMAT_PREMULTIPLIED; 412 case YCbCr420Tile: 413 return (C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_MACROTILED); 414 case YCbCr420SP: 415 case NV12_2K: 416 case NV12_128m: 417 return C2D_COLOR_FORMAT_420_NV12; 418 case YCbCr420P: 419 return C2D_COLOR_FORMAT_420_I420; 420 case YCrCb420P: 421 return C2D_COLOR_FORMAT_420_YV12; 422 case NV12_UBWC: 423 return C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_UBWC_COMPRESSED; 424 default: 425 ALOGE("Format not supported , %d\n", format); 426 return -1; 427 } 428 } 429 430 size_t C2DColorConverter::calcStride(ColorConvertFormat format, size_t width) 431 { 432 switch (format) { 433 case RGB565: 434 return ALIGN(width, ALIGN32) * 2; // RGB565 has width as twice 435 case RGBA8888: 436 if (mSrcStride) 437 return mSrcStride * 4; 438 else 439 return ALIGN(width, ALIGN32) * 4; 440 case YCbCr420Tile: 441 return ALIGN(width, ALIGN128); 442 case YCbCr420SP: 443 return ALIGN(width, ALIGN16); 444 case NV12_2K: 445 return ALIGN(width, ALIGN16); 446 case NV12_128m: 447 return ALIGN(width, ALIGN128); 448 case YCbCr420P: 449 return ALIGN(width, ALIGN16); 450 case YCrCb420P: 451 return ALIGN(width, ALIGN16); 452 case NV12_UBWC: 453 return VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width); 454 default: 455 return 0; 456 } 457 } 458 459 size_t C2DColorConverter::calcYSize(ColorConvertFormat format, size_t width, size_t height) 460 { 461 switch (format) { 462 case YCbCr420SP: 463 return (ALIGN(width, ALIGN16) * height); 464 case YCbCr420P: 465 return ALIGN(width, ALIGN16) * height; 466 case YCrCb420P: 467 return ALIGN(width, ALIGN16) * height; 468 case YCbCr420Tile: 469 return ALIGN(ALIGN(width, ALIGN128) * ALIGN(height, ALIGN32), ALIGN8K); 470 case NV12_2K: { 471 size_t alignedw = ALIGN(width, ALIGN16); 472 size_t lumaSize = ALIGN(alignedw * height, ALIGN2K); 473 return lumaSize; 474 } 475 case NV12_128m: 476 return ALIGN(width, ALIGN128) * ALIGN(height, ALIGN32); 477 case NV12_UBWC: 478 return ALIGN( VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width) * 479 VENUS_Y_SCANLINES(COLOR_FMT_NV12_UBWC, height), ALIGN4K) + 480 ALIGN( VENUS_Y_META_STRIDE(COLOR_FMT_NV12_UBWC, width) * 481 VENUS_Y_META_SCANLINES(COLOR_FMT_NV12_UBWC, height), ALIGN4K); 482 default: 483 return 0; 484 } 485 } 486 487 size_t C2DColorConverter::calcSize(ColorConvertFormat format, size_t width, size_t height) 488 { 489 int32_t alignedw = 0; 490 int32_t alignedh = 0; 491 int32_t size = 0; 492 int32_t tile_mode = 0; 493 int32_t raster_mode = 0; 494 int32_t padding_threshold = 512; /* hardcode for RGB formats */ 495 int32_t bpp = 0; 496 497 switch (format) { 498 case RGB565: 499 bpp = 2; 500 mAdrenoComputeAlignedWidthAndHeight(width, height, bpp, tile_mode, raster_mode, padding_threshold, 501 &alignedw, &alignedh); 502 size = alignedw * alignedh * bpp; 503 size = ALIGN(size, ALIGN4K); 504 break; 505 case RGBA8888: 506 bpp = 4; 507 mAdrenoComputeAlignedWidthAndHeight(width, height, bpp, tile_mode, raster_mode, padding_threshold, 508 &alignedw, &alignedh); 509 if (mSrcStride) 510 size = mSrcStride * alignedh * bpp; 511 else 512 size = alignedw * alignedh * bpp; 513 size = ALIGN(size, ALIGN4K); 514 break; 515 case YCbCr420SP: 516 alignedw = ALIGN(width, ALIGN16); 517 size = ALIGN((alignedw * height) + (ALIGN(width/2, ALIGN32) * (height/2) * 2), ALIGN4K); 518 break; 519 case YCbCr420P: 520 alignedw = ALIGN(width, ALIGN16); 521 size = ALIGN((alignedw * height) + (ALIGN(width/2, ALIGN16) * (height/2) * 2), ALIGN4K); 522 break; 523 case YCrCb420P: 524 alignedw = ALIGN(width, ALIGN16); 525 size = ALIGN((alignedw * height) + (ALIGN(width/2, ALIGN16) * (height/2) * 2), ALIGN4K); 526 break; 527 case YCbCr420Tile: 528 alignedw = ALIGN(width, ALIGN128); 529 alignedh = ALIGN(height, ALIGN32); 530 size = ALIGN(alignedw * alignedh, ALIGN8K) + ALIGN(alignedw * ALIGN(height/2, ALIGN32), ALIGN8K); 531 break; 532 case NV12_2K: { 533 alignedw = ALIGN(width, ALIGN16); 534 size_t lumaSize = ALIGN(alignedw * height, ALIGN2K); 535 size_t chromaSize = ALIGN((alignedw * height)/2, ALIGN2K); 536 size = ALIGN(lumaSize + chromaSize, ALIGN4K); 537 ALOGV("NV12_2k, width = %d, height = %d, size = %d", width, height, size); 538 } 539 break; 540 case NV12_128m: 541 alignedw = ALIGN(width, ALIGN128); 542 alignedh = ALIGN(height, ALIGN32); 543 size = ALIGN(alignedw * alignedh + (alignedw * ALIGN(height/2, ALIGN16)), ALIGN4K); 544 break; 545 case NV12_UBWC: 546 size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height); 547 default: 548 break; 549 } 550 return size; 551 } 552 /* 553 * Tells GPU to map given buffer and returns a physical address of mapped buffer 554 */ 555 void * C2DColorConverter::getMappedGPUAddr(int bufFD, void *bufPtr, size_t bufLen) 556 { 557 C2D_STATUS status; 558 void *gpuaddr = NULL; 559 560 status = mC2DMapAddr(bufFD, bufPtr, bufLen, 0, KGSL_USER_MEM_TYPE_ION, 561 &gpuaddr); 562 if (status != C2D_STATUS_OK) { 563 ALOGE("c2dMapAddr failed: status %d fd %d ptr %p len %d flags %d\n", 564 status, bufFD, bufPtr, bufLen, KGSL_USER_MEM_TYPE_ION); 565 return NULL; 566 } 567 ALOGV("c2d mapping created: gpuaddr %p fd %d ptr %p len %d\n", 568 gpuaddr, bufFD, bufPtr, bufLen); 569 570 return gpuaddr; 571 } 572 573 bool C2DColorConverter::unmapGPUAddr(unsigned long gAddr) 574 { 575 576 C2D_STATUS status = mC2DUnMapAddr((void*)gAddr); 577 578 if (status != C2D_STATUS_OK) 579 ALOGE("c2dUnMapAddr failed: status %d gpuaddr %08lx\n", status, gAddr); 580 581 return (status == C2D_STATUS_OK); 582 } 583 584 int32_t C2DColorConverter::getBuffReq(int32_t port, C2DBuffReq *req) { 585 if (!req) return -1; 586 587 if (port != C2D_INPUT && port != C2D_OUTPUT) return -1; 588 589 memset(req, 0, sizeof(C2DBuffReq)); 590 if (port == C2D_INPUT) { 591 req->width = mSrcWidth; 592 req->height = mSrcHeight; 593 req->stride = calcStride(mSrcFormat, mSrcWidth); 594 req->sliceHeight = mSrcHeight; 595 req->lumaAlign = calcLumaAlign(mSrcFormat); 596 req->sizeAlign = calcSizeAlign(mSrcFormat); 597 req->size = calcSize(mSrcFormat, mSrcWidth, mSrcHeight); 598 req->bpp = calcBytesPerPixel(mSrcFormat); 599 ALOGV("input req->size = %d\n", req->size); 600 } else if (port == C2D_OUTPUT) { 601 req->width = mDstWidth; 602 req->height = mDstHeight; 603 req->stride = calcStride(mDstFormat, mDstWidth); 604 req->sliceHeight = mDstHeight; 605 req->lumaAlign = calcLumaAlign(mDstFormat); 606 req->sizeAlign = calcSizeAlign(mDstFormat); 607 req->size = calcSize(mDstFormat, mDstWidth, mDstHeight); 608 req->bpp = calcBytesPerPixel(mDstFormat); 609 ALOGV("output req->size = %d\n", req->size); 610 } 611 return 0; 612 } 613 614 size_t C2DColorConverter::calcLumaAlign(ColorConvertFormat format) { 615 if (!isYUVSurface(format)) return 1; //no requirement 616 617 switch (format) { 618 case NV12_2K: 619 return ALIGN2K; 620 case NV12_128m: 621 return 1; 622 case NV12_UBWC: 623 return ALIGN4K; 624 default: 625 ALOGE("unknown format passed for luma alignment number"); 626 return 1; 627 } 628 } 629 630 size_t C2DColorConverter::calcSizeAlign(ColorConvertFormat format) { 631 if (!isYUVSurface(format)) return 1; //no requirement 632 633 switch (format) { 634 case YCbCr420SP: //OR NV12 635 case YCbCr420P: 636 case NV12_2K: 637 case NV12_128m: 638 case NV12_UBWC: 639 return ALIGN4K; 640 default: 641 ALOGE("unknown format passed for size alignment number"); 642 return 1; 643 } 644 } 645 646 C2DBytesPerPixel C2DColorConverter::calcBytesPerPixel(ColorConvertFormat format) { 647 C2DBytesPerPixel bpp; 648 bpp.numerator = 0; 649 bpp.denominator = 1; 650 651 switch (format) { 652 case RGB565: 653 bpp.numerator = 2; 654 break; 655 case RGBA8888: 656 bpp.numerator = 4; 657 break; 658 case YCbCr420SP: 659 case YCbCr420P: 660 case YCrCb420P: 661 case YCbCr420Tile: 662 case NV12_2K: 663 case NV12_128m: 664 case NV12_UBWC: 665 bpp.numerator = 3; 666 bpp.denominator = 2; 667 break; 668 default: 669 break; 670 } 671 return bpp; 672 } 673 674 int32_t C2DColorConverter::dumpOutput(char * filename, char mode) { 675 int fd; 676 size_t stride, sliceHeight; 677 if (!filename) return -1; 678 679 int flags = O_RDWR | O_CREAT; 680 if (mode == 'a') { 681 flags |= O_APPEND; 682 } 683 684 if ((fd = open(filename, flags)) < 0) { 685 ALOGE("open dump file failed w/ errno %s", strerror(errno)); 686 return -1; 687 } 688 689 int ret = 0; 690 if (isYUVSurface(mDstFormat)) { 691 C2D_YUV_SURFACE_DEF * dstSurfaceDef = (C2D_YUV_SURFACE_DEF *)mDstSurfaceDef; 692 uint8_t * base = (uint8_t *)dstSurfaceDef->plane0; 693 stride = dstSurfaceDef->stride0; 694 sliceHeight = dstSurfaceDef->height; 695 /* dump luma */ 696 for (size_t i = 0; i < sliceHeight; i++) { 697 ret = write(fd, base, mDstWidth); //will work only for the 420 ones 698 if (ret < 0) goto cleanup; 699 base += stride; 700 } 701 702 if (mDstFormat == YCbCr420P || 703 mDstFormat == YCrCb420P) { 704 printf("Dump Cb and Cr separately for Planar\n"); 705 //dump Cb/Cr 706 base = (uint8_t *)dstSurfaceDef->plane1; 707 stride = dstSurfaceDef->stride1; 708 for (size_t i = 0; i < sliceHeight/2;i++) { //will work only for the 420 ones 709 ret = write(fd, base, mDstWidth/2); 710 if (ret < 0) goto cleanup; 711 base += stride; 712 } 713 714 //dump Cr/Cb 715 base = (uint8_t *)dstSurfaceDef->plane2; 716 stride = dstSurfaceDef->stride2; 717 718 for (size_t i = 0; i < sliceHeight/2;i++) { //will work only for the 420 ones 719 ret = write(fd, base, mDstWidth/2); 720 if (ret < 0) goto cleanup; 721 base += stride; 722 } 723 724 } else { 725 /* dump chroma */ 726 base = (uint8_t *)dstSurfaceDef->plane1; 727 stride = dstSurfaceDef->stride1; 728 for (size_t i = 0; i < sliceHeight/2;i++) { //will work only for the 420 ones 729 ret = write(fd, base, mDstWidth); 730 if (ret < 0) goto cleanup; 731 base += stride; 732 } 733 } 734 } else { 735 C2D_RGB_SURFACE_DEF * dstSurfaceDef = (C2D_RGB_SURFACE_DEF *)mDstSurfaceDef; 736 uint8_t * base = (uint8_t *)dstSurfaceDef->buffer; 737 stride = dstSurfaceDef->stride; 738 sliceHeight = dstSurfaceDef->height; 739 740 printf("rgb surface base is %p", base); 741 printf("rgb surface dumpsslice height is %lu\n", (unsigned long)sliceHeight); 742 printf("rgb surface dump stride is %lu\n", (unsigned long)stride); 743 744 int bpp = 1; //bytes per pixel 745 if (mDstFormat == RGB565) { 746 bpp = 2; 747 } else if (mDstFormat == RGBA8888) { 748 bpp = 4; 749 } 750 751 int count = 0; 752 for (size_t i = 0; i < sliceHeight; i++) { 753 ret = write(fd, base, mDstWidth*bpp); 754 if (ret < 0) { 755 printf("write failed, count = %d\n", count); 756 goto cleanup; 757 } 758 base += stride; 759 count += stride; 760 } 761 } 762 cleanup: 763 if (ret < 0) { 764 ALOGE("file write failed w/ errno %s", strerror(errno)); 765 } 766 close(fd); 767 return ret < 0 ? ret : 0; 768 } 769 770 extern "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) 771 { 772 return new C2DColorConverter(srcWidth, srcHeight, dstWidth, dstHeight, srcFormat, dstFormat, flags, srcStride); 773 } 774 775 extern "C" void destroyC2DColorConverter(C2DColorConverterBase* C2DCC) 776 { 777 delete C2DCC; 778 } 779 780 } 781