Merge "copybit: Fix type conversion error for GCC 4.7"
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 8e7afa2..4f26191 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -38,6 +38,8 @@
 #include "profiler.h"
 
 using namespace qhwc;
+using namespace overlay;
+
 #define VSYNC_DEBUG 0
 #define BLANK_DEBUG 0
 
@@ -200,7 +202,7 @@
 
     ctx->mOverlay->configBegin();
     ctx->mRotMgr->configBegin();
-    ctx->mNeedsRotator = false;
+    Overlay::setDMAMode(Overlay::DMA_LINE_MODE);
 
     for (int32_t i = numDisplays; i >= 0; i--) {
         hwc_display_contents_1_t *list = displays[i];
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index b8e6976..9f91a99 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -21,6 +21,9 @@
 #define DEBUG_FBUPDATE 0
 #include <gralloc_priv.h>
 #include "hwc_fbupdate.h"
+#include "mdp_version.h"
+
+using namespace qdutils;
 
 namespace qhwc {
 
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 30178a0..6381f59 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -23,7 +23,8 @@
 #include "mdp_version.h"
 #include <overlayRotator.h>
 
-using overlay::Rotator;
+using namespace overlay;
+using namespace qdutils;
 using namespace overlay::utils;
 namespace ovutils = overlay::utils;
 
@@ -103,9 +104,10 @@
     }
 
     sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
-    if(property_get("debug.mdpcomp.maxpermixer", property, NULL) > 0) {
-        if(atoi(property) != 0)
-            sMaxPipesPerMixer = true;
+    if(property_get("debug.mdpcomp.maxpermixer", property, "-1") > 0) {
+        int val = atoi(property);
+        if(val >= 0)
+            sMaxPipesPerMixer = min(val, MAX_PIPES_PER_MIXER);
     }
 
     unsigned long idle_timeout = DEFAULT_IDLE_TIME;
@@ -289,7 +291,6 @@
     case MDPCOMP_OV_DMA:
         mdp_pipe = ov.nextPipe(ovutils::OV_MDP_PIPE_DMA, mDpy);
         if(mdp_pipe != ovutils::OV_INVALID) {
-            ctx->mDMAInUse = true;
             return mdp_pipe;
         }
     case MDPCOMP_OV_ANY:
@@ -350,7 +351,7 @@
         return false;
     }
 
-    if(mdpCount > (sMaxPipesPerMixer-fbNeeded)) {
+    if(mdpCount > (sMaxPipesPerMixer - fbNeeded)) {
         ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
         return false;
     }
@@ -400,28 +401,27 @@
         return false;
     }
 
-    if(ctx->mNeedsRotator && ctx->mDMAInUse) {
-        ALOGE("%s: No DMA for Rotator",__FUNCTION__);
-        return false;
-    }
-
     if(isSecuring(ctx, layer)) {
         ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__);
         return false;
     }
 
-    /* Workaround for downscales larger than 4x. Will be removed once decimator
-     * block is enabled for MDSS*/
-    if(ctx->mMDP.version == qdutils::MDSS_V5) {
+    if(!qdutils::MDPVersion::getInstance().supportsDecimation()) {
+        const uint32_t downscale =
+                qdutils::MDPVersion::getInstance().getMaxMDPDownscale();
         hwc_rect_t crop = layer->sourceCrop;
         hwc_rect_t dst = layer->displayFrame;
-
         int cWidth = crop.right - crop.left;
         int cHeight = crop.bottom - crop.top;
         int dWidth = dst.right - dst.left;
         int dHeight = dst.bottom - dst.top;
 
-        if((cWidth/dWidth) > 4 || (cHeight/dHeight) > 4)
+        if(layer->transform & HAL_TRANSFORM_ROT_90) {
+            swap(cWidth, cHeight);
+        }
+
+        if(cWidth > MAX_DISPLAY_DIM || (cWidth/dWidth) > downscale ||
+                    (cHeight/dHeight) > downscale)
             return false;
     }
     return true;
@@ -468,6 +468,7 @@
     ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__,
              mCurrentFrame.fbCount);
 }
