Merge "hwc: Fix right mixer layer positioning."
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 3bf1504..9bf0c45 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -41,7 +41,7 @@
 using namespace overlay;
 
 #define VSYNC_DEBUG 0
-#define BLANK_DEBUG 0
+#define BLANK_DEBUG 1
 
 static int hwc_device_open(const struct hw_module_t* module,
                            const char* name,
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 9f91a99..bfa33ca 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -73,6 +73,8 @@
         //Request an RGB pipe
         ovutils::eDest dest = ov.nextPipe(ovutils::OV_MDP_PIPE_ANY, mDpy);
         if(dest == ovutils::OV_INVALID) { //None available
+            ALOGE("%s: No pipes available to configure fb for dpy %d",
+                __FUNCTION__, mDpy);
             return false;
         }
 
@@ -171,11 +173,15 @@
         //Request left RGB pipe
         ovutils::eDest destL = ov.nextPipe(ovutils::OV_MDP_PIPE_RGB, mDpy);
         if(destL == ovutils::OV_INVALID) { //None available
+            ALOGE("%s: No pipes available to configure fb for dpy %d's left"
+                    " mixer", __FUNCTION__, mDpy);
             return false;
         }
         //Request right RGB pipe
         ovutils::eDest destR = ov.nextPipe(ovutils::OV_MDP_PIPE_RGB, mDpy);
         if(destR == ovutils::OV_INVALID) { //None available
+            ALOGE("%s: No pipes available to configure fb for dpy %d's right"
+                    " mixer", __FUNCTION__, mDpy);
             return false;
         }
 
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 6381f59..eb46304 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -160,9 +160,6 @@
                 layer->compositionType = HWC_OVERLAY;
         }
     }
