Merge "hwc: Call blank IOCTL on virtual as well if it is connected."
diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp
index da0396f..771d483 100644
--- a/libcopybit/copybit_c2d.cpp
+++ b/libcopybit/copybit_c2d.cpp
@@ -257,6 +257,7 @@
 static int get_format(int format) {
     switch (format) {
         case HAL_PIXEL_FORMAT_RGB_565:        return C2D_COLOR_FORMAT_565_RGB;
+        case HAL_PIXEL_FORMAT_RGB_888:        return C2D_COLOR_FORMAT_888_RGB;
         case HAL_PIXEL_FORMAT_RGBX_8888:      return C2D_COLOR_FORMAT_8888_ARGB |
                                               C2D_FORMAT_SWAP_RB |
                                                   C2D_FORMAT_DISABLE_ALPHA;
@@ -315,6 +316,9 @@
         case C2D_COLOR_FORMAT_8888_ARGB:
             c2dBpp = 32;
             break;
+        case C2D_COLOR_FORMAT_888_RGB:
+            c2dBpp = 24;
+            break;
         case C2D_COLOR_FORMAT_8_L:
         case C2D_COLOR_FORMAT_8_A:
             c2dBpp = 8;
@@ -396,6 +400,7 @@
     switch(format) {
         case HAL_PIXEL_FORMAT_RGBA_8888:
         case HAL_PIXEL_FORMAT_RGBX_8888:
+        case HAL_PIXEL_FORMAT_RGB_888:
         case HAL_PIXEL_FORMAT_RGB_565:
         case HAL_PIXEL_FORMAT_BGRA_8888: {
             return COPYBIT_SUCCESS;
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index a69e6ee..1702336 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -271,7 +271,12 @@
 //-------------- IonController-----------------------//
 IonController::IonController()
 {
-    mIonAlloc = new IonAlloc();
+    allocateIonMem();
+}
+
+void IonController::allocateIonMem()
+{
+   mIonAlloc = new IonAlloc();
 }
 
 int IonController::allocate(alloc_data& data, int usage)
diff --git a/libgralloc/alloc_controller.h b/libgralloc/alloc_controller.h
index 5fe81fa..f0b8ed9 100644
--- a/libgralloc/alloc_controller.h
+++ b/libgralloc/alloc_controller.h
@@ -65,6 +65,7 @@
 
     private:
     IonAlloc* mIonAlloc;
+    void allocateIonMem();
 
 };
 } //end namespace gralloc
diff --git a/libgralloc/gralloc.cpp b/libgralloc/gralloc.cpp
index 6b41ce6..c1c61aa 100644
--- a/libgralloc/gralloc.cpp
+++ b/libgralloc/gralloc.cpp
@@ -105,6 +105,9 @@
         gpu_context_t *dev;
         IAllocController* alloc_ctrl = IAllocController::getInstance();
         dev = new gpu_context_t(m, alloc_ctrl);
+        if(!dev)
+            return status;
+
         *device = &dev->common;
         status = 0;
     } else {
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 83966b8..37958f7 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -551,7 +551,8 @@
         if(ctx->mMDP.hasOverlay) {
             supported |= HWC_DISPLAY_VIRTUAL_BIT;
             if(!(qdutils::MDPVersion::getInstance().is8x26() ||
-                        qdutils::MDPVersion::getInstance().is8x16()))
+                        qdutils::MDPVersion::getInstance().is8x16() ||
+                        qdutils::MDPVersion::getInstance().is8x39()))
                 supported |= HWC_DISPLAY_EXTERNAL_BIT;
         }
         value[0] = supported;
@@ -607,8 +608,20 @@
             }
         }
 
-        if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd,
-                                            ctx->listStats[dpy].roi)) {
+        int lSplit = getLeftSplit(ctx, dpy);
+        qhwc::ovutils::Dim lRoi = qhwc::ovutils::Dim {
+            ctx->listStats[dpy].lRoi.left,
+            ctx->listStats[dpy].lRoi.top,
+            ctx->listStats[dpy].lRoi.right - ctx->listStats[dpy].lRoi.left,
+            ctx->listStats[dpy].lRoi.bottom - ctx->listStats[dpy].lRoi.top };
+
+        qhwc::ovutils::Dim rRoi = qhwc::ovutils::Dim {
+            ctx->listStats[dpy].rRoi.left - lSplit,
+            ctx->listStats[dpy].rRoi.top,
+            ctx->listStats[dpy].rRoi.right - ctx->listStats[dpy].rRoi.left,
+            ctx->listStats[dpy].rRoi.bottom - ctx->listStats[dpy].rRoi.top };
+
+        if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd, lRoi, rRoi)) {
             ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
             ret = -1;
         }
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index fdf6e67..49e7e2a 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -41,37 +41,6 @@
 using namespace overlay::utils;
 namespace qhwc {
 
-//Opens writeback framebuffer and returns fd.
-static int openWbFb() {
-    int wbFd = -1;
-    //Check opening which FB would connect LM to WB
-    const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
-    if(wbFbNum >= 0) {
-        char wbFbPath[256];
-        snprintf (wbFbPath, sizeof(wbFbPath),
-                "/sys/class/graphics/fb%d", wbFbNum);
-        //Opening writeback fb first time would create ad node if the device
-        //supports adaptive display
-        wbFd = open(wbFbPath, O_RDONLY);
-        if(wbFd < 0) {
-            ALOGE("%s: Failed to open /sys/class/graphics/fb%d with error %s",
-                    __func__, wbFbNum, strerror(errno));
-        }
-    } else {
-        ALOGD_IF(DEBUG, "%s: No writeback available", __func__);
-    }
-    return wbFd;
-}
-
-static inline void closeWbFb(int& fd) {
-    if(fd >= 0) {
-        close(fd);
-        fd = -1;
-    } else {
-        ALOGE("%s: Invalid fd %d", __func__, fd);
-    }
-}
-
 //Helper to write data to ad node
 static void adWrite(const int& value) {
     const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
@@ -124,32 +93,31 @@
     return ret;
 }
 
-AssertiveDisplay::AssertiveDisplay(hwc_context_t *ctx) : mWbFd(-1),
-        mDoable(false), mFeatureEnabled(false),
-        mDest(overlay::utils::OV_INVALID) {
-    int fd = openWbFb();
-    if(fd >= 0) {
-        //Values in ad node:
-        //-1 means feature is disabled on device
-        // 0 means feature exists but turned off, will be turned on by hwc
-        // 1 means feature is turned on by hwc
-        // Plus, we do this feature only on split primary displays.
-        // Plus, we do this feature only if ro.qcom.ad=2
+AssertiveDisplay::AssertiveDisplay(hwc_context_t *ctx) :
+     mTurnedOff(true), mFeatureEnabled(false),
+     mDest(overlay::utils::OV_INVALID)
+{
+    //Values in ad node:
+    //-1 means feature is disabled on device
+    // 0 means feature exists but turned off, will be turned on by hwc
+    // 1 means feature is turned on by hwc
+    // Plus, we do this feature only on split primary displays.
+    // Plus, we do this feature only if ro.qcom.ad=2
 
-        char property[PROPERTY_VALUE_MAX];
-        const int ENABLED = 2;
-        int val = 0;
+    char property[PROPERTY_VALUE_MAX];
+    const int ENABLED = 2;
+    int val = 0;
 
-        if(property_get("ro.qcom.ad", property, "0") > 0) {
-            val = atoi(property);
-        }
+    if(property_get("ro.qcom.ad", property, "0") > 0) {
+        val = atoi(property);
+    }
 
-        if(adRead() >= 0 && isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY) &&
-                val == ENABLED) {
-            ALOGD_IF(DEBUG, "Assertive display feature supported");
-            mFeatureEnabled = true;
-        }
-        closeWbFb(fd);
+    if(adRead() >= 0 && isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY) &&
+            val == ENABLED) {
+        ALOGD_IF(DEBUG, "Assertive display feature supported");
+        mFeatureEnabled = true;
+        // If feature exists but is turned off, set mTurnedOff to true
+        mTurnedOff = adRead() > 0 ? false : true;
     }
 }
 
@@ -168,17 +136,24 @@
     }
 }
 
