Merge "hwc: Add target specific checks in hwcomposer"
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 9f95667..a69e6ee 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -547,6 +547,71 @@
     size = getSize(format, width, height, alignedw, alignedh);
 }
 
+int getYUVPlaneInfo(private_handle_t* hnd, struct android_ycbcr* ycbcr)
+{
+    int err = 0;
+    size_t ystride, cstride;
+    memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
+
+    // Get the chroma offsets from the handle width/height. We take advantage
+    // of the fact the width _is_ the stride
+    switch (hnd->format) {
+        //Semiplanar
+        case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+        case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+        case HAL_PIXEL_FORMAT_NV12_ENCODEABLE: //Same as YCbCr_420_SP_VENUS
+            ystride = hnd->width;
+            cstride = hnd->width/2;
+            ycbcr->y  = (void*)hnd->base;
+            ycbcr->cb = (void*)(hnd->base + ystride * hnd->height);
+            ycbcr->cr = (void*)(hnd->base + ystride * hnd->height + 1);
+            ycbcr->ystride = ystride;
+            ycbcr->cstride = cstride;
+            ycbcr->chroma_step = 2;
+        break;
+
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+        case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
+        case HAL_PIXEL_FORMAT_NV21_ZSL:
+        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+            ystride = hnd->width;
+            cstride = hnd->width/2;
+            ycbcr->y  = (void*)hnd->base;
+            ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
+            ycbcr->cb = (void*)(hnd->base + ystride * hnd->height + 1);
+            ycbcr->ystride = ystride;
+            ycbcr->cstride = cstride;
+            ycbcr->chroma_step = 2;
+        break;
+
+        //Planar
+        case HAL_PIXEL_FORMAT_YV12:
+            ystride = hnd->width;
+            cstride = hnd->width/2;
+            ycbcr->y  = (void*)hnd->base;
+            ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
+            ycbcr->cb = (void*)(hnd->base + ystride * hnd->height +
+                    cstride * hnd->height/2);
+            ycbcr->ystride = ystride;
+            ycbcr->cstride = cstride;
+            ycbcr->chroma_step = 1;
+
+        break;
+        //Unsupported formats
+        case HAL_PIXEL_FORMAT_YCbCr_422_I:
+        case HAL_PIXEL_FORMAT_YCrCb_422_I:
+        case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+        default:
+        ALOGD("%s: Invalid format passed: 0x%x", __FUNCTION__,
+                hnd->format);
+        err = -EINVAL;
+    }
+    return err;
+
+}
+
 
 
 // Allocate buffer from width, height and format into a
diff --git a/libgralloc/gr.h b/libgralloc/gr.h
index fbde8c2..32f3256 100644
--- a/libgralloc/gr.h
+++ b/libgralloc/gr.h
@@ -69,6 +69,7 @@
 // It is the responsibility of the caller to free the buffer
 int alloc_buffer(private_handle_t **pHnd, int w, int h, int format, int usage);
 void free_buffer(private_handle_t *hnd);
+int getYUVPlaneInfo(private_handle_t* pHnd, struct android_ycbcr* ycbcr);
 
 /*****************************************************************************/
 
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index b2714c5..8704354 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -82,6 +82,7 @@
     GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_AND_HEIGHT_FROM_HANDLE,
     GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES,
     GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE,
+    GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO,
 };
 
 #define GRALLOC_HEAP_MASK   (GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |\
diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp
index c419da6..4adc67d 100644
--- a/libgralloc/mapper.cpp
+++ b/libgralloc/mapper.cpp
@@ -259,28 +259,8 @@
 {
     private_handle_t* hnd = (private_handle_t*)handle;
     int err = gralloc_map_and_invalidate(module, handle, usage);
-    size_t ystride, cstride;
-    if(!err) {
-        //hnd->format holds our implementation defined format
-        //HAL_PIXEL_FORMAT_YCrCb_420_SP is the only one set right now.
-        switch (hnd->format) {
-            case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-                ystride = ALIGN(hnd->width, 16);
-                cstride = ALIGN(hnd->width, 16)/2;
-                ycbcr->y  = (void*)hnd->base;
-                ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
-                ycbcr->cb = (void*)(hnd->base + ystride * hnd->height + 1);
-                ycbcr->ystride = ystride;
-                ycbcr->cstride = cstride;
-                ycbcr->chroma_step = 2;
-                memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
-                break;
-            default:
-                ALOGD("%s: Invalid format passed: 0x%x", __FUNCTION__,
-                      hnd->format);
-                err = -EINVAL;
-        }
-    }
+    if(!err)
+        err = getYUVPlaneInfo(hnd, ycbcr);
     return err;
 }
 