-    mCachedFrame.mdpCount = mCurrentFrame.mdpCount;
-    mCachedFrame.cacheCount = mCurrentFrame.fbCount;
-    mCachedFrame.layerCount = ctx->listStats[mDpy].numAppLayers;
 }
 
 /*
@@ -205,13 +202,11 @@
     return true;
 }
 MDPComp::FrameInfo::FrameInfo() {
-    layerCount = 0;
-    reset();
+    reset(0);
 }
 
-void MDPComp::FrameInfo::reset() {
-
-    for(int i = 0 ; i < MAX_PIPES_PER_MIXER && layerCount; i++ ) {
+void MDPComp::FrameInfo::reset(const int& numLayers) {
+    for(int i = 0 ; i < MAX_PIPES_PER_MIXER && numLayers; i++ ) {
         if(mdpToLayer[i].pipeInfo) {
             delete mdpToLayer[i].pipeInfo;
             mdpToLayer[i].pipeInfo = NULL;
@@ -222,24 +217,50 @@
 
     memset(&mdpToLayer, 0, sizeof(mdpToLayer));
     memset(&layerToMDP, -1, sizeof(layerToMDP));
-    memset(&isFBComposed, 0, sizeof(isFBComposed));
+    memset(&isFBComposed, 1, sizeof(isFBComposed));
 
-    layerCount = 0;
+    layerCount = numLayers;
+    fbCount = numLayers;
     mdpCount = 0;
-    fbCount = 0;
     needsRedraw = false;
     fbZ = 0;
 }
 
+void MDPComp::FrameInfo::map() {
+    // populate layer and MDP maps
+    int mdpIdx = 0;
+    for(int idx = 0; idx < layerCount; idx++) {
+        if(!isFBComposed[idx]) {
+            mdpToLayer[mdpIdx].listIndex = idx;
+            layerToMDP[idx] = mdpIdx++;
+        }
+    }
+}
+
 MDPComp::LayerCache::LayerCache() {
     reset();
 }
 
 void MDPComp::LayerCache::reset() {
-    memset(&hnd, 0, sizeof(buffer_handle_t));
+    memset(&hnd, 0, sizeof(hnd));
     mdpCount = 0;
     cacheCount = 0;
     layerCount = 0;
+    fbZ = -1;
+}
+
+void MDPComp::LayerCache::cacheAll(hwc_display_contents_1_t* list) {
+    const int numAppLayers = list->numHwLayers - 1;
+    for(int i = 0; i < numAppLayers; i++) {
+        hnd[i] = list->hwLayers[i].handle;
+    }
+}
+
+void MDPComp::LayerCache::updateCounts(const FrameInfo& curFrame) {
+    mdpCount = curFrame.mdpCount;
+    cacheCount = curFrame.fbCount;
+    layerCount = curFrame.layerCount;
+    fbZ = curFrame.fbZ;
 }
 
 bool MDPComp::isWidthValid(hwc_context_t *ctx, hwc_layer_1_t *layer) {
@@ -315,25 +336,30 @@
 
 bool MDPComp::isFrameDoable(hwc_context_t *ctx) {
     int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+    bool ret = true;
 
     if(!isEnabled()) {
         ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
-        return false;
-    }
-
-    if(ctx->mExtDispConfiguring) {
+        ret = false;
+    } else if(ctx->mExtDispConfiguring) {
         ALOGD_IF( isDebug(),"%s: External Display connection is pending",
                   __FUNCTION__);
-        return false;
-    }
-
-    if(ctx->listStats[mDpy].needsAlphaScale
+        ret = false;
+    } else if(ctx->listStats[mDpy].needsAlphaScale
        && ctx->mMDP.version < qdutils::MDSS_V5) {
         ALOGD_IF(isDebug(), "%s: frame needs alpha downscaling",__FUNCTION__);
-        return false;
+        ret = false;
+    } else if(ctx->isPaddingRound) {
+        ctx->isPaddingRound = false;
+        ALOGD_IF(isDebug(), "%s: padding round",__FUNCTION__);
+        ret = false;
+    } else if(sIdleFallBack) {
+        sIdleFallBack = false;
+        ALOGD_IF(isDebug(), "%s: idle fallback",__FUNCTION__);
+        ret = false;
     }
 
-    return true;
+    return ret;
 }
 
 /* Checks for conditions where all the layers marked for MDP comp cannot be
@@ -341,9 +367,7 @@
 bool MDPComp::isFullFrameDoable(hwc_context_t *ctx,
                                 hwc_display_contents_1_t* list){
 
-    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
-    int mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount;
-    int fbNeeded = int(mCurrentFrame.fbCount != 0);
+    const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
 
     if(mDpy > HWC_DISPLAY_PRIMARY){
         ALOGD_IF(isDebug(), "%s: Cannot support External display(s)",
@@ -351,25 +375,10 @@
         return false;
     }
 
-    if(mdpCount > (sMaxPipesPerMixer - fbNeeded)) {
-        ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
-        return false;
-    }
-
-    if(pipesNeeded(ctx, list) > getAvailablePipes(ctx)) {
-        ALOGD_IF(isDebug(), "%s: Insufficient MDP pipes",__FUNCTION__);
-        return false;
-    }
-
     if(isSkipPresent(ctx, mDpy)) {
-        ALOGD_IF(isDebug(), "%s: Skip layers present",__FUNCTION__);
-        return false;
-    }
-
-    //FB composition on idle timeout
-    if(sIdleFallBack) {
-        sIdleFallBack = false;
-        ALOGD_IF(isDebug(), "%s: idle fallback",__FUNCTION__);
+        ALOGD_IF(isDebug(),"%s: SKIP present: %d",
+                __FUNCTION__,
+                isSkipPresent(ctx, mDpy));
         return false;
     }
 
@@ -390,6 +399,94 @@
             return false;
         }
     }
+
+    //If all above hard conditions are met we can do full or partial MDP comp.
+    bool ret = false;
+    if(fullMDPComp(ctx, list)) {
+        ret = true;
+    } else if (partialMDPComp(ctx, list)) {
+        ret = true;
+    }
+    return ret;
+}
+
+bool MDPComp::fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    //Setup mCurrentFrame
+    mCurrentFrame.mdpCount = mCurrentFrame.layerCount;
+    mCurrentFrame.fbCount = 0;
+    mCurrentFrame.fbZ = -1;
+    memset(&mCurrentFrame.isFBComposed, 0, sizeof(mCurrentFrame.isFBComposed));
+
+    int mdpCount = mCurrentFrame.mdpCount;
+    if(mdpCount > sMaxPipesPerMixer) {
+        ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
+        return false;
+    }
+
+    int numPipesNeeded = pipesNeeded(ctx, list);
+    int availPipes = getAvailablePipes(ctx);
+
+    if(numPipesNeeded > availPipes) {
+        ALOGD_IF(isDebug(), "%s: Insufficient MDP pipes, needed %d, avail %d",
+                __FUNCTION__, numPipesNeeded, availPipes);
+        return false;
+    }
+
+    return true;
+}
+
+bool MDPComp::partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list)
+{
+    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+    //Setup mCurrentFrame
+    mCurrentFrame.reset(numAppLayers);
+    updateLayerCache(ctx, list);
+    updateYUV(ctx, list);
+    batchLayers(); //sets up fbZ also
+
+    int mdpCount = mCurrentFrame.mdpCount;
+    if(mdpCount > (sMaxPipesPerMixer - 1)) { // -1 since FB is used
+        ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
+        return false;
+    }
+
+    int numPipesNeeded = pipesNeeded(ctx, list);
+    int availPipes = getAvailablePipes(ctx);
+
+    if(numPipesNeeded > availPipes) {
+        ALOGD_IF(isDebug(), "%s: Insufficient MDP pipes, needed %d, avail %d",
+                __FUNCTION__, numPipesNeeded, availPipes);
+        return false;
+    }
+
+    return true;
+}
+
+bool MDPComp::isOnlyVideoDoable(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list){
+    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+    mCurrentFrame.reset(numAppLayers);
+    updateYUV(ctx, list);
+    int mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount;
+    int fbNeeded = int(mCurrentFrame.fbCount != 0);
+
+    if(!isYuvPresent(ctx, mDpy)) {
+        return false;
+    }
+
+    if(mdpCount > (sMaxPipesPerMixer - fbNeeded)) {
+        ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
+        return false;
+    }
+
+    int numPipesNeeded = pipesNeeded(ctx, list);
+    int availPipes = getAvailablePipes(ctx);
+    if(numPipesNeeded > availPipes) {
+        ALOGD_IF(isDebug(), "%s: Insufficient MDP pipes, needed %d, avail %d",
+                __FUNCTION__, numPipesNeeded, availPipes);
+        return false;
+    }
+
     return true;
 }
 
@@ -436,9 +533,14 @@
     int maxBatchCount = 0;
 
     /* All or Nothing is cached. No batching needed */
