liboverlay: Rotator-assisted MDP downscaling of videos.

Engage the rotator to assist MDP in performing video downscale for
primary and external. This saves bandwidth and avoids causing the
driver to make too many panel mode switches between BLT (writeback)
and non-BLT (direct) modes.

Change-Id: Icfabc2c0f978a23cf96c78a9976cf69cea697b5f
CRs-Fixed: 434852
diff --git a/liboverlay/mdpWrapper.h b/liboverlay/mdpWrapper.h
index 255ffd7..1f4a0be 100644
--- a/liboverlay/mdpWrapper.h
+++ b/liboverlay/mdpWrapper.h
@@ -243,9 +243,9 @@
     }
 }
 inline void dump(const char* const s, const msm_rotator_img_info& rot) {
-    ALOGE("%s msm_rotator_img_info sessid=%u dstx=%d dsty=%d rot=%d, ena=%d",
+    ALOGE("%s msm_rotator_img_info sessid=%u dstx=%d dsty=%d rot=%d, ena=%d scale=%d",
             s, rot.session_id, rot.dst_x, rot.dst_y,
-            rot.rotations, rot.enable);
+            rot.rotations, rot.enable, rot.downscale_ratio);
     dump("src", rot.src);
     dump("dst", rot.dst);
     dump("src_rect", rot.src_rect);
diff --git a/liboverlay/overlayCtrl.cpp b/liboverlay/overlayCtrl.cpp
index ac4a296..03d2564 100644
--- a/liboverlay/overlayCtrl.cpp
+++ b/liboverlay/overlayCtrl.cpp
@@ -57,15 +57,19 @@
     return true;
 }
 
-bool Ctrl::setTransform(const utils::eTransform& orient, const bool& rotUsed)
+bool Ctrl::setTransform(const utils::eTransform& orient)
 {
-    if(!mMdp.setTransform(orient, rotUsed)) {
+    if(!mMdp.setTransform(orient)) {
         ALOGE("Ctrl setTransform failed for Mdp");
         return false;
     }
     return true;
 }
 
+void Ctrl::setRotatorUsed(const bool& rotUsed) {
+    mMdp.setRotatorUsed(rotUsed);
+}
+
 bool Ctrl::setCrop(const utils::Dim& d)
 {
     if(!mMdp.setCrop(d)) {
diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h
index f4c95f9..58f46b3 100644
--- a/liboverlay/overlayCtrlData.h
+++ b/liboverlay/overlayCtrlData.h
@@ -62,7 +62,9 @@
     /* set crop info and pass it down to mdp */
     bool setCrop(const utils::Dim& d);
     /* set orientation */
-    bool setTransform(const utils::eTransform& p, const bool&);
+    bool setTransform(const utils::eTransform& p);
+    /* set whether rotator can be used */
+    void setRotatorUsed(const bool& rotUsed);
     /* set mdp position using dim */
     bool setPosition(const utils::Dim& dim);
     /* mdp set overlay/commit changes */
@@ -82,6 +84,16 @@
     /* dump the state of the object */
     void dump() const;
 
+    /* Perform transformation calculations */
+    void doTransform();
+
+    /* Performs downscale calculations */
+    void doDownscale(int dscale_factor);
+
+    /* Get downscale factor */
+    int getDownscalefactor();
+
+
 private:
     /* Retrieve screen info from underlying mdp */
     bool getScreenInfo(utils::ScreenInfo& info);
@@ -183,6 +195,18 @@
     return mMdp.getSrcRectDim();
 }
 
+inline void Ctrl::doTransform() {
+    return mMdp.doTransform();
+}
+
+inline void Ctrl::doDownscale(int dscale_factor) {
+    mMdp.doDownscale(dscale_factor);
+}
+
+inline int Ctrl::getDownscalefactor() {
+    return mMdp.getDownscalefactor();
+}
+
 inline Data::Data() {
     mMdp.reset();
 }
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 48630a5..12ff8a9 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -111,19 +111,22 @@
     return true;
 }
 
-bool MdpCtrl::setTransform(const utils::eTransform& orient,
-        const bool& rotUsed) {
+bool MdpCtrl::setTransform(const utils::eTransform& orient) {
     int rot = utils::getMdpOrient(orient);
     setUserData(rot);
     //getMdpOrient will switch the flips if the source is 90 rotated.
     //Clients in Android dont factor in 90 rotation while deciding the flip.
     mOrientation = static_cast<utils::eTransform>(rot);
 
-    //Rotator can be requested by client even if layer has 0 orientation.
-    mRotUsed = rotUsed;
     return true;
 }
 
+void MdpCtrl::setRotatorUsed(const bool& rotUsed) {
+    //rotUsed dictates whether rotator hardware can be used.
+    //It is set if transformation or downscaling is required.
+    mRotUsed = rotUsed;
+}
+
 void MdpCtrl::doTransform() {
     adjustSrcWhf(mRotUsed);
     setRotationFlags();
@@ -140,9 +143,52 @@
     }
 }
 
+int MdpCtrl::getDownscalefactor() {
+    int dscale_factor = utils::ROT_DS_NONE;
+    int src_w = mOVInfo.src_rect.w;
+    int src_h = mOVInfo.src_rect.h;
+    int dst_w = mOVInfo.dst_rect.w;
+    int dst_h = mOVInfo.dst_rect.h;
+    // We need this check to engage the rotator whenever possible to assist MDP
+    // in performing video downscale.
+    // This saves bandwidth and avoids causing the driver to make too many panel
+    // -mode switches between BLT (writeback) and non-BLT (Direct) modes.
+    // Use-case: Video playback [with downscaling and rotation].
+
+    if (dst_w && dst_h)
+    {
+        uint32_t dscale = (src_w * src_h) / (dst_w * dst_h);
+
+        if(dscale < 2) {
+            // Down-scale to > 50% of orig.
+            dscale_factor = utils::ROT_DS_NONE;
+        } else if(dscale < 4) {
+            // Down-scale to between > 25% to <= 50% of orig.
+            dscale_factor = utils::ROT_DS_HALF;
+        } else if(dscale < 8) {
+            // Down-scale to between > 12.5% to <= 25% of orig.
+            dscale_factor = utils::ROT_DS_FOURTH;
+        } else {
+            // Down-scale to <= 12.5% of orig.
+            dscale_factor = utils::ROT_DS_EIGHTH;
+        }
+    }
+
+    return dscale_factor;
+}
+
+void MdpCtrl::doDownscale(int dscale_factor) {
+
+    if( dscale_factor ) {
+        mOVInfo.src_rect.x >>= dscale_factor;
+        mOVInfo.src_rect.y >>= dscale_factor;
+        mOVInfo.src_rect.w >>= dscale_factor;
+        mOVInfo.src_rect.h >>= dscale_factor;
+    }
+}
+
 bool MdpCtrl::set() {
     //deferred calcs, so APIs could be called in any order.
-    doTransform();
     utils::Whf whf = getSrcWhf();
     if(utils::isYuv(whf.format)) {
         normalizeCrop(mOVInfo.src_rect.x, mOVInfo.src_rect.w);
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index 4128068..24aa3c1 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -130,7 +130,10 @@
      */
     bool setCrop(const utils::Dim& d);
 
-    bool setTransform(const utils::eTransform& orient, const bool& rotUsed);
+    bool setTransform(const utils::eTransform& orient);
+
+    /* set whether rotator can be used */
+    void setRotatorUsed(const bool& rotUsed);
 
     /* given a dim and w/h, set overlay dim */
     bool setPosition(const utils::Dim& dim, int w, int h);
@@ -141,10 +144,18 @@
     /* dump state of the object */
     void dump() const;
 
+    /* Perform transformation calculations */
+    void doTransform();
+
+    /* Performs downscale calculations */
+    void doDownscale(int dscale_factor);
+
+    /* Get downscale factor */
+    int getDownscalefactor();
+
 private:
 
     /* helper functions for overlayTransform */
-    void doTransform();
     void overlayTransFlipH();
     void overlayTransFlipV();
     void overlayTransRot90();
diff --git a/liboverlay/overlayMdpRot.cpp b/liboverlay/overlayMdpRot.cpp
index f96ddb7..5052bc8 100644
--- a/liboverlay/overlayMdpRot.cpp
+++ b/liboverlay/overlayMdpRot.cpp
@@ -53,6 +53,20 @@
     mRotDataInfo.src.flags |= MDP_MEMORY_ID_TYPE_FB;
 }
 
+void MdpRot::setDownscale(int ds) {
+    if (mRotImgInfo.src.format == MDP_Y_CR_CB_GH2V2 &&
+                            (mRotImgInfo.src_rect.h & 0xF)) {
+        mRotImgInfo.src_rect.h = utils::aligndown(mRotImgInfo.src_rect.h, 16);
+    } else if ((utils::ROT_DS_EIGHTH == ds) && (mRotImgInfo.src_rect.h & 0xF)) {
+        // Ensure src_rect.h is a multiple of 16 for 1/8 downscaling.
+        // This is an undocumented MDP Rotator constraint.
+        // Note that src_rect.h is already ensured to be 32 pixel height aligned
+        // for MDP_Y_CRCB_H2V2_TILE and MDP_Y_CBCR_H2V2_TILE formats.
+        mRotImgInfo.src_rect.h = utils::alignup(mRotImgInfo.src_rect.h, 16);
+    }
+    mRotImgInfo.downscale_ratio = ds;
+}
+
 void MdpRot::save() {
     mLSRotImgInfo = mRotImgInfo;
 }
@@ -103,7 +117,7 @@
         mRotImgInfo.secure = 1;
 }
 
-void MdpRot::setTransform(const utils::eTransform& rot, const bool& rotUsed)
+void MdpRot::setTransform(const utils::eTransform& rot)
 {
     int r = utils::getMdpOrient(rot);
     setRotations(r);
@@ -111,7 +125,9 @@
     //Clients in Android dont factor in 90 rotation while deciding the flip.
     mOrientation = static_cast<utils::eTransform>(r);
     ALOGE_IF(DEBUG_OVERLAY, "%s: r=%d", __FUNCTION__, r);
+}
 
+void MdpRot::setRotatorUsed(const bool& rotUsed) {
     setDisable();
     if(rotUsed) {
         setEnable();
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index b0f51c1..c00e732 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -95,11 +95,14 @@
     mBufSize = awhf.size;
 }
 
+void MdssRot::setDownscale(int ds) {
+}
+
 void MdssRot::setFlags(const utils::eMdpFlags& flags) {
     mRotInfo.flags |= flags;
 }
 
-void MdssRot::setTransform(const utils::eTransform& rot, const bool& rotUsed)
+void MdssRot::setTransform(const utils::eTransform& rot)
 {
     int flags = utils::getMdpOrient(rot);
     if (flags != -1)
@@ -108,7 +111,9 @@
     //Clients in Android dont factor in 90 rotation while deciding the flip.
     mOrientation = static_cast<utils::eTransform>(flags);
     ALOGE_IF(DEBUG_OVERLAY, "%s: rot=%d", __FUNCTION__, flags);
+}
 
+void MdssRot::setRotatorUsed(const bool& rotUsed) {
     setDisable();
     if(rotUsed) {
         setEnable();
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index ca71402..118f71f 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -47,11 +47,12 @@
     virtual bool close() = 0;
     virtual void setSource(const utils::Whf& wfh) = 0;
     virtual void setFlags(const utils::eMdpFlags& flags) = 0;
-    virtual void setTransform(const utils::eTransform& rot,
-            const bool& rotUsed) = 0;
+    virtual void setTransform(const utils::eTransform& rot) = 0;
+    virtual void setRotatorUsed(const bool& rotUsed) = 0;
     virtual bool commit() = 0;
     virtual void setRotations(uint32_t r) = 0;
     virtual void setSrcFB() = 0;
+    virtual void setDownscale(int ds) = 0;
     virtual int getDstMemId() const = 0;
     virtual uint32_t getDstOffset() const = 0;
     virtual void setEnable() = 0;
@@ -116,11 +117,12 @@
     virtual bool close();
     virtual void setSource(const utils::Whf& wfh);
     virtual void setFlags(const utils::eMdpFlags& flags);
-    virtual void setTransform(const utils::eTransform& rot,
-            const bool& rotUsed);
+    virtual void setTransform(const utils::eTransform& rot);
+    virtual void setRotatorUsed(const bool& rotUsed);
     virtual bool commit();
     virtual void setRotations(uint32_t r);
     virtual void setSrcFB();
+    virtual void setDownscale(int ds);
     virtual int getDstMemId() const;
     virtual uint32_t getDstOffset() const;
     virtual void setEnable();
@@ -176,11 +178,12 @@
     virtual bool close();
     virtual void setSource(const utils::Whf& wfh);
     virtual void setFlags(const utils::eMdpFlags& flags);
-    virtual void setTransform(const utils::eTransform& rot,
-            const bool& rotUsed);
+    virtual void setTransform(const utils::eTransform& rot);
+    virtual void setRotatorUsed(const bool& rotUsed);
     virtual bool commit();
     virtual void setRotations(uint32_t r);
     virtual void setSrcFB();
+    virtual void setDownscale(int ds);
     virtual int getDstMemId() const;
     virtual uint32_t getDstOffset() const;
     virtual void setEnable();
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index cbacf3e..cbacf7f 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -276,9 +276,21 @@
  * ROT_FLAG_DISABLED: Rotator not used unless required.
  * ROT_FLAG_ENABLED: Rotator used even if not required.
  * */
-enum eRotFlags {
-    ROT_FLAG_DISABLED = 0,
-    ROT_FLAG_ENABLED = 1 // needed in rot
+ enum eRotFlags {
+    ROT_FLAGS_NONE = 0,
+    //Use rotator for 0 rotation. It is used anyway for others.
+    ROT_0_ENABLED = 1 << 0,
+    //Enable rotator downscale optimization for hardware bugs not handled in
+    //driver. If downscale optimizatation is required,
+    //then rotator will be used even if its 0 rotation case.
+    ROT_DOWNSCALE_ENABLED = 1 << 1,
+};
+
+enum eRotDownscale {
+    ROT_DS_NONE = 0,
+    ROT_DS_HALF = 1,
+    ROT_DS_FOURTH = 2,
+    ROT_DS_EIGHTH = 3,
 };
 
 /* The values for is_fg flag for control alpha and transp
@@ -372,7 +384,7 @@
     PipeArgs() : mdpFlags(OV_MDP_FLAGS_NONE),
         zorder(Z_SYSTEM_ALLOC),
         isFg(IS_FG_OFF),
-        rotFlags(ROT_FLAG_DISABLED){
+        rotFlags(ROT_FLAGS_NONE){
     }
 
     PipeArgs(eMdpFlags f, Whf _whf,
@@ -447,6 +459,11 @@
     return a ? ((((value - 1) / a) + 1) * a) : value;
 }
 
+inline int aligndown(int value, int a) {
+    //if align = 0, return the value. Else, do alignment.
+    return a ? ((value) & ~(a-1)) : value;
+}
+
 // FIXME that align should replace the upper one.
 inline int align(int value, int a) {
     //if align = 0, return the value. Else, do alignment.
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 9f08c14..aaaa0f1 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -29,11 +29,12 @@
 
 #include "overlayGenPipe.h"
 #include "overlay.h"
+#include "mdp_version.h"
 
 namespace overlay {
 
 GenericPipe::GenericPipe(int dpy) : mFbNum(dpy), mRot(0), mRotUsed(false),
-        pipeState(CLOSED) {
+        mRotDownscaleOpt(false), pipeState(CLOSED) {
     init();
 }
 
@@ -45,6 +46,7 @@
 {
     ALOGE_IF(DEBUG_OVERLAY, "GenericPipe init");
     mRotUsed = false;
+    mRotDownscaleOpt = false;
     if(mFbNum)
         mFbNum = Overlay::getInstance()->getExtFbNum();
 
@@ -101,7 +103,9 @@
     newargs.whf = whf;
 
     //Cache if user wants 0-rotation
-    mRotUsed = newargs.rotFlags & utils::ROT_FLAG_ENABLED;
+    mRotUsed = newargs.rotFlags & utils::ROT_0_ENABLED;
+    mRotDownscaleOpt = newargs.rotFlags & utils::ROT_DOWNSCALE_ENABLED;
+
     mRot->setSource(newargs.whf);
     mRot->setFlags(newargs.mdpFlags);
     return mCtrlData.ctrl.setSource(newargs);
@@ -118,9 +122,9 @@
     //Rotation could be enabled by user for zero-rot or the layer could have
     //some transform. Mark rotation enabled in either case.
     mRotUsed |= (orient != utils::OVERLAY_TRANSFORM_0);
-    mRot->setTransform(orient, mRotUsed);
+    mRot->setTransform(orient);
 
-    return mCtrlData.ctrl.setTransform(orient, mRotUsed);
+    return mCtrlData.ctrl.setTransform(orient);
 }
 
 bool GenericPipe::setPosition(const utils::Dim& d)
@@ -128,10 +132,31 @@
     return mCtrlData.ctrl.setPosition(d);
 }
 
+void GenericPipe::setRotatorUsed(const bool& rotUsed) {
+    mRot->setRotatorUsed(rotUsed);
+    mCtrlData.ctrl.setRotatorUsed(rotUsed);
+}
+
 bool GenericPipe::commit() {
     bool ret = false;
-    //If wanting to use rotator, start it.
+    int downscale_factor = utils::ROT_DS_NONE;
+
+    if(mRotDownscaleOpt) {
+        /* Can go ahead with calculation of downscale_factor since
+         * we consider area when calculating it */
+        downscale_factor = mCtrlData.ctrl.getDownscalefactor();
+        if(downscale_factor)
+            mRotUsed = true;
+    }
+
+    setRotatorUsed(mRotUsed);
+    mCtrlData.ctrl.doTransform();
+
+    mCtrlData.ctrl.doDownscale(downscale_factor);
+    mRot->setDownscale(downscale_factor);
+
     if(mRotUsed) {
+        //If wanting to use rotator, start it.
         if(!mRot->commit()) {
             ALOGE("GenPipe Rotator commit failed");
             //If rot commit fails, flush rotator session, memory, fd and create
@@ -224,4 +249,5 @@
     return true;
 }
 
+
 } //namespace overlay
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index d0bb3a8..604529a 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -88,6 +88,9 @@
     /* set Closed pipe */
     bool setClosed();
 
+    /* Set whether rotator can be used */
+    void setRotatorUsed(const bool& rotUsed);
+
     int mFbNum;
 
     /* Ctrl/Data aggregator */
@@ -98,6 +101,10 @@
     //Whether rotator is used for 0-rot or otherwise
     bool mRotUsed;
 
+    //Whether we will do downscale opt. This is just a request. If the frame is
+    //not a candidate, we might not do it.
+    bool mRotDownscaleOpt;
+
     /* Pipe open or closed */
     enum ePipeState {
         CLOSED,