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