-    if(!mCurrentFrame.fbCount ||
-       (mCurrentFrame.fbCount ==  mCurrentFrame.layerCount))
+    if(!mCurrentFrame.fbCount) {
+        mCurrentFrame.fbZ = -1;
         return;
+    }
+    if(!mCurrentFrame.mdpCount) {
+        mCurrentFrame.fbZ = 0;
+        return;
+    }
 
     /* Search for max number of contiguous (cached) layers */
     int i = 0;
@@ -450,6 +552,7 @@
         if(count > maxBatchCount) {
             maxBatchCount = count;
             maxBatchStart = i - count;
+            mCurrentFrame.fbZ = maxBatchStart;
         }
         if(i < mCurrentFrame.layerCount) i++;
     }
@@ -464,6 +567,8 @@
     }
 
     mCurrentFrame.fbCount = maxBatchCount;
+    mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
+            mCurrentFrame.fbCount;
 
     ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__,
              mCurrentFrame.fbCount);
@@ -475,23 +580,19 @@
     int numAppLayers = ctx->listStats[mDpy].numAppLayers;
     int numCacheableLayers = 0;
 
-    if((list->flags & HWC_GEOMETRY_CHANGED) || (isSkipPresent(ctx, mDpy))) {
-        ALOGD_IF(isDebug(),"%s: No Caching: \
-                 GEOMETRY change: %d SKIP present: %d", __FUNCTION__,
-                 (list->flags & HWC_GEOMETRY_CHANGED),isSkipPresent(ctx, mDpy));
-        mCachedFrame.reset();
-        return;
-    }
-
     for(int i = 0; i < numAppLayers; i++) {
         if (mCachedFrame.hnd[i] == list->hwLayers[i].handle) {
             numCacheableLayers++;
             mCurrentFrame.isFBComposed[i] = true;
         } else {
+            mCurrentFrame.isFBComposed[i] = false;
             mCachedFrame.hnd[i] = list->hwLayers[i].handle;
         }
     }
+
     mCurrentFrame.fbCount = numCacheableLayers;
+    mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
+            mCurrentFrame.fbCount;
     ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__, numCacheableLayers);
 }
 
@@ -512,14 +613,6 @@
     return numAvailable;
 }
 
