Merge "liboverlay: Rotator-assisted MDP downscaling of videos."
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index ecbf813..e0331ad 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -89,7 +89,7 @@
                 info,
                 ovutils::ZORDER_0,
                 ovutils::IS_FG_SET,
-                ovutils::ROT_FLAG_DISABLED);
+                ovutils::ROT_FLAGS_NONE);
         ov.setSource(parg, dest);
 
         hwc_rect_t sourceCrop = layer->sourceCrop;
@@ -193,7 +193,7 @@
                 info,
                 ovutils::ZORDER_0,
                 ovutils::IS_FG_SET,
-                ovutils::ROT_FLAG_DISABLED);
+                ovutils::ROT_FLAGS_NONE);
         ov.setSource(pargL, destL);
 
         ovutils::eMdpFlags mdpFlagsR = mdpFlagsL;
@@ -202,7 +202,7 @@
                 info,
                 ovutils::ZORDER_0,
                 ovutils::IS_FG_SET,
-                ovutils::ROT_FLAG_DISABLED);
+                ovutils::ROT_FLAGS_NONE);
         ov.setSource(pargR, destR);
 
         hwc_rect_t sourceCrop = layer->sourceCrop;
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 2e58b93..bbea007 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -20,6 +20,7 @@
 #include <sys/ioctl.h>
 #include "external.h"
 #include "qdMetaData.h"
+#include "mdp_version.h"
 
 namespace qhwc {
 
@@ -325,11 +326,17 @@
         orient = static_cast<ovutils::eTransform>(layer->transform);
     }
 
+    ovutils::eRotFlags rotFlags = ovutils::ROT_FLAGS_NONE;
+    if(isYuvBuffer(hnd) && (ctx->mMDP.version >= qdutils::MDP_V4_2 &&
+                           ctx->mMDP.version < qdutils::MDSS_V5)) {
+        rotFlags = ovutils::ROT_DOWNSCALE_ENABLED;
+    }
+
     ovutils::PipeArgs parg(mdpFlags,
             info,
             zOrder,
             ovutils::IS_FG_OFF,
-            ovutils::ROT_FLAG_DISABLED);
+            rotFlags);
 
     ov.setSource(parg, dest);
 
diff --git a/libhwcomposer/hwc_video.cpp b/libhwcomposer/hwc_video.cpp
index 13f3cdd..41d4365 100644
--- a/libhwcomposer/hwc_video.cpp
+++ b/libhwcomposer/hwc_video.cpp
@@ -20,6 +20,7 @@
 #include "hwc_video.h"
 #include "hwc_utils.h"
 #include "qdMetaData.h"
+#include "mdp_version.h"
 
 namespace qhwc {
 
@@ -119,11 +120,17 @@
         isFgFlag = ovutils::IS_FG_SET;
     }
 
+    ovutils::eRotFlags rotFlags = ovutils::ROT_FLAGS_NONE;
+    if(ctx->mMDP.version >= qdutils::MDP_V4_2 &&
+                ctx->mMDP.version < qdutils::MDSS_V5) {
+        rotFlags = ovutils::ROT_DOWNSCALE_ENABLED;
+    }
+
     ovutils::PipeArgs parg(mdpFlags,
             info,
             ovutils::ZORDER_1,
             isFgFlag,
-            ovutils::ROT_FLAG_DISABLED);
+            rotFlags);
 
     ov.setSource(parg, dest);
 
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,