@@ -447,6 +427,15 @@
                     res = 0;
                 }
             } break;
+        case GRALLOC_MODULE_PERFORM_GET_YUV_PLANE_INFO:
+            {
+                private_handle_t* hnd =  va_arg(args, private_handle_t*);
+                android_ycbcr* ycbcr = va_arg(args, struct android_ycbcr *);
+                if (private_handle_t::validate(hnd)) {
+                    res = getYUVPlaneInfo(hnd, ycbcr);
+                }
+            } break;
+
         default:
             break;
     }
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index aa7a187..a2c7ad3 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -260,6 +260,48 @@
     }
 }
 
+static bool optimizePrepare(hwc_context_t *ctx, int numDisplays,
+                            hwc_display_contents_1_t** displays) {
+
+    /* Do not re-program H/W, if frame geometry has not changed.
+     * But honor these exceptions:
+     * 1. Padding round
+     * 2. Idle fallback
+     * 3. Overlay is not configured
+     * 4. External/Virtual display is in Configure state
+     * 5. External/Virtual is Paused OR not connected/active
+     * 6. Non-Overlay device
+     */
+
+    if (ctx->isPaddingRound || MDPComp::isIdleFallback() ||
+        !ctx->mOverlay->isConfigured() || isSecondaryConfiguring(ctx) ||
+        ctx->mMDP.version < qdutils::MDP_V4_0) {
+        return false;
+    }
+
+    bool isOptimized = false;
+    for (uint32_t i = 0; i < numDisplays; i++) {
+        hwc_display_contents_1_t *list = displays[i];
+
+        if (list) {
+            if (list->flags & HWC_GEOMETRY_CHANGED) {
+                return false;
+            }
+            int dpy = getDpyforExternalDisplay(ctx, i);
+            if (dpy && (ctx->dpyAttr[dpy].isPause ||
+                !ctx->dpyAttr[dpy].connected ||
+                !ctx->dpyAttr[dpy].isActive)) {
+                return false;
+            }
+            // Set layer composition type as per last frame
+            ctx->mMDPComp[dpy]->setMDPCompLayerFlags(ctx, list);
+            isOptimized = true;
+        }
+    }
+
+    return isOptimized;
+}
+
 static int hwc_prepare_primary(hwc_composer_device_1 *dev,
         hwc_display_contents_1_t *list) {
     ATRACE_CALL();
@@ -279,7 +321,10 @@
 
         if (fbComp) {
             const int fbZ = 0;
-            ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
+            if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ)) {
+                ctx->mOverlay->clear(dpy);
+                ctx->mLayerRotMap[dpy]->clear();
+            }
         }
 
         if (ctx->mMDP.version < qdutils::MDP_V4_0) {
@@ -306,7 +351,11 @@
             setListStats(ctx, list, dpy);
             if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
                 const int fbZ = 0;
-                ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
+                if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
+                {
+                    ctx->mOverlay->clear(dpy);
+                    ctx->mLayerRotMap[dpy]->clear();
+                }
             }
         } else {
             /* External Display is in Pause state.
@@ -338,6 +387,12 @@
     setPaddingRound(ctx,numDisplays,displays);
     setDMAState(ctx,numDisplays,displays);
     setNumActiveDisplays(ctx,numDisplays,displays);
+
+    if (optimizePrepare(ctx, numDisplays, displays)) {
+        // Do not re-program H/W, if it is not needed
+        return ret;
+    }
+
     reset(ctx, (int)numDisplays, displays);
 
     ctx->mOverlay->configBegin();
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 0843da4..d7afa19 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -158,7 +158,10 @@
     //framebuffers
 
     if ( updatingLayerCount ==  1 ) {
-       hwc_rect_t dirtyRect =list->hwLayers[changingLayerIndex].dirtyRect;
+       hwc_rect_t dirtyRect = list->hwLayers[changingLayerIndex].displayFrame;
+#ifdef QCOM_BSP
+       dirtyRect = list->hwLayers[changingLayerIndex].dirtyRect;
+#endif
 
        for (int k = ctx->listStats[dpy].numAppLayers-1; k >= 0 ; k--){
             //disable swap rect for overlapping visible layer(s)
@@ -379,7 +382,11 @@
     mDirtyLayerIndex =  checkDirtyRect(ctx, list, dpy);
     if( mDirtyLayerIndex != -1){
           hwc_layer_1_t *layer = &list->hwLayers[mDirtyLayerIndex];
+#ifdef QCOM_BSP
           clear(renderBuffer,layer->dirtyRect);
+#else
+          clear(renderBuffer,layer->displayFrame);
+#endif
     } else {
           hwc_rect_t clearRegion = {0,0,0,0};
           if(CBUtils::getuiClearRegion(list, clearRegion, layerProp))
@@ -509,6 +516,7 @@
     copybit_rect_t dstRect = {displayFrame.left, displayFrame.top,
                               displayFrame.right,
                               displayFrame.bottom};
+#ifdef QCOM_BSP
     //change src and dst with dirtyRect
     if(mDirtyLayerIndex != -1) {
       srcRect.l = layer->dirtyRect.left;
@@ -517,6 +525,7 @@
       srcRect.b = layer->dirtyRect.bottom;
       dstRect = srcRect;
     }
+#endif
     // Copybit dst
     copybit_image_t dst;
     dst.w = ALIGN(fbHandle->width,32);
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 0374dec..a58ea07 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -208,8 +208,6 @@
                 sourceCrop, mdpFlags, rotFlags);
         if(!ret) {
             ALOGE("%s: preRotate for external Failed!", __FUNCTION__);
-            ctx->mOverlay->clear(mDpy);
-            ctx->mLayerRotMap[mDpy]->clear();
             return false;
         }
         //For the mdp, since either we are pre-rotating or MDP does flips
@@ -224,7 +222,6 @@
         if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
                     NULL, mDest) < 0) {
             ALOGE("%s: configMdp failed for dpy %d", __FUNCTION__, mDpy);
-            ctx->mLayerRotMap[mDpy]->clear();
             ret = false;
         }
     }
@@ -387,10 +384,6 @@
                 ret = false;
             }
         }
-
-        if(ret == false) {
-            ctx->mLayerRotMap[mDpy]->clear();
-        }
     }
     return ret;
 }
@@ -425,7 +418,6 @@
 
 bool FBSrcSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
         hwc_rect_t fbUpdatingRect, int fbZorder) {
-    bool ret = false;
     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
     int extOnlyLayerIndex = ctx->listStats[mDpy].extOnlyLayerIndex;
     // ext only layer present..
@@ -502,7 +494,6 @@
         if(configMdp(ctx->mOverlay, parg, orient,
                     cropL, cropL, NULL /*metadata*/, destL) < 0) {
             ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
-            ctx->mLayerRotMap[mDpy]->clear();
             return false;
         }
     }