-void MDPComp::resetFrameForFB(hwc_context_t* ctx,
-                              hwc_display_contents_1_t* list) {
-    mCurrentFrame.fbCount = mCurrentFrame.layerCount;
-    memset(&mCurrentFrame.isFBComposed, 1,
-           sizeof(mCurrentFrame.isFBComposed));
-    mCurrentFrame.needsRedraw = true;
-}
-
 void MDPComp::updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list) {
 
     int nYuvCount = ctx->listStats[mDpy].yuvCount;
@@ -539,22 +632,23 @@
             }
         }
     }
+
+    mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
+            mCurrentFrame.fbCount;
     ALOGD_IF(isDebug(),"%s: cached count: %d",__FUNCTION__,
              mCurrentFrame.fbCount);
 }
 
-int MDPComp::programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
-    int fbZOrder = -1;
-
+bool MDPComp::programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     if(!allocLayerPipes(ctx, list)) {
         ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
-        goto fn_exit;
+        return false;
     }
 
+    bool fbBatch = false;
     for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount;
-                                                                      index++) {
+            index++) {
         if(!mCurrentFrame.isFBComposed[index]) {
-
             int mdpIndex = mCurrentFrame.layerToMDP[index];
             hwc_layer_1_t* layer = &list->hwLayers[index];
 
@@ -564,80 +658,106 @@
             if(configure(ctx, layer, mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
                 ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
                          layer %d",__FUNCTION__, index);
-                goto fn_exit;
+                return false;
             }
-        } else if(fbZOrder < 0) {
-            fbZOrder = mdpNextZOrder++;
-        };
+        } else if(fbBatch == false) {
+                mdpNextZOrder++;
+                fbBatch = true;
+        }
     }
 
-    return fbZOrder;
+    return true;
+}
 
- fn_exit:
-        //Complete fallback to FB
-        resetFrameForFB(ctx, list);
-        return 0;
+bool MDPComp::programYUV(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    if(!allocLayerPipes(ctx, list)) {
+        ALOGD_IF(isDebug(), "%s: Unable to allocate MDP pipes", __FUNCTION__);
+        return false;
+    }
+    //If we are in this block, it means we have yuv + rgb layers both
+    int mdpIdx = 0;
+    for (int index = 0; index < mCurrentFrame.layerCount; index++) {
+        if(!mCurrentFrame.isFBComposed[index]) {
+            hwc_layer_1_t* layer = &list->hwLayers[index];
+            int mdpIndex = mCurrentFrame.layerToMDP[index];
+            MdpPipeInfo* cur_pipe =
+                    mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+            cur_pipe->zOrder = mdpIdx++;
+
+            if(configure(ctx, layer,
+                        mCurrentFrame.mdpToLayer[mdpIndex]) != 0 ){
+                ALOGD_IF(isDebug(), "%s: Failed to configure overlay for \
+                        layer %d",__FUNCTION__, index);
+                return false;
+            }
+        }
+    }
+    return true;
 }
 
 int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
 
     //reset old data
-    mCurrentFrame.reset();
+    const int numLayers = ctx->listStats[mDpy].numAppLayers;
+    mCurrentFrame.reset(numLayers);
 
+    //Hard conditions, if not met, cannot do MDP comp
     if(!isFrameDoable(ctx)) {
         ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
                   __FUNCTION__);
+        mCurrentFrame.reset(numLayers);
+        mCachedFrame.cacheAll(list);
+        mCachedFrame.updateCounts(mCurrentFrame);
         return 0;
     }
 
-    mCurrentFrame.layerCount = ctx->listStats[mDpy].numAppLayers;
-
-    //Iterate layer list for cached layers
-    updateLayerCache(ctx, list);
-
-    //Add YUV layers to cached list
-    updateYUV(ctx, list);
-
-    //Optimze for bypass
-    batchLayers();
-
-    //list is already parsed / batched for optimal mixed mode composition.
     //Check whether layers marked for MDP Composition is actually doable.