+
 void MDPComp::updateLayerCache(hwc_context_t* ctx,
                                hwc_display_contents_1_t* list) {
 
@@ -501,7 +502,7 @@
     int numAvailable = ov.availablePipes(mDpy);
 
     //Reserve DMA for rotator
-    if(ctx->mNeedsRotator)
+    if(Overlay::getDMAMode() == Overlay::DMA_BLOCK_MODE)
         numAvailable -= numDMAPipes;
 
     //Reserve pipe(s)for FB
@@ -544,7 +545,6 @@
 
 int MDPComp::programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     int fbZOrder = -1;
-    ctx->mDMAInUse = false;
 
     if(!allocLayerPipes(ctx, list)) {
         ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
@@ -718,8 +718,9 @@
 
         ePipeType type = MDPCOMP_OV_ANY;
 
-        if(!qhwc::needsScaling(layer) && !ctx->mNeedsRotator
-           && ctx->mMDP.version >= qdutils::MDSS_V5) {
+        if(!qhwc::needsScaling(layer)
+            && Overlay::getDMAMode() != Overlay::DMA_BLOCK_MODE
+            && ctx->mMDP.version >= qdutils::MDSS_V5) {
             type = MDPCOMP_OV_DMA;
         }
 
@@ -889,8 +890,9 @@
 
         ePipeType type = MDPCOMP_OV_ANY;
 
-        if(!qhwc::needsScaling(layer) && !ctx->mNeedsRotator
-           && ctx->mMDP.version >= qdutils::MDSS_V5)
+        if(!qhwc::needsScaling(layer)
+            && Overlay::getDMAMode() != Overlay::DMA_BLOCK_MODE
+            && ctx->mMDP.version >= qdutils::MDSS_V5)
             type = MDPCOMP_OV_DMA;
 
         if(!acquireMDPPipes(ctx, layer, pipe_info, type)) {
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index db927e5..a578bb0 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -332,8 +332,9 @@
             ctx->listStats[dpy].yuvIndices[yuvCount] = i;
             yuvCount++;
 
-            if(layer->transform & HWC_TRANSFORM_ROT_90)
-                ctx->mNeedsRotator = true;
+            if(layer->transform & HWC_TRANSFORM_ROT_90) {
+                Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
+            }
         }
         if(layer->blending == HWC_BLENDING_PREMULT)
             ctx->listStats[dpy].preMultipliedAlpha = true;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 8c51b38..d4f5d94 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -34,7 +34,6 @@
 #define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
 #define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
 #define MAX_NUM_LAYERS 32 //includes fb layer
-#define MAX_DISPLAY_DIM 2048
 
 // For support of virtual displays
 #define HWC_DISPLAY_VIRTUAL     (HWC_DISPLAY_EXTERNAL+1)
@@ -274,10 +273,6 @@
     mutable Locker mExtSetLock;
     //Vsync
     struct vsync_state vstate;
-    //DMA used for rotator
-    bool mDMAInUse;
-    //MDP rotater needed
-    bool mNeedsRotator;
 };
 
 namespace qhwc {
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index 1faeadf..43b6589 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -92,6 +92,11 @@
             if((mPipeBook[i].mDisplay == PipeBook::DPY_UNUSED ||
                     mPipeBook[i].mDisplay == dpy) &&
                     PipeBook::isNotAllocated(i)) {
+                //In block mode we don't allow line operations
+                if(sDMAMode == DMA_BLOCK_MODE &&
+                    PipeBook::getPipeType((eDest)i) == OV_MDP_PIPE_DMA)
+                    continue;
+
                 dest = (eDest)i;
                 PipeBook::setAllocation(i);
                 break;
@@ -311,6 +316,7 @@
 
 Overlay* Overlay::sInstance = 0;
 int Overlay::sExtFbIndex = 1;
+int Overlay::sDMAMode = DMA_LINE_MODE;
 int Overlay::PipeBook::NUM_PIPES = 0;
 int Overlay::PipeBook::sPipeUsageBitmap = 0;
 int Overlay::PipeBook::sLastUsageBitmap = 0;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index fdeebc2..0cedac9 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -40,6 +40,8 @@
 
 class Overlay : utils::NoCopy {
 public:
+    enum { DMA_BLOCK_MODE, DMA_LINE_MODE };
+
     /* dtor close */
     ~Overlay();
 
@@ -84,6 +86,8 @@
      * to populate.
      */
     void getDump(char *buf, size_t len);
+    static void setDMAMode(const int& mode);
+    static int getDMAMode();
 
 private:
     /* Ctor setup */
@@ -148,6 +152,7 @@
     /* Singleton Instance*/
     static Overlay *sInstance;
     static int sExtFbIndex;
+    static int sDMAMode;
 };
 
 inline void Overlay::validate(int index) {
@@ -176,6 +181,15 @@
     return sExtFbIndex;
 }
 
+inline void Overlay::setDMAMode(const int& mode) {
+    if(mode == DMA_LINE_MODE || mode == DMA_BLOCK_MODE)
+        sDMAMode = mode;
+}
+
+inline int Overlay::getDMAMode() {
+    return sDMAMode;
+}
+
 inline bool Overlay::PipeBook::valid() {
     return (mPipe != NULL);
 }
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 96cb56e..d70ab64 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -15,6 +15,7 @@
 * limitations under the License.
 */
 
+#include <math.h>
 #include <mdp_version.h>
 #include "overlayUtils.h"
 #include "overlayMdp.h"
@@ -22,10 +23,17 @@
 
 #define HSIC_SETTINGS_DEBUG 0
 
+using namespace qdutils;
+
 static inline bool isEqual(float f1, float f2) {
         return ((int)(f1*100) == (int)(f2*100)) ? true : false;
 }
 
+//Since this is unavailable on Android, defining it in terms of base 10
+static inline float log2f(const float& x) {
+    return log(x) / log(2);
+}
+
 namespace ovutils = overlay::utils;
 namespace overlay {
 
@@ -130,14 +138,52 @@
 }
 
 void MdpCtrl::doDownscale() {
-    mOVInfo.src_rect.x >>= mDownscale;
-    mOVInfo.src_rect.y >>= mDownscale;
-    mOVInfo.src_rect.w >>= mDownscale;
-    mOVInfo.src_rect.h >>= mDownscale;
+    int mdpVersion = MDPVersion::getInstance().getMDPVersion();
+    if(mdpVersion < MDSS_V5) {
+        mOVInfo.src_rect.x >>= mDownscale;
+        mOVInfo.src_rect.y >>= mDownscale;
+        mOVInfo.src_rect.w >>= mDownscale;
+        mOVInfo.src_rect.h >>= mDownscale;
+    } else if(MDPVersion::getInstance().supportsDecimation()) {
+        //Decimation + MDP Downscale
+        mOVInfo.horz_deci = 0;
+        mOVInfo.vert_deci = 0;
+        int minHorDeci = 0;
+        if(mOVInfo.src_rect.w > 2048) {
+            //If the client sends us something > what a layer mixer supports
+            //then it means it doesn't want to use split-pipe but wants us to
+            //decimate. A minimum decimation of 2 will ensure that the width is
+            //always within layer mixer limits.
+            minHorDeci = 2;
+        }
+
+        float horDscale = ceilf((float)mOVInfo.src_rect.w /
+                (float)mOVInfo.dst_rect.w);
+        float verDscale = ceilf((float)mOVInfo.src_rect.h /
+                (float)mOVInfo.dst_rect.h);
+
+        //Next power of 2, if not already
+        horDscale = powf(2.0f, ceilf(log2f(horDscale)));
+        verDscale = powf(2.0f, ceilf(log2f(verDscale)));
+
+        //Since MDP can do 1/4 dscale and has better quality, split the task
+        //between decimator and MDP downscale
+        horDscale /= 4.0f;
+        verDscale /= 4.0f;
+
+        if(horDscale < minHorDeci)
+            horDscale = minHorDeci;
+
+        if((int)horDscale)
+            mOVInfo.horz_deci = (int)log2f(horDscale);
+
+        if((int)verDscale)
+            mOVInfo.vert_deci = (int)log2f(verDscale);
+    }
 }
 
 bool MdpCtrl::set() {
-    int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
+    int mdpVersion = MDPVersion::getInstance().getMDPVersion();
     //deferred calcs, so APIs could be called in any order.
     doTransform();
     doDownscale();
@@ -145,7 +191,7 @@
     if(utils::isYuv(whf.format)) {
         normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
         normalizeCrop(mOVInfo.src_rect.y, mOVInfo.src_rect.h);
-        if(mdpVersion < qdutils::MDSS_V5) {
+        if(mdpVersion < MDSS_V5) {
             utils::even_floor(mOVInfo.dst_rect.w);
             utils::even_floor(mOVInfo.dst_rect.h);
         }
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index edf3cec..8849984 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -356,9 +356,10 @@
         const mdp_overlay& ov) {
     char str[256] = {'\0'};
     snprintf(str, 256,
-            "%s id=%d z=%d fg=%d alpha=%d mask=%d flags=0x%x\n",
+            "%s id=%d z=%d fg=%d alpha=%d mask=%d flags=0x%x H.Deci=%d,"
+            "V.Deci=%d\n",
             prefix, ov.id, ov.z_order, ov.is_fg, ov.alpha,
-            ov.transp_mask, ov.flags);
+            ov.transp_mask, ov.flags, ov.horz_deci, ov.vert_deci);
     strncat(buf, str, strlen(str));
     getDump(buf, len, "\tsrc(msmfb_img)", ov.src);
     getDump(buf, len, "\tsrc_rect(mdp_rect)", ov.src_rect);
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index cd21490..8da293d 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -44,8 +44,12 @@
     struct fb_fix_screeninfo fb_finfo;
 
     mMdpRev = 0;
-    mRGBPipes = mVGPipes = 0;
+    mRGBPipes = 0;
+    mVGPipes = 0;
     mDMAPipes = 0;
+    mFeatures = 0;
+    //TODO get this from driver, default for A-fam to 8
+    mMDPDownscale = 8;
 
     if (ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_finfo) < 0) {
         ALOGE("FBIOGET_FSCREENINFO failed");
@@ -80,6 +84,7 @@
                 mRGBPipes = metadata.data.caps.rgb_pipes;
                 mVGPipes = metadata.data.caps.vig_pipes;
                 mDMAPipes = metadata.data.caps.dma_pipes;
+                mFeatures = metadata.data.caps.features;
             }
 #endif
         } else {
@@ -96,7 +101,21 @@
     mHasOverlay = false;
     if((mMDPVersion >= MDP_V4_0) || (mMDPVersion == MDP_V_UNKNOWN))
         mHasOverlay = true;
+    if(mMDPVersion >= MDSS_V5) {
+        //TODO get this from driver
+        mMDPDownscale = 4;
+    }
+
     mPanelType = panel_type;
 }
+
+bool MDPVersion::supportsDecimation() {
+    return mFeatures & MDP_DECIMATION_EN;
+}
+
+uint32_t MDPVersion::getMaxMDPDownscale() {
+    return mMDPDownscale;
+}
+
 }; //namespace qdutils
 
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 98de371..2fca640 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -52,6 +52,10 @@
     MDSS_V5     = 500,
 };
 
+enum {
+    MAX_DISPLAY_DIM = 2048,
+};
+
 #define MDDI_PANEL       '1'
 #define EBI2_PANEL       '2'
 #define LCDC_PANEL       '3'
@@ -76,6 +80,8 @@
     uint8_t getRGBPipes() { return mRGBPipes; }
     uint8_t getVGPipes() { return mVGPipes; }
     uint8_t getDMAPipes() { return mDMAPipes; }
+    bool supportsDecimation();
+    uint32_t getMaxMDPDownscale();
 private:
     int mMDPVersion;
     char mPanelType;
@@ -84,6 +90,8 @@
     uint8_t mRGBPipes;
     uint8_t mVGPipes;
     uint8_t mDMAPipes;
+    uint32_t mFeatures;
+    uint32_t mMDPDownscale;
 };
 }; //namespace qdutils
 #endif //INCLUDE_LIBQCOMUTILS_MDPVER