@@ -512,7 +503,6 @@
         if(configMdp(ctx->mOverlay, parg, orient,
                     cropR, cropR, NULL /*metadata*/, destR) < 0) {
             ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
-            ctx->mLayerRotMap[mDpy]->clear();
             return false;
         }
     }
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index d008147..581f57c 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -479,43 +479,44 @@
     return true;
 }
 
+bool MDPComp::canDoPartialUpdate(hwc_context_t *ctx,
+                               hwc_display_contents_1_t* list){
+    if(!qdutils::MDPVersion::getInstance().isPartialUpdateEnabled() || mDpy ||
+       isSkipPresent(ctx, mDpy) || (list->flags & HWC_GEOMETRY_CHANGED)||
+       isDisplaySplit(ctx, mDpy)) {
+        return false;
+    }
+    return true;
+}
+
 void MDPComp::generateROI(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     int numAppLayers = ctx->listStats[mDpy].numAppLayers;
 
-    if(!sEnablePartialFrameUpdate) {
-        return;
-    }
-
-    if(mDpy || isDisplaySplit(ctx, mDpy)){
-        ALOGE_IF(isDebug(), "%s: ROI not supported for"
-                 "the (1) external / virtual display's (2) dual DSI displays",
-                 __FUNCTION__);
-        return;
-    }
-
-    if(isSkipPresent(ctx, mDpy))
-        return;
-
-    if(list->flags & HWC_GEOMETRY_CHANGED)
+    if(!canDoPartialUpdate(ctx, list))
         return;
 
     struct hwc_rect roi = (struct hwc_rect){0, 0, 0, 0};
     for(int index = 0; index < numAppLayers; index++ ) {
-        if ((mCachedFrame.hnd[index] != list->hwLayers[index].handle) ||
-            isYuvBuffer((private_handle_t *)list->hwLayers[index].handle)) {
-            hwc_rect_t dstRect = list->hwLayers[index].displayFrame;
-            hwc_rect_t srcRect = integerizeSourceCrop(
-                                        list->hwLayers[index].sourceCropf);
-
-            /* Intersect against display boundaries */
-            roi = getUnion(roi, dstRect);
+        hwc_layer_1_t* layer = &list->hwLayers[index];
+        if ((mCachedFrame.hnd[index] != layer->handle) ||
+            isYuvBuffer((private_handle_t *)layer->handle)) {
+            hwc_rect_t updatingRect = layer->displayFrame;
+#ifdef QCOM_BSP
+            if(!needsScaling(layer))
+                updatingRect =  layer->dirtyRect;
+#endif
+            roi = getUnion(roi, updatingRect);
         }
     }
 
-    if(!validateAndApplyROI(ctx, list, roi)){
-        roi = (struct hwc_rect) {0, 0,
-                    (int)ctx->dpyAttr[mDpy].xres, (int)ctx->dpyAttr[mDpy].yres};
-    }
+    hwc_rect fullFrame = (struct hwc_rect) {0, 0,(int)ctx->dpyAttr[mDpy].xres,
+        (int)ctx->dpyAttr[mDpy].yres};
+
+    // Align ROI coordinates to panel restrictions
+    roi = sanitizeROI(roi, fullFrame);
+
+    if(!validateAndApplyROI(ctx, list, roi))
+        roi = fullFrame;
 
     ctx->listStats[mDpy].roi.x = roi.left;
     ctx->listStats[mDpy].roi.y = roi.top;
@@ -616,15 +617,6 @@
             ALOGD_IF(isDebug(), "%s: Unsupported layer in list",__FUNCTION__);
             return false;
         }
-
-        //For 8x26, if there is only one layer which needs scale for secondary
-        //while no scale for primary display, DMA pipe is occupied by primary.
-        //If need to fall back to GLES composition, virtual display lacks DMA
-        //pipe and error is reported.
-        if(qdutils::MDPVersion::getInstance().is8x26() &&
-                                mDpy >= HWC_DISPLAY_EXTERNAL &&
-                                qhwc::needsScaling(layer))
-            return false;
     }
 
     mCurrentFrame.fbCount = 0;
