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//-----------------------------------------------------
49namespace android {
50
51class C2DColorConverter : public C2DColorConverterBase {
52
53public:
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);
57protected:
58    virtual ~C2DColorConverter();
59    virtual int convertC2D(int srcFd, void *srcBase, void * srcData, int dstFd, void *dstBase, void * dstData);
60
61private:
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
109C2DColorConverter::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
167C2DColorConverter::~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
190int 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
256bool 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
273void* 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
315C2D_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
344C2D_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
364uint32_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
387size_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
414size_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
437size_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 */
492void * 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
510bool 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
521int32_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
551size_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
567size_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
582C2DBytesPerPixel 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
609int32_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
705extern "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
710extern "C" void destroyC2DColorConverter(C2DColorConverterBase* C2DCC)
711{
712    delete C2DCC;
713}
714
715}
716