1/*
2* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
3*
4* Redistribution and use in source and binary forms, with or without
5* modification, are permitted provided that the following conditions are
6* met:
7*    * Redistributions of source code must retain the above copyright
8*      notice, this list of conditions and the following disclaimer.
9*    * Redistributions in binary form must reproduce the above
10*      copyright notice, this list of conditions and the following
11*      disclaimer in the documentation and/or other materials provided
12*      with the distribution.
13*    * Neither the name of The Linux Foundation nor the names of its
14*      contributors may be used to endorse or promote products derived
15*      from this software without specific prior written permission.
16*
17* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30#include <stdlib.h>
31#include <math.h>
32#include <utils/Log.h>
33#include <linux/msm_mdp.h>
34#include <cutils/properties.h>
35#include "gralloc_priv.h"
36#include "overlayUtils.h"
37#include "mdpWrapper.h"
38#include "mdp_version.h"
39#include <hardware/hwcomposer_defs.h>
40
41// just a helper static thingy
42namespace {
43struct IOFile {
44    IOFile(const char* s, const char* mode) : fp(0) {
45        fp = ::fopen(s, mode);
46        if(!fp) {
47            ALOGE("Failed open %s", s);
48        }
49    }
50    template <class T>
51            size_t read(T& r, size_t elem) {
52                if(fp) {
53                    return ::fread(&r, sizeof(T), elem, fp);
54                }
55                return 0;
56            }
57    size_t write(const char* s, uint32_t val) {
58        if(fp) {
59            return ::fprintf(fp, s, val);
60        }
61        return 0;
62    }
63    bool valid() const { return fp != 0; }
64    ~IOFile() {
65        if(fp) ::fclose(fp);
66        fp=0;
67    }
68    FILE* fp;
69};
70}
71
72namespace overlay {
73
74//----------From class Res ------------------------------
75const char* const Res::fbPath = "/dev/graphics/fb%u";
76const char* const Res::rotPath = "/dev/msm_rotator";
77const char* const Res::format3DFile =
78        "/sys/class/graphics/fb1/format_3d";
79const char* const Res::edid3dInfoFile =
80        "/sys/class/graphics/fb1/3d_present";
81const char* const Res::barrierFile =
82        "/sys/devices/platform/mipi_novatek.0/enable_3d_barrier";
83//--------------------------------------------------------
84
85
86
87namespace utils {
88
89//--------------------------------------------------------
90//Refer to graphics.h, gralloc_priv.h, msm_mdp.h
91int getMdpFormat(int format) {
92    switch (format) {
93        //From graphics.h
94        case HAL_PIXEL_FORMAT_RGBA_8888 :
95            return MDP_RGBA_8888;
96        case HAL_PIXEL_FORMAT_RGBX_8888:
97            return MDP_RGBX_8888;
98        case HAL_PIXEL_FORMAT_RGB_888:
99            return MDP_RGB_888;
100        case HAL_PIXEL_FORMAT_RGB_565:
101            return MDP_RGB_565;
102        case HAL_PIXEL_FORMAT_BGRA_8888:
103            return MDP_BGRA_8888;
104        case HAL_PIXEL_FORMAT_BGRX_8888:
105            return MDP_BGRX_8888;
106        case HAL_PIXEL_FORMAT_YV12:
107            return MDP_Y_CR_CB_GH2V2;
108        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
109            return MDP_Y_CBCR_H2V1;
110        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
111            return MDP_Y_CRCB_H2V2;
112
113        //From gralloc_priv.h
114        case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
115            return MDP_Y_CBCR_H2V2_TILE;
116        case HAL_PIXEL_FORMAT_YCbCr_420_SP:
117            return MDP_Y_CBCR_H2V2;
118        case HAL_PIXEL_FORMAT_YCrCb_422_SP:
119            return MDP_Y_CRCB_H2V1;
120        case HAL_PIXEL_FORMAT_YCbCr_422_I:
121            return MDP_YCBYCR_H2V1;
122        case HAL_PIXEL_FORMAT_YCrCb_422_I:
123            return MDP_YCRYCB_H2V1;
124        case HAL_PIXEL_FORMAT_YCbCr_444_SP:
125            return MDP_Y_CBCR_H1V1;
126        case HAL_PIXEL_FORMAT_YCrCb_444_SP:
127            return MDP_Y_CRCB_H1V1;
128        case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
129        case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
130            //NV12 encodeable format maps to the venus format on
131            //B-Family targets
132            return MDP_Y_CBCR_H2V2_VENUS;
133        default:
134            //Unsupported by MDP
135            //---graphics.h--------
136            //HAL_PIXEL_FORMAT_RGBA_5551
137            //HAL_PIXEL_FORMAT_RGBA_4444
138            //---gralloc_priv.h-----
139            //HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO    = 0x7FA30C01
140            //HAL_PIXEL_FORMAT_R_8                    = 0x10D
141            //HAL_PIXEL_FORMAT_RG_88                  = 0x10E
142            ALOGE("%s: Unsupported HAL format = 0x%x", __func__, format);
143            return -1;
144    }
145    // not reached
146    return -1;
147}
148
149// This function returns corresponding tile format
150// MDSS support following RGB tile formats
151//  32 bit formats
152//  16 bit formats
153int getMdpFormat(int format, bool tileEnabled)
154{
155    if(!tileEnabled) {
156        return getMdpFormat(format);
157    }
158    switch (format) {
159        case HAL_PIXEL_FORMAT_RGBA_8888 :
160            return MDP_RGBA_8888_TILE;
161        case HAL_PIXEL_FORMAT_RGBX_8888:
162            return MDP_RGBX_8888_TILE;
163        case HAL_PIXEL_FORMAT_RGB_565:
164            return MDP_RGB_565_TILE;
165        case HAL_PIXEL_FORMAT_BGRA_8888:
166            return MDP_BGRA_8888_TILE;
167        case HAL_PIXEL_FORMAT_BGRX_8888:
168            return MDP_BGRX_8888_TILE;
169        default:
170            return getMdpFormat(format);
171    }
172}
173
174
175
176//Takes mdp format as input and translates to equivalent HAL format
177//Refer to graphics.h, gralloc_priv.h, msm_mdp.h for formats.
178int getHALFormat(int mdpFormat) {
179    switch (mdpFormat) {
180        //From graphics.h
181        case MDP_RGBA_8888:
182            return HAL_PIXEL_FORMAT_RGBA_8888;
183        case MDP_RGBX_8888:
184            return HAL_PIXEL_FORMAT_RGBX_8888;
185        case MDP_RGB_888:
186            return HAL_PIXEL_FORMAT_RGB_888;
187        case MDP_RGB_565:
188            return HAL_PIXEL_FORMAT_RGB_565;
189        case MDP_BGRA_8888:
190            return HAL_PIXEL_FORMAT_BGRA_8888;
191        case MDP_Y_CR_CB_GH2V2:
192            return HAL_PIXEL_FORMAT_YV12;
193        case MDP_Y_CBCR_H2V1:
194            return HAL_PIXEL_FORMAT_YCbCr_422_SP;
195        case MDP_Y_CRCB_H2V2:
196            return HAL_PIXEL_FORMAT_YCrCb_420_SP;
197
198        //From gralloc_priv.h
199        case MDP_Y_CBCR_H2V2_TILE:
200            return HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED;
201        case MDP_Y_CBCR_H2V2:
202            return HAL_PIXEL_FORMAT_YCbCr_420_SP;
203        case MDP_Y_CRCB_H2V1:
204            return HAL_PIXEL_FORMAT_YCrCb_422_SP;
205        case MDP_YCBYCR_H2V1:
206            return HAL_PIXEL_FORMAT_YCbCr_422_I;
207        case MDP_YCRYCB_H2V1:
208            return HAL_PIXEL_FORMAT_YCrCb_422_I;
209         case MDP_Y_CBCR_H1V1:
210            return HAL_PIXEL_FORMAT_YCbCr_444_SP;
211        case MDP_Y_CRCB_H1V1:
212            return HAL_PIXEL_FORMAT_YCrCb_444_SP;
213        case MDP_Y_CBCR_H2V2_VENUS:
214            return HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS;
215        default:
216            ALOGE("%s: Unsupported MDP format = 0x%x", __func__, mdpFormat);
217            return -1;
218    }
219    // not reached
220    return -1;
221}
222
223int getMdpOrient(eTransform rotation) {
224    int retTrans = 0;
225    bool trans90 = false;
226    int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
227    bool aFamily = (mdpVersion < qdutils::MDSS_V5);
228
229    ALOGD_IF(DEBUG_OVERLAY, "%s: In rotation = %d", __FUNCTION__, rotation);
230    if(rotation & OVERLAY_TRANSFORM_ROT_90) {
231        retTrans |= MDP_ROT_90;
232        trans90 = true;
233    }
234
235    if(rotation & OVERLAY_TRANSFORM_FLIP_H) {
236        if(trans90 && aFamily) {
237            //Swap for a-family, since its driver does 90 first
238            retTrans |= MDP_FLIP_UD;
239        } else {
240            retTrans |= MDP_FLIP_LR;
241        }
242    }
243
244    if(rotation & OVERLAY_TRANSFORM_FLIP_V) {
245        if(trans90 && aFamily) {
246            //Swap for a-family, since its driver does 90 first
247            retTrans |= MDP_FLIP_LR;
248        } else {
249            retTrans |= MDP_FLIP_UD;
250        }
251    }
252
253    ALOGD_IF(DEBUG_OVERLAY, "%s: Out rotation = %d", __FUNCTION__, retTrans);
254    return retTrans;
255}
256
257int getDownscaleFactor(const int& src_w, const int& src_h,
258        const int& dst_w, const int& dst_h) {
259    int dscale_factor = utils::ROT_DS_NONE;
260    // We need this check to engage the rotator whenever possible to assist MDP
261    // in performing video downscale.
262    // This saves bandwidth and avoids causing the driver to make too many panel
263    // -mode switches between BLT (writeback) and non-BLT (Direct) modes.
264    // Use-case: Video playback [with downscaling and rotation].
265    if (dst_w && dst_h)
266    {
267        float fDscale =  (float)(src_w * src_h) / (float)(dst_w * dst_h);
268        uint32_t dscale = (int)sqrtf(fDscale);
269
270        if(dscale < 2) {
271            // Down-scale to > 50% of orig.
272            dscale_factor = utils::ROT_DS_NONE;
273        } else if(dscale < 4) {
274            // Down-scale to between > 25% to <= 50% of orig.
275            dscale_factor = utils::ROT_DS_HALF;
276        } else if(dscale < 8) {
277            // Down-scale to between > 12.5% to <= 25% of orig.
278            dscale_factor = utils::ROT_DS_FOURTH;
279        } else {
280            // Down-scale to <= 12.5% of orig.
281            dscale_factor = utils::ROT_DS_EIGHTH;
282        }
283    }
284    return dscale_factor;
285}
286
287void getDecimationFactor(const int& src_w, const int& src_h,
288        const int& dst_w, const int& dst_h, float& horDscale,
289        float& verDscale) {
290    horDscale = ceilf((float)src_w / (float)dst_w);
291    verDscale = ceilf((float)src_h / (float)dst_h);
292
293    //Next power of 2, if not already
294    horDscale = powf(2.0f, ceilf(log2f(horDscale)));
295    verDscale = powf(2.0f, ceilf(log2f(verDscale)));
296
297    //Since MDP can do 1/4 dscale and has better quality, split the task
298    //between decimator and MDP downscale
299    horDscale /= 4.0f;
300    verDscale /= 4.0f;
301}
302
303static inline int compute(const uint32_t& x, const uint32_t& y,
304        const uint32_t& z) {
305    return x - ( y + z );
306}
307
308void preRotateSource(const eTransform& tr, Whf& whf, Dim& srcCrop) {
309    if(tr & OVERLAY_TRANSFORM_FLIP_H) {
310        srcCrop.x = compute(whf.w, srcCrop.x, srcCrop.w);
311    }
312    if(tr & OVERLAY_TRANSFORM_FLIP_V) {
313        srcCrop.y = compute(whf.h, srcCrop.y, srcCrop.h);
314    }
315    if(tr & OVERLAY_TRANSFORM_ROT_90) {
316        int tmp = srcCrop.x;
317        srcCrop.x = compute(whf.h,
318                srcCrop.y,
319                srcCrop.h);
320        srcCrop.y = tmp;
321        swap(whf.w, whf.h);
322        swap(srcCrop.w, srcCrop.h);
323    }
324}
325
326bool is3DTV() {
327    char is3DTV = '0';
328    IOFile fp(Res::edid3dInfoFile, "r");
329    (void)fp.read(is3DTV, 1);
330    ALOGI("3DTV EDID flag: %d", is3DTV);
331    return (is3DTV == '0') ? false : true;
332}
333
334bool isPanel3D() {
335    OvFD fd;
336    if(!overlay::open(fd, 0 /*fb*/, Res::fbPath)){
337        ALOGE("isPanel3D Can't open framebuffer 0");
338        return false;
339    }
340    fb_fix_screeninfo finfo;
341    if(!mdp_wrapper::getFScreenInfo(fd.getFD(), finfo)) {
342        ALOGE("isPanel3D read fb0 failed");
343    }
344    fd.close();
345    return (FB_TYPE_3D_PANEL == finfo.type) ? true : false;
346}
347
348bool usePanel3D() {
349    if(!isPanel3D())
350        return false;
351    char value[PROPERTY_VALUE_MAX];
352    property_get("persist.user.panel3D", value, "0");
353    int usePanel3D = atoi(value);
354    return usePanel3D ? true : false;
355}
356
357bool send3DInfoPacket (uint32_t format3D) {
358    IOFile fp(Res::format3DFile, "wb");
359    (void)fp.write("%d", format3D);
360    if(!fp.valid()) {
361        ALOGE("send3DInfoPacket: no sysfs entry for setting 3d mode");
362        return false;
363    }
364    return true;
365}
366
367bool enableBarrier (uint32_t orientation) {
368    IOFile fp(Res::barrierFile, "wb");
369    (void)fp.write("%d", orientation);
370    if(!fp.valid()) {
371        ALOGE("enableBarrier no sysfs entry for "
372                "enabling barriers on 3D panel");
373        return false;
374    }
375    return true;
376}
377
378uint32_t getS3DFormat(uint32_t fmt) {
379    // The S3D is part of the HAL_PIXEL_FORMAT_YV12 value. Add
380    // an explicit check for the format
381    if (fmt == HAL_PIXEL_FORMAT_YV12) {
382        return 0;
383    }
384    uint32_t fmt3D = format3D(fmt);
385    uint32_t fIn3D = format3DInput(fmt3D); // MSB 2 bytes - inp
386    uint32_t fOut3D = format3DOutput(fmt3D); // LSB 2 bytes - out
387    fmt3D = fIn3D | fOut3D;
388    if (!fIn3D) {
389        fmt3D |= fOut3D << SHIFT_TOT_3D; //Set the input format
390    }
391    if (!fOut3D) {
392        switch (fIn3D) {
393            case HAL_3D_IN_SIDE_BY_SIDE_L_R:
394            case HAL_3D_IN_SIDE_BY_SIDE_R_L:
395                // For all side by side formats, set the output
396                // format as Side-by-Side i.e 0x1
397                fmt3D |= HAL_3D_IN_SIDE_BY_SIDE_L_R >> SHIFT_TOT_3D;
398                break;
399            default:
400                fmt3D |= fIn3D >> SHIFT_TOT_3D; //Set the output format
401        }
402    }
403    return fmt3D;
404}
405
406void getDump(char *buf, size_t len, const char *prefix,
407        const mdp_overlay& ov) {
408    char str[256] = {'\0'};
409    snprintf(str, 256,
410            "%s id=%d z=%d fg=%d alpha=%d mask=%d flags=0x%x H.Deci=%d,"
411            "V.Deci=%d\n",
412            prefix, ov.id, ov.z_order, ov.is_fg, ov.alpha,
413            ov.transp_mask, ov.flags, ov.horz_deci, ov.vert_deci);
414    strlcat(buf, str, len);
415    getDump(buf, len, "\tsrc", ov.src);
416    getDump(buf, len, "\tsrc_rect", ov.src_rect);
417    getDump(buf, len, "\tdst_rect", ov.dst_rect);
418}
419
420void getDump(char *buf, size_t len, const char *prefix,
421        const msmfb_img& ov) {
422    char str_src[256] = {'\0'};
423    snprintf(str_src, 256,
424            "%s w=%d h=%d format=%d %s\n",
425            prefix, ov.width, ov.height, ov.format,
426            overlay::utils::getFormatString(ov.format));
427    strlcat(buf, str_src, len);
428}
429
430void getDump(char *buf, size_t len, const char *prefix,
431        const mdp_rect& ov) {
432    char str_rect[256] = {'\0'};
433    snprintf(str_rect, 256,
434            "%s x=%d y=%d w=%d h=%d\n",
435            prefix, ov.x, ov.y, ov.w, ov.h);
436    strlcat(buf, str_rect, len);
437}
438
439void getDump(char *buf, size_t len, const char *prefix,
440        const msmfb_overlay_data& ov) {
441    char str[256] = {'\0'};
442    snprintf(str, 256,
443            "%s id=%d\n",
444            prefix, ov.id);
445    strlcat(buf, str, len);
446    getDump(buf, len, "\tdata", ov.data);
447}
448
449void getDump(char *buf, size_t len, const char *prefix,
450        const msmfb_data& ov) {
451    char str_data[256] = {'\0'};
452    snprintf(str_data, 256,
453            "%s offset=%d memid=%d id=%d flags=0x%x\n",
454            prefix, ov.offset, ov.memory_id, ov.id, ov.flags);
455    strlcat(buf, str_data, len);
456}
457
458void getDump(char *buf, size_t len, const char *prefix,
459        const msm_rotator_img_info& rot) {
460    char str[256] = {'\0'};
461    snprintf(str, 256, "%s sessid=%u rot=%d, enable=%d downscale=%d\n",
462            prefix, rot.session_id, rot.rotations, rot.enable,
463            rot.downscale_ratio);
464    strlcat(buf, str, len);
465    getDump(buf, len, "\tsrc", rot.src);
466    getDump(buf, len, "\tdst", rot.dst);
467    getDump(buf, len, "\tsrc_rect", rot.src_rect);
468}
469
470void getDump(char *buf, size_t len, const char *prefix,
471        const msm_rotator_data_info& rot) {
472    char str[256] = {'\0'};
473    snprintf(str, 256,
474            "%s sessid=%u\n",
475            prefix, rot.session_id);
476    strlcat(buf, str, len);
477    getDump(buf, len, "\tsrc", rot.src);
478    getDump(buf, len, "\tdst", rot.dst);
479}
480
481//Helper to even out x,w and y,h pairs
482//x,y are always evened to ceil and w,h are evened to floor
483void normalizeCrop(uint32_t& xy, uint32_t& wh) {
484    if(xy & 1) {
485        even_ceil(xy);
486        if(wh & 1)
487            even_floor(wh);
488        else
489            wh -= 2;
490    } else {
491        even_floor(wh);
492    }
493}
494
495} // utils
496
497} // overlay
498