@@ -1412,6 +1404,7 @@
                 ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres > 1024);
         pipeSpecs.dpy = mDpy;
         pipeSpecs.fb = false;
+        pipeSpecs.numActiveDisplays = ctx->numActiveDisplays;
 
         pipe_info.index = ctx->mOverlay->getPipe(pipeSpecs);
 
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index beb858b..7d4214a 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -54,6 +54,9 @@
     static void resetIdleFallBack() { sIdleFallBack = false; }
     static void reset() { sHandleTimeout = false; };
     static bool isIdleFallback() { return sIdleFallBack; }
+    /* set/reset flags for MDPComp */
+    void setMDPCompLayerFlags(hwc_context_t *ctx,
+                              hwc_display_contents_1_t* list);
 
 protected:
     enum { MAX_SEC_LAYERS = 1 }; //TODO add property support
@@ -142,9 +145,6 @@
     /* configures 4kx2k yuv layer*/
     virtual int configure4k2kYuv(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);
     void setRedraw(hwc_context_t *ctx,
             hwc_display_contents_1_t* list);
     /* checks for conditions where mdpcomp is not possible */
@@ -213,6 +213,7 @@
     bool isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer);
     bool resourceCheck();
     hwc_rect_t getUpdatingFBRect(hwc_display_contents_1_t* list);
