overlay: Add support for rotator downscale

Add support for rotator downscale. This is enabled from 8994 onwards
Constraints:
--Downscale should be a power of 2, max upto 32
--Both directions should have equal downscale
--{src_w, src_h} mod downscale = 0
--No BWC
--No Interlaced video support

The rotator's destination rect is modified to reflect the presence of
downscale. Any downscale calcs should be done only after adjusting
crop to meet rotator's requirements.

Smaller downscale is used if we need to chop off any more than 1
line or pixel.

Change-Id: Id07d62fefa3213035f16cca49497800716484a95
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 267815f..3c224ca 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -147,7 +147,8 @@
                      * to BLOCK_MODE */
 
                     if (canUseRotator(ctx, dpy) &&
-                        has90Transform(layer) && isRotationDoable(ctx, hnd)) {
+                        (has90Transform(layer) || getRotDownscale(ctx, layer))
+                        && isRotationDoable(ctx, hnd)) {
                         if(not ctx->mOverlay->isDMAMultiplexingSupported()) {
                             if(ctx->mOverlay->isPipeTypeAttached(
                                              overlay::utils::OV_MDP_PIPE_DMA))
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 162ee4f..1df5419 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -156,6 +156,7 @@
     }
 
     if(!qdutils::MDPVersion::getInstance().isSrcSplit() &&
+        !qdutils::MDPVersion::getInstance().isRotDownscaleEnabled() &&
             property_get("persist.mdpcomp.4k2kSplit", property, "0") > 0 &&
             (!strncmp(property, "1", PROPERTY_VALUE_MAX) ||
             !strncasecmp(property,"true", PROPERTY_VALUE_MAX))) {
@@ -2311,6 +2312,10 @@
     int dstWidth = dst.right - dst.left;
     int cropWidth = crop.right - crop.left;
 
+    //TODO Even if a 4k video is going to be rot-downscaled to dimensions under
+    //pipe line length, we are still using 2 pipes. This is fine just because
+    //this is source split where destination doesn't matter. Evaluate later to
+    //see if going through all the calcs to save a pipe is worth it
     if(dstWidth > mdpHw.getMaxMixerWidth() or
             cropWidth > mdpHw.getMaxMixerWidth() or
             (primarySplitAlways and (cropWidth > lSplit))) {
@@ -2351,7 +2356,6 @@
     hwc_rect_t dst = layer->displayFrame;
     int transform = layer->transform;
     eTransform orient = static_cast<eTransform>(transform);
-    const int downscale = 0;
     int rotFlags = ROT_FLAGS_NONE;
     uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
     Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size);
@@ -2367,21 +2371,22 @@
             whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
     }
 
+    int downscale = getRotDownscale(ctx, layer);
     eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
-    setMdpFlags(ctx, layer, mdpFlags, 0, transform);
+    setMdpFlags(ctx, layer, mdpFlags, downscale, transform);
 
     if(lDest != OV_INVALID && rDest != OV_INVALID) {
         //Enable overfetch
         setMdpFlags(mdpFlags, OV_MDSS_MDP_DUAL_PIPE);
     }
 
-    if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
+    if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) {
         (*rot) = ctx->mRotMgr->getNext();
         if((*rot) == NULL) return -1;
         ctx->mLayerRotMap[mDpy]->add(layer, *rot);
         //If the video is using a single pipe, enable BWC
         if(rDest == OV_INVALID) {
-            BwcPM::setBwc(crop, dst, transform, mdpFlags);
+            BwcPM::setBwc(crop, dst, transform, downscale, mdpFlags);
         }
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
@@ -2389,7 +2394,7 @@
             return -1;
         }
         updateSource(orient, whf, crop, *rot);
-        rotFlags |= ROT_PREROTATED;
+        rotFlags |= ovutils::ROT_PREROTATED;
     }
 
     //If 2 pipes being used, divide layer into half, crop and dst
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 3696c05..a58eec4 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -1633,6 +1633,47 @@
     crop.bottom = transformedCrop.y + transformedCrop.h;
 }
 
+int getRotDownscale(hwc_context_t *ctx, const hwc_layer_1_t *layer) {
+    if(not qdutils::MDPVersion::getInstance().isRotDownscaleEnabled()) {
+        return 0;
+    }
+
+    int downscale = 0;
+    hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+    hwc_rect_t dst = layer->displayFrame;
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+
+    if(not hnd) {
+        return 0;
+    }
+
+    MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+    bool isInterlaced = metadata && (metadata->operation & PP_PARAM_INTERLACED)
+                && metadata->interlaced;
+    int transform = layer->transform;
+    uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
+
+    if(isYuvBuffer(hnd)) {
+        if(ctx->mMDP.version >= qdutils::MDP_V4_2 &&
+                ctx->mMDP.version < qdutils::MDSS_V5) {
+            downscale = Rotator::getDownscaleFactor(crop.right - crop.left,
+                    crop.bottom - crop.top, dst.right - dst.left,
+                    dst.bottom - dst.top, format, isInterlaced);
+        } else {
+            Dim adjCrop(crop.left, crop.top, crop.right - crop.left,
+                    crop.bottom - crop.top);
+            Dim pos(dst.left, dst.top, dst.right - dst.left,
+                    dst.bottom - dst.top);
+            if(transform & HAL_TRANSFORM_ROT_90) {
+                swap(adjCrop.w, adjCrop.h);
+            }
+            downscale = Rotator::getDownscaleFactor(adjCrop.w, adjCrop.h, pos.w,
+                    pos.h, format, isInterlaced);
+        }
+    }
+    return downscale;
+}
+
 int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
         eIsFg& isFg, const eDest& dest, Rotator **rot) {
@@ -1654,7 +1695,6 @@
     hwc_rect_t dst = layer->displayFrame;
     int transform = layer->transform;
     eTransform orient = static_cast<eTransform>(transform);
-    int downscale = 0;
     int rotFlags = ovutils::ROT_FLAGS_NONE;
     uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
     Whf whf(getWidth(hnd), getHeight(hnd), format, (uint32_t)hnd->size);
@@ -1668,36 +1708,24 @@
     }
 
     calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