-    if(!isFullFrameDoable(ctx, list)){
+    if(isFullFrameDoable(ctx, list)){
+        if(mCurrentFrame.mdpCount) {
+            mCurrentFrame.map();
+            //Acquire and Program MDP pipes
+            if(!programMDP(ctx, list)) {
+                mCurrentFrame.reset(numLayers);
+                mCachedFrame.cacheAll(list);
+            }
+        }
+    } else if(isOnlyVideoDoable(ctx, list)) {
         //All layers marked for MDP comp cannot be bypassed.
         //Try to compose atleast YUV layers through MDP comp and let
         //all the RGB layers compose in FB
-        resetFrameForFB(ctx, list);
-        updateYUV(ctx, list);
-    }
+        //Destination over
+        mCurrentFrame.fbZ = -1;
+        if(mCurrentFrame.fbCount)
+            mCurrentFrame.fbZ = ctx->listStats[mDpy].yuvCount;
 
-    mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
-                             mCurrentFrame.fbCount;
-
-    if(mCurrentFrame.mdpCount) {
-        // populate layer and MDP maps
-        for(int idx = 0, mdpIdx = 0; idx < mCurrentFrame.layerCount; idx++) {
-            if(!mCurrentFrame.isFBComposed[idx]) {
-                mCurrentFrame.mdpToLayer[mdpIdx].listIndex = idx;
-                mCurrentFrame.layerToMDP[idx] = mdpIdx++;
-            }
+        mCurrentFrame.map();
+        if(!programYUV(ctx, list)) {
+            mCurrentFrame.reset(numLayers);
+            mCachedFrame.cacheAll(list);
         }
-        //Acquire and Program MDP pipes
-        mCurrentFrame.fbZ = programMDP(ctx, list);
+    } else {
+        mCurrentFrame.reset(numLayers);
+        mCachedFrame.cacheAll(list);
     }
 
     /* Any change in composition types needs an FB refresh*/
     if(mCurrentFrame.fbCount &&
-       ((mCurrentFrame.mdpCount != mCachedFrame.mdpCount) ||
-       (mCurrentFrame.fbCount != mCachedFrame.cacheCount) ||
-       !mCurrentFrame.mdpCount)) {
+            ((mCurrentFrame.mdpCount != mCachedFrame.mdpCount) ||
+            (mCurrentFrame.fbCount != mCachedFrame.cacheCount) ||
+            (mCurrentFrame.fbZ != mCachedFrame.fbZ) ||
+            (!mCurrentFrame.mdpCount) ||
+            (list->flags & HWC_GEOMETRY_CHANGED) ||
+            isSkipPresent(ctx, mDpy) ||
+            (mDpy > HWC_DISPLAY_PRIMARY))) {
         mCurrentFrame.needsRedraw = true;
     }
 
     //UpdateLayerFlags
     setMDPCompLayerFlags(ctx, list);
+    mCachedFrame.updateCounts(mCurrentFrame);
 
     if(isDebug()) {
+        ALOGD("GEOMETRY change: %d", (list->flags & HWC_GEOMETRY_CHANGED));
         android::String8 sDump("");
         dump(sDump);
         ALOGE("%s",sDump.string());
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 7970cd3..4aedd77 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -93,7 +93,8 @@
         /* c'tor */
         FrameInfo();
         /* clear old frame data */
-        void reset();
+        void reset(const int& numLayers);
+        void map();
     };
 
     /* cached data */
@@ -101,12 +102,15 @@
         int layerCount;
         int mdpCount;
         int cacheCount;
+        int fbZ;
         buffer_handle_t hnd[MAX_NUM_LAYERS];
 
         /* c'tor */
         LayerCache();
         /* clear caching info*/
         void reset();
+        void cacheAll(hwc_display_contents_1_t* list);
+        void updateCounts(const FrameInfo&);
     };
 
     /* No of pipes needed for Framebuffer */
@@ -121,7 +125,6 @@
     virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
                           PipeLayerPair& pipeLayerPair) = 0;
 
-
     /* set/reset flags for MDPComp */
     void setMDPCompLayerFlags(hwc_context_t *ctx,
                               hwc_display_contents_1_t* list);