+void AssertiveDisplay::turnOffAD() {
+    if(mFeatureEnabled) {
+        if(!mTurnedOff) {
+            const int off = 0;
+            adWrite(off);
+            mTurnedOff = true;
+        }
+    }
+    mDoable = false;
+}
+
 bool AssertiveDisplay::prepare(hwc_context_t *ctx,
         const hwc_rect_t& crop,
         const Whf& whf,
         const private_handle_t *hnd) {
     if(!isDoable()) {
-        if(isModeOn()) {
-            //Cleanup one time during this switch
-            const int off = 0;
-            adWrite(off);
-            closeWbFb(mWbFd);
-        }
+        //Cleanup one time during this switch
+        turnOffAD();
         return false;
     }
 
@@ -246,27 +221,30 @@
     }
 
     mDest = dest;
-    if(!isModeOn()) {
-        mWbFd = openWbFb();
-        if(mWbFd >= 0) {
-            //write to sysfs, one time during this switch
-            const int on = 1;
-            adWrite(on);
-        }
-    }
-
-    if(!ctx->mOverlay->validateAndSet(overlay::Overlay::DPY_WRITEBACK,
-            mWbFd)) {
+    int wbFd = wb->getFbFd();
+    if(mFeatureEnabled && wbFd >= 0 &&
+        !ctx->mOverlay->validateAndSet(overlay::Overlay::DPY_WRITEBACK, wbFd))
+    {
         ALOGE("%s: Failed to validate and set overlay for dpy %d"
                 ,__FUNCTION__, overlay::Overlay::DPY_WRITEBACK);
+        turnOffAD();
         return false;
     }
 
+    // Only turn on AD if there are no errors during configuration stage
+    // and if it was previously in OFF state.
+    if(mFeatureEnabled && mTurnedOff) {
+        //write to sysfs, one time during this switch
+        const int on = 1;
+        adWrite(on);
+        mTurnedOff = false;
+    }
+
     return true;
 }
 
 bool AssertiveDisplay::draw(hwc_context_t *ctx, int fd, uint32_t offset) {
-    if(!isDoable() || !isModeOn()) {
+    if(!isDoable()) {
         return false;
     }
 
diff --git a/libhwcomposer/hwc_ad.h b/libhwcomposer/hwc_ad.h
index 3bfde17..0be5f5d 100644
--- a/libhwcomposer/hwc_ad.h
+++ b/libhwcomposer/hwc_ad.h
@@ -50,17 +50,16 @@
             mDest = overlay::utils::OV_INVALID;
     }
     bool isDoable() const { return mDoable; }
-    bool isModeOn() const { return (mWbFd >= 0); }
     int getDstFd() const;
     uint32_t getDstOffset() const;
 
 private:
-    //State of feature turned on and off
-    int mWbFd;
     bool mDoable;
+    bool mTurnedOff;
     //State of feature existence on certain devices and configs.
     bool mFeatureEnabled;
     overlay::utils::eDest mDest;
+    void turnOffAD();
 };
 
 }
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index d7afa19..f379cf8 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -811,7 +811,7 @@
 }
 
 CopyBit::CopyBit(hwc_context_t *ctx, const int& dpy) : mIsModeOn(false),