-
-    if(isYuvBuffer(hnd) && ctx->mMDP.version >= qdutils::MDP_V4_2 &&
-       ctx->mMDP.version < qdutils::MDSS_V5) {
-        downscale =  getDownscaleFactor(
-            crop.right - crop.left,
-            crop.bottom - crop.top,
-            dst.right - dst.left,
-            dst.bottom - dst.top);
-        if(downscale) {
-            rotFlags = ROT_DOWNSCALE_ENABLED;
-        }
-    }
-
+    int downscale = getRotDownscale(ctx, layer);
     setMdpFlags(ctx, layer, mdpFlags, downscale, transform);
 
     //if 90 component or downscale, use rot
-    if((has90Transform(layer) && isRotationDoable(ctx, hnd)) || downscale) {
+    if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) {
         *rot = ctx->mRotMgr->getNext();
         if(*rot == NULL) return -1;
         ctx->mLayerRotMap[dpy]->add(layer, *rot);
         // BWC is not tested for other formats So enable it only for YUV format
         if(!dpy && isYuvBuffer(hnd))
-            BwcPM::setBwc(crop, dst, transform, mdpFlags);
+            BwcPM::setBwc(crop, dst, transform, downscale, mdpFlags);
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
             return -1;
         }
         updateSource(orient, whf, crop, *rot);
-        rotFlags |= ovutils::ROT_PREROTATED;
+        rotFlags |= ROT_PREROTATED;
     }
 
     //For the mdp, since either we are pre-rotating or MDP does flips
@@ -1761,7 +1789,6 @@
     hwc_rect_t dst = layer->displayFrame;
     int transform = layer->transform;
     eTransform orient = static_cast<eTransform>(transform);
-    const int downscale = 0;
     int rotFlags = ROT_FLAGS_NONE;
     uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
     Whf whf(getWidth(hnd), getHeight(hnd), format, (uint32_t)hnd->size);
@@ -1777,8 +1804,8 @@
     /* Calculate the external display position based on MDP downscale,
        ActionSafe, and extorientation features. */
     calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
-
-    setMdpFlags(ctx, layer, mdpFlagsL, 0, transform);
+    int downscale = getRotDownscale(ctx, layer);
+    setMdpFlags(ctx, layer, mdpFlagsL, downscale, transform);
 
     if(lDest != OV_INVALID && rDest != OV_INVALID) {
         //Enable overfetch
@@ -1792,7 +1819,7 @@
         whf.format = wb->getOutputFormat();
     }
 
-    if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
+    if((has90Transform(layer) or downscale) and isRotationDoable(ctx, hnd)) {
         (*rot) = ctx->mRotMgr->getNext();
         if((*rot) == NULL) return -1;
         ctx->mLayerRotMap[dpy]->add(layer, *rot);
@@ -1928,7 +1955,7 @@
         ctx->mLayerRotMap[dpy]->add(layer, *rot);
         // BWC is not tested for other formats So enable it only for YUV format
         if(!dpy && isYuvBuffer(hnd))
-            BwcPM::setBwc(crop, dst, transform, mdpFlagsL);
+            BwcPM::setBwc(crop, dst, transform, downscale, mdpFlagsL);
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
@@ -2175,9 +2202,12 @@
     return (eqBounds == 3);
 }
 
-void BwcPM::setBwc(const hwc_rect_t& crop,
-            const hwc_rect_t& dst, const int& transform,
-            ovutils::eMdpFlags& mdpFlags) {
+void BwcPM::setBwc(const hwc_rect_t& crop, const hwc_rect_t& dst,
+        const int& transform,const int& downscale,
+        ovutils::eMdpFlags& mdpFlags) {
+    //BWC not supported with rot-downscale
+    if(downscale) return;
+
     //Target doesnt support Bwc
     qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
     if(!mdpHw.supportsBWC()) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 66fdc65..28289d5 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -161,8 +161,8 @@
 };
 
 struct BwcPM {
-    static void setBwc(const hwc_rect_t& crop,
-            const hwc_rect_t& dst, const int& transform,
+    static void setBwc(const hwc_rect_t& crop, const hwc_rect_t& dst,
+            const int& transform, const int& downscale,
             ovutils::eMdpFlags& mdpFlags);
 };
 
@@ -387,6 +387,8 @@
 
 bool isDisplaySplit(hwc_context_t* ctx, int dpy);
 
+int getRotDownscale(hwc_context_t *ctx, const hwc_layer_1_t *layer);
+
 // Set the GPU hint flag to high for MIXED/GPU composition only for
 // first frame after MDP to GPU/MIXED mode transition.
 // Set the GPU hint to default if the current composition type is GPU