@@ -132,6 +135,12 @@
     bool isFrameDoable(hwc_context_t *ctx);
     /* checks for conditions where RGB layers cannot be bypassed */
     bool isFullFrameDoable(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+    /* checks if full MDP comp can be done */
+    bool fullMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+    /* check if we can use layer cache to do at least partial MDP comp */
+    bool partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+    /* checks for conditions where only video can be bypassed */
+    bool isOnlyVideoDoable(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     /* checks for conditions where YUV layers cannot be bypassed */
     bool isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
 
@@ -145,16 +154,14 @@
     bool isWidthValid(hwc_context_t *ctx, hwc_layer_1_t *layer);
     /* tracks non updating layers*/
     void updateLayerCache(hwc_context_t* ctx, hwc_display_contents_1_t* list);
-    /* resets cache for complete fallback */
-    void resetFrameForFB(hwc_context_t* ctx, hwc_display_contents_1_t* list);
     /* optimize layers for mdp comp*/
     void batchLayers();
     /* gets available pipes for mdp comp */
     int getAvailablePipes(hwc_context_t* ctx);
     /* updates cache map with YUV info */
     void updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list);
-    int programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list);
-
+    bool programMDP(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+    bool programYUV(hwc_context_t *ctx, hwc_display_contents_1_t* list);
 
     int mDpy;
     static bool sEnabled;
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 3bbed7c..e919be8 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -344,6 +344,9 @@
             yuvCount++;
 
             if(layer->transform & HWC_TRANSFORM_ROT_90) {
+                if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
+                    ctx->isPaddingRound = true;
+                }
                 Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
             }
         }
@@ -556,8 +559,11 @@
     }
 
     if(ret < 0) {
-        ALOGE("ioctl MSMFB_BUFFER_SYNC failed, err=%s",
-                strerror(errno));
+        ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed, err=%s",
+                  __FUNCTION__, strerror(errno));
+        ALOGE("%s: acq_fen_fd_cnt=%d flags=%d fd=%d dpy=%d numHwLayers=%d",
+              __FUNCTION__, data.acq_fen_fd_cnt, data.flags, fbFd,
+              dpy, list->numHwLayers);
     }
 
     for(uint32_t i = 0; i < list->numHwLayers; i++) {
@@ -649,9 +655,12 @@
 }
 
 static inline int configRotator(Rotator *rot, const Whf& whf,
-        const eMdpFlags& mdpFlags, const eTransform& orient,
-        const int& downscale) {
+        const hwc_rect_t& crop, const eMdpFlags& mdpFlags,
+        const eTransform& orient, const int& downscale) {
+    Dim rotCrop(crop.left, crop.top, (crop.right - crop.left),
+        (crop.bottom - crop.top));
     rot->setSource(whf);
+    rot->setCrop(rotCrop);
     rot->setFlags(mdpFlags);
     rot->setTransform(orient);
     rot->setDownscale(downscale);
@@ -692,10 +701,22 @@
             crop.bottom - crop.top);
     orient = static_cast<eTransform>(ovutils::getMdpOrient(orient));
     preRotateSource(orient, whf, srcCrop);
-    crop.left = srcCrop.x;
-    crop.top = srcCrop.y;
-    crop.right = srcCrop.x + srcCrop.w;
-    crop.bottom = srcCrop.y + srcCrop.h;
+    if (qdutils::MDPVersion::getInstance().getMDPVersion() >=
+        qdutils::MDSS_V5) {
+        // Source for overlay will be the cropped (and rotated)
+        crop.left = 0;
+        crop.top = 0;
+        crop.right = srcCrop.w;
+        crop.bottom = srcCrop.h;
+        // Set width & height equal to sourceCrop w & h
+        whf.w = srcCrop.w;
+        whf.h = srcCrop.h;
+    } else {
+        crop.left = srcCrop.x;
+        crop.top = srcCrop.y;
+        crop.right = srcCrop.x + srcCrop.w;
+        crop.bottom = srcCrop.y + srcCrop.h;
+    }
 }
 
 int configureLowRes(hwc_context_t *ctx, hwc_layer_1_t *layer,
@@ -739,8 +760,10 @@
         *rot = ctx->mRotMgr->getNext();
         if(*rot == NULL) return -1;
         //Configure rotator for pre-rotation
-        if(configRotator(*rot, whf, mdpFlags, orient, downscale) < 0)
+        if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
+            ALOGE("%s: configRotator failed!", __FUNCTION__);
             return -1;
+        }
         whf.format = (*rot)->getDstFormat();
         updateSource(orient, whf, crop);
         rotFlags |= ovutils::ROT_PREROTATED;
@@ -789,8 +812,10 @@
         (*rot) = ctx->mRotMgr->getNext();
         if((*rot) == NULL) return -1;
         //Configure rotator for pre-rotation
-        if(configRotator(*rot, whf, mdpFlagsL, orient, downscale) < 0)
+        if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
+            ALOGE("%s: configRotator failed!", __FUNCTION__);
             return -1;