+    bool canDoPartialUpdate(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 efeff98..699db24 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -1177,6 +1177,11 @@
                      layer->sourceCropf.top = (float)bottomCrop.top;
                      layer->sourceCropf.right = (float)bottomCrop.right;
                      layer->sourceCropf.bottom = (float)bottomCrop.bottom;
+#ifdef QCOM_BSP
+                     //Update layer dirtyRect
+                     layer->dirtyRect = getIntersection(bottomCrop,
+                                            layer->dirtyRect);
+#endif
                   }
                }
                j--;
@@ -2157,4 +2162,58 @@
     }
 }
 
+hwc_rect_t sanitizeROI(struct hwc_rect roi, hwc_rect boundary)
+{
+   if(!isValidRect(roi))
+      return roi;
+
+   struct hwc_rect t_roi = roi;
+
+   const int LEFT_ALIGN = qdutils::MDPVersion::getInstance().getLeftAlign();
+   const int WIDTH_ALIGN = qdutils::MDPVersion::getInstance().getWidthAlign();
+   const int TOP_ALIGN = qdutils::MDPVersion::getInstance().getTopAlign();
+   const int HEIGHT_ALIGN = qdutils::MDPVersion::getInstance().getHeightAlign();
+   const int MIN_WIDTH = qdutils::MDPVersion::getInstance().getMinROIWidth();
+
+   /* Align to minimum width recommended by the panel */
+   if((t_roi.right - t_roi.left) < MIN_WIDTH) {
+       if((t_roi.left + MIN_WIDTH) > boundary.right)
+           t_roi.left = t_roi.right - MIN_WIDTH;
+       else
+           t_roi.right = t_roi.left + MIN_WIDTH;
+   }
+
+   /* Align left and width to meet panel restrictions */
+   if(WIDTH_ALIGN) {
+       int width = t_roi.right - t_roi.left;
+       width = WIDTH_ALIGN * ((width + (WIDTH_ALIGN - 1)) / WIDTH_ALIGN);
+       t_roi.right = t_roi.left + width;
+
+       if(t_roi.right > boundary.right) {
+           t_roi.right = boundary.right;
+           t_roi.left = t_roi.right - width;
+       }
+   }
+
+   if(LEFT_ALIGN)
+       t_roi.left = t_roi.left - (t_roi.left % LEFT_ALIGN);
+
+   /* Align top and height to meet panel restrictions */
+   if(HEIGHT_ALIGN) {
+       int height = t_roi.bottom - t_roi.top;
+       height = HEIGHT_ALIGN *  ((height + (HEIGHT_ALIGN - 1)) / HEIGHT_ALIGN);
+       t_roi.bottom = t_roi.top  + height;
+
+       if(t_roi.bottom > boundary.bottom) {
+           t_roi.bottom = boundary.bottom;
+           t_roi.top = t_roi.bottom - height;
+       }
+   }
+
+   if(TOP_ALIGN)
+       t_roi.top = t_roi.top - (t_roi.top % TOP_ALIGN);
+
+   return t_roi;
+}
+
 };//namespace qhwc
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 6fe993a..6f527aa 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -295,6 +295,9 @@
 /* Get External State names */
 const char* getExternalDisplayState(uint32_t external_state);
 
+// Aligns updating ROI to panel restrictions
+hwc_rect_t sanitizeROI(struct hwc_rect roi, hwc_rect boundary);
+
 // Handles wfd Pause and resume events
 void handle_pause(hwc_context_t *ctx, int dpy);
 void handle_resume(hwc_context_t *ctx, int dpy);
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
index 10ed9d1..97b19ea 100644
--- a/libhwcomposer/hwc_virtual.cpp
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -126,7 +126,11 @@
 
             if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
                 const int fbZ = 0;
-                ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
+                if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
+                {
+                    ctx->mOverlay->clear(dpy);
+                    ctx->mLayerRotMap[dpy]->clear();
+                }
             }
         } else {
             /* Virtual Display is in Pause state.
@@ -260,7 +264,11 @@
             setListStats(ctx, list, dpy);
             if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
                 const int fbZ = 0;
-                ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ);
+                if(not ctx->mFBUpdate[dpy]->prepareAndValidate(ctx, list, fbZ))
+                {
+                    ctx->mOverlay->clear(dpy);
+                    ctx->mLayerRotMap[dpy]->clear();
+                }
             }
         } else {
             /* Virtual Display is in Pause state.
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index f4b0ecc..d53b46d 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -203,7 +203,9 @@
     if(pipeSpecs.formatClass == FORMAT_YUV) { //video
         return nextPipe(OV_MDP_PIPE_VG, pipeSpecs.dpy, pipeSpecs.mixer);
     } else if(pipeSpecs.fb == false) { //RGB app layers
-        if(not pipeSpecs.needsScaling) {
+        if((not pipeSpecs.needsScaling) and
+          (not (pipeSpecs.numActiveDisplays > 1 &&
+                pipeSpecs.dpy == DPY_PRIMARY))) {
             dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs.dpy, pipeSpecs.mixer);
         }
         if(dest == OV_INVALID) {
@@ -220,7 +222,9 @@
                 dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs.dpy, pipeSpecs.mixer);
             }
         }
-        if(dest == OV_INVALID and (not pipeSpecs.needsScaling)) {
+        if(dest == OV_INVALID and (not pipeSpecs.needsScaling) and
+          (not (pipeSpecs.numActiveDisplays > 1 &&
+                pipeSpecs.dpy == DPY_PRIMARY))) {
             dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs.dpy, pipeSpecs.mixer);
         }
     }
@@ -233,23 +237,15 @@
     eDest dest = OV_INVALID;
     if(pipeSpecs.formatClass == FORMAT_YUV or pipeSpecs.needsScaling) {
         return nextPipe(OV_MDP_PIPE_VG, pipeSpecs.dpy, pipeSpecs.mixer);
-    } else if(pipeSpecs.fb == false) { //RGB app layers
+    } else {
         //Since this is a specific func, we can assume stuff like RGB pipe not
         //having scalar blocks
         dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs.dpy, pipeSpecs.mixer);
         if(dest == OV_INVALID) {
             dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs.dpy, pipeSpecs.mixer);
         }
-    } else {
-        //For 8x16 Secondary we use DMA always for FB for inline rotation
-        if(pipeSpecs.dpy == DPY_PRIMARY) {
-            dest = nextPipe(OV_MDP_PIPE_RGB, pipeSpecs.dpy, pipeSpecs.mixer);
-            if(dest == OV_INVALID) {
-                dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs.dpy, pipeSpecs.mixer);
-            }
-        }
         if(dest == OV_INVALID) {
-            dest = nextPipe(OV_MDP_PIPE_DMA, pipeSpecs.dpy, pipeSpecs.mixer);
+            dest = nextPipe(OV_MDP_PIPE_VG, pipeSpecs.dpy, pipeSpecs.mixer);
         }
     }
     return dest;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 0b785d5..17c75e8 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -57,12 +57,13 @@
 
     struct PipeSpecs {
         PipeSpecs() : formatClass(FORMAT_RGB), needsScaling(false), fb(false),
-                dpy(DPY_PRIMARY), mixer(MIXER_DEFAULT) {}
+                dpy(DPY_PRIMARY), mixer(MIXER_DEFAULT), numActiveDisplays(1) {}
         int formatClass;
         bool needsScaling;
         bool fb;
         int dpy;
         int mixer;
+        int numActiveDisplays;
     };
 
     /* dtor close */
@@ -139,6 +140,8 @@
     void clear(int dpy);
     /* Validate the set of pipes for a display and set them in driver */
     bool validateAndSet(const int& dpy, const int& fbFd);
+    /* Returns true if PipeBook has been configured, false otherwise */
+    bool isConfigured();
 
     /* Closes open pipes, called during startup */
     static int initOverlay();
@@ -203,6 +206,7 @@
         static void resetAllocation(int index);
         static bool isAllocated(int index);
         static bool isNotAllocated(int index);
+        static bool isConfigured();
 
         static utils::eMdpPipeType getPipeType(utils::eDest dest);
         static const char* getDestStr(utils::eDest dest);
@@ -405,6 +409,14 @@
     return "Invalid";
 }
 
+inline bool Overlay::PipeBook::isConfigured() {
+    return (sAllocatedBitmap != 0);
+}
+
+inline bool Overlay::isConfigured() {
+    return PipeBook::isConfigured();
+}
+
 }; // overlay
 
 #endif // OVERLAY_H