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