+        }
         whf.format = (*rot)->getDstFormat();
         updateSource(orient, whf, crop);
         rotFlags |= ROT_PREROTATED;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index d4f5d94..e0fff77 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -273,6 +273,8 @@
     mutable Locker mExtSetLock;
     //Vsync
     struct vsync_state vstate;
+    //Drawing round when we use GPU
+    bool isPaddingRound;
 };
 
 namespace qhwc {
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index 3563cbc..8aca0f6 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -124,6 +124,16 @@
     return dest;
 }
 
+bool Overlay::isPipeTypeAttached(eMdpPipeType type) {
+    for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+        if(type == PipeBook::getPipeType((eDest)i) &&
+                mPipeBook[i].mDisplay != PipeBook::DPY_UNUSED) {
+            return true;
+        }
+    }
+    return false;
+}
+
 bool Overlay::commit(utils::eDest dest) {
     bool ret = false;
     int index = (int)dest;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 0cedac9..bf85b70 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -78,6 +78,10 @@
     static Overlay* getInstance();
     /* Returns available ("unallocated") pipes for a display */
     int availablePipes(int dpy);
+    /* Returns if any of the requested pipe type is attached to any of the
+     * displays
+     */
+    bool isPipeTypeAttached(utils::eMdpPipeType type);
     /* set the framebuffer index for external display */
     void setExtFbNum(int fbNum);
     /* Returns framebuffer index of the current external display */
diff --git a/liboverlay/overlayMdpRot.cpp b/liboverlay/overlayMdpRot.cpp
index 81a3f44..ce2ef5b 100755
--- a/liboverlay/overlayMdpRot.cpp
+++ b/liboverlay/overlayMdpRot.cpp
@@ -94,6 +94,10 @@
     mRotImgInfo.dst.height = whf.h;
 }
 
+void MdpRot::setCrop(const utils::Dim& crop) {
+    // NO-OP for non-mdss rotator due to possible h/w limitations
+}
+
 void MdpRot::setFlags(const utils::eMdpFlags& flags) {
     mRotImgInfo.secure = 0;
     if(flags & utils::OV_MDP_SECURE_OVERLAY_SESSION)
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index 58790fc..1fabdca 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -74,15 +74,21 @@
     utils::Whf whf(awhf);
 
     mRotInfo.src.format = whf.format;
-
     mRotInfo.src.width = whf.w;
     mRotInfo.src.height = whf.h;
+}
 
-    mRotInfo.src_rect.w = whf.w;
-    mRotInfo.src_rect.h = whf.h;
+void MdssRot::setCrop(const utils::Dim& crop) {
 
-    mRotInfo.dst_rect.w = whf.w;
-    mRotInfo.dst_rect.h = whf.h;
+    mRotInfo.src_rect.x = crop.x;
+    mRotInfo.src_rect.y = crop.y;
+    mRotInfo.src_rect.w = crop.w;
+    mRotInfo.src_rect.h = crop.h;
+
+    mRotInfo.dst_rect.x = 0;
+    mRotInfo.dst_rect.y = 0;
+    mRotInfo.dst_rect.w = crop.w;
+    mRotInfo.dst_rect.h = crop.h;
 }
 
 void MdssRot::setDownscale(int ds) {}
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index 36fe581..c02dfba 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -44,6 +44,7 @@
     enum { TYPE_MDP, TYPE_MDSS };
     virtual ~Rotator();
     virtual void setSource(const utils::Whf& wfh) = 0;
+    virtual void setCrop(const utils::Dim& crop) = 0;
     virtual void setFlags(const utils::eMdpFlags& flags) = 0;
     virtual void setTransform(const utils::eTransform& rot) = 0;
     virtual bool commit() = 0;
@@ -109,6 +110,7 @@
 public:
     virtual ~MdpRot();
     virtual void setSource(const utils::Whf& wfh);
+    virtual void setCrop(const utils::Dim& crop);
     virtual void setFlags(const utils::eMdpFlags& flags);
     virtual void setTransform(const utils::eTransform& rot);
     virtual bool commit();
@@ -167,6 +169,7 @@
 public:
     virtual ~MdssRot();
     virtual void setSource(const utils::Whf& wfh);
+    virtual void setCrop(const utils::Dim& crop);
     virtual void setFlags(const utils::eMdpFlags& flags);
     virtual void setTransform(const utils::eTransform& rot);
     virtual bool commit();