overlay: Add support for decimation.

Add support for decimation on top of what MDP can downscale,
because decimation can have quality issues.
B-family MDP downscale of 1/4, plus decimation of 1/16 can let
us have a total downscale of 1/64.

Also decimate by 2 (min) if width is greater than what layer mixer
supports and is not handled by the client.

Change-Id: I3b7c4bf321c7561bd98206ad118f4ac1ee2879ae
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 b81eb5e..6381f59 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -24,6 +24,7 @@
 #include <overlayRotator.h>
 
 using namespace overlay;
+using namespace qdutils;
 using namespace overlay::utils;
 namespace ovutils = overlay::utils;
 
@@ -405,12 +406,11 @@
         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;
@@ -420,7 +420,8 @@
             swap(cWidth, cHeight);
         }
 
-        if((cWidth/dWidth) > 4 || (cHeight/dHeight) > 4)
+        if(cWidth > MAX_DISPLAY_DIM || (cWidth/dWidth) > downscale ||
+                    (cHeight/dHeight) > downscale)
             return false;
     }
     return true;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 001e3e8..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)
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