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