-        mCopyBitDraw(false), mCurRenderBufferIndex(0) {
+        mCopyBitDraw(false), mCurRenderBufferIndex(0), mEngine(0) {
 
     getBufferSizeAndDimensions(ctx->dpyAttr[dpy].xres,
             ctx->dpyAttr[dpy].yres,
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 8a717c0..b75af03 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -42,7 +42,6 @@
 bool MDPComp::sDebugLogs = false;
 bool MDPComp::sEnabled = false;
 bool MDPComp::sEnableMixedMode = true;
-bool MDPComp::sEnablePartialFrameUpdate = false;
 int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
 bool MDPComp::sEnable4k2kYUVSplit = false;
 bool MDPComp::sSrcSplitEnabled = false;
@@ -116,18 +115,6 @@
             sDebugLogs = true;
     }
 
-    // We read from drivers if panel supports partial updating
-    // and we enable partial update computations if supported.
-    // Keeping this property to disable partial update for
-    // debugging by setting below property to 0 & only 0.
-    property_get("persist.hwc.partialupdate", property, "-1");
-    if((atoi(property) != 0) &&
-        qdutils::MDPVersion::getInstance().isPartialUpdateEnabled()) {
-            sEnablePartialFrameUpdate = true;
-    }
-    ALOGE_IF(isDebug(), "%s: Partial Update applicable?: %d",__FUNCTION__,
-                                                    sEnablePartialFrameUpdate);
-
     sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
     if(property_get("debug.mdpcomp.maxpermixer", property, "-1") > 0) {
         int val = atoi(property);
@@ -402,7 +389,8 @@
         ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
         ret = false;
     } else if((qdutils::MDPVersion::getInstance().is8x26() ||
-               qdutils::MDPVersion::getInstance().is8x16()) &&
+               qdutils::MDPVersion::getInstance().is8x16() ||
+               qdutils::MDPVersion::getInstance().is8x39()) &&
             ctx->mVideoTransFlag &&
             isSecondaryConnected(ctx)) {
         //1 Padding round to shift pipes across mixers
@@ -421,23 +409,21 @@
     return ret;
 }
 
-/*
- * 1) Identify layers that are not visible in the updating ROI and drop them
- * from composition.
- * 2) If we have a scaling layers which needs cropping against generated ROI.
- * Reset ROI to full resolution.
- */
-bool MDPComp::validateAndApplyROI(hwc_context_t *ctx,
-                               hwc_display_contents_1_t* list, hwc_rect_t roi) {
+void MDPCompNonSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) {
+    hwc_rect_t roi = ctx->listStats[mDpy].lRoi;
+    fbRect = getIntersection(fbRect, roi);
+}
+
+/* 1) Identify layers that are not visible or lying outside the updating ROI and
+ *    drop them from composition.
+ * 2) If we have a scaling layer which needs cropping against generated
+ *    ROI, reset ROI to full resolution. */
+bool MDPCompNonSplit::validateAndApplyROI(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
     int numAppLayers = ctx->listStats[mDpy].numAppLayers;
-
-    if(!isValidRect(roi))
-        return false;
-
-    hwc_rect_t visibleRect = roi;
+    hwc_rect_t visibleRect = ctx->listStats[mDpy].lRoi;
 
     for(int i = numAppLayers - 1; i >= 0; i--){
-
         if(!isValidRect(visibleRect)) {
             mCurrentFrame.drop[i] = true;
             mCurrentFrame.dropCount++;
@@ -445,24 +431,16 @@
         }
 
         const hwc_layer_1_t* layer =  &list->hwLayers[i];
-
         hwc_rect_t dstRect = layer->displayFrame;
-        hwc_rect_t srcRect = integerizeSourceCrop(layer->sourceCropf);
-
         hwc_rect_t res  = getIntersection(visibleRect, dstRect);
 
-        int res_w = res.right - res.left;
-        int res_h = res.bottom - res.top;
-        int dst_w = dstRect.right - dstRect.left;
-        int dst_h = dstRect.bottom - dstRect.top;
-
         if(!isValidRect(res)) {
             mCurrentFrame.drop[i] = true;
             mCurrentFrame.dropCount++;
-        }else {
+        } else {
             /* Reset frame ROI when any layer which needs scaling also needs ROI
              * cropping */
-            if((res_w != dst_w || res_h != dst_h) && needsScaling (layer)) {
+            if(!isSameRect(res, dstRect) && needsScaling (layer)) {
                 ALOGI("%s: Resetting ROI due to scaling", __FUNCTION__);
                 memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
                 mCurrentFrame.dropCount = 0;
@@ -477,52 +455,183 @@
     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) {
+/* Calculate ROI for the frame by accounting all the layer's dispalyFrame which
+ * are updating. If DirtyRegion is applicable, calculate it by accounting all
+ * the changing layer's dirtyRegion. */
+void MDPCompNonSplit::generateROI(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
     int numAppLayers = ctx->listStats[mDpy].numAppLayers;
-
-    if(!canDoPartialUpdate(ctx, list))
+    if(!canPartialUpdate(ctx, list))
         return;
 
     struct hwc_rect roi = (struct hwc_rect){0, 0, 0, 0};
+    hwc_rect fullFrame = (struct hwc_rect) {0, 0,(int)ctx->dpyAttr[mDpy].xres,
+        (int)ctx->dpyAttr[mDpy].yres};
+
     for(int index = 0; index < numAppLayers; index++ ) {
         hwc_layer_1_t* layer = &list->hwLayers[index];
         if ((mCachedFrame.hnd[index] != layer->handle) ||
-            isYuvBuffer((private_handle_t *)layer->handle)) {
+                isYuvBuffer((private_handle_t *)layer->handle)) {
             hwc_rect_t updatingRect = layer->displayFrame;
+
 #ifdef QCOM_BSP
-            if(!needsScaling(layer))
+            if(!needsScaling(layer) && !layer->transform)
                 updatingRect =  layer->dirtyRect;
 #endif
+
             roi = getUnion(roi, updatingRect);
         }
     }
 
-    hwc_rect fullFrame = (struct hwc_rect) {0, 0,(int)ctx->dpyAttr[mDpy].xres,
-        (int)ctx->dpyAttr[mDpy].yres};
+    /* No layer is updating. Still SF wants a refresh.*/
+    if(!isValidRect(roi))
+        return;
 
     // Align ROI coordinates to panel restrictions
-    roi = sanitizeROI(roi, fullFrame);
+    roi = getSanitizeROI(roi, fullFrame);
 
-    if(!validateAndApplyROI(ctx, list, roi))
-        roi = fullFrame;
-
-    ctx->listStats[mDpy].roi.x = roi.left;
-    ctx->listStats[mDpy].roi.y = roi.top;
-    ctx->listStats[mDpy].roi.w = roi.right - roi.left;
-    ctx->listStats[mDpy].roi.h = roi.bottom - roi.top;
+    ctx->listStats[mDpy].lRoi = roi;
+    if(!validateAndApplyROI(ctx, list))
+        resetROI(ctx, mDpy);
 
     ALOGD_IF(isDebug(),"%s: generated ROI: [%d, %d, %d, %d]", __FUNCTION__,
-                               roi.left, roi.top, roi.right, roi.bottom);
+            ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top,
+            ctx->listStats[mDpy].lRoi.right, ctx->listStats[mDpy].lRoi.bottom);
+}
+
+void MDPCompSplit::trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) {
+    hwc_rect l_roi = ctx->listStats[mDpy].lRoi;
+    hwc_rect r_roi = ctx->listStats[mDpy].rRoi;
+
+    hwc_rect_t l_fbRect = getIntersection(fbRect, l_roi);
+    hwc_rect_t r_fbRect = getIntersection(fbRect, r_roi);
+    fbRect = getUnion(l_fbRect, r_fbRect);
+}
+/* 1) Identify layers that are not visible or lying outside BOTH the updating
+ *    ROI's and drop them from composition. If a layer is spanning across both
+ *    the halves of the screen but needed by only ROI, the non-contributing
+ *    half will not be programmed for MDP.
+ * 2) If we have a scaling layer which needs cropping against generated
+ *    ROI, reset ROI to full resolution. */
+bool MDPCompSplit::validateAndApplyROI(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
+
+    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+
+    hwc_rect_t visibleRectL = ctx->listStats[mDpy].lRoi;
+    hwc_rect_t visibleRectR = ctx->listStats[mDpy].rRoi;
+
+    for(int i = numAppLayers - 1; i >= 0; i--){
+        if(!isValidRect(visibleRectL) && !isValidRect(visibleRectR))
+        {
+            mCurrentFrame.drop[i] = true;
+            mCurrentFrame.dropCount++;
+            continue;
+        }
+
+        const hwc_layer_1_t* layer =  &list->hwLayers[i];
+        hwc_rect_t dstRect = layer->displayFrame;
+
+        hwc_rect_t l_res  = getIntersection(visibleRectL, dstRect);
+        hwc_rect_t r_res  = getIntersection(visibleRectR, dstRect);
+        hwc_rect_t res = getUnion(l_res, r_res);
+
+        if(!isValidRect(l_res) && !isValidRect(r_res)) {
+            mCurrentFrame.drop[i] = true;
+            mCurrentFrame.dropCount++;
+        } else {
+            /* Reset frame ROI when any layer which needs scaling also needs ROI
+             * cropping */
+            if(!isSameRect(res, dstRect) && needsScaling (layer)) {
+                memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
+                mCurrentFrame.dropCount = 0;
+                return false;
+            }
+
+            if (layer->blending == HWC_BLENDING_NONE) {
+                visibleRectL = deductRect(visibleRectL, l_res);
+                visibleRectR = deductRect(visibleRectR, r_res);
+            }
+        }
+    }
+    return true;
+}
+/* Calculate ROI for the frame by accounting all the layer's dispalyFrame which
+ * are updating. If DirtyRegion is applicable, calculate it by accounting all
+ * the changing layer's dirtyRegion. */
+void MDPCompSplit::generateROI(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
+    if(!canPartialUpdate(ctx, list))
+        return;
+
+    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+    int lSplit = getLeftSplit(ctx, mDpy);
+
+    int hw_h = (int)ctx->dpyAttr[mDpy].yres;
+    int hw_w = (int)ctx->dpyAttr[mDpy].xres;
+
+    struct hwc_rect l_frame = (struct hwc_rect){0, 0, lSplit, hw_h};
+    struct hwc_rect r_frame = (struct hwc_rect){lSplit, 0, hw_w, hw_h};
+
+    struct hwc_rect l_roi = (struct hwc_rect){0, 0, 0, 0};
+    struct hwc_rect r_roi = (struct hwc_rect){0, 0, 0, 0};
+
+    for(int index = 0; index < numAppLayers; index++ ) {
+        hwc_layer_1_t* layer = &list->hwLayers[index];
+        if ((mCachedFrame.hnd[index] != layer->handle) ||
+                isYuvBuffer((private_handle_t *)layer->handle)) {
+            hwc_rect_t dst = layer->displayFrame;
+            hwc_rect_t updatingRect = dst;
+
+#ifdef QCOM_BSP
+            if(!needsScaling(layer) && !layer->transform)
+            {
+                hwc_rect_t src = integerizeSourceCrop(layer->sourceCropf);
+                int x_off = dst.left - src.left;
+                int y_off = dst.top - src.top;
+                updatingRect = moveRect(layer->dirtyRect, x_off, y_off);
+            }
+#endif
+
+            hwc_rect_t l_dst  = getIntersection(l_frame, updatingRect);
+            if(isValidRect(l_dst))
+                l_roi = getUnion(l_roi, l_dst);
+
+            hwc_rect_t r_dst  = getIntersection(r_frame, updatingRect);
+            if(isValidRect(r_dst))
+                r_roi = getUnion(r_roi, r_dst);
+        }
+    }
+
+    /* For panels that cannot accept commands in both the interfaces, we cannot
+     * send two ROI's (for each half). We merge them into single ROI and split
+     * them across lSplit for MDP mixer use. The ROI's will be merged again
+     * finally before udpating the panel in the driver. */
+    if(qdutils::MDPVersion::getInstance().needsROIMerge()) {
+        hwc_rect_t temp_roi = getUnion(l_roi, r_roi);
+        l_roi = getIntersection(temp_roi, l_frame);
+        r_roi = getIntersection(temp_roi, r_frame);
+    }
+
+    /* No layer is updating. Still SF wants a refresh. */
+    if(!isValidRect(l_roi) && !isValidRect(r_roi))
+        return;
+
+    l_roi = getSanitizeROI(l_roi, l_frame);
+    r_roi = getSanitizeROI(r_roi, r_frame);
+
+    ctx->listStats[mDpy].lRoi = l_roi;
+    ctx->listStats[mDpy].rRoi = r_roi;
+
+    if(!validateAndApplyROI(ctx, list))
+        resetROI(ctx, mDpy);
+
+    ALOGD_IF(isDebug(),"%s: generated L_ROI: [%d, %d, %d, %d]"
+            "R_ROI: [%d, %d, %d, %d]", __FUNCTION__,
+            ctx->listStats[mDpy].lRoi.left, ctx->listStats[mDpy].lRoi.top,
+            ctx->listStats[mDpy].lRoi.right, ctx->listStats[mDpy].lRoi.bottom,
+            ctx->listStats[mDpy].rRoi.left, ctx->listStats[mDpy].rRoi.top,
+            ctx->listStats[mDpy].rRoi.right, ctx->listStats[mDpy].rRoi.bottom);
 }
 
 /* Checks for conditions where all the layers marked for MDP comp cannot be
@@ -799,6 +908,16 @@
     return true;
 }
 
+bool MDPComp::canPartialUpdate(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list){
+    if(!qdutils::MDPVersion::getInstance().isPartialUpdateEnabled() ||
+            isSkipPresent(ctx, mDpy) || (list->flags & HWC_GEOMETRY_CHANGED) ||
+            mDpy ) {
+        return false;
+    }
+    return true;
+}
+
 bool MDPComp::tryVideoOnly(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
     const bool secureOnly = true;
@@ -1093,7 +1212,8 @@
              mCurrentFrame.fbCount);
 }
 
-hwc_rect_t MDPComp::getUpdatingFBRect(hwc_display_contents_1_t* list){
+hwc_rect_t MDPComp::getUpdatingFBRect(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list){
     hwc_rect_t fbRect = (struct hwc_rect){0, 0, 0, 0};
 
     /* Update only the region of FB needed for composition */
@@ -1104,6 +1224,7 @@
             fbRect = getUnion(fbRect, dst);
         }
     }
+    trimAgainstROI(ctx, fbRect);
     return fbRect;
 }
 
@@ -1124,7 +1245,7 @@
 
     //Configure framebuffer first if applicable
     if(mCurrentFrame.fbZ >= 0) {
-        hwc_rect_t fbRect = getUpdatingFBRect(list);
+        hwc_rect_t fbRect = getUpdatingFBRect(ctx, list);
         if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list, fbRect, mCurrentFrame.fbZ))
         {
             ALOGD_IF(isDebug(), "%s configure framebuffer failed",
@@ -1276,6 +1397,7 @@
         if(tryFullFrame(ctx, list) || tryVideoOnly(ctx, list)) {
             setMDPCompLayerFlags(ctx, list);
         } else {
+            resetROI(ctx, mDpy);
             reset(ctx);
             memset(&mCurrentFrame.drop, 0, sizeof(mCurrentFrame.drop));
             mCurrentFrame.dropCount = 0;
@@ -1587,13 +1709,17 @@
     pipeSpecs.mixer = Overlay::MIXER_LEFT;
     pipeSpecs.fb = false;
 
-    if (dst.left < lSplit) {
+    // Acquire pipe only for the updating half
+    hwc_rect_t l_roi = ctx->listStats[mDpy].lRoi;
+    hwc_rect_t r_roi = ctx->listStats[mDpy].rRoi;
+
+    if (dst.left < lSplit && isValidRect(getIntersection(dst, l_roi))) {
         pipe_info.lIndex = ctx->mOverlay->getPipe(pipeSpecs);
         if(pipe_info.lIndex == ovutils::OV_INVALID)
             return false;
     }
 
-    if(dst.right > lSplit) {
+    if(dst.right > lSplit && isValidRect(getIntersection(dst, r_roi))) {
         pipeSpecs.mixer = Overlay::MIXER_RIGHT;
         pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs);
         if(pipe_info.rIndex == ovutils::OV_INVALID)
@@ -1766,11 +1892,9 @@
             int fd = hnd->fd;
             int offset = (uint32_t)hnd->offset;
 
-            if(ctx->mAD->isModeOn()) {
-                if(ctx->mAD->draw(ctx, fd, offset)) {
-                    fd = ctx->mAD->getDstFd();
-                    offset = ctx->mAD->getDstOffset();
-                }
+            if(ctx->mAD->draw(ctx, fd, offset)) {
+                fd = ctx->mAD->getDstFd();
+                offset = ctx->mAD->getDstOffset();
             }
 
             if(rot) {
@@ -1904,6 +2028,10 @@
         (*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);
+        }
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlags, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 8186fff..d974875 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -142,6 +142,15 @@
     /* configures 4kx2k yuv layer*/
     virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
             PipeLayerPair& PipeLayerPair) = 0;
+    /* generates ROI based on the modified area of the frame */
+    virtual void generateROI(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list) = 0;
+    /* validates the ROI generated for fallback conditions */
+    virtual bool validateAndApplyROI(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list) = 0;
+    /* Trims fbRect calculated against ROI generated */
+    virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect) = 0;
+
     /* set/reset flags for MDPComp */
     void setMDPCompLayerFlags(hwc_context_t *ctx,
                               hwc_display_contents_1_t* list);
@@ -173,11 +182,6 @@
     /* checks if MDP/MDSS can process current list w.r.to HW limitations
      * All peculiar HW limitations should go here */
     bool hwLimitationsCheck(hwc_context_t* ctx, hwc_display_contents_1_t* list);
-    /* generates ROI based on the modified area of the frame */
-    void generateROI(hwc_context_t *ctx, hwc_display_contents_1_t* list);
-    bool validateAndApplyROI(hwc_context_t *ctx, hwc_display_contents_1_t* list,
-                             hwc_rect_t roi);
-
     /* Is debug enabled */
     static bool isDebug() { return sDebugLogs ? true : false; };
     /* Is feature enabled */
@@ -212,14 +216,14 @@
     void reset(hwc_context_t *ctx);
     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);
+    hwc_rect_t getUpdatingFBRect(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
+    /* checks for conditions to enable partial udpate */
+    bool canPartialUpdate(hwc_context_t *ctx, hwc_display_contents_1_t* list);
 
     int mDpy;
     static bool sEnabled;
     static bool sEnableMixedMode;
-    /* Enables Partial frame composition */
-    static bool sEnablePartialFrameUpdate;
     static bool sDebugLogs;
     static bool sIdleFallBack;
     /* Handles the timeout event from kernel, if the value is set to true */
@@ -262,6 +266,14 @@
     /* configures 4kx2k yuv layer to 2 VG pipes*/
     virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
             PipeLayerPair& PipeLayerPair);
+    /* generates ROI based on the modified area of the frame */
+    virtual void generateROI(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
+    /* validates the ROI generated for fallback conditions */
+    virtual bool validateAndApplyROI(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
+    /* Trims fbRect calculated against ROI generated */
+    virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect);
 };
 
 class MDPCompSplit : public MDPComp {
@@ -287,7 +299,6 @@
     /* allocates pipes to selected candidates */
     virtual bool allocLayerPipes(hwc_context_t *ctx,
                                  hwc_display_contents_1_t* list);
-
 private:
     /* Increments mdpCount if 4k2k yuv layer split is enabled.
      * updates framebuffer z order if fb lies above source-split layer */
@@ -297,6 +308,14 @@
     /* configures 4kx2k yuv layer*/
     virtual int configure4k2kYuv(hwc_context_t *ctx, hwc_layer_1_t *layer,
             PipeLayerPair& PipeLayerPair);
+    /* generates ROI based on the modified area of the frame */
+    virtual void generateROI(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
+    /* validates the ROI generated for fallback conditions */
+    virtual bool validateAndApplyROI(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
+    /* Trims fbRect calculated against ROI generated */
+    virtual void trimAgainstROI(hwc_context_t *ctx, hwc_rect_t& fbRect);
 };
 
 class MDPCompSrcSplit : public MDPCompSplit {
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 4cc8243..972f12f 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -834,13 +834,13 @@
     char property[PROPERTY_VALUE_MAX];
     ctx->listStats[dpy].extOnlyLayerIndex = -1;
     ctx->listStats[dpy].isDisplayAnimating = false;
-    ctx->listStats[dpy].roi = ovutils::Dim(0, 0,
-                      (int)ctx->dpyAttr[dpy].xres, (int)ctx->dpyAttr[dpy].yres);
     ctx->listStats[dpy].secureUI = false;
     ctx->listStats[dpy].yuv4k2kCount = 0;
     ctx->mViewFrame[dpy] = (hwc_rect_t){0, 0, 0, 0};
     ctx->dpyAttr[dpy].mActionSafePresent = isActionSafePresent(ctx, dpy);
 
+    resetROI(ctx, dpy);
+
     // Calculate view frame of ext display from primary resolution
     // and primary device orientation.
     ctx->mViewFrame[dpy] = calculateDisplayViewFrame(ctx, dpy);
@@ -1070,6 +1070,12 @@
     return isValidRect(irect);
 }
 
+bool isSameRect(const hwc_rect& rect1, const hwc_rect& rect2)
+{
+   return ((rect1.left == rect2.left) && (rect1.top == rect2.top) &&
+           (rect1.right == rect2.right) && (rect1.bottom == rect2.bottom));
+}
+
 bool isValidRect(const hwc_rect& rect)
 {
    return ((rect.bottom > rect.top) && (rect.right > rect.left)) ;
@@ -1082,6 +1088,21 @@
     return false;
 }
 
+hwc_rect_t moveRect(const hwc_rect_t& rect, const int& x_off, const int& y_off)
+{
+    hwc_rect_t res;
+
+    if(!isValidRect(rect))
+        return (hwc_rect_t){0, 0, 0, 0};
+
+    res.left = rect.left + x_off;
+    res.top = rect.top + y_off;
+    res.right = rect.right + x_off;
+    res.bottom = rect.bottom + y_off;
+
+    return res;
+}
+
 /* computes the intersection of two rects */
 hwc_rect_t getIntersection(const hwc_rect_t& rect1, const hwc_rect_t& rect2)
 {
@@ -2164,7 +2185,20 @@
     }
 }
 
-hwc_rect_t sanitizeROI(struct hwc_rect roi, hwc_rect boundary)
+void resetROI(hwc_context_t *ctx, const int dpy) {
+    const int fbXRes = (int)ctx->dpyAttr[dpy].xres;
+    const int fbYRes = (int)ctx->dpyAttr[dpy].yres;
+    if(isDisplaySplit(ctx, dpy)) {
+        const int lSplit = getLeftSplit(ctx, dpy);
+        ctx->listStats[dpy].lRoi = (struct hwc_rect){0, 0, lSplit, fbYRes};
+        ctx->listStats[dpy].rRoi = (struct hwc_rect){lSplit, 0, fbXRes, fbYRes};
+    } else  {
+        ctx->listStats[dpy].lRoi = (struct hwc_rect){0, 0,fbXRes, fbYRes};
+        ctx->listStats[dpy].rRoi = (struct hwc_rect){0, 0, 0, 0};
+    }
+}
+
+hwc_rect_t getSanitizeROI(struct hwc_rect roi, hwc_rect boundary)
 {
    if(!isValidRect(roi))
       return roi;
@@ -2176,6 +2210,7 @@
    const int TOP_ALIGN = qdutils::MDPVersion::getInstance().getTopAlign();
    const int HEIGHT_ALIGN = qdutils::MDPVersion::getInstance().getHeightAlign();
    const int MIN_WIDTH = qdutils::MDPVersion::getInstance().getMinROIWidth();
+   const int MIN_HEIGHT = qdutils::MDPVersion::getInstance().getMinROIHeight();
 
    /* Align to minimum width recommended by the panel */
    if((t_roi.right - t_roi.left) < MIN_WIDTH) {
@@ -2185,7 +2220,18 @@
            t_roi.right = t_roi.left + MIN_WIDTH;
    }
 
+  /* Align to minimum height recommended by the panel */
+   if((t_roi.bottom - t_roi.top) < MIN_HEIGHT) {
+       if((t_roi.top + MIN_HEIGHT) > boundary.bottom)
+           t_roi.top = t_roi.bottom - MIN_HEIGHT;
+       else
+           t_roi.bottom = t_roi.top + MIN_HEIGHT;
+   }
+
    /* Align left and width to meet panel restrictions */
+   if(LEFT_ALIGN)
+       t_roi.left = t_roi.left - (t_roi.left % LEFT_ALIGN);
+
    if(WIDTH_ALIGN) {
        int width = t_roi.right - t_roi.left;
        width = WIDTH_ALIGN * ((width + (WIDTH_ALIGN - 1)) / WIDTH_ALIGN);
@@ -2194,13 +2240,17 @@
        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);
        }
    }
 
-   if(LEFT_ALIGN)
-       t_roi.left = t_roi.left - (t_roi.left % LEFT_ALIGN);
 
    /* Align top and height to meet panel restrictions */
+   if(TOP_ALIGN)
+       t_roi.top = t_roi.top - (t_roi.top % TOP_ALIGN);
+
    if(HEIGHT_ALIGN) {
        int height = t_roi.bottom - t_roi.top;
        height = HEIGHT_ALIGN *  ((height + (HEIGHT_ALIGN - 1)) / HEIGHT_ALIGN);
@@ -2209,11 +2259,12 @@
        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);
        }
    }
 
-   if(TOP_ALIGN)
-       t_roi.top = t_roi.top - (t_roi.top % TOP_ALIGN);
 
    return t_roi;
 }
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 0883a51..4cfed2a 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -123,9 +123,10 @@
     // Notifies hwcomposer about the start and end of animation
     // This will be set to true during animation, otherwise false.
     bool isDisplayAnimating;
-    ovutils::Dim roi;
     bool secureUI; // Secure display layer
     bool isSecurePresent;
+    hwc_rect_t lRoi;  //left ROI
+    hwc_rect_t rRoi;  //right ROI. Unused in single DSI panels.
 };
 
 struct LayerProp {
@@ -260,6 +261,8 @@
 int getExtOrientation(hwc_context_t* ctx);
 bool isValidRect(const hwc_rect_t& rect);
 hwc_rect_t deductRect(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
+bool isSameRect(const hwc_rect& rect1, const hwc_rect& rect2);
+hwc_rect_t moveRect(const hwc_rect_t& rect, const int& x_off, const int& y_off);
 hwc_rect_t getIntersection(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
 hwc_rect_t getUnion(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
 void optimizeLayerRects(const hwc_display_contents_1_t *list);
@@ -295,8 +298,11 @@
 /* Get External State names */
 const char* getExternalDisplayState(uint32_t external_state);
 
+// Resets display ROI to full panel resoluion
+void resetROI(hwc_context_t *ctx, const int dpy);
+
 // Aligns updating ROI to panel restrictions
-hwc_rect_t sanitizeROI(struct hwc_rect roi, hwc_rect boundary);
+hwc_rect_t getSanitizeROI(struct hwc_rect roi, hwc_rect boundary);
 
 // Handles wfd Pause and resume events
 void handle_pause(hwc_context_t *ctx, int dpy);
diff --git a/libmemtrack/kgsl.c b/libmemtrack/kgsl.c
index 6dd4e27..6194043 100644
--- a/libmemtrack/kgsl.c
+++ b/libmemtrack/kgsl.c
@@ -47,7 +47,6 @@
     size_t allocated_records = min(*num_records, ARRAY_SIZE(record_templates));
     int i;
     FILE *fp;
-    FILE *smaps_fp = NULL;
     char line[1024];
     char tmp[128];
     size_t accounted_size = 0;
@@ -70,19 +69,14 @@
         return -errno;
     }
 
-    if (type == MEMTRACK_TYPE_GL) {
-        snprintf(tmp, sizeof(tmp), "/proc/%d/smaps", pid);
-        smaps_fp = fopen(tmp, "r");
-        if (smaps_fp == NULL) {
-            fclose(fp);
-            return -errno;
-        }
-    }
-
+    /* Go through each line of <pid>/mem file and for every entry of type "gpumem"
+     * check if the gpubuffer entry is usermapped or not. If the entry is usermapped
+     * count the entry as accounted else count the entry as unaccounted.
+     */
     while (1) {
-        unsigned long uaddr;
         unsigned long size;
         char line_type[7];
+        char flags[7];
         int ret;
 
         if (fgets(line, sizeof(line), fp) == NULL) {
@@ -91,49 +85,21 @@
 
         /* Format:
          *  gpuaddr useraddr     size    id flags       type            usage sglen
-         * 545ba000 545ba000     4096     1 ----p     gpumem      arraybuffer     1
+         * 545ba000 545ba000     4096     1 ----pY     gpumem      arraybuffer     1
          */
-        ret = sscanf(line, "%*x %lx %lu %*d %*s %6s %*s %*d\n",
-                     &uaddr, &size, line_type);
+        ret = sscanf(line, "%*x %*lx %lu %*d %6s %6s %*s %*d\n",
+                     &size, flags, line_type);
         if (ret != 3) {
             continue;
         }
 
         if (type == MEMTRACK_TYPE_GL && strcmp(line_type, "gpumem") == 0) {
-            bool accounted = false;
-            /*
-             * We need to cross reference the user address against smaps,
-             *  luckily both are sorted.
-             */
-            while (smaps_addr <= uaddr) {
-                unsigned long start;
-                unsigned long end;
-                unsigned long smaps_size;
 
-                if (fgets(line, sizeof(line), smaps_fp) == NULL) {
-                    break;
-                }
-
-                if (sscanf(line, "%8lx-%8lx", &start, &end) == 2) {
-                    smaps_addr = start;
-                    continue;
-                }
-
-                if (smaps_addr != uaddr) {
-                    continue;
-                }
-
-                if (sscanf(line, "Rss: %lu kB", &smaps_size) == 1) {
-                    if (smaps_size) {
-                        accounted = true;
-                        accounted_size += size;
-                        break;
-                    }
-                }
-            }
-            if (!accounted) {
+            if (flags[6] == 'Y')
+                accounted_size += size;
+            else
                 unaccounted_size += size;
-            }
+
         } else if (type == MEMTRACK_TYPE_GRAPHICS && strcmp(line_type, "ion") == 0) {
             unaccounted_size += size;
         }
@@ -146,8 +112,6 @@
         records[1].size_in_bytes = unaccounted_size;
     }
 
-    if (smaps_fp)
-        fclose(smaps_fp);
     fclose(fp);
 
     return 0;
diff --git a/liboverlay/Android.mk b/liboverlay/Android.mk
index d8c2ab5..277b44c 100644
--- a/liboverlay/Android.mk
+++ b/liboverlay/Android.mk
@@ -9,9 +9,6 @@
 LOCAL_SHARED_LIBRARIES        := $(common_libs) libqdutils libmemalloc \
                                  libsync libdl
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdoverlay\"
-ifeq ($(TARGET_USES_QSEED_SCALAR),true)
-    LOCAL_CFLAGS += -DUSES_QSEED_SCALAR
-endif
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
 LOCAL_SRC_FILES := \
       overlay.cpp \
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index d53b46d..fe7bd2c 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -33,11 +33,6 @@
 #include "mdp_version.h"
 #include "qdMetaData.h"
 
-#ifdef USES_QSEED_SCALAR
-#include <scale/scale.h>
-using namespace scale;
-#endif
-
 #define PIPE_DEBUG 0
 
 namespace overlay {
@@ -163,6 +158,8 @@
         return getPipe_8x26(pipeSpecs);
     } else if(MDPVersion::getInstance().is8x16()) {
         return getPipe_8x16(pipeSpecs);
+    } else if(MDPVersion::getInstance().is8x39()) {
+        return getPipe_8x39(pipeSpecs);
     }
 
     eDest dest = OV_INVALID;
@@ -251,6 +248,12 @@
     return dest;
 }
 
+utils::eDest Overlay::getPipe_8x39(const PipeSpecs& pipeSpecs) {
+    //8x16 & 8x36 has same number of pipes, pipe-types & scaling capabilities.
+    //Rely on 8x16 until we see a need to change.
+    return getPipe_8x16(pipeSpecs);
+}
+
 void Overlay::endAllSessions() {
     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
         if(mPipeBook[i].valid() && mPipeBook[i].mSession==PipeBook::START)
@@ -283,14 +286,13 @@
 
 bool Overlay::commit(utils::eDest dest) {
     bool ret = false;
-    int index = (int)dest;
-    validate(index);
+    validate((int)dest);
 
-    if(mPipeBook[index].mPipe->commit()) {
+    if(mPipeBook[dest].mPipe->commit()) {
         ret = true;
         PipeBook::setUse((int)dest);
     } else {
-        int dpy = mPipeBook[index].mDisplay;
+        int dpy = mPipeBook[dest].mDisplay;
         for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
             if (mPipeBook[i].mDisplay == dpy) {
                 PipeBook::resetAllocation(i);
@@ -303,52 +305,46 @@
 
 bool Overlay::queueBuffer(int fd, uint32_t offset,
         utils::eDest dest) {
-    int index = (int)dest;
     bool ret = false;
-    validate(index);
+    validate((int)dest);
     //Queue only if commit() has succeeded (and the bit set)
     if(PipeBook::isUsed((int)dest)) {
-        ret = mPipeBook[index].mPipe->queueBuffer(fd, offset);
+        ret = mPipeBook[dest].mPipe->queueBuffer(fd, offset);
     }
     return ret;
 }
 
 void Overlay::setCrop(const utils::Dim& d,
         utils::eDest dest) {
-    int index = (int)dest;
-    validate(index);
-    mPipeBook[index].mPipe->setCrop(d);
+    validate((int)dest);
+    mPipeBook[dest].mPipe->setCrop(d);
 }
 
 void Overlay::setColor(const uint32_t color,
         utils::eDest dest) {
-    int index = (int)dest;
-    validate(index);
-    mPipeBook[index].mPipe->setColor(color);
+    validate((int)dest);
+    mPipeBook[dest].mPipe->setColor(color);
 }
 
 void Overlay::setPosition(const utils::Dim& d,
         utils::eDest dest) {
-    int index = (int)dest;
-    validate(index);
-    mPipeBook[index].mPipe->setPosition(d);
+    validate((int)dest);
+    mPipeBook[dest].mPipe->setPosition(d);
 }
 
 void Overlay::setTransform(const int orient,
         utils::eDest dest) {
-    int index = (int)dest;
-    validate(index);
+    validate((int)dest);
 
     utils::eTransform transform =
             static_cast<utils::eTransform>(orient);
-    mPipeBook[index].mPipe->setTransform(transform);
+    mPipeBook[dest].mPipe->setTransform(transform);
 
 }
 
 void Overlay::setSource(const utils::PipeArgs args,
         utils::eDest dest) {
-    int index = (int)dest;
-    validate(index);
+    validate((int)dest);
 
     PipeArgs newArgs(args);
     if(PipeBook::getPipeType(dest) == OV_MDP_PIPE_VG) {
@@ -363,13 +359,12 @@
         clearMdpFlags(newArgs.mdpFlags, OV_MDP_PIPE_FORCE_DMA);
     }
 
-    mPipeBook[index].mPipe->setSource(newArgs);
+    mPipeBook[dest].mPipe->setSource(newArgs);
 }
 
 void Overlay::setVisualParams(const MetaData_t& metadata, utils::eDest dest) {
-    int index = (int)dest;
-    validate(index);
-    mPipeBook[index].mPipe->setVisualParams(metadata);
+    validate((int)dest);
+    mPipeBook[dest].mPipe->setVisualParams(metadata);
 }
 
 Overlay* Overlay::getInstance() {
@@ -471,19 +466,24 @@
 }
 
 bool Overlay::displayCommit(const int& fd) {
-    utils::Dim roi;
-    return displayCommit(fd, roi);
+    utils::Dim lRoi, rRoi;
+    return displayCommit(fd, lRoi, rRoi);
 }
 
-bool Overlay::displayCommit(const int& fd, const utils::Dim& roi) {
+bool Overlay::displayCommit(const int& fd, const utils::Dim& lRoi,
+        const utils::Dim& rRoi) {
     //Commit
     struct mdp_display_commit info;
     memset(&info, 0, sizeof(struct mdp_display_commit));
     info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
-    info.roi.x = roi.x;
-    info.roi.y = roi.y;
-    info.roi.w = roi.w;
-    info.roi.h = roi.h;
+    info.l_roi.x = lRoi.x;
+    info.l_roi.y = lRoi.y;
+    info.l_roi.w = lRoi.w;
+    info.l_roi.h = lRoi.h;
+    info.r_roi.x = rRoi.x;
+    info.r_roi.y = rRoi.y;
+    info.r_roi.w = rRoi.w;
+    info.r_roi.h = rRoi.h;
 
     if(!mdp_wrapper::displayCommit(fd, info)) {
         ALOGE("%s: commit failed", __func__);
@@ -530,7 +530,7 @@
 
 bool Overlay::validateAndSet(const int& dpy, const int& fbFd) {
     GenericPipe* pipeArray[PipeBook::NUM_PIPES];
-    memset(&pipeArray, 0, sizeof(pipeArray));
+    memset(pipeArray, 0, sizeof(GenericPipe*)*(PipeBook::NUM_PIPES));
 
     int num = 0;
     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
@@ -545,39 +545,20 @@
 }
 
 void Overlay::initScalar() {
-#ifdef USES_QSEED_SCALAR
     if(sLibScaleHandle == NULL) {
         sLibScaleHandle = dlopen("libscale.so", RTLD_NOW);
-    }
-
-    if(sLibScaleHandle) {
-        if(sScale == NULL) {
-            Scale* (*getInstance)();
-            *(void **) &getInstance = dlsym(sLibScaleHandle, "getInstance");
-            if(getInstance) {
-                sScale = getInstance();
-            }
+        if(sLibScaleHandle) {
+            *(void **) &sFnProgramScale =
+                    dlsym(sLibScaleHandle, "programScale");
         }
     }
-#endif
 }
 
 void Overlay::destroyScalar() {
-#ifdef USES_QSEED_SCALAR
     if(sLibScaleHandle) {
-        if(sScale) {
-            void (*destroyInstance)(Scale*);
-            *(void **) &destroyInstance = dlsym(sLibScaleHandle,
-                    "destroyInstance");
-            if(destroyInstance) {
-                destroyInstance(sScale);
-                sScale = NULL;
-            }
-        }
         dlclose(sLibScaleHandle);
         sLibScaleHandle = NULL;
     }
-#endif
 }
 
 void Overlay::PipeBook::init() {
@@ -607,6 +588,6 @@
 utils::eMdpPipeType Overlay::PipeBook::pipeTypeLUT[utils::OV_MAX] =
     {utils::OV_MDP_PIPE_ANY};
 void *Overlay::sLibScaleHandle = NULL;
-scale::Scale *Overlay::sScale = NULL;
+int (*Overlay::sFnProgramScale)(struct mdp_overlay_list *) = NULL;
 
 }; // namespace overlay
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 455f547..99186db 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -35,9 +35,6 @@
 #include "utils/threads.h"
 
 struct MetaData_t;
-namespace scale {
-class Scale;
-};
 
 namespace overlay {
 class GenericPipe;
@@ -149,8 +146,12 @@
     static int getDMAMode();
     /* Returns the framebuffer node backing up the display */
     static int getFbForDpy(const int& dpy);
-    static bool displayCommit(const int& fd, const utils::Dim& roi);
+
     static bool displayCommit(const int& fd);
+    /* Overloads display commit with ROI's of each halves.
+     * Single interface panels will only update left ROI. */
+    static bool displayCommit(const int& fd, const utils::Dim& lRoi,
+                              const utils::Dim& rRoi);
 
 private:
     /* Ctor setup */
@@ -170,9 +171,10 @@
     /* Helpers that enfore target specific policies while returning pipes */
     utils::eDest getPipe_8x26(const PipeSpecs& pipeSpecs);
     utils::eDest getPipe_8x16(const PipeSpecs& pipeSpecs);
+    utils::eDest getPipe_8x39(const PipeSpecs& pipeSpecs);
 
-    /* Returns the scalar object */
-    static scale::Scale *getScalar();
+    /* Returns the handle to libscale.so's programScale function */
+    static int (*getFnProgramScale())(struct mdp_overlay_list *);
     /* Creates a scalar object using libscale.so */
     static void initScalar();
     /* Destroys the scalar object using libscale.so */
@@ -243,7 +245,7 @@
     static int sDMAMode;
     static bool sDMAMultiplexingSupported;
     static void *sLibScaleHandle;
-    static scale::Scale *sScale;
+    static int (*sFnProgramScale)(struct mdp_overlay_list *);
 
     friend class MdpCtrl;
 };
@@ -317,7 +319,8 @@
 
 inline bool Overlay::isUIScalingOnExternalSupported() {
     if(qdutils::MDPVersion::getInstance().is8x26() or
-       qdutils::MDPVersion::getInstance().is8x16()) {
+       qdutils::MDPVersion::getInstance().is8x16() or
+       qdutils::MDPVersion::getInstance().is8x39()) {
         return false;
     }
     return true;
@@ -332,8 +335,8 @@
     return sDpyFbMap[dpy];
 }
 
-inline scale::Scale *Overlay::getScalar() {
-    return sScale;
+inline int (*Overlay::getFnProgramScale())(struct mdp_overlay_list *) {
+    return sFnProgramScale;
 }
 
 inline bool Overlay::PipeBook::valid() {
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 3af9eaa..c4427ae 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -22,11 +22,6 @@
 #include "mdp_version.h"
 #include <overlay.h>
 
-#ifdef USES_QSEED_SCALAR
-#include <scale/scale.h>
-using namespace scale;
-#endif
-
 #define HSIC_SETTINGS_DEBUG 0
 
 using namespace qdutils;
@@ -371,12 +366,11 @@
     list.num_overlays = count;
     list.overlay_list = ovArray;
 
-#ifdef USES_QSEED_SCALAR
-    Scale *scalar = Overlay::getScalar();
-    if(scalar) {
-        scalar->applyScale(&list);
+   int (*fnProgramScale)(struct mdp_overlay_list *) =
+        Overlay::getFnProgramScale();
+    if(fnProgramScale) {
+        fnProgramScale(&list);
     }
-#endif
 
     if(!mdp_wrapper::validateAndSet(fbFd, list)) {
         /* No dump for failure due to insufficient resource */
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 16505ba..96ed4d2 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -61,6 +61,12 @@
 #ifndef MDSS_MDP_HW_REV_107
 #define MDSS_MDP_HW_REV_107 0x10070000 //Next version
 #endif
+#ifndef MDSS_MDP_HW_REV_108
+#define MDSS_MDP_HW_REV_108 0x10080000 //8x39 & 8x36
+#endif
+#ifndef MDSS_MDP_HW_REV_109
+#define MDSS_MDP_HW_REV_109 0x10090000 //Next version
+#endif
 #ifndef MDSS_MDP_HW_REV_200
 #define MDSS_MDP_HW_REV_200 0x20000000 //8092
 #endif
@@ -200,6 +206,10 @@
                     mPanelInfo.mMinROIHeight = atoi(tokens[1]);
                     ALOGI("Min ROI Height: %d", mPanelInfo.mMinROIHeight);
                 }
+                if(!strncmp(tokens[0], "roi_merge", strlen("roi_merge"))) {
+                    mPanelInfo.mNeedsROIMerge = atoi(tokens[1]);
+                    ALOGI("Needs ROI Merge: %d", mPanelInfo.mNeedsROIMerge);
+                }
             }
         }
         fclose(panelInfoNodeFP);
@@ -390,5 +400,11 @@
             mMdpRev < MDSS_MDP_HW_REV_107);
 }
 
+bool MDPVersion::is8x39() {
+    return (mMdpRev >= MDSS_MDP_HW_REV_108 and
+            mMdpRev < MDSS_MDP_HW_REV_109);
+}
+
+
 }; //namespace qdutils
 
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index cace430..e862d2d 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -101,9 +101,10 @@
     int mHeightAlign;            // ROI height alignment restriction
     int mMinROIWidth;            // Min width needed for ROI
     int mMinROIHeight;           // Min height needed for ROI
+    bool mNeedsROIMerge;         // Merge ROI's of both the DSI's
     PanelInfo() : mType(NO_PANEL), mPartialUpdateEnable(0),
     mLeftAlign(0), mWidthAlign(0), mTopAlign(0), mHeightAlign(0),
-    mMinROIWidth(0), mMinROIHeight(0){}
+    mMinROIWidth(0), mMinROIHeight(0), mNeedsROIMerge(false){}
     friend class MDPVersion;
 };
 
@@ -128,16 +129,14 @@
     bool supportsMacroTile();
     int getLeftSplit() { return mSplit.left(); }
     int getRightSplit() { return mSplit.right(); }
-    bool isPartialUpdateEnabled() {
-        return mPanelInfo.mPartialUpdateEnable &&
-                mPanelInfo.mType == MIPI_CMD_PANEL;
-    }
+    bool isPartialUpdateEnabled() { return mPanelInfo.mPartialUpdateEnable; }
     int getLeftAlign() { return mPanelInfo.mLeftAlign; }
     int getWidthAlign() { return mPanelInfo.mWidthAlign; }
     int getTopAlign() { return mPanelInfo.mTopAlign; }
     int getHeightAlign() { return mPanelInfo.mHeightAlign; }
     int getMinROIWidth() { return mPanelInfo.mMinROIWidth; }
     int getMinROIHeight() { return mPanelInfo.mMinROIHeight; }
+    bool needsROIMerge() { return mPanelInfo.mNeedsROIMerge; }
     unsigned long getLowBw() { return mLowBw; }
     unsigned long getHighBw() { return mHighBw; }
     bool isSrcSplit() const;
@@ -147,6 +146,7 @@
     bool is8084();
     bool is8092();
     bool is8x16();
+    bool is8x39();
 
 private:
     bool updateSysFsInfo();