1 /* Copyright (c) 2012 - 2020, 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
swap(size_t & x,size_t & y)32 void swap(size_t &x, size_t &y)
33 {
34 x = x ^ y;
35 y = x ^ y;
36 x = x ^ y;
37 }
38
C2DColorConverter()39 C2DColorConverter::C2DColorConverter()
40 : mC2DLibHandle(NULL),
41 mAdrenoUtilsHandle(NULL)
42 {
43
44 enabled = true;
45 mSrcSurface = 0;
46 mDstSurface = 0;
47
48 mSrcWidth = 0;
49 mSrcHeight = 0;
50 mSrcStride = 0;
51 mDstWidth = 0;
52 mDstHeight = 0;
53 mRotation = C2D_TARGET_ROTATE_0;
54 mSrcFormat = NO_COLOR_FORMAT;
55 mDstFormat = NO_COLOR_FORMAT;
56 mSrcSurfaceDef = NULL;
57 mDstSurfaceDef = NULL;
58
59 mConversionNeeded = false;
60
61 pthread_mutex_init(&mLock, NULL);
62
63 mC2DLibHandle = dlopen("libC2D2.so", RTLD_NOW);
64 if (!mC2DLibHandle) {
65 ALOGE("%s: ERROR: could not dlopen libc2d2.so: %s. C2D is disabled.",
66 __FUNCTION__, dlerror());
67 enabled = false;
68 return;
69 }
70 mAdrenoUtilsHandle = dlopen("libadreno_utils.so", RTLD_NOW);
71 if (!mAdrenoUtilsHandle) {
72 ALOGE("%s: ERROR: could not dlopen libadreno_utils.so: %s.. C2D is disabled.",
73 __FUNCTION__, dlerror());
74 enabled = false;
75 return;
76 }
77
78 mC2DCreateSurface = (LINK_c2dCreateSurface)dlsym(mC2DLibHandle, "c2dCreateSurface");
79 mC2DUpdateSurface = (LINK_c2dUpdateSurface)dlsym(mC2DLibHandle, "c2dUpdateSurface");
80 mC2DReadSurface = (LINK_c2dReadSurface)dlsym(mC2DLibHandle, "c2dReadSurface");
81 mC2DDraw = (LINK_c2dDraw)dlsym(mC2DLibHandle, "c2dDraw");
82 mC2DFlush = (LINK_c2dFlush)dlsym(mC2DLibHandle, "c2dFlush");
83 mC2DFinish = (LINK_c2dFinish)dlsym(mC2DLibHandle, "c2dFinish");
84 mC2DWaitTimestamp = (LINK_c2dWaitTimestamp)dlsym(mC2DLibHandle, "c2dWaitTimestamp");
85 mC2DDestroySurface = (LINK_c2dDestroySurface)dlsym(mC2DLibHandle, "c2dDestroySurface");
86 mC2DMapAddr = (LINK_c2dMapAddr)dlsym(mC2DLibHandle, "c2dMapAddr");
87 mC2DUnMapAddr = (LINK_c2dUnMapAddr)dlsym(mC2DLibHandle, "c2dUnMapAddr");
88
89 if (!mC2DCreateSurface || !mC2DUpdateSurface || !mC2DReadSurface
90 || !mC2DDraw || !mC2DFlush || !mC2DFinish || !mC2DWaitTimestamp
91 || !mC2DDestroySurface || !mC2DMapAddr || !mC2DUnMapAddr) {
92 ALOGE("%s: dlsym ERROR. C2D is disabled. mC2DCreateSurface[%p] mC2DUpdateSurface[%p] "
93 "mC2DReadSurface[%p] mC2DDraw[%p] mC2DFlush[%p] mC2DFinish[%p] mC2DWaitTimestamp[%p] "
94 "mC2DDestroySurface[%p] mC2DMapAddr[%p] mC2DUnMapAddr[%p]", __FUNCTION__,
95 mC2DCreateSurface, mC2DUpdateSurface, mC2DReadSurface, mC2DDraw, mC2DFlush, mC2DFinish,
96 mC2DWaitTimestamp, mC2DDestroySurface, mC2DMapAddr, mC2DUnMapAddr);
97 enabled = false;
98 return;
99 }
100
101 mAdrenoComputeFmtAlignedWidthAndHeight = (LINK_adreno_compute_fmt_aligned_width_and_height)dlsym(mAdrenoUtilsHandle, "compute_fmt_aligned_width_and_height");
102 if (!mAdrenoComputeFmtAlignedWidthAndHeight) {
103 ALOGE("%s: dlsym compute_aligned_width_and_height ERROR. C2D is disabled.", __FUNCTION__);
104 enabled = false;
105 return;
106 }
107 }
108
~C2DColorConverter()109 C2DColorConverter::~C2DColorConverter()
110 {
111 if (enabled) {
112
113 if (mDstSurface) {
114 mC2DDestroySurface(mDstSurface);
115 mDstSurface = 0;
116 }
117 if (mSrcSurface) {
118 mC2DDestroySurface(mSrcSurface);
119 mSrcSurface = 0;
120 }
121
122 if (mSrcSurfaceDef) {
123 if (isYUVSurface(mSrcFormat)) {
124 delete ((C2D_YUV_SURFACE_DEF *)mSrcSurfaceDef);
125 } else {
126 delete ((C2D_RGB_SURFACE_DEF *)mSrcSurfaceDef);
127 }
128 }
129
130 if (mDstSurfaceDef) {
131 if (isYUVSurface(mDstFormat)) {
132 delete ((C2D_YUV_SURFACE_DEF *)mDstSurfaceDef);
133 } else {
134 delete ((C2D_RGB_SURFACE_DEF *)mDstSurfaceDef);
135 }
136 }
137 mSrcSurfaceDef = NULL;
138 mDstSurfaceDef = NULL;
139 }
140
141 if (mC2DLibHandle) {
142 dlclose(mC2DLibHandle);
143 mC2DLibHandle = NULL;
144 }
145 if (mAdrenoUtilsHandle) {
146 dlclose(mAdrenoUtilsHandle);
147 mAdrenoUtilsHandle = NULL;
148 }
149
150 }
151
isPropChanged(size_t srcWidth,size_t srcHeight,size_t dstWidth,size_t dstHeight,ColorConvertFormat srcFormat,ColorConvertFormat dstFormat,int32_t flags,size_t srcStride)152 bool C2DColorConverter::isPropChanged(size_t srcWidth, size_t srcHeight, size_t dstWidth,
153 size_t dstHeight, ColorConvertFormat srcFormat,
154 ColorConvertFormat dstFormat, int32_t flags,
155 size_t srcStride)
156 {
157 return (mSrcWidth != srcWidth ||
158 mSrcHeight != srcHeight ||
159 mDstWidth != dstWidth ||
160 mDstHeight != dstHeight ||
161 mSrcFormat != srcFormat ||
162 mDstFormat != dstFormat ||
163 mSrcStride != srcStride ||
164 (mFlags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) !=
165 (flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED));
166 }
167
setResolution(size_t srcWidth,size_t srcHeight,size_t dstWidth,size_t dstHeight,ColorConvertFormat srcFormat,ColorConvertFormat dstFormat,int32_t flags,size_t srcStride)168 bool C2DColorConverter::setResolution(size_t srcWidth, size_t srcHeight,
169 size_t dstWidth, size_t dstHeight,
170 ColorConvertFormat srcFormat,
171 ColorConvertFormat dstFormat,
172 int32_t flags, size_t srcStride)
173 {
174 int32_t retval = -1;
175 if (enabled) {
176 pthread_mutex_lock(&mLock);
177
178 ClearSurfaces();
179
180 mSrcWidth = srcWidth;
181 mSrcHeight = srcHeight;
182 mSrcStride = srcStride;
183 mDstWidth = dstWidth;
184 mDstHeight = dstHeight;
185 mSrcFormat = srcFormat;
186 mDstFormat = dstFormat;
187
188 if (mRotation == C2D_TARGET_ROTATE_90 ||
189 mRotation == C2D_TARGET_ROTATE_270) {
190 swap(mDstWidth, mDstHeight);
191 }
192 mSrcSize = calcSize(srcFormat, mSrcWidth, mSrcHeight);
193 mDstSize = calcSize(dstFormat, mDstWidth, mDstHeight);
194 mSrcYSize = calcYSize(srcFormat, mSrcWidth, mSrcHeight);
195 mDstYSize = calcYSize(dstFormat, mDstWidth, mDstHeight);
196 mFlags = flags;
197
198 retval = getDummySurfaceDef(srcFormat, mSrcWidth, mSrcHeight, true);
199 retval |= getDummySurfaceDef(dstFormat, mDstWidth, mDstHeight, false);
200
201 if (retval == 0) {
202 memset((void*)&mBlit,0,sizeof(C2D_OBJECT));
203 mBlit.source_rect.x = 0 << 16;
204 mBlit.source_rect.y = 0 << 16;
205 mBlit.source_rect.width = srcWidth << 16;
206 mBlit.source_rect.height = srcHeight << 16;
207 mBlit.target_rect.x = 0 << 16;
208 mBlit.target_rect.y = 0 << 16;
209 mBlit.target_rect.width = dstWidth << 16;
210 mBlit.target_rect.height = dstHeight << 16;
211 mBlit.config_mask = C2D_ALPHA_BLEND_NONE |
212 C2D_NO_BILINEAR_BIT |
213 C2D_NO_ANTIALIASING_BIT |
214 C2D_TARGET_RECT_BIT;
215 mBlit.surface_id = mSrcSurface;
216 }
217
218 pthread_mutex_unlock(&mLock);
219 }
220
221 return retval == 0? true:false;
222 }
223
setRotation(int32_t rotation)224 void C2DColorConverter::setRotation(int32_t rotation) {
225 // C2D does rotation in anticlock wise, where as VPE rotates in clockwise
226 // Hence swapping the 90 and 270 angles to rotate in clockwise
227 switch (rotation) {
228 case 90:
229 mRotation = C2D_TARGET_ROTATE_270;
230 break;
231 case 180:
232 mRotation = C2D_TARGET_ROTATE_180;
233 break;
234 case 270:
235 mRotation = C2D_TARGET_ROTATE_90;
236 break;
237 default:
238 mRotation = C2D_TARGET_ROTATE_0;
239 break;
240 }
241 }
convertC2D(int srcFd,void * srcBase,void * srcData,int dstFd,void * dstBase,void * dstData)242 bool C2DColorConverter::convertC2D(int srcFd, void *srcBase, void * srcData,
243 int dstFd, void *dstBase, void * dstData)
244 {
245 C2D_STATUS ret;
246 uint8_t *srcMappedGpuAddr = nullptr;
247 uint8_t *dstMappedGpuAddr = nullptr;
248 bool status = false;
249
250 if (enabled) {
251 pthread_mutex_lock(&mLock);
252 if (srcFd < 0 || dstFd < 0
253 || srcData == NULL || dstData == NULL
254 || srcBase == NULL || dstBase == NULL) {
255 ALOGE("%s: Color conversion failed. Incorrect input parameters FD (%d:%d) Data (%p:%p) Base (%p:%p)",
256 __FUNCTION__, srcFd, dstFd, srcData, dstData, srcBase, dstBase);
257 status = false;
258 } else {
259
260 srcMappedGpuAddr = (uint8_t *)getMappedGPUAddr(srcFd, srcData, mSrcSize);
261 if (!srcMappedGpuAddr) {
262 pthread_mutex_unlock(&mLock);
263 return false;
264 }
265
266 if (isYUVSurface(mSrcFormat)) {
267 ret = updateYUVSurfaceDef(srcMappedGpuAddr, srcBase, srcData, true);
268 } else {
269 ret = updateRGBSurfaceDef(srcMappedGpuAddr, srcData, true);
270 }
271
272 if (ret == C2D_STATUS_OK) {
273
274 dstMappedGpuAddr = (uint8_t *)getMappedGPUAddr(dstFd, dstData, mDstSize);
275 if (!dstMappedGpuAddr) {
276 unmapGPUAddr((unsigned long)srcMappedGpuAddr);
277 pthread_mutex_unlock(&mLock);
278 return false;
279 }
280
281 if (isYUVSurface(mDstFormat)) {
282 ret = updateYUVSurfaceDef(dstMappedGpuAddr, dstBase, dstData, false);
283 } else {
284 ret = updateRGBSurfaceDef(dstMappedGpuAddr, dstData, false);
285 }
286
287 if (ret == C2D_STATUS_OK) {
288
289 mBlit.surface_id = mSrcSurface;
290 ret = mC2DDraw(mDstSurface, mRotation, 0, 0, 0, &mBlit, 1);
291 mC2DFinish(mDstSurface);
292
293 if (ret == C2D_STATUS_OK) {
294 bool unmappedSrcSuccess;
295 unmappedSrcSuccess = unmapGPUAddr((unsigned long)srcMappedGpuAddr);
296
297 bool unmappedDstSuccess;
298 unmappedDstSuccess = unmapGPUAddr((unsigned long)dstMappedGpuAddr);
299
300 if (!unmappedSrcSuccess || !unmappedDstSuccess) {
301 ALOGE("%s: unmapping GPU address failed (%d:%d)", __FUNCTION__,
302 unmappedSrcSuccess, unmappedDstSuccess);
303 status = false;
304 } else {
305 status = true;
306 }
307 } else {
308 ALOGE("%s: C2D Draw failed (%d)", __FUNCTION__, ret);
309 status = false;
310 }
311 } else {
312 ALOGE("%s: Update dst surface def failed (%d)", __FUNCTION__, ret);
313 unmapGPUAddr((unsigned long)srcMappedGpuAddr);
314 unmapGPUAddr((unsigned long)dstMappedGpuAddr);
315 status = false;
316 }
317 } else {
318 ALOGE("%s: Update src surface def failed (%d)", __FUNCTION__, ret);
319 unmapGPUAddr((unsigned long)srcMappedGpuAddr);
320 status = false;
321 }
322 }
323
324 pthread_mutex_unlock(&mLock);
325 }
326
327 return status;
328 }
329
isYUVSurface(ColorConvertFormat format)330 bool C2DColorConverter::isYUVSurface(ColorConvertFormat format)
331 {
332 switch (format) {
333 case YCbCr420Tile:
334 case YCbCr420SP:
335 case YCbCr420P:
336 case YCrCb420P:
337 case NV12_2K:
338 case NV12_512:
339 case NV12_128m:
340 case NV12_UBWC:
341 case TP10_UBWC:
342 case P010:
343 case VENUS_P010:
344 return true;
345 default:
346 return false;
347 }
348 }
349
ClearSurfaces()350 void C2DColorConverter::ClearSurfaces()
351 {
352 if (mSrcSurface) {
353 mC2DDestroySurface(mSrcSurface);
354 mSrcSurface = 0;
355 }
356
357 if (mSrcSurfaceDef) {
358 if (isYUVSurface(mSrcFormat)) {
359 delete ((C2D_YUV_SURFACE_DEF *)mSrcSurfaceDef);
360 } else {
361 delete ((C2D_RGB_SURFACE_DEF *)mSrcSurfaceDef);
362 }
363 mSrcSurfaceDef = NULL;
364 }
365
366 if (mDstSurface) {
367 mC2DDestroySurface(mDstSurface);
368 mDstSurface = 0;
369 }
370
371 if (mDstSurfaceDef) {
372 if (isYUVSurface(mDstFormat)) {
373 delete ((C2D_YUV_SURFACE_DEF *)mDstSurfaceDef);
374 } else {
375 delete ((C2D_RGB_SURFACE_DEF *)mDstSurfaceDef);
376 }
377 mDstSurfaceDef = NULL;
378 }
379 }
380
getDummySurfaceDef(ColorConvertFormat format,size_t width,size_t height,bool isSource)381 int32_t C2DColorConverter::getDummySurfaceDef(ColorConvertFormat format,
382 size_t width, size_t height,
383 bool isSource)
384 {
385 void *surfaceDef = NULL;
386 C2D_SURFACE_TYPE hostSurfaceType;
387 C2D_STATUS ret;
388
389 if (isYUVSurface(format)) {
390 C2D_YUV_SURFACE_DEF **surfaceYUVDef = (C2D_YUV_SURFACE_DEF **)
391 (isSource ? &mSrcSurfaceDef : &mDstSurfaceDef);
392 if (*surfaceYUVDef == NULL) {
393 *surfaceYUVDef = (C2D_YUV_SURFACE_DEF *)
394 calloc(1, sizeof(C2D_YUV_SURFACE_DEF));
395 if (*surfaceYUVDef == NULL) {
396 ALOGE("%s: surfaceYUVDef allocation failed", __FUNCTION__);
397 return -1;
398 }
399 } else {
400 memset(*surfaceYUVDef, 0, sizeof(C2D_YUV_SURFACE_DEF));
401 }
402 (*surfaceYUVDef)->format = getC2DFormat(format, isSource);
403 (*surfaceYUVDef)->width = width;
404 (*surfaceYUVDef)->height = height;
405 (*surfaceYUVDef)->plane0 = (void *)0xaaaaaaaa;
406 (*surfaceYUVDef)->phys0 = (void *)0xaaaaaaaa;
407 (*surfaceYUVDef)->stride0 = calcStride(format, width);
408 (*surfaceYUVDef)->plane1 = (void *)0xaaaaaaaa;
409 (*surfaceYUVDef)->phys1 = (void *)0xaaaaaaaa;
410 (*surfaceYUVDef)->stride1 = calcStride(format, width);
411 (*surfaceYUVDef)->stride2 = calcStride(format, width);
412 (*surfaceYUVDef)->phys2 = NULL;
413 (*surfaceYUVDef)->plane2 = NULL;
414
415 if (mFlags & private_handle_t::PRIV_FLAGS_ITU_R_601_FR) {
416 (*surfaceYUVDef)->format |= C2D_FORMAT_BT601_FULLRANGE;
417 }
418
419 if (format == YCbCr420P ||
420 format == YCrCb420P) {
421 ALOGI("%s: half stride for Cb Cr planes \n", __FUNCTION__);
422 (*surfaceYUVDef)->stride1 = calcStride(format, width) / 2;
423 (*surfaceYUVDef)->phys2 = (void *)0xaaaaaaaa;
424 (*surfaceYUVDef)->stride2 = calcStride(format, width) / 2;
425 }
426
427 surfaceDef = *surfaceYUVDef;
428 hostSurfaceType = C2D_SURFACE_YUV_HOST;
429 } else {
430 C2D_RGB_SURFACE_DEF **surfaceRGBDef = (C2D_RGB_SURFACE_DEF **)
431 (isSource ? &mSrcSurfaceDef : &mDstSurfaceDef);
432 if (*surfaceRGBDef == NULL) {
433 *surfaceRGBDef = (C2D_RGB_SURFACE_DEF *)
434 calloc(1, sizeof(C2D_RGB_SURFACE_DEF));
435 if (*surfaceRGBDef == NULL) {
436 ALOGE("%s: surfaceRGBDef allocation failed", __FUNCTION__);
437 return -1;
438 }
439 } else {
440 memset(*surfaceRGBDef, 0, sizeof(C2D_RGB_SURFACE_DEF));
441 }
442 (*surfaceRGBDef)->format = getC2DFormat(format, isSource);
443
444 if (mFlags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED ||
445 mFlags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED_PI)
446 (*surfaceRGBDef)->format |= C2D_FORMAT_UBWC_COMPRESSED;
447 (*surfaceRGBDef)->width = width;
448 (*surfaceRGBDef)->height = height;
449 (*surfaceRGBDef)->buffer = (void *)0xaaaaaaaa;
450 (*surfaceRGBDef)->phys = (void *)0xaaaaaaaa;
451 (*surfaceRGBDef)->stride = calcStride(format, width);
452
453 surfaceDef = *surfaceRGBDef;
454 hostSurfaceType = C2D_SURFACE_RGB_HOST;
455 }
456
457 ret = mC2DCreateSurface(isSource ? &mSrcSurface :
458 &mDstSurface,
459 isSource ? C2D_SOURCE : C2D_TARGET,
460 (C2D_SURFACE_TYPE)(hostSurfaceType
461 | C2D_SURFACE_WITH_PHYS
462 | C2D_SURFACE_WITH_PHYS_DUMMY),
463 surfaceDef);
464 return (int32_t) ret;
465 }
466
updateYUVSurfaceDef(uint8_t * gpuAddr,void * base,void * data,bool isSource)467 C2D_STATUS C2DColorConverter::updateYUVSurfaceDef(uint8_t *gpuAddr, void *base,
468 void *data, bool isSource)
469 {
470 if (isSource) {
471 C2D_YUV_SURFACE_DEF * srcSurfaceDef = (C2D_YUV_SURFACE_DEF *)mSrcSurfaceDef;
472 srcSurfaceDef->plane0 = data;
473 srcSurfaceDef->phys0 = gpuAddr + ((uint8_t *)data - (uint8_t *)base);
474 srcSurfaceDef->plane1 = (uint8_t *)data + mSrcYSize;
475 srcSurfaceDef->phys1 = (uint8_t *)srcSurfaceDef->phys0 + mSrcYSize;
476 if (srcSurfaceDef->format & C2D_COLOR_FORMAT_420_I420 ||
477 srcSurfaceDef->format & C2D_COLOR_FORMAT_420_YV12) {
478 srcSurfaceDef->plane2 = (uint8_t *)srcSurfaceDef->plane1 + mSrcYSize/4;
479 srcSurfaceDef->phys2 = (uint8_t *)srcSurfaceDef->phys1 + mSrcYSize/4;
480 }
481 return mC2DUpdateSurface(mSrcSurface, C2D_SOURCE,
482 (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS),
483 &(*srcSurfaceDef));
484 } else {
485 C2D_YUV_SURFACE_DEF * dstSurfaceDef = (C2D_YUV_SURFACE_DEF *)mDstSurfaceDef;
486 dstSurfaceDef->plane0 = data;
487 dstSurfaceDef->phys0 = gpuAddr + ((uint8_t *)data - (uint8_t *)base);
488 dstSurfaceDef->plane1 = (uint8_t *)data + mDstYSize;
489 dstSurfaceDef->phys1 = (uint8_t *)dstSurfaceDef->phys0 + mDstYSize;
490 if (dstSurfaceDef->format & C2D_COLOR_FORMAT_420_I420 ||
491 dstSurfaceDef->format & C2D_COLOR_FORMAT_420_YV12) {
492 dstSurfaceDef->plane2 = (uint8_t *)dstSurfaceDef->plane1 + mDstYSize/4;
493 dstSurfaceDef->phys2 = (uint8_t *)dstSurfaceDef->phys1 + mDstYSize/4;
494 }
495
496 return mC2DUpdateSurface(mDstSurface, C2D_TARGET,
497 (C2D_SURFACE_TYPE)(C2D_SURFACE_YUV_HOST | C2D_SURFACE_WITH_PHYS),
498 &(*dstSurfaceDef));
499 }
500 }
501
updateRGBSurfaceDef(uint8_t * gpuAddr,void * data,bool isSource)502 C2D_STATUS C2DColorConverter::updateRGBSurfaceDef(uint8_t *gpuAddr, void * data, bool isSource)
503 {
504 if (isSource) {
505 C2D_RGB_SURFACE_DEF * srcSurfaceDef = (C2D_RGB_SURFACE_DEF *)mSrcSurfaceDef;
506 srcSurfaceDef->buffer = data;
507 srcSurfaceDef->phys = gpuAddr;
508 return mC2DUpdateSurface(mSrcSurface, C2D_SOURCE,
509 (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS),
510 &(*srcSurfaceDef));
511 } else {
512 C2D_RGB_SURFACE_DEF * dstSurfaceDef = (C2D_RGB_SURFACE_DEF *)mDstSurfaceDef;
513 dstSurfaceDef->buffer = data;
514 ALOGV("%s: dstSurfaceDef->buffer = %p", __FUNCTION__, data);
515 dstSurfaceDef->phys = gpuAddr;
516 return mC2DUpdateSurface(mDstSurface, C2D_TARGET,
517 (C2D_SURFACE_TYPE)(C2D_SURFACE_RGB_HOST | C2D_SURFACE_WITH_PHYS),
518 &(*dstSurfaceDef));
519 }
520 }
521
getC2DFormat(ColorConvertFormat format,bool isSource)522 uint32_t C2DColorConverter::getC2DFormat(ColorConvertFormat format, bool isSource)
523 {
524 uint32_t C2DFormat;
525 switch (format) {
526 case RGB565:
527 return C2D_COLOR_FORMAT_565_RGB;
528 case RGBA8888:
529 C2DFormat = C2D_COLOR_FORMAT_8888_RGBA | C2D_FORMAT_SWAP_ENDIANNESS;
530 if (isSource)
531 C2DFormat |= C2D_FORMAT_PREMULTIPLIED;
532 return C2DFormat;
533 case RGBA8888_UBWC:
534 C2DFormat = C2D_COLOR_FORMAT_8888_RGBA |
535 C2D_FORMAT_SWAP_ENDIANNESS |
536 C2D_FORMAT_UBWC_COMPRESSED;
537 if (isSource)
538 C2DFormat |= C2D_FORMAT_PREMULTIPLIED;
539 return C2DFormat;
540 case YCbCr420Tile:
541 return (C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_MACROTILED);
542 case YCbCr420SP:
543 case NV12_2K:
544 case NV12_512:
545 case NV12_128m:
546 return C2D_COLOR_FORMAT_420_NV12;
547 case YCbCr420P:
548 return C2D_COLOR_FORMAT_420_I420;
549 case YCrCb420P:
550 return C2D_COLOR_FORMAT_420_YV12;
551 case NV12_UBWC:
552 return C2D_COLOR_FORMAT_420_NV12 | C2D_FORMAT_UBWC_COMPRESSED;
553 case TP10_UBWC:
554 return C2D_COLOR_FORMAT_420_TP10 | C2D_FORMAT_UBWC_COMPRESSED;
555 case P010:
556 case VENUS_P010:
557 return C2D_COLOR_FORMAT_420_P010;
558 default:
559 ALOGW("%s: Format not supported , %d", __FUNCTION__, format);
560 return -1;
561 }
562 }
563
calcStride(ColorConvertFormat format,size_t width)564 size_t C2DColorConverter::calcStride(ColorConvertFormat format, size_t width)
565 {
566 switch (format) {
567 case RGB565:
568 return ALIGN(width, ALIGN32) * 2; // RGB565 has width as twice
569 case RGBA8888:
570 if (mSrcStride)
571 return mSrcStride * 4;
572 else
573 return ALIGN(width, ALIGN32) * 4;
574 case YCbCr420Tile:
575 return ALIGN(width, ALIGN128);
576 case YCbCr420SP:
577 return ALIGN(width, ALIGN16);
578 case NV12_2K:
579 return ALIGN(width, ALIGN16);
580 case NV12_512:
581 return ALIGN(width, ALIGN512);
582 case NV12_128m: {
583 int32_t stride_alignment = VENUS_Y_STRIDE(COLOR_FMT_NV12, 1);
584 return ALIGN(width, stride_alignment);
585 }
586 case YCbCr420P:
587 return ALIGN(width, ALIGN16);
588 case YCrCb420P:
589 return ALIGN(width, ALIGN16);
590 case NV12_UBWC:
591 return VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width);
592 case TP10_UBWC:
593 return VENUS_Y_STRIDE(COLOR_FMT_NV12_BPP10_UBWC, width);
594 case P010:
595 return ALIGN(width*2, ALIGN64);
596 case VENUS_P010:
597 return ALIGN(width*2, ALIGN256);
598 default:
599 ALOGW("%s: Format not supported , %d", __FUNCTION__, format);
600 return 0;
601 }
602 }
603
calcYSize(ColorConvertFormat format,size_t width,size_t height)604 size_t C2DColorConverter::calcYSize(ColorConvertFormat format, size_t width, size_t height)
605 {
606 switch (format) {
607 case YCbCr420SP:
608 return (ALIGN(width, ALIGN16) * height);
609 case YCbCr420P:
610 return ALIGN(width, ALIGN16) * height;
611 case YCrCb420P:
612 return ALIGN(width, ALIGN16) * height;
613 case YCbCr420Tile:
614 return ALIGN(ALIGN(width, ALIGN128) * ALIGN(height, ALIGN32), ALIGN8K);
615 case NV12_2K: {
616 size_t alignedw = ALIGN(width, ALIGN16);
617 size_t lumaSize = ALIGN(alignedw * height, ALIGN2K);
618 return lumaSize;
619 }
620 case NV12_512:
621 return ALIGN(width, ALIGN512) * ALIGN(height, ALIGN512);
622 case NV12_128m: {
623 int32_t stride_alignment = VENUS_Y_STRIDE(COLOR_FMT_NV12, 1);
624 int32_t scanline_alignment = VENUS_Y_SCANLINES(COLOR_FMT_NV12, 1);
625 return ALIGN(width, stride_alignment) * ALIGN(height, scanline_alignment);
626 }
627 case NV12_UBWC:
628 return ALIGN( VENUS_Y_STRIDE(COLOR_FMT_NV12_UBWC, width) *
629 VENUS_Y_SCANLINES(COLOR_FMT_NV12_UBWC, height), ALIGN4K) +
630 ALIGN( VENUS_Y_META_STRIDE(COLOR_FMT_NV12_UBWC, width) *
631 VENUS_Y_META_SCANLINES(COLOR_FMT_NV12_UBWC, height), ALIGN4K);
632 case TP10_UBWC:
633 return ALIGN( VENUS_Y_STRIDE(COLOR_FMT_NV12_BPP10_UBWC, width) *
634 VENUS_Y_SCANLINES(COLOR_FMT_NV12_BPP10_UBWC, height), ALIGN4K) +
635 ALIGN( VENUS_Y_META_STRIDE(COLOR_FMT_NV12_BPP10_UBWC, width) *
636 VENUS_Y_META_SCANLINES(COLOR_FMT_NV12_BPP10_UBWC, height), ALIGN4K);
637 case P010:
638 return (ALIGN(width*2, ALIGN64) * height);
639 case VENUS_P010:
640 return (ALIGN(width*2, ALIGN256) * ALIGN(height, ALIGN32));
641 default:
642 ALOGW("%s: Format not supported , %d", __FUNCTION__, format);
643 return 0;
644 }
645 }
646
calcSize(ColorConvertFormat format,size_t width,size_t height)647 size_t C2DColorConverter::calcSize(ColorConvertFormat format, size_t width, size_t height)
648 {
649 int32_t alignedw = 0;
650 int32_t alignedh = 0;
651 int32_t size = 0;
652 int32_t tile_mode = 0;
653 int32_t raster_mode = 0;
654 int32_t padding_threshold = 512; /* hardcode for RGB formats */
655 int32_t bpp = 0;
656
657 switch (format) {
658 case RGB565:
659 bpp = 2;
660 mAdrenoComputeFmtAlignedWidthAndHeight(width, height,
661 0, ADRENO_PIXELFORMAT_B5G6R5,
662 1, tile_mode, raster_mode,
663 padding_threshold,
664 &alignedw, &alignedh);
665 ALOGV("%s: alignedw %d alignedh %d", __FUNCTION__,alignedw, alignedh);
666 size = alignedw * alignedh * bpp;
667 size = ALIGN(size, ALIGN4K);
668 break;
669 case RGBA8888:
670 bpp = 4;
671 mAdrenoComputeFmtAlignedWidthAndHeight(width, height,
672 0, ADRENO_PIXELFORMAT_R8G8B8A8 ,
673 1, tile_mode, raster_mode,
674 padding_threshold,
675 &alignedw, &alignedh);
676 ALOGV("%s: alignedw %d alignedh %d", __FUNCTION__,alignedw, alignedh);
677 if (mSrcStride)
678 size = mSrcStride * alignedh * bpp;
679 else
680 size = alignedw * alignedh * bpp;
681 size = ALIGN(size, ALIGN4K);
682 break;
683 case YCbCr420SP:
684 alignedw = ALIGN(width, ALIGN16);
685 size = ALIGN((alignedw * height) + (ALIGN((width+1)/2, ALIGN32) * ((height+1)/2) * 2), ALIGN4K);
686 break;
687 case YCbCr420P:
688 alignedw = ALIGN(width, ALIGN16);
689 size = ALIGN((alignedw * height) + (ALIGN((width+1)/2, ALIGN16) * ((height+1)/2) * 2), ALIGN4K);
690 break;
691 case YCrCb420P:
692 alignedw = ALIGN(width, ALIGN16);
693 size = ALIGN((alignedw * height) + (ALIGN((width+1)/2, ALIGN16) * ((height+1)/2) * 2), ALIGN4K);
694 break;
695 case YCbCr420Tile:
696 alignedw = ALIGN(width, ALIGN128);
697 alignedh = ALIGN(height, ALIGN32);
698 size = ALIGN(alignedw * alignedh, ALIGN8K) + ALIGN(alignedw * ALIGN((height+1)/2, ALIGN32), ALIGN8K);
699 break;
700 case NV12_2K: {
701 alignedw = ALIGN(width, ALIGN16);
702 size_t lumaSize = ALIGN(alignedw * height, ALIGN2K);
703 size_t chromaSize = ALIGN((alignedw * height)/2, ALIGN2K);
704 size = ALIGN(lumaSize + chromaSize, ALIGN4K);
705 ALOGV("%s: NV12_2k, width = %zu, height = %zu, size = %d",
706 __FUNCTION__, width, height, size);
707 }
708 break;
709 case NV12_512:
710 alignedw = ALIGN(width, ALIGN512);
711 alignedh = ALIGN(height, ALIGN512);
712 size = ALIGN(alignedw * alignedh + (alignedw * ALIGN(height/2, ALIGN256)), ALIGN4K);
713 break;
714 case NV12_128m:
715 alignedw = VENUS_Y_STRIDE(COLOR_FMT_NV12, width);
716 alignedh = VENUS_Y_SCANLINES(COLOR_FMT_NV12, height);
717 size = ALIGN(alignedw * alignedh + (alignedw * ALIGN((height+1)/2, VENUS_Y_SCANLINES(COLOR_FMT_NV12, 1)/2)), ALIGN4K);
718 break;
719 case NV12_UBWC:
720 size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_UBWC, width, height);
721 break;
722 case TP10_UBWC:
723 size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12_BPP10_UBWC, width, height);
724 break;
725 case P010:
726 alignedw = ALIGN(width*2, ALIGN64);
727 size = (alignedw * height) + (alignedw * height / 2);
728 break;
729 case VENUS_P010:
730 // Y plane
731 alignedw = ALIGN(width*2, ALIGN256);
732 alignedh = ALIGN(height, ALIGN32);
733 size = (alignedw * alignedh);
734 // UV plane
735 alignedw = ALIGN(width*2, ALIGN256);
736 alignedh = ALIGN(height/2, ALIGN16);
737 size = ALIGN(size + (alignedw * alignedh), ALIGN4K);
738 break;
739 default:
740 ALOGW("%s: Format not supported , %d", __FUNCTION__, format);
741 break;
742 }
743 return size;
744 }
745 /*
746 * Tells GPU to map given buffer and returns a physical address of mapped buffer
747 */
getMappedGPUAddr(int bufFD,void * bufPtr,size_t bufLen)748 void * C2DColorConverter::getMappedGPUAddr(int bufFD, void *bufPtr, size_t bufLen)
749 {
750 C2D_STATUS status;
751 void *gpuaddr = NULL;
752 status = mC2DMapAddr(bufFD, bufPtr, bufLen, 0, KGSL_USER_MEM_TYPE_ION,
753 &gpuaddr);
754 if (status != C2D_STATUS_OK) {
755 ALOGE("%s: c2dMapAddr failed: status %d fd %d ptr %p len %zu flags %d",
756 __FUNCTION__, status, bufFD, bufPtr, bufLen, KGSL_USER_MEM_TYPE_ION);
757 return NULL;
758 }
759 ALOGV("%s: c2d mapping created: gpuaddr %p fd %d ptr %p len %zu",
760 __FUNCTION__, gpuaddr, bufFD, bufPtr, bufLen);
761 return gpuaddr;
762 }
763
unmapGPUAddr(unsigned long gAddr)764 bool C2DColorConverter::unmapGPUAddr(unsigned long gAddr)
765 {
766
767 C2D_STATUS status = mC2DUnMapAddr((void*)gAddr);
768
769 if (status != C2D_STATUS_OK)
770 ALOGE("%s: c2dUnMapAddr failed: status %d gpuaddr %08lx",
771 __FUNCTION__, status, gAddr);
772
773 return (status == C2D_STATUS_OK);
774 }
775
getBuffSize(int32_t port)776 int32_t C2DColorConverter::getBuffSize(int32_t port)
777 {
778 if (enabled) {
779 if (port == C2D_INPUT) {
780 return calcSize(mSrcFormat, mSrcWidth, mSrcHeight);
781 } else if (port == C2D_OUTPUT) {
782 return calcSize(mDstFormat, mDstWidth, mDstHeight);
783 }
784 }
785 return 0;
786 }
787
getBuffFilledLen(int32_t port,unsigned int & filled_length)788 bool C2DColorConverter::getBuffFilledLen(int32_t port, unsigned int &filled_length)
789 {
790 bool ret = false;
791 C2DBuffReq req;
792 if (enabled) {
793 ret = getBuffReq(port, &req);
794 if (ret) {
795 filled_length = req.size;
796 }
797 }
798
799 return ret;
800 }
801
getBuffReq(int32_t port,C2DBuffReq * req)802 bool C2DColorConverter::getBuffReq(int32_t port, C2DBuffReq *req) {
803 if (!req
804 || (port != C2D_INPUT
805 && port != C2D_OUTPUT)) return false;
806
807 memset(req, 0, sizeof(C2DBuffReq));
808 if (port == C2D_INPUT) {
809 req->width = mSrcWidth;
810 req->height = mSrcHeight;
811 req->stride = calcStride(mSrcFormat, mSrcWidth);
812 req->sliceHeight = mSrcHeight;
813 req->lumaAlign = calcLumaAlign(mSrcFormat);
814 req->sizeAlign = calcSizeAlign(mSrcFormat);
815 req->size = calcSize(mSrcFormat, mSrcWidth, mSrcHeight);
816 req->bpp = calcBytesPerPixel(mSrcFormat);
817 ALOGV("%s: input req->size = %d", __FUNCTION__, req->size);
818 } else if (port == C2D_OUTPUT) {
819 req->width = mDstWidth;
820 req->height = mDstHeight;
821 req->stride = calcStride(mDstFormat, mDstWidth);
822 req->sliceHeight = mDstHeight;
823 req->lumaAlign = calcLumaAlign(mDstFormat);
824 req->sizeAlign = calcSizeAlign(mDstFormat);
825 req->size = calcSize(mDstFormat, mDstWidth, mDstHeight);
826 req->bpp = calcBytesPerPixel(mDstFormat);
827 ALOGV("%s: output req->size = %d", __FUNCTION__, req->size);
828 }
829 return true;
830 }
831
calcLumaAlign(ColorConvertFormat format)832 size_t C2DColorConverter::calcLumaAlign(ColorConvertFormat format) {
833 if (!isYUVSurface(format)) return 1; //no requirement
834
835 switch (format) {
836 case NV12_2K:
837 return ALIGN2K;
838 case NV12_512:
839 return ALIGN512;
840 case NV12_128m:
841 return 1;
842 case NV12_UBWC:
843 case TP10_UBWC:
844 case P010:
845 case VENUS_P010:
846 return ALIGN4K;
847 default:
848 ALOGW("%s: unknown format (%d) passed for luma alignment number.",
849 __FUNCTION__, format);
850 return 1;
851 }
852 }
853
calcSizeAlign(ColorConvertFormat format)854 size_t C2DColorConverter::calcSizeAlign(ColorConvertFormat format) {
855 if (!isYUVSurface(format)) return 1; //no requirement
856
857 switch (format) {
858 case YCbCr420SP: //OR NV12
859 case YCbCr420P:
860 case NV12_2K:
861 case NV12_512:
862 case NV12_128m:
863 case NV12_UBWC:
864 case TP10_UBWC:
865 case P010:
866 case VENUS_P010:
867 return ALIGN4K;
868 default:
869 ALOGW("%s: unknown format (%d) passed for size alignment number",
870 __FUNCTION__, format);
871 return 1;
872 }
873 }
874
calcBytesPerPixel(ColorConvertFormat format)875 C2DBytesPerPixel C2DColorConverter::calcBytesPerPixel(ColorConvertFormat format) {
876 C2DBytesPerPixel bpp;
877 bpp.numerator = 0;
878 bpp.denominator = 1;
879
880 switch (format) {
881 case RGB565:
882 bpp.numerator = 2;
883 break;
884 case RGBA8888:
885 case RGBA8888_UBWC:
886 bpp.numerator = 4;
887 break;
888 case YCbCr420SP:
889 case YCbCr420P:
890 case YCrCb420P:
891 case YCbCr420Tile:
892 case NV12_2K:
893 case NV12_512:
894 case NV12_128m:
895 case NV12_UBWC:
896 case TP10_UBWC:
897 case P010:
898 case VENUS_P010:
899 bpp.numerator = 3;
900 bpp.denominator = 2;
901 break;
902 default:
903 ALOGW("%s: unknown format (%d) passed.", __FUNCTION__, format);
904 break;
905 }
906 return bpp;
907 }
908
dumpOutput(char * filename,char mode)909 int32_t C2DColorConverter::dumpOutput(char * filename, char mode) {
910 int fd;
911 size_t stride, sliceHeight;
912 if (!filename) return -1;
913
914 int flags = O_RDWR | O_CREAT;
915 if (mode == 'a') {
916 flags |= O_APPEND;
917 }
918
919 if ((fd = open(filename, flags)) < 0) {
920 ALOGE("%s: open dump file failed w/ errno %s", __FUNCTION__, strerror(errno));
921 return -1;
922 }
923
924 int ret = 0;
925 if (isYUVSurface(mDstFormat)) {
926 C2D_YUV_SURFACE_DEF * dstSurfaceDef = (C2D_YUV_SURFACE_DEF *)mDstSurfaceDef;
927 uint8_t * base = (uint8_t *)dstSurfaceDef->plane0;
928 stride = dstSurfaceDef->stride0;
929 sliceHeight = dstSurfaceDef->height;
930 /* dump luma */
931 for (size_t i = 0; i < sliceHeight; i++) {
932 ret = write(fd, base, mDstWidth); //will work only for the 420 ones
933 if (ret < 0) goto cleanup;
934 base += stride;
935 }
936
937 if (mDstFormat == YCbCr420P ||
938 mDstFormat == YCrCb420P) {
939 ALOGI("%s: Dump Cb and Cr separately for Planar\n", __FUNCTION__);
940 //dump Cb/Cr
941 base = (uint8_t *)dstSurfaceDef->plane1;
942 stride = dstSurfaceDef->stride1;
943 for (size_t i = 0; i < (sliceHeight+1)/2;i++) { //will work only for the 420 ones
944 ret = write(fd, base, (mDstWidth+1)/2);
945 if (ret < 0) goto cleanup;
946 base += stride;
947 }
948
949 //dump Cr/Cb
950 base = (uint8_t *)dstSurfaceDef->plane2;
951 stride = dstSurfaceDef->stride2;
952
953 for (size_t i = 0; i < (sliceHeight+1)/2;i++) { //will work only for the 420 ones
954 ret = write(fd, base, (mDstWidth+1)/2);
955 if (ret < 0) goto cleanup;
956 base += stride;
957 }
958
959 } else {
960 /* dump chroma */
961 base = (uint8_t *)dstSurfaceDef->plane1;
962 stride = dstSurfaceDef->stride1;
963 for (size_t i = 0; i < (sliceHeight+1)/2;i++) { //will work only for the 420 ones
964 ret = write(fd, base, mDstWidth);
965 if (ret < 0) goto cleanup;
966 base += stride;
967 }
968 }
969 } else {
970 C2D_RGB_SURFACE_DEF * dstSurfaceDef = (C2D_RGB_SURFACE_DEF *)mDstSurfaceDef;
971 uint8_t * base = (uint8_t *)dstSurfaceDef->buffer;
972 stride = dstSurfaceDef->stride;
973 sliceHeight = dstSurfaceDef->height;
974
975 ALOGI("%s: rgb surface base is %p", __FUNCTION__, base);
976 ALOGI("%s: rgb surface dumpsslice height is %lu\n",
977 __FUNCTION__, (unsigned long)sliceHeight);
978 ALOGI("%s: rgb surface dump stride is %lu\n",
979 __FUNCTION__, (unsigned long)stride);
980
981 int bpp = 1; //bytes per pixel
982 if (mDstFormat == RGB565) {
983 bpp = 2;
984 } else if (mDstFormat == RGBA8888 || mDstFormat == RGBA8888_UBWC) {
985 bpp = 4;
986 }
987
988 int count = 0;
989 for (size_t i = 0; i < sliceHeight; i++) {
990 ret = write(fd, base, mDstWidth*bpp);
991 if (ret < 0) {
992 ALOGI("%s: write failed, count = %d\n", __FUNCTION__, count);
993 goto cleanup;
994 }
995 base += stride;
996 count += stride;
997 }
998 }
999 cleanup:
1000 if (ret < 0) {
1001 ALOGE("%s: file write failed w/ errno %s", __FUNCTION__, strerror(errno));
1002 }
1003 close(fd);
1004 return ret < 0 ? ret : 0;
1005 }
1006