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