Merge "hwc: Fix null dereference"
diff --git a/common.mk b/common.mk
index 01cdd3f..774050e 100644
--- a/common.mk
+++ b/common.mk
@@ -28,7 +28,7 @@
 endif
 
 ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610 apq8084 \
-        mpq8092 msm_bronze msm8916), true)
+        mpq8092 msm_bronze msm8916 msm8994), true)
     common_flags += -DVENUS_COLOR_FORMAT
     common_flags += -DMDSS_TARGET
 endif
diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp
index 645cd81..84d7620 100644
--- a/libcopybit/copybit.cpp
+++ b/libcopybit/copybit.cpp
@@ -705,7 +705,7 @@
 {
     int status = -EINVAL;
 
-    if (!strcmp(name, COPYBIT_HARDWARE_COPYBIT0)) {
+    if (strcmp(name, COPYBIT_HARDWARE_COPYBIT0)) {
         return COPYBIT_FAILURE;
     }
     copybit_context_t *ctx;
diff --git a/libcopybit/copybit_c2d.cpp b/libcopybit/copybit_c2d.cpp
index 771d483..d2b00dd 100644
--- a/libcopybit/copybit_c2d.cpp
+++ b/libcopybit/copybit_c2d.cpp
@@ -257,7 +257,8 @@
 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_RGB_888:        return C2D_COLOR_FORMAT_888_RGB |
+                                              C2D_FORMAT_SWAP_RB;
         case HAL_PIXEL_FORMAT_RGBX_8888:      return C2D_COLOR_FORMAT_8888_ARGB |
                                               C2D_FORMAT_SWAP_RB |
                                                   C2D_FORMAT_DISABLE_ALPHA;
@@ -961,7 +962,7 @@
 /* Function to get the required size for a particular format, inorder for C2D to perform
  * the blit operation.
  */
-static size_t get_size(const bufferInfo& info)
+static int get_size(const bufferInfo& info)
 {
     int size = 0;
     int w = info.width;
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 98a22cd..982146e 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -191,7 +191,7 @@
         return;
     } else {
         len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
-        ALOGD("%s: Scan Info string: %s length = %zu",
+        ALOGD("%s: Scan Info string: %s length = %zd",
                  __FUNCTION__, scanInfo, len);
         if (len <= 0) {
             close(hdmiScanInfoFile);
@@ -313,7 +313,7 @@
         return false;
     } else {
         len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1);
-        ALOGD_IF(DEBUG, "%s: EDID string: %s length = %zu",
+        ALOGD_IF(DEBUG, "%s: EDID string: %s length = %zd",
                  __FUNCTION__, edidStr, len);
         if ( len <= 0) {
             ALOGE("%s: edid_modes file empty '%s'",
@@ -620,6 +620,13 @@
                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true;
             }
         }
+        //Initialize the display viewFrame info
+        mHwcContext->mViewFrame[HWC_DISPLAY_EXTERNAL].left = 0;
+        mHwcContext->mViewFrame[HWC_DISPLAY_EXTERNAL].top = 0;
+        mHwcContext->mViewFrame[HWC_DISPLAY_EXTERNAL].right =
+            (int)mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres;
+        mHwcContext->mViewFrame[HWC_DISPLAY_EXTERNAL].bottom =
+            (int)mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres;
         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
                 (int) 1000000000l / fps;
     }
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 6af0eea..7255391 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -181,6 +181,7 @@
     } else {
         switch (format)
         {
+            case HAL_PIXEL_FORMAT_YCrCb_420_SP:
             case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
             case HAL_PIXEL_FORMAT_RAW_SENSOR:
                 aligned_w = ALIGN(width, 32);
@@ -189,7 +190,6 @@
                 aligned_w = ALIGN(width, 128);
                 break;
             case HAL_PIXEL_FORMAT_YCbCr_420_SP:
-            case HAL_PIXEL_FORMAT_YCrCb_420_SP:
             case HAL_PIXEL_FORMAT_YV12:
             case HAL_PIXEL_FORMAT_YCbCr_422_SP:
             case HAL_PIXEL_FORMAT_YCrCb_422_SP:
@@ -566,8 +566,7 @@
         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;
+            ystride = cstride = hnd->width;
             ycbcr->y  = (void*)hnd->base;
             ycbcr->cb = (void*)(hnd->base + ystride * hnd->height);
             ycbcr->cr = (void*)(hnd->base + ystride * hnd->height + 1);
@@ -581,8 +580,7 @@
         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;
+            ystride = cstride = hnd->width;
             ycbcr->y  = (void*)hnd->base;
             ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
             ycbcr->cb = (void*)(hnd->base + ystride * hnd->height + 1);
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index 0cba07a..8739f34 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -69,7 +69,8 @@
 
     /* force 1MB alignment selectively for secure buffers, MDP5 onwards */
 #ifdef MDSS_TARGET
-    if (usage & GRALLOC_USAGE_PROTECTED) {
+    if ((usage & GRALLOC_USAGE_PROTECTED) &&
+        (usage & GRALLOC_USAGE_PRIVATE_MM_HEAP)) {
         data.align = ALIGN((int) data.align, SZ_1M);
         size = ALIGN(size, data.align);
     }
@@ -151,6 +152,10 @@
             flags |= private_handle_t::PRIV_FLAGS_TILE_RENDERED;
         }
 
+        if(usage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) {
+            flags |= private_handle_t::PRIV_FLAGS_CPU_RENDERED;
+        }
+
         flags |= data.allocType;
         uint64_t eBaseAddr = (uint64_t)(eData.base) + eData.offset;
         private_handle_t *hnd = new private_handle_t(data.fd, size, flags,
@@ -232,7 +237,7 @@
     // find a free slot
     for (uint32_t i=0 ; i<numBuffers ; i++) {
         if ((bufferMask & (1LU<<i)) == 0) {
-            m->bufferMask |= (1LU<<i);
+            m->bufferMask |= (uint32_t)(1LU<<i);
             break;
         }
         vaddr += bufferSize;
@@ -322,7 +327,7 @@
         const unsigned int bufferSize = m->finfo.line_length * m->info.yres;
         unsigned int index = (unsigned int) ((hnd->base - m->framebuffer->base)
                 / bufferSize);
-        m->bufferMask &= ~(1LU<<index);
+        m->bufferMask &= (uint32_t)~(1LU<<index);
     } else {
 
         terminateBuffer(&m->base, const_cast<private_handle_t*>(hnd));
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index 7a4fc15..f029b80 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -202,7 +202,9 @@
             PRIV_FLAGS_ITU_R_709          = 0x00800000,
             PRIV_FLAGS_SECURE_DISPLAY     = 0x01000000,
             // Buffer is rendered in Tile Format
-            PRIV_FLAGS_TILE_RENDERED      = 0x02000000
+            PRIV_FLAGS_TILE_RENDERED      = 0x02000000,
+            // Buffer rendered using CPU/SW renderer
+            PRIV_FLAGS_CPU_RENDERED       = 0x04000000
         };
 
         // file-descriptors
@@ -259,7 +261,7 @@
                 hnd->magic != sMagic)
             {
                 ALOGD("Invalid gralloc handle (at %p): "
-                      "ver(%d/%u) ints(%d/%d) fds(%d/%d)"
+                      "ver(%d/%zu) ints(%d/%d) fds(%d/%d)"
                       "magic(%c%c%c%c/%c%c%c%c)",
                       h,
                       h ? h->version : -1, sizeof(native_handle),
diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp
index 2097320..ccf6ed5 100644
--- a/libgralloc/ionalloc.cpp
+++ b/libgralloc/ionalloc.cpp
@@ -114,7 +114,7 @@
     data.base = base;
     data.fd = fd_data.fd;
     ioctl(mIonFd, ION_IOC_FREE, &handle_data);
-    ALOGD_IF(DEBUG, "ion: Allocated buffer base:%p size:%u fd:%d",
+    ALOGD_IF(DEBUG, "ion: Allocated buffer base:%p size:%zu fd:%d",
           data.base, ionAllocData.len, data.fd);
     return 0;
 }
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 902f882..267815f 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -143,11 +143,11 @@
                     hwc_layer_1_t const* layer = &list->hwLayers[layerIndex];
                     private_handle_t *hnd = (private_handle_t *)layer->handle;
 
-                    /* If a video layer requires rotation, set the DMA state
+                    /* If a layer requires rotation, set the DMA state
                      * to BLOCK_MODE */
 
-                    if (UNLIKELY(isYuvBuffer(hnd)) && canUseRotator(ctx, dpy) &&
-                        (layer->transform & HWC_TRANSFORM_ROT_90)) {
+                    if (canUseRotator(ctx, dpy) &&
+                        has90Transform(layer) && isRotationDoable(ctx, hnd)) {
                         if(not ctx->mOverlay->isDMAMultiplexingSupported()) {
                             if(ctx->mOverlay->isPipeTypeAttached(
                                              overlay::utils::OV_MDP_PIPE_DMA))
@@ -214,6 +214,8 @@
 
         }
 
+        if(ctx->mMDPComp[i])
+            ctx->mMDPComp[i]->reset();
         if(ctx->mFBUpdate[i])
             ctx->mFBUpdate[i]->reset();
         if(ctx->mCopyBit[i])
@@ -223,7 +225,6 @@
     }
 
     ctx->mAD->reset();
-    MDPComp::reset();
     if(ctx->mHWCVirtual)
         ctx->mHWCVirtual->destroy(ctx, numDisplays, displays);
 }
@@ -334,9 +335,9 @@
 
     //Will be unlocked at the end of set
     ctx->mDrawLock.lock();
-    setPaddingRound(ctx,numDisplays,displays);
-    setDMAState(ctx,numDisplays,displays);
-    setNumActiveDisplays(ctx,numDisplays,displays);
+    setPaddingRound(ctx, (int)numDisplays, displays);
+    setDMAState(ctx, (int)numDisplays, displays);
+    setNumActiveDisplays(ctx, (int)numDisplays, displays);
     reset(ctx, (int)numDisplays, displays);
 
     ctx->mOverlay->configBegin();
@@ -424,7 +425,11 @@
         ctx->mOverlay->configBegin();
         ctx->mOverlay->configDone();
         ctx->mRotMgr->clear();
-        overlay::Writeback::clear();
+        // If VDS is connected, do not clear WB object as it
+        // will end up detaching IOMMU. This is required
+        // to send black frame to WFD sink on power suspend.
+        // Note: With this change, we keep the WriteBack object
+        // alive on power suspend for AD use case.
     }
     switch(dpy) {
     case HWC_DISPLAY_PRIMARY:
@@ -478,13 +483,6 @@
                     ret = -1;
                 }
             }
-            value = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK;
-            if(ioctl(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].fd, FBIOBLANK, value) < 0
-                    ) {
-                ALOGE("%s: Failed to handle blank event(%d) for virtual!!",
-                        __FUNCTION__, blank );
-                return -1;
-            }
             ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
         }
         break;
@@ -580,8 +578,14 @@
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         int fd = -1; //FenceFD from the Copybit(valid in async mode)
         bool copybitDone = false;
-        if(ctx->mCopyBit[dpy])
-            copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+
+        if (ctx->mCopyBit[dpy]) {
+            if (ctx->mMDP.version < qdutils::MDP_V4_0)
+                copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+            else
+                fd = ctx->mMDPComp[dpy]->drawOverlap(ctx, list);
+        }
+
         if(list->numHwLayers > 1)
             hwc_sync(ctx, list, dpy, fd);
 
@@ -831,7 +835,7 @@
     dumpsys_log(aBuf, "  DisplayPanel=%c\n", ctx->mMDP.panel);
     for(int dpy = 0; dpy < HWC_NUM_DISPLAY_TYPES; dpy++) {
         if(ctx->mMDPComp[dpy])
-            ctx->mMDPComp[dpy]->dump(aBuf);
+            ctx->mMDPComp[dpy]->dump(aBuf, ctx);
     }
     char ovDump[2048] = {'\0'};
     ctx->mOverlay->getDump(ovDump, 2048);
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index 49e7e2a..a26f659 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -130,7 +130,8 @@
         int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndices[0];
         const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
-        if(hnd && hnd->width <= qdutils::MAX_DISPLAY_DIM) {
+        qdutils::MDPVersion& mdpHw =  qdutils::MDPVersion::getInstance();
+        if(hnd && hnd->width <= mdpHw.getMaxMixerWidth()) {
             mDoable = true;
         }
     }
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 1df8635..a5ecb3a 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -208,6 +208,67 @@
    return -1;
 }
 
+bool CopyBit::prepareOverlap(hwc_context_t *ctx,
+                             hwc_display_contents_1_t *list) {
+
+    if (ctx->mMDP.version < qdutils::MDP_V4_0) {
+        ALOGE("%s: Invalid request", __FUNCTION__);
+        return false;
+    }
+
+    if (mEngine == NULL || !(validateParams(ctx, list))) {
+        ALOGE("%s: Invalid Params", __FUNCTION__);
+        return false;
+    }
+    PtorInfo* ptorInfo = &(ctx->mPtorInfo);
+
+    // Allocate render buffers if they're not allocated
+    int alignW = 0, alignH = 0;
+    int finalW = 0, finalH = 0;
+    for (int i = 0; i < ptorInfo->count; i++) {
+        int ovlapIndex = ptorInfo->layerIndex[i];
+        hwc_rect_t overlap = list->hwLayers[ovlapIndex].displayFrame;
+        // render buffer width will be the max of two layers
+        // Align Widht and height to 32, Mdp would be configured
+        // with Aligned overlap w/h
+        finalW = max(finalW, ALIGN((overlap.right - overlap.left), 32));
+        finalH += ALIGN((overlap.bottom - overlap.top), 32);
+        if(finalH > ALIGN((overlap.bottom - overlap.top), 32)) {
+            // Calculate the offset for RGBA(4BPP)
+            ptorInfo->mRenderBuffOffset[i] = finalW *
+                (finalH - ALIGN((overlap.bottom - overlap.top), 32)) * 4;
+            // Calculate the dest top, left will always be zero
+            ptorInfo->displayFrame[i].top = (finalH -
+                                (ALIGN((overlap.bottom - overlap.top), 32)));
+        }
+        // calculate the right and bottom values
+        ptorInfo->displayFrame[i].right =  ptorInfo->displayFrame[i].left +
+                                            (overlap.right - overlap.left);
+        ptorInfo->displayFrame[i].bottom = ptorInfo->displayFrame[i].top +
+                                            (overlap.bottom - overlap.top);
+    }
+
+    getBufferSizeAndDimensions(finalW, finalH, HAL_PIXEL_FORMAT_RGBA_8888,
+                               alignW, alignH);
+
+    if ((mAlignedWidth != alignW) || (mAlignedHeight != alignH)) {
+        // Overlap rect has changed, so free render buffers
+        freeRenderBuffers();
+    }
+
+    int ret = allocRenderBuffers(alignW, alignH, HAL_PIXEL_FORMAT_RGBA_8888);
+
+    if (ret < 0) {
+        ALOGE("%s: Render buffer allocation failed", __FUNCTION__);
+        return false;
+    }
+
+    mAlignedWidth = alignW;
+    mAlignedHeight = alignH;
+    mCurRenderBufferIndex = (mCurRenderBufferIndex + 1) % NUM_RENDER_BUFFERS;
+    return true;
+}
+
 bool CopyBit::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
                                                             int dpy) {
 
@@ -286,8 +347,8 @@
     //Allocate render buffers if they're not allocated
     if (ctx->mMDP.version != qdutils::MDP_V3_0_4 &&
             (useCopybitForYUV || useCopybitForRGB)) {
-        int ret = allocRenderBuffers(mAlignedFBWidth,
-                                     mAlignedFBHeight,
+        int ret = allocRenderBuffers(mAlignedWidth,
+                                     mAlignedHeight,
                                      HAL_PIXEL_FORMAT_RGBA_8888);
         if (ret < 0) {
             return false;
@@ -344,7 +405,7 @@
                                       hwc_display_contents_1_t *list,
                                       int dpy, int *copybitFd) {
      int layerCount = 0;
-     uint32_t last = list->numHwLayers - 1;
+     uint32_t last = (uint32_t)list->numHwLayers - 1;
      hwc_layer_1_t *fbLayer = &list->hwLayers[last];
      private_handle_t *fbhnd = (private_handle_t *)fbLayer->handle;
 
@@ -375,9 +436,20 @@
        if(layerCount == 1)
           return true;
 
-       if(layerCount == MAX_LAYERS_FOR_ABC) {
-          // Pass the Acquire Fence FD to driver for base layer
+       if(layerCount ==  MAX_LAYERS_FOR_ABC) {
           int abcRenderBufIdx = ctx->listStats[dpy].renderBufIndexforABC;
+          //enable ABC only for non intersecting layers.
+          hwc_rect_t displayFrame =
+                  list->hwLayers[abcRenderBufIdx].displayFrame;
+          for (int i = abcRenderBufIdx + 1; i < layerCount; i++) {
+             hwc_rect_t tmpDisplayFrame = list->hwLayers[i].displayFrame;
+             hwc_rect_t result = getIntersection(displayFrame,tmpDisplayFrame);
+             if (isValidRect(result)) {
+                ctx->listStats[dpy].renderBufIndexforABC = -1;
+                return false;
+             }
+          }
+          // Pass the Acquire Fence FD to driver for base layer
           private_handle_t *renderBuffer =
           (private_handle_t *)list->hwLayers[abcRenderBufIdx].handle;
           copybit_device_t *copybit = getCopyBitDevice();
@@ -385,7 +457,7 @@
              copybit->set_sync(copybit,
              list->hwLayers[abcRenderBufIdx].acquireFenceFd);
           }
-          for(int i = 1; i < layerCount; i++){
+          for(int i = abcRenderBufIdx + 1; i < layerCount; i++){
              int retVal = drawLayerUsingCopybit(ctx,
                &(list->hwLayers[i]),renderBuffer, 0);
              if(retVal < 0) {
@@ -461,7 +533,6 @@
 
     // numAppLayers-1, as we iterate from 0th layer index with HWC_COPYBIT flag
     for (int i = 0; i <= (ctx->listStats[dpy].numAppLayers-1); i++) {
-        hwc_layer_1_t *layer = &list->hwLayers[i];
         if(!(layerProp[i].mFlags & HWC_COPYBIT)) {
             ALOGD_IF(DEBUG_COPYBIT, "%s: Not Marked for copybit", __FUNCTION__);
             continue;
@@ -502,6 +573,149 @@
     return true;
 }
 
+int CopyBit::drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
+    int fd = -1;
+    PtorInfo* ptorInfo = &(ctx->mPtorInfo);
+
+    if (ctx->mMDP.version < qdutils::MDP_V4_0) {
+        ALOGE("%s: Invalid request", __FUNCTION__);
+        return fd;
+    }
+
+    private_handle_t *renderBuffer = getCurrentRenderBuffer();
+
+    if (!renderBuffer) {
+        ALOGE("%s: Render buffer layer handle is NULL", __FUNCTION__);
+        return fd;
+    }
+
+    int copybitLayerCount = 0;
+    for(int j = 0; j < ptorInfo->count; j++) {
+        int ovlapIndex = ptorInfo->layerIndex[j];
+        hwc_rect_t overlap = list->hwLayers[ovlapIndex].displayFrame;
+
+        // Draw overlapped content of layers on render buffer
+        for (int i = 0; i <= ovlapIndex; i++) {
+            hwc_layer_1_t *layer = &list->hwLayers[i];
+            if(!isValidRect(getIntersection(layer->displayFrame,
+                                               overlap))) {
+                continue;
+            }
+            if ((list->hwLayers[i].acquireFenceFd != -1)) {
+                // Wait for acquire fence on the App buffers.
+                if(sync_wait(list->hwLayers[i].acquireFenceFd, 1000) < 0) {
+                    ALOGE("%s: sync_wait error!! error no = %d err str = %s",
+                          __FUNCTION__, errno, strerror(errno));
+                }
+                close(list->hwLayers[i].acquireFenceFd);
+                list->hwLayers[i].acquireFenceFd = -1;
+            }
+
+            int retVal = drawRectUsingCopybit(ctx, layer, renderBuffer, overlap,
+                                                ptorInfo->displayFrame[j]);
+            copybitLayerCount++;
+            if(retVal < 0) {
+                ALOGE("%s: drawRectUsingCopybit failed", __FUNCTION__);
+                copybitLayerCount = 0;
+            }
+        }
+    }
+
+    if (copybitLayerCount) {
+        copybit_device_t *copybit = getCopyBitDevice();
+        copybit->flush_get_fence(copybit, &fd);
+    }
+
+    ALOGD_IF(DEBUG_COPYBIT, "%s: done! copybitLayerCount = %d", __FUNCTION__,
+             copybitLayerCount);
+    return fd;
+}
+
+int CopyBit::drawRectUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
+                        private_handle_t *renderBuffer, hwc_rect_t overlap,
+                        hwc_rect_t destRect)
+{
+    hwc_context_t* ctx = (hwc_context_t*)(dev);
+    if (!ctx) {
+        ALOGE("%s: null context ", __FUNCTION__);
+        return -1;
+    }
+
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+    if (!hnd) {
+        ALOGE("%s: invalid handle", __FUNCTION__);
+        return -1;
+    }
+
+    private_handle_t *dstHandle = (private_handle_t *)renderBuffer;
+    if (!dstHandle) {
+        ALOGE("%s: RenderBuffer handle is NULL", __FUNCTION__);
+        return -1;
+    }
+
+    // Set the Copybit Source
+    copybit_image_t src;
+    src.handle = (native_handle_t *)layer->handle;
+    src.w = hnd->width;
+    src.h = hnd->height;
+    src.base = (void *)hnd->base;
+    src.format = hnd->format;
+    src.horiz_padding = 0;
+    src.vert_padding = 0;
+
+
+    hwc_rect_t dispFrame = layer->displayFrame;
+    hwc_rect_t iRect = getIntersection(dispFrame, overlap);
+    hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+    qhwc::calculate_crop_rects(crop, dispFrame, iRect,
+                               layer->transform);
+
+    // Copybit source rect
+    copybit_rect_t srcRect = {crop.left, crop.top, crop.right,
+        crop.bottom};
+
+    // Copybit destination rect
+    copybit_rect_t dstRect = {destRect.left, destRect.top, destRect.right,
+        destRect.bottom};
+
+    // Copybit dst
+    copybit_image_t dst;
+    dst.handle = (native_handle_t *)dstHandle;
+    dst.w = ALIGN(dstHandle->width, 32);
+    dst.h = dstHandle->height;
+    dst.base = (void *)dstHandle->base;
+    dst.format = dstHandle->format;
+
+    copybit_device_t *copybit = mEngine;
+
+    // Copybit region is the destRect
+    hwc_rect_t regRect = {dstRect.l,dstRect.t, dstRect.r, dstRect.b};
+    hwc_region_t region;
+    region.numRects = 1;
+    region.rects  = &regRect;
+    region_iterator copybitRegion(region);
+    int acquireFd = layer->acquireFenceFd;
+
+    copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_WIDTH,
+                           renderBuffer->width);
+    copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT,
+                           renderBuffer->height);
+    copybit->set_parameter(copybit, COPYBIT_TRANSFORM, layer->transform);
+    copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, layer->planeAlpha);
+    copybit->set_parameter(copybit, COPYBIT_BLEND_MODE, layer->blending);
+    copybit->set_parameter(copybit, COPYBIT_DITHER,
+        (dst.format == HAL_PIXEL_FORMAT_RGB_565) ? COPYBIT_ENABLE :
+        COPYBIT_DISABLE);
+    copybit->set_sync(copybit, acquireFd);
+    int err = copybit->stretch(copybit, &dst, &src, &dstRect, &srcRect,
+                               &copybitRegion);
+
+    if (err < 0)
+        ALOGE("%s: copybit stretch failed",__FUNCTION__);
+
+    return err;
+}
+
 int  CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
                           private_handle_t *renderBuffer, bool isFG)
 {
@@ -872,18 +1086,30 @@
     mRelFd[mCurRenderBufferIndex] = dup(fd);
 }
 
+void CopyBit::setReleaseFdSync(int fd) {
+    if (mRelFd[mCurRenderBufferIndex] >=0) {
+        int ret = -1;
+        ret = sync_wait(mRelFd[mCurRenderBufferIndex], 1000);
+        if (ret < 0)
+            ALOGE("%s: sync_wait error! errno = %d, err str = %s",
+                  __FUNCTION__, errno, strerror(errno));
+        close(mRelFd[mCurRenderBufferIndex]);
+    }
+    mRelFd[mCurRenderBufferIndex] = dup(fd);
+}
+
 struct copybit_device_t* CopyBit::getCopyBitDevice() {
     return mEngine;
 }
 
-CopyBit::CopyBit(hwc_context_t *ctx, const int& dpy) : mIsModeOn(false),
-        mCopyBitDraw(false), mCurRenderBufferIndex(0), mEngine(0) {
+CopyBit::CopyBit(hwc_context_t *ctx, const int& dpy) :  mEngine(0),
+    mIsModeOn(false), mCopyBitDraw(false), mCurRenderBufferIndex(0) {
 
     getBufferSizeAndDimensions(ctx->dpyAttr[dpy].xres,
             ctx->dpyAttr[dpy].yres,
             HAL_PIXEL_FORMAT_RGBA_8888,
-            mAlignedFBWidth,
-            mAlignedFBHeight);
+            mAlignedWidth,
+            mAlignedHeight);
 
     hw_module_t const *module;
     for (int i = 0; i < NUM_RENDER_BUFFERS; i++) {
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index 3e9dff0..99a39c8 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -49,6 +49,12 @@
 
     void setReleaseFd(int fd);
 
+    void setReleaseFdSync(int fd);
+
+    bool prepareOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+
+    int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+
 private:
     /* cached data */
     struct LayerCache {
@@ -79,6 +85,10 @@
     // Helper functions for copybit composition
     int  drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
                           private_handle_t *renderBuffer, bool isFG);
+    // Helper function to draw copybit layer for PTOR comp
+    int drawRectUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
+                          private_handle_t *renderBuffer, hwc_rect_t overlap,
+                          hwc_rect_t destRect);
     int fillColorUsingCopybit(hwc_layer_1_t *layer,
                           private_handle_t *renderBuffer);
     bool canUseCopybitForYUV (hwc_context_t *ctx);
@@ -114,8 +124,8 @@
     //Dynamic composition threshold for deciding copybit usage.
     double mDynThreshold;
     bool mSwapRectEnable;
-    int mAlignedFBWidth;
-    int mAlignedFBHeight;
+    int mAlignedWidth;
+    int mAlignedHeight;
     int mDirtyLayerIndex;
     LayerCache mLayerCache;
     FbCache mFbCache;
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index ae29f8f..5014af9 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -109,8 +109,7 @@
             mRot = NULL;
             return false;
         }
-        info.format = (mRot)->getDstFormat();
-        updateSource(orient, info, sourceCrop);
+        updateSource(orient, info, sourceCrop, mRot);
         rotFlags |= ovutils::ROT_PREROTATED;
     }
     return true;
@@ -208,7 +207,7 @@
                                    transform, orient);
         //Store the displayFrame, will be used in getDisplayViewFrame
         ctx->dpyAttr[mDpy].mDstRect = displayFrame;
-        setMdpFlags(layer, mdpFlags, 0, transform);
+        setMdpFlags(ctx, layer, mdpFlags, 0, transform);
         // For External use rotator if there is a rotation value set
         ret = preRotateExtDisplay(ctx, layer, info,
                 sourceCrop, mdpFlags, rotFlags);
@@ -275,8 +274,8 @@
                  __FUNCTION__);
         return false;
     }
-    ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
     mModeOn = configure(ctx, list, fbUpdatingRect, fbZorder);
+    ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
     return mModeOn;
 }
 
@@ -474,9 +473,18 @@
 
     ovutils::eDest destR = ovutils::OV_INVALID;
 
-    //Request right pipe (2 pipes needed only if dim > 2048)
-    if((fbUpdatingRect.right - fbUpdatingRect.left) >
-            qdutils::MAX_DISPLAY_DIM) {
+    /*  Use 2 pipes IF
+        a) FB's width is > Mixer width or
+        b) On primary, driver has indicated with caps to split always. This is
+           based on an empirically derived value of panel height.
+    */
+
+    bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
+            qdutils::MDPVersion::getInstance().isSrcSplitAlways();
+
+    if(((fbUpdatingRect.right - fbUpdatingRect.left) >
+            (int)qdutils::MDPVersion::getInstance().getMaxMixerWidth()) or
+            primarySplitAlways) {
         destR = ov.getPipe(pipeSpecs);
         if(destR == ovutils::OV_INVALID) {
             ALOGE("%s: No pipes available to configure fb for dpy %d's right"
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 06e0b12..adf30fe 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -26,6 +26,7 @@
 #include "hwc_fbupdate.h"
 #include "hwc_ad.h"
 #include <overlayRotator.h>
+#include "hwc_copybit.h"
 
 using namespace overlay;
 using namespace qdutils;
@@ -58,7 +59,7 @@
 
 MDPComp::MDPComp(int dpy):mDpy(dpy){};
 
-void MDPComp::dump(android::String8& buf)
+void MDPComp::dump(android::String8& buf, hwc_context_t *ctx)
 {
     if(mCurrentFrame.layerCount > MAX_NUM_APP_LAYERS)
         return;
@@ -72,6 +73,21 @@
     dumpsys_log(buf,"needsFBRedraw:%3s  pipesUsed:%2d  MaxPipesPerMixer: %d \n",
                 (mCurrentFrame.needsRedraw? "YES" : "NO"),
                 mCurrentFrame.mdpCount, sMaxPipesPerMixer);
+    if(isDisplaySplit(ctx, mDpy)) {
+        dumpsys_log(buf, "Programmed ROI's: Left: [%d, %d, %d, %d] "
+                "Right: [%d, %d, %d, %d] \n",
+                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);
+    } else {
+        dumpsys_log(buf, "Programmed ROI: [%d, %d, %d, %d] \n",
+                ctx->listStats[mDpy].lRoi.left,ctx->listStats[mDpy].lRoi.top,
+                ctx->listStats[mDpy].lRoi.right,
+                ctx->listStats[mDpy].lRoi.bottom);
+    }
     dumpsys_log(buf," ---------------------------------------------  \n");
     dumpsys_log(buf," listIdx | cached? | mdpIndex | comptype  |  Z  \n");
     dumpsys_log(buf," ---------------------------------------------  \n");
@@ -111,11 +127,6 @@
         sEnableMixedMode = false;
     }
 
-    if(property_get("debug.mdpcomp.logs", property, NULL) > 0) {
-        if(atoi(property) != 0)
-            sDebugLogs = true;
-    }
-
     sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
     if(property_get("debug.mdpcomp.maxpermixer", property, "-1") > 0) {
         int val = atoi(property);
@@ -144,11 +155,20 @@
         }
     }
 
-    if((property_get("debug.mdpcomp.4k2kSplit", property, "0") > 0) &&
-            (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
-             (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+    if(!qdutils::MDPVersion::getInstance().isSrcSplit() &&
+            property_get("persist.mdpcomp.4k2kSplit", property, "0") > 0 &&
+            (!strncmp(property, "1", PROPERTY_VALUE_MAX) ||
+            !strncasecmp(property,"true", PROPERTY_VALUE_MAX))) {
         sEnable4k2kYUVSplit = true;
     }
+
+    if ((property_get("persist.hwc.ptor.enable", property, NULL) > 0) &&
+            ((!strncasecmp(property, "true", PROPERTY_VALUE_MAX )) ||
+             (!strncmp(property, "1", PROPERTY_VALUE_MAX )))) {
+        ctx->mCopyBit[HWC_DISPLAY_PRIMARY] = new CopyBit(ctx,
+                                                    HWC_DISPLAY_PRIMARY);
+    }
+
     return true;
 }
 
@@ -159,6 +179,11 @@
     ctx->mLayerRotMap[mDpy]->clear();
 }
 
+void MDPComp::reset() {
+    sHandleTimeout = false;
+    mModeOn = false;
+}
+
 void MDPComp::timeout_handler(void *udata) {
     struct hwc_context_t* ctx = (struct hwc_context_t*)(udata);
 
@@ -290,7 +315,7 @@
 
 bool MDPComp::isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer) {
     private_handle_t *hnd = (private_handle_t *)layer->handle;
-    if((not isYuvBuffer(hnd) and has90Transform(layer)) or
+    if((has90Transform(layer) and (not isRotationDoable(ctx, hnd))) ||
         (not isValidDimension(ctx,layer))
         //More conditions here, SKIP, sRGB+Blend etc
         ) {
@@ -317,12 +342,14 @@
 
     hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
     hwc_rect_t dst = layer->displayFrame;
-    int crop_w = crop.right - crop.left;
-    int crop_h = crop.bottom - crop.top;
+    bool rotated90 = (bool)(layer->transform & HAL_TRANSFORM_ROT_90);
+    int crop_w = rotated90 ? crop.bottom - crop.top : crop.right - crop.left;
+    int crop_h = rotated90 ? crop.right - crop.left : crop.bottom - crop.top;
     int dst_w = dst.right - dst.left;
     int dst_h = dst.bottom - dst.top;
     float w_scale = ((float)crop_w / (float)dst_w);
     float h_scale = ((float)crop_h / (float)dst_h);
+    MDPVersion& mdpHw = MDPVersion::getInstance();
 
     /* Workaround for MDP HW limitation in DSI command mode panels where
      * FPS will not go beyond 30 if buffers on RGB pipes are of width or height
@@ -334,29 +361,29 @@
         return false;
 
     if((w_scale > 1.0f) || (h_scale > 1.0f)) {
-        const uint32_t maxMDPDownscale =
-            qdutils::MDPVersion::getInstance().getMaxMDPDownscale();
+        const uint32_t maxMDPDownscale = mdpHw.getMaxMDPDownscale();
         const float w_dscale = w_scale;
         const float h_dscale = h_scale;
 
         if(ctx->mMDP.version >= qdutils::MDSS_V5) {
 
-            if(!qdutils::MDPVersion::getInstance().supportsDecimation()) {
+            if(!mdpHw.supportsDecimation()) {
                 /* On targets that doesnt support Decimation (eg.,8x26)
                  * maximum downscale support is overlay pipe downscale.
                  */
-                if(crop_w > MAX_DISPLAY_DIM || w_dscale > maxMDPDownscale ||
+                if(crop_w > mdpHw.getMaxMixerWidth() ||
+                        w_dscale > maxMDPDownscale ||
                         h_dscale > maxMDPDownscale)
                     return false;
             } else {
                 // Decimation on macrotile format layers is not supported.
                 if(isTileRendered(hnd)) {
-                    /* MDP can read maximum MAX_DISPLAY_DIM width.
-                     * Bail out if
-                     *      1. Src crop > MAX_DISPLAY_DIM on nonsplit MDPComp
+                    /* Bail out if
+                     *      1. Src crop > Mixer limit on nonsplit MDPComp
                      *      2. exceeds maximum downscale limit
                      */
-                    if(((crop_w > MAX_DISPLAY_DIM) && !sSrcSplitEnabled) ||
+                    if(((crop_w > mdpHw.getMaxMixerWidth()) &&
+                                !sSrcSplitEnabled) ||
                             w_dscale > maxMDPDownscale ||
                             h_dscale > maxMDPDownscale) {
                         return false;
@@ -371,8 +398,7 @@
     }
 
     if((w_scale < 1.0f) || (h_scale < 1.0f)) {
-        const uint32_t upscale =
-            qdutils::MDPVersion::getInstance().getMaxMDPUpscale();
+        const uint32_t upscale = mdpHw.getMaxMDPUpscale();
         const float w_uscale = 1.0f / w_scale;
         const float h_uscale = 1.0f / h_scale;
 
@@ -473,11 +499,17 @@
         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;
+            hwc_rect_t dst = layer->displayFrame;
+            hwc_rect_t updatingRect = dst;
 
 #ifdef QCOM_BSP
             if(!needsScaling(layer) && !layer->transform)
-                updatingRect =  layer->dirtyRect;
+            {
+                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
 
             roi = getUnion(roi, updatingRect);
@@ -579,8 +611,9 @@
 
     for(int index = 0; index < numAppLayers; index++ ) {
         hwc_layer_1_t* layer = &list->hwLayers[index];
+        private_handle_t *hnd = (private_handle_t *)layer->handle;
         if ((mCachedFrame.hnd[index] != layer->handle) ||
-                isYuvBuffer((private_handle_t *)layer->handle)) {
+                isYuvBuffer(hnd)) {
             hwc_rect_t dst = layer->displayFrame;
             hwc_rect_t updatingRect = dst;
 
@@ -655,8 +688,10 @@
         return false;
     }
 
-    if(mDpy > HWC_DISPLAY_PRIMARY && (priDispW > MAX_DISPLAY_DIM) &&
-                              (ctx->dpyAttr[mDpy].xres < MAX_DISPLAY_DIM)) {
+    MDPVersion& mdpHw = MDPVersion::getInstance();
+    if(mDpy > HWC_DISPLAY_PRIMARY &&
+            (priDispW >  mdpHw.getMaxMixerWidth()) &&
+            (ctx->dpyAttr[mDpy].xres <  mdpHw.getMaxMixerWidth())) {
         // Disable MDP comp on Secondary when the primary is highres panel and
         // the secondary is a normal 1080p, because, MDP comp on secondary under
         // in such usecase, decimation gets used for downscale and there will be
@@ -677,7 +712,7 @@
         hwc_layer_1_t* layer = &list->hwLayers[i];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
 
-        if(isYuvBuffer(hnd) && has90Transform(layer)) {
+        if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
             if(!canUseRotator(ctx, mDpy)) {
                 ALOGD_IF(isDebug(), "%s: Can't use rotator for dpy %d",
                         __FUNCTION__, mDpy);
@@ -688,11 +723,9 @@
         //For 8x26 with panel width>1k, if RGB layer needs HFLIP fail mdp comp
         // may not need it if Gfx pre-rotation can handle all flips & rotations
         int transform = (layer->flags & HWC_COLOR_FILL) ? 0 : layer->transform;
-        if(qdutils::MDPVersion::getInstance().is8x26() &&
-                                (ctx->dpyAttr[mDpy].xres > 1024) &&
-                                (transform & HWC_TRANSFORM_FLIP_H) &&
-                                (!isYuvBuffer(hnd)))
-                   return false;
+        if( mdpHw.is8x26() && (ctx->dpyAttr[mDpy].xres > 1024) &&
+                (transform & HWC_TRANSFORM_FLIP_H) && (!isYuvBuffer(hnd)))
+            return false;
     }
 
     if(ctx->mAD->isDoable()) {
@@ -703,6 +736,8 @@
     bool ret = false;
     if(fullMDPComp(ctx, list)) {
         ret = true;
+    } else if(fullMDPCompWithPTOR(ctx, list)) {
+        ret = true;
     } else if(partialMDPComp(ctx, list)) {
         ret = true;
     }
@@ -752,6 +787,177 @@
     return true;
 }
 
+/* Full MDP Composition with Peripheral Tiny Overlap Removal.
+ * MDP bandwidth limitations can be avoided, if the overlap region
+ * covered by the smallest layer at a higher z-order, gets composed
+ * by Copybit on a render buffer, which can be queued to MDP.
+ */
+bool MDPComp::fullMDPCompWithPTOR(hwc_context_t *ctx,
+    hwc_display_contents_1_t* list) {
+
+    const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+    const int stagesForMDP = min(sMaxPipesPerMixer,
+            ctx->mOverlay->availablePipes(mDpy, Overlay::MIXER_DEFAULT));
+
+    // Hard checks where we cannot use this mode
+    if (mDpy || !ctx->mCopyBit[mDpy] || isDisplaySplit(ctx, mDpy)) {
+        ALOGD_IF(isDebug(), "%s: Feature not supported!", __FUNCTION__);
+        return false;
+    }
+
+    // Frame level checks
+    if ((numAppLayers > stagesForMDP) || isSkipPresent(ctx, mDpy) ||
+        isYuvPresent(ctx, mDpy) || mCurrentFrame.dropCount ||
+        isSecurePresent(ctx, mDpy)) {
+        ALOGD_IF(isDebug(), "%s: Frame not supported!", __FUNCTION__);
+        return false;
+    }
+    // MDP comp checks
+    for(int i = 0; i < numAppLayers; i++) {
+        hwc_layer_1_t* layer = &list->hwLayers[i];
+        if(not isSupportedForMDPComp(ctx, layer)) {
+            ALOGD_IF(isDebug(), "%s: Unsupported layer in list",__FUNCTION__);
+            return false;
+        }
+    }
+
+    /* We cannot use this composition mode, if:
+     1. A below layer needs scaling.
+     2. Overlap is not peripheral to display.
+     3. Overlap or a below layer has 90 degree transform.
+     4. Overlap area > (1/3 * FrameBuffer) area, based on Perf inputs.
+     */
+
+    int minLayerIndex[MAX_PTOR_LAYERS] = { -1, -1};
+    hwc_rect_t overlapRect[MAX_PTOR_LAYERS];
+    memset(overlapRect, 0, sizeof(overlapRect));
+    int layerPixelCount, minPixelCount = 0;
+    int numPTORLayersFound = 0;
+    for (int i = numAppLayers-1; (i >= 0 &&
+                                  numPTORLayersFound < MAX_PTOR_LAYERS); i--) {
+        hwc_layer_1_t* layer = &list->hwLayers[i];
+        hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+        hwc_rect_t dispFrame = layer->displayFrame;
+        layerPixelCount = (crop.right - crop.left) * (crop.bottom - crop.top);
+        // PTOR layer should be peripheral and cannot have transform
+        if (!isPeripheral(dispFrame, ctx->mViewFrame[mDpy]) ||
+                                has90Transform(layer)) {
+            continue;
+        }
+        if((3 * (layerPixelCount + minPixelCount)) >
+                ((int)ctx->dpyAttr[mDpy].xres * (int)ctx->dpyAttr[mDpy].yres)) {
+            // Overlap area > (1/3 * FrameBuffer) area, based on Perf inputs.
+            continue;
+        }
+        // Found the PTOR layer
+        bool found = true;
+        for (int j = i-1; j >= 0; j--) {
+            // Check if the layers below this layer qualifies for PTOR comp
+            hwc_layer_1_t* layer = &list->hwLayers[j];
+            hwc_rect_t disFrame = layer->displayFrame;
+            //layer below PTOR is intersecting and has 90 degree transform or
+            // needs scaling cannot be supported.
+            if ((isValidRect(getIntersection(dispFrame, disFrame)))
+                            && (has90Transform(layer) || needsScaling(layer))) {
+                found = false;
+                break;
+            }
+        }
+        // Store the minLayer Index
+        if(found) {
+            minLayerIndex[numPTORLayersFound] = i;
+            overlapRect[numPTORLayersFound] = list->hwLayers[i].displayFrame;
+            minPixelCount += layerPixelCount;
+            numPTORLayersFound++;
+        }
+    }
+
+    if(isValidRect(getIntersection(overlapRect[0], overlapRect[1]))) {
+        ALOGD_IF(isDebug(), "%s: Ignore Rect2 its intersects with Rect1",
+                 __FUNCTION__);
+        // reset second minLayerIndex[1];
+        minLayerIndex[1] = -1;
+        numPTORLayersFound--;
+    }
+
+    // No overlap layers
+    if (!numPTORLayersFound)
+        return false;
+
+    ctx->mPtorInfo.count = numPTORLayersFound;
+    for(int i = 0; i < MAX_PTOR_LAYERS; i++) {
+        ctx->mPtorInfo.layerIndex[i] = minLayerIndex[i];
+    }
+
+    if (!ctx->mCopyBit[mDpy]->prepareOverlap(ctx, list)) {
+        // reset PTOR
+        ctx->mPtorInfo.count = 0;
+        return false;
+    }
+    // Store the displayFrame and the sourceCrops of the layers
+    hwc_rect_t displayFrame[numAppLayers];
+    hwc_rect_t sourceCrop[numAppLayers];
+    for(int i = 0; i < numAppLayers; i++) {
+        hwc_layer_1_t* layer = &list->hwLayers[i];
+        displayFrame[i] = layer->displayFrame;
+        sourceCrop[i] = integerizeSourceCrop(layer->sourceCropf);
+    }
+
+    for(int j = 0; j < numPTORLayersFound; j++) {
+        int index =  ctx->mPtorInfo.layerIndex[j];
+        // Remove overlap from crop & displayFrame of below layers
+        for (int i = 0; i < index && index !=-1; i++) {
+            hwc_layer_1_t* layer = &list->hwLayers[i];
+            if(!isValidRect(getIntersection(layer->displayFrame,
+                                            overlapRect[j])))  {
+                continue;
+            }
+            // Update layer attributes
+            hwc_rect_t srcCrop = integerizeSourceCrop(layer->sourceCropf);
+            hwc_rect_t destRect = deductRect(layer->displayFrame,
+                                             overlapRect[j]);
+            qhwc::calculate_crop_rects(srcCrop, layer->displayFrame, destRect,
+                                       layer->transform);
+            layer->sourceCropf.left = (float)srcCrop.left;
+            layer->sourceCropf.top = (float)srcCrop.top;
+            layer->sourceCropf.right = (float)srcCrop.right;
+            layer->sourceCropf.bottom = (float)srcCrop.bottom;
+        }
+    }
+
+    mCurrentFrame.mdpCount = numAppLayers;
+    mCurrentFrame.fbCount = 0;
+    mCurrentFrame.fbZ = -1;
+
+    for (int j = 0; j < numAppLayers; j++)
+        mCurrentFrame.isFBComposed[j] = false;
+
+    bool result = postHeuristicsHandling(ctx, list);
+
+    // Restore layer attributes
+    for(int i = 0; i < numAppLayers; i++) {
+        hwc_layer_1_t* layer = &list->hwLayers[i];
+        layer->displayFrame = displayFrame[i];
+        layer->sourceCropf.left = (float)sourceCrop[i].left;
+        layer->sourceCropf.top = (float)sourceCrop[i].top;
+        layer->sourceCropf.right = (float)sourceCrop[i].right;
+        layer->sourceCropf.bottom = (float)sourceCrop[i].bottom;
+    }
+
+    if (!result) {
+        // reset PTOR
+        ctx->mPtorInfo.count = 0;
+        reset(ctx);
+    } else {
+        ALOGD_IF(isDebug(), "%s: PTOR Indexes: %d and %d", __FUNCTION__,
+                 ctx->mPtorInfo.layerIndex[0],  ctx->mPtorInfo.layerIndex[1]);
+    }
+
+    ALOGD_IF(isDebug(), "%s: Postheuristics %s!", __FUNCTION__,
+             (result ? "successful" : "failed"));
+    return result;
+}
+
 bool MDPComp::partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list)
 {
     if(!sEnableMixedMode) {
@@ -931,6 +1137,8 @@
             mDpy ) {
         return false;
     }
+    if(ctx->listStats[mDpy].secureUI)
+        return false;
     return true;
 }
 
@@ -989,7 +1197,7 @@
         return false;
     }
 
-    if(layer->transform & HWC_TRANSFORM_ROT_90 && !canUseRotator(ctx,mDpy)) {
+    if(has90Transform(layer) && !canUseRotator(ctx, mDpy)) {
         ALOGD_IF(isDebug(), "%s: no free DMA pipe",__FUNCTION__);
         return false;
     }
@@ -1252,7 +1460,7 @@
         hwc_display_contents_1_t* list) {
 
     //Capability checks
-    if(!resourceCheck()) {
+    if(!resourceCheck(ctx, list)) {
         ALOGD_IF(isDebug(), "%s: resource check failed", __FUNCTION__);
         return false;
     }
@@ -1326,12 +1534,31 @@
     return true;
 }
 
-bool MDPComp::resourceCheck() {
+bool MDPComp::resourceCheck(hwc_context_t* ctx,
+        hwc_display_contents_1_t* list) {
     const bool fbUsed = mCurrentFrame.fbCount;
     if(mCurrentFrame.mdpCount > sMaxPipesPerMixer - fbUsed) {
         ALOGD_IF(isDebug(), "%s: Exceeds MAX_PIPES_PER_MIXER",__FUNCTION__);
         return false;
     }
+    // Init rotCount to number of rotate sessions used by other displays
+    int rotCount = ctx->mRotMgr->getNumActiveSessions();
+    // Count the number of rotator sessions required for current display
+    for (int index = 0; index < mCurrentFrame.layerCount; index++) {
+        if(!mCurrentFrame.isFBComposed[index]) {
+            hwc_layer_1_t* layer = &list->hwLayers[index];
+            private_handle_t *hnd = (private_handle_t *)layer->handle;
+            if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
+                rotCount++;
+            }
+        }
+    }
+    // if number of layers to rotate exceeds max rotator sessions, bail out.
+    if(rotCount > RotMgr::MAX_ROT_SESS) {
+        ALOGD_IF(isDebug(), "%s: Exceeds max rotator sessions  %d",
+                                    __FUNCTION__, mDpy);
+        return false;
+    }
     return true;
 }
 
@@ -1379,9 +1606,16 @@
 
 int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     int ret = 0;
-    const int numLayers = ctx->listStats[mDpy].numAppLayers;
     char property[PROPERTY_VALUE_MAX];
 
+    if(!ctx || !list) {
+        ALOGE("%s: Invalid context or list",__FUNCTION__);
+        mCachedFrame.reset();
+        return -1;
+    }
+
+    const int numLayers = ctx->listStats[mDpy].numAppLayers;
+
     if(property_get("debug.hwc.simulate", property, NULL) > 0) {
         int currentFlags = atoi(property);
         if(currentFlags != sSimulationFlags) {
@@ -1390,6 +1624,9 @@
                     sSimulationFlags, sSimulationFlags);
         }
     }
+    // reset PTOR
+    if(!mDpy)
+        memset(&(ctx->mPtorInfo), 0, sizeof(ctx->mPtorInfo));
 
     //Do not cache the information for next draw cycle.
     if(numLayers > MAX_NUM_APP_LAYERS or (!numLayers)) {
@@ -1424,7 +1661,8 @@
     if(isFrameDoable(ctx)) {
         generateROI(ctx, list);
 
-        if(tryFullFrame(ctx, list) || tryVideoOnly(ctx, list)) {
+        mModeOn = tryFullFrame(ctx, list) || tryVideoOnly(ctx, list);
+        if(mModeOn) {
             setMDPCompLayerFlags(ctx, list);
         } else {
             resetROI(ctx, mDpy);
@@ -1443,7 +1681,7 @@
         ALOGD("GEOMETRY change: %d",
                 (list->flags & HWC_GEOMETRY_CHANGED));
         android::String8 sDump("");
-        dump(sDump);
+        dump(sDump, ctx);
         ALOGD("%s",sDump.string());
     }
 
@@ -1484,25 +1722,45 @@
     }
     return bRet;
 }
+
+int MDPComp::drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    int fd = -1;
+    if (ctx->mPtorInfo.isActive()) {
+        fd = ctx->mCopyBit[mDpy]->drawOverlap(ctx, list);
+        if (fd < 0) {
+            ALOGD_IF(isDebug(),"%s: failed", __FUNCTION__);
+        }
+    }
+    return fd;
+}
 //=============MDPCompNonSplit==================================================
 
 void MDPCompNonSplit::adjustForSourceSplit(hwc_context_t *ctx,
-        hwc_display_contents_1_t*) {
-    //As we split 4kx2k yuv layer and program to 2 VG pipes
-    //(if available) increase mdpcount accordingly
-    mCurrentFrame.mdpCount += ctx->listStats[mDpy].yuv4k2kCount;
-
+        hwc_display_contents_1_t* list) {
     //If 4k2k Yuv layer split is possible,  and if
     //fbz is above 4k2k layer, increment fb zorder by 1
     //as we split 4k2k layer and increment zorder for right half
     //of the layer
+    if(!ctx)
+        return;
     if(mCurrentFrame.fbZ >= 0) {
-        int n4k2kYuvCount = ctx->listStats[mDpy].yuv4k2kCount;
-        for(int index = 0; index < n4k2kYuvCount; index++){
-            int n4k2kYuvIndex =
-                    ctx->listStats[mDpy].yuv4k2kIndices[index];
-            if(mCurrentFrame.fbZ >= n4k2kYuvIndex){
-                mCurrentFrame.fbZ += 1;
+        for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount;
+                index++) {
+            if(!mCurrentFrame.isFBComposed[index]) {
+                if(mdpNextZOrder == mCurrentFrame.fbZ) {
+                    mdpNextZOrder++;
+                }
+                mdpNextZOrder++;
+                hwc_layer_1_t* layer = &list->hwLayers[index];
+                private_handle_t *hnd = (private_handle_t *)layer->handle;
+                if(is4kx2kYuvBuffer(hnd)) {
+                    if(mdpNextZOrder <= mCurrentFrame.fbZ)
+                        mCurrentFrame.fbZ += 1;
+                    mdpNextZOrder++;
+                    //As we split 4kx2k yuv layer and program to 2 VG pipes
+                    //(if available) increase mdpcount by 1.
+                    mCurrentFrame.mdpCount++;
+                }
             }
         }
     }
@@ -1583,18 +1841,8 @@
 
 bool MDPCompNonSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
 
-    if(!isEnabled()) {
-        ALOGD_IF(isDebug(),"%s: MDP Comp not configured", __FUNCTION__);
-        return true;
-    }
-
-    if(!ctx || !list) {
-        ALOGE("%s: invalid contxt or list",__FUNCTION__);
-        return false;
-    }
-
-    if(ctx->listStats[mDpy].numAppLayers > MAX_NUM_APP_LAYERS) {
-        ALOGD_IF(isDebug(),"%s: Exceeding max layer count", __FUNCTION__);
+    if(!isEnabled() or !mModeOn) {
+        ALOGD_IF(isDebug(),"%s: MDP Comp not enabled/configured", __FUNCTION__);
         return true;
     }
 
@@ -1674,13 +1922,20 @@
                 continue;
             }
 
+            int fd = hnd->fd;
+            uint32_t offset = (uint32_t)hnd->offset;
+            int index = ctx->mPtorInfo.getPTORArrayIndex(i);
+            if (!mDpy && (index != -1)) {
+                hnd = ctx->mCopyBit[mDpy]->getCurrentRenderBuffer();
+                fd = hnd->fd;
+                // Use the offset of the RenderBuffer
+                offset = ctx->mPtorInfo.mRenderBuffOffset[index];
+            }
+
             ALOGD_IF(isDebug(),"%s: MDP Comp: Drawing layer: %p hnd: %p \
                     using  pipe: %d", __FUNCTION__, layer,
                     hnd, dest );
 
-            int fd = hnd->fd;
-            uint32_t offset = (uint32_t)hnd->offset;
-
             Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
             if(rot) {
                 if(!rot->queueBuffer(fd, offset))
@@ -1707,17 +1962,27 @@
          hwc_display_contents_1_t* list){
     //if 4kx2k yuv layer is totally present in either in left half
     //or right half then try splitting the yuv layer to avoid decimation
-    int n4k2kYuvCount = ctx->listStats[mDpy].yuv4k2kCount;
     const int lSplit = getLeftSplit(ctx, mDpy);
-    for(int index = 0; index < n4k2kYuvCount; index++){
-        int n4k2kYuvIndex = ctx->listStats[mDpy].yuv4k2kIndices[index];
-        hwc_layer_1_t* layer = &list->hwLayers[n4k2kYuvIndex];
-        hwc_rect_t dst = layer->displayFrame;
-        if((dst.left > lSplit) || (dst.right < lSplit)) {
-            mCurrentFrame.mdpCount += 1;
-        }
-        if(mCurrentFrame.fbZ >= n4k2kYuvIndex){
-            mCurrentFrame.fbZ += 1;
+    if(mCurrentFrame.fbZ >= 0) {
+        for (int index = 0, mdpNextZOrder = 0; index < mCurrentFrame.layerCount;
+                index++) {
+            if(!mCurrentFrame.isFBComposed[index]) {
+                if(mdpNextZOrder == mCurrentFrame.fbZ) {
+                    mdpNextZOrder++;
+                }
+                mdpNextZOrder++;
+                hwc_layer_1_t* layer = &list->hwLayers[index];
+                private_handle_t *hnd = (private_handle_t *)layer->handle;
+                if(is4kx2kYuvBuffer(hnd)) {
+                    hwc_rect_t dst = layer->displayFrame;
+                    if((dst.left > lSplit) || (dst.right < lSplit)) {
+                        mCurrentFrame.mdpCount += 1;
+                    }
+                    if(mdpNextZOrder <= mCurrentFrame.fbZ)
+                        mCurrentFrame.fbZ += 1;
+                    mdpNextZOrder++;
+                }
+            }
         }
     }
 }
@@ -1834,18 +2099,8 @@
 
 bool MDPCompSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
 
-    if(!isEnabled()) {
-        ALOGD_IF(isDebug(),"%s: MDP Comp not configured", __FUNCTION__);
-        return true;
-    }
-
-    if(!ctx || !list) {
-        ALOGE("%s: invalid contxt or list",__FUNCTION__);
-        return false;
-    }
-
-    if(ctx->listStats[mDpy].numAppLayers > MAX_NUM_APP_LAYERS) {
-        ALOGD_IF(isDebug(),"%s: Exceeding max layer count", __FUNCTION__);
+    if(!isEnabled() or !mModeOn) {
+        ALOGD_IF(isDebug(),"%s: MDP Comp not enabled/configured", __FUNCTION__);
         return true;
     }
 
@@ -1920,7 +2175,13 @@
             ovutils::eDest indexR = pipe_info.rIndex;
 
             int fd = hnd->fd;
-            int offset = (uint32_t)hnd->offset;
+            uint32_t offset = (uint32_t)hnd->offset;
+            int index = ctx->mPtorInfo.getPTORArrayIndex(i);
+            if (!mDpy && (index != -1)) {
+                hnd = ctx->mCopyBit[mDpy]->getCurrentRenderBuffer();
+                fd = hnd->fd;
+                offset = ctx->mPtorInfo.mRenderBuffOffset[index];
+            }
 
             if(ctx->mAD->draw(ctx, fd, offset)) {
                 fd = ctx->mAD->getDstFd();
@@ -1990,9 +2251,24 @@
         return false;
     }
 
-    //If layer's crop width or dest width > 2048, use 2 pipes
-    if((dst.right - dst.left) > qdutils::MAX_DISPLAY_DIM or
-            (crop.right - crop.left) > qdutils::MAX_DISPLAY_DIM) {
+    /* Use 2 pipes IF
+        a) Layer's crop width is > 2048 or
+        b) Layer's dest width > 2048 or
+        c) On primary, driver has indicated with caps to split always. This is
+           based on an empirically derived value of panel height. Applied only
+           if the layer's width is > mixer's width
+    */
+
+    MDPVersion& mdpHw = MDPVersion::getInstance();
+    bool primarySplitAlways = (mDpy == HWC_DISPLAY_PRIMARY) and
+            mdpHw.isSrcSplitAlways();
+    int lSplit = getLeftSplit(ctx, mDpy);
+    int dstWidth = dst.right - dst.left;
+    int cropWidth = crop.right - crop.left;
+
+    if(dstWidth > mdpHw.getMaxMixerWidth() or
+            cropWidth > mdpHw.getMaxMixerWidth() or
+            (primarySplitAlways and (cropWidth > lSplit))) {
         pipe_info.rIndex = ctx->mOverlay->getPipe(pipeSpecs);
         if(pipe_info.rIndex == ovutils::OV_INVALID) {
             return false;
@@ -2047,14 +2323,14 @@
     }
 
     eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
-    setMdpFlags(layer, mdpFlags, 0, transform);
+    setMdpFlags(ctx, layer, mdpFlags, 0, transform);
 
     if(lDest != OV_INVALID && rDest != OV_INVALID) {
         //Enable overfetch
         setMdpFlags(mdpFlags, OV_MDSS_MDP_DUAL_PIPE);
     }
 
-    if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
+    if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
         (*rot) = ctx->mRotMgr->getNext();
         if((*rot) == NULL) return -1;
         ctx->mLayerRotMap[mDpy]->add(layer, *rot);
@@ -2067,8 +2343,7 @@
             ALOGE("%s: configRotator failed!", __FUNCTION__);
             return -1;
         }
-        whf.format = (*rot)->getDstFormat();
-        updateSource(orient, whf, crop);
+        updateSource(orient, whf, crop, *rot);
         rotFlags |= ROT_PREROTATED;
     }
 
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 4d9d232..1ebe0bd 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -43,17 +43,20 @@
     int prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     /* draw */
     virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;
+    //Reset values
+    void reset();
     /* dumpsys */
-    void dump(android::String8& buf);
+    void dump(android::String8& buf, hwc_context_t *ctx);
     bool isGLESOnlyComp() { return (mCurrentFrame.mdpCount == 0); }
+    int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     static MDPComp* getObject(hwc_context_t *ctx, const int& dpy);
     /* Handler to invoke frame redraw on Idle Timer expiry */
     static void timeout_handler(void *udata);
     /* Initialize MDP comp*/
     static bool init(hwc_context_t *ctx);
     static void resetIdleFallBack() { sIdleFallBack = false; }
-    static void reset() { sHandleTimeout = false; };
     static bool isIdleFallback() { return sIdleFallBack; }
+    static void dynamicDebug(bool enable){ sDebugLogs = enable; }
 
 protected:
     enum { MAX_SEC_LAYERS = 1 }; //TODO add property support
@@ -170,6 +173,8 @@
     bool tryFullFrame(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);
+    /* Full MDP Composition with Peripheral Tiny Overlap Removal */
+    bool fullMDPCompWithPTOR(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);
     /* Partial MDP comp that uses caching to save power as primary goal */
@@ -223,7 +228,7 @@
             hwc_display_contents_1_t* list);
     void reset(hwc_context_t *ctx);
     bool isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer);
-    bool resourceCheck();
+    bool resourceCheck(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 */
@@ -244,6 +249,7 @@
     struct LayerCache mCachedFrame;
     //Enable 4kx2k yuv layer split
     static bool sEnable4k2kYUVSplit;
+    bool mModeOn; // if prepare happened
     bool allocSplitVGPipesfor4k2k(hwc_context_t *ctx, int index);
 };
 
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 0bb71f0..892e9c0 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -31,6 +31,7 @@
 #include <IQService.h>
 #include <hwc_utils.h>
 #include <mdp_version.h>
+#include <hwc_mdpcomp.h>
 
 #define QCLIENT_DEBUG 0
 
@@ -193,6 +194,46 @@
     }
 }
 
+
+static status_t setViewFrame(hwc_context_t* ctx, const Parcel* inParcel) {
+    int dpy = inParcel->readInt32();
+    if(dpy >= HWC_DISPLAY_PRIMARY && dpy <= HWC_DISPLAY_VIRTUAL) {
+        Locker::Autolock _sl(ctx->mDrawLock);
+        ctx->mViewFrame[dpy].left   = inParcel->readInt32();
+        ctx->mViewFrame[dpy].top    = inParcel->readInt32();
+        ctx->mViewFrame[dpy].right  = inParcel->readInt32();
+        ctx->mViewFrame[dpy].bottom = inParcel->readInt32();
+        ALOGD_IF(QCLIENT_DEBUG, "%s: mViewFrame[%d] = [%d %d %d %d]",
+            __FUNCTION__, dpy,
+            ctx->mViewFrame[dpy].left, ctx->mViewFrame[dpy].top,
+            ctx->mViewFrame[dpy].right, ctx->mViewFrame[dpy].bottom);
+        return NO_ERROR;
+    } else {
+        ALOGE("In %s: invalid dpy index %d", __FUNCTION__, dpy);
+        return BAD_VALUE;
+    }
+}
+
+static void toggleDynamicDebug(hwc_context_t* ctx, const Parcel* inParcel) {
+    int debug_type = inParcel->readInt32();
+    bool enable = !!inParcel->readInt32();
+    ALOGD("%s: debug_type: %d enable:%d",
+            __FUNCTION__, debug_type, enable);
+    Locker::Autolock _sl(ctx->mDrawLock);
+    switch (debug_type) {
+        //break is ignored for DEBUG_ALL to toggle all of them at once
+        case IQService::DEBUG_ALL:
+        case IQService::DEBUG_MDPCOMP:
+            qhwc::MDPComp::dynamicDebug(enable);
+            if (debug_type != IQService::DEBUG_ALL)
+                break;
+        case IQService::DEBUG_VSYNC:
+            ctx->vstate.debug = enable;
+            if (debug_type != IQService::DEBUG_ALL)
+                break;
+    }
+}
+
 status_t QClient::notifyCallback(uint32_t command, const Parcel* inParcel,
         Parcel* outParcel) {
     status_t ret = NO_ERROR;
@@ -232,6 +273,12 @@
         case IQService::SET_WFD_STATUS:
             setWfdStatus(mHwcContext,inParcel->readInt32());
             break;
+        case IQService::SET_VIEW_FRAME:
+            setViewFrame(mHwcContext, inParcel);
+            break;
+        case IQService::DYNAMIC_DEBUG:
+            toggleDynamicDebug(mHwcContext, inParcel);
+            break;
         default:
             ret = NO_ERROR;
     }
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index fd02d30..a0cbc68 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -78,12 +78,13 @@
 
 bool isValidResolution(hwc_context_t *ctx, uint32_t xres, uint32_t yres)
 {
-    return !((xres > qdutils::MAX_DISPLAY_DIM &&
+    return !((xres > qdutils::MDPVersion::getInstance().getMaxMixerWidth() &&
                 !isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY)) ||
             (xres < MIN_DISPLAY_XRES || yres < MIN_DISPLAY_YRES));
 }
 
-void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig) {
+void changeResolution(hwc_context_t *ctx, int xres_orig, int yres_orig,
+                      int width, int height) {
     //Store original display resolution.
     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_orig;
     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_orig;
@@ -99,6 +100,12 @@
             ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres_new = xres_new;
             ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres_new = yres_new;
             ctx->dpyAttr[HWC_DISPLAY_PRIMARY].customFBSize = true;
+
+            //Caluculate DPI according to changed resolution.
+            float xdpi = ((float)xres_new * 25.4f) / (float)width;
+            float ydpi = ((float)yres_new * 25.4f) / (float)height;
+            ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xdpi = xdpi;
+            ctx->dpyAttr[HWC_DISPLAY_PRIMARY].ydpi = ydpi;
         }
     }
 }
@@ -168,7 +175,7 @@
             (uint32_t)(1000000000l / fps);
 
     //To change resolution of primary display
-    changeResolution(ctx, info.xres, info.yres);
+    changeResolution(ctx, info.xres, info.yres, info.width, info.height);
 
     //Unblank primary on first boot
     if(ioctl(fb_fd, FBIOBLANK,FB_BLANK_UNBLANK) < 0) {
@@ -225,6 +232,13 @@
     ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
          MDPComp::getObject(ctx, HWC_DISPLAY_PRIMARY);
     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
+    //Initialize the primary display viewFrame info
+    ctx->mViewFrame[HWC_DISPLAY_PRIMARY].left = 0;
+    ctx->mViewFrame[HWC_DISPLAY_PRIMARY].top = 0;
+    ctx->mViewFrame[HWC_DISPLAY_PRIMARY].right =
+        (int)ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+    ctx->mViewFrame[HWC_DISPLAY_PRIMARY].bottom =
+         (int)ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
 
     ctx->mVDSEnabled = false;
     if((property_get("persist.hwc.enable_vds", value, NULL) > 0)) {
@@ -291,9 +305,10 @@
 
     ctx->mGPUHintInfo.mEGLDisplay = NULL;
     ctx->mGPUHintInfo.mEGLContext = NULL;
-    ctx->mGPUHintInfo.mPrevCompositionGLES = false;
+    ctx->mGPUHintInfo.mCompositionState = COMPOSITION_STATE_MDP;
     ctx->mGPUHintInfo.mCurrGPUPerfMode = EGL_GPU_LEVEL_0;
 #endif
+    memset(&(ctx->mPtorInfo), 0, sizeof(ctx->mPtorInfo));
     ALOGI("Initializing Qualcomm Hardware Composer");
     ALOGI("MDP version: %d", ctx->mMDP.version);
 }
@@ -480,10 +495,10 @@
         width = float(rect.right - rect.left);
         height = float(rect.bottom - rect.top);
     }
-    xRatio = (float)(inPos.x/actualWidth);
-    yRatio = (float)(inPos.y/actualHeight);
-    wRatio = (float)(inPos.w/actualWidth);
-    hRatio = (float)(inPos.h/actualHeight);
+    xRatio = (float)((float)inPos.x/actualWidth);
+    yRatio = (float)((float)inPos.y/actualHeight);
+    wRatio = (float)((float)inPos.w/actualWidth);
+    hRatio = (float)((float)inPos.h/actualHeight);
 
     //Calculate the pos9ition...
     outPos.x = uint32_t((xRatio * width) + (float)xPos);
@@ -809,28 +824,6 @@
     }
 }
 
-hwc_rect_t calculateDisplayViewFrame(hwc_context_t *ctx, int dpy) {
-    int dstWidth = ctx->dpyAttr[dpy].xres;
-    int dstHeight = ctx->dpyAttr[dpy].yres;
-    int srcWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
-    int srcHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
-    // default we assume viewframe as a full frame for primary display
-    hwc_rect outRect = {0, 0, dstWidth, dstHeight};
-    if(dpy) {
-        // swap srcWidth and srcHeight, if the device orientation is 90 or 270.
-        if(ctx->deviceOrientation & 0x1) {
-            swap(srcWidth, srcHeight);
-        }
-        // Get Aspect Ratio for external
-        getAspectRatioPosition(dstWidth, dstHeight, srcWidth,
-                            srcHeight, outRect);
-    }
-    ALOGD_IF(HWC_UTILS_DEBUG, "%s: view frame for dpy %d is [%d %d %d %d]",
-        __FUNCTION__, dpy, outRect.left, outRect.top,
-        outRect.right, outRect.bottom);
-    return outRect;
-}
-
 void setListStats(hwc_context_t *ctx,
         hwc_display_contents_1_t *list, int dpy) {
     const int prevYuvCount = ctx->listStats[dpy].yuvCount;
@@ -846,19 +839,13 @@
     ctx->listStats[dpy].isDisplayAnimating = false;
     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);
     ctx->listStats[dpy].renderBufIndexforABC = -1;
 
     resetROI(ctx, dpy);
 
-    // Calculate view frame of ext display from primary resolution
-    // and primary device orientation.
-    ctx->mViewFrame[dpy] = calculateDisplayViewFrame(ctx, dpy);
-
     trimList(ctx, list, dpy);
     optimizeLayerRects(list);
-
     for (size_t i = 0; i < (size_t)ctx->listStats[dpy].numAppLayers; i++) {
         hwc_layer_1_t const* layer = &list->hwLayers[i];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -982,6 +969,32 @@
         return false;
 }
 
+bool isRotatorSupportedFormat(private_handle_t *hnd) {
+    // Following rotator src formats are supported by mdp driver
+    // TODO: Add more formats in future, if mdp driver adds support
+    switch(hnd->format) {
+        case HAL_PIXEL_FORMAT_RGBA_8888:
+        case HAL_PIXEL_FORMAT_RGB_565:
+        case HAL_PIXEL_FORMAT_RGB_888:
+        case HAL_PIXEL_FORMAT_BGRA_8888:
+            return true;
+        default:
+            return false;
+    }
+    return false;
+}
+
+bool isRotationDoable(hwc_context_t *ctx, private_handle_t *hnd) {
+    // Rotate layers, if it is YUV type or rendered by CPU and not
+    // for the MDP versions below MDP5
+    if((isCPURendered(hnd) && isRotatorSupportedFormat(hnd) &&
+        !ctx->mMDP.version < qdutils::MDSS_V5)
+                   || isYuvBuffer(hnd)) {
+        return true;
+    }
+    return false;
+}
+
 // returns true if Action safe dimensions are set and target supports Actionsafe
 bool isActionSafePresent(hwc_context_t *ctx, int dpy) {
     // if external supports underscan, do nothing
@@ -1315,6 +1328,7 @@
         if(ret < 0) {
             ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed for rot sync, err=%s",
                     __FUNCTION__, strerror(errno));
+            close(rotReleaseFd);
         } else {
             close(currLayer->acquireFenceFd);
             //For MDP to wait on.
@@ -1364,15 +1378,17 @@
         }
     }
 
+    if ((fd >= 0) && !dpy && ctx->mPtorInfo.isActive()) {
+        // Acquire c2d fence of Overlap render buffer
+        acquireFd[count++] = fd;
+    }
+
     data.acq_fen_fd_cnt = count;
     fbFd = ctx->dpyAttr[dpy].fd;
 
     //Waits for acquire fences, returns a release fence
     if(LIKELY(!swapzero)) {
-        uint64_t start = systemTime();
         ret = ioctl(fbFd, MSMFB_BUFFER_SYNC, &data);
-        ALOGD_IF(HWC_UTILS_DEBUG, "%s: time taken for MSMFB_BUFFER_SYNC IOCTL = %d",
-                            __FUNCTION__, (size_t) ns2ms(systemTime() - start));
     }
 
     if(ret < 0) {
@@ -1381,6 +1397,10 @@
         ALOGE("%s: acq_fen_fd_cnt=%d flags=%d fd=%d dpy=%d numHwLayers=%zu",
               __FUNCTION__, data.acq_fen_fd_cnt, data.flags, fbFd,
               dpy, list->numHwLayers);
+        close(releaseFd);
+        releaseFd = -1;
+        close(retireFd);
+        retireFd = -1;
     }
 
     for(uint32_t i = 0; i < list->numHwLayers; i++) {
@@ -1424,8 +1444,12 @@
         fd = -1;
     }
 
-    if (ctx->mCopyBit[dpy])
-        ctx->mCopyBit[dpy]->setReleaseFd(releaseFd);
+    if (!dpy && ctx->mCopyBit[dpy]) {
+        if (ctx->mPtorInfo.isActive())
+            ctx->mCopyBit[dpy]->setReleaseFdSync(releaseFd);
+        else
+            ctx->mCopyBit[dpy]->setReleaseFd(releaseFd);
+    }
 
     //Signals when MDP finishes reading rotator buffers.
     ctx->mLayerRotMap[dpy]->setReleaseFd(releaseFd);
@@ -1440,7 +1464,7 @@
     return ret;
 }
 
-void setMdpFlags(hwc_layer_1_t *layer,
+void setMdpFlags(hwc_context_t *ctx, hwc_layer_1_t *layer,
         ovutils::eMdpFlags &mdpFlags,
         int rotDownscale, int transform) {
     private_handle_t *hnd = (private_handle_t *)layer->handle;
@@ -1461,11 +1485,6 @@
             ovutils::setMdpFlags(mdpFlags,
                     ovutils::OV_MDP_DEINTERLACE);
         }
-        //Pre-rotation will be used using rotator.
-        if(transform & HWC_TRANSFORM_ROT_90) {
-            ovutils::setMdpFlags(mdpFlags,
-                    ovutils::OV_MDP_SOURCE_ROTATED_90);
-        }
     }
 
     if(isSecureDisplayBuffer(hnd)) {
@@ -1475,6 +1494,12 @@
         ovutils::setMdpFlags(mdpFlags,
                              ovutils::OV_MDP_SECURE_DISPLAY_OVERLAY_SESSION);
     }
+
+    //Pre-rotation will be used using rotator.
+    if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
+        ovutils::setMdpFlags(mdpFlags,
+                ovutils::OV_MDP_SOURCE_ROTATED_90);
+    }
     //No 90 component and no rot-downscale then flips done by MDP
     //If we use rot then it might as well do flips
     if(!(transform & HWC_TRANSFORM_ROT_90) && !rotDownscale) {
@@ -1509,18 +1534,8 @@
 
     if (qdutils::MDPVersion::getInstance().getMDPVersion() >=
         qdutils::MDSS_V5) {
-        uint32_t crop_w = (crop.right - crop.left);
-        uint32_t crop_h = (crop.bottom - crop.top);
-        if (ovutils::isYuv(whf.format)) {
-            ovutils::normalizeCrop((uint32_t&)crop.left, crop_w);
-            ovutils::normalizeCrop((uint32_t&)crop.top, crop_h);
-            // For interlaced, crop.h should be 4-aligned
-            if ((mdpFlags & ovutils::OV_MDP_DEINTERLACE) && (crop_h % 4))
-                crop_h = ovutils::aligndown(crop_h, 4);
-            crop.right = crop.left + crop_w;
-            crop.bottom = crop.top + crop_h;
-        }
-        Dim rotCrop(crop.left, crop.top, crop_w, crop_h);
+         Dim rotCrop(crop.left, crop.top, crop.right - crop.left,
+                crop.bottom - crop.top);
         rot->setCrop(rotCrop);
     }
 
@@ -1595,28 +1610,27 @@
 }
 
 void updateSource(eTransform& orient, Whf& whf,
-        hwc_rect_t& crop) {
-    Dim srcCrop(crop.left, crop.top,
+        hwc_rect_t& crop, Rotator *rot) {
+    Dim transformedCrop(crop.left, crop.top,
             crop.right - crop.left,
             crop.bottom - crop.top);
-    orient = static_cast<eTransform>(ovutils::getMdpOrient(orient));
-    preRotateSource(orient, whf, srcCrop);
     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;
+        //B-family rotator internally could modify destination dimensions if
+        //downscaling is supported
+        whf = rot->getDstWhf();
+        transformedCrop = rot->getDstDimensions();
     } else {
-        crop.left = srcCrop.x;
-        crop.top = srcCrop.y;
-        crop.right = srcCrop.x + srcCrop.w;
-        crop.bottom = srcCrop.y + srcCrop.h;
+        //A-family rotator rotates entire buffer irrespective of crop, forcing
+        //us to recompute the crop based on transform
+        orient = static_cast<eTransform>(ovutils::getMdpOrient(orient));
+        preRotateSource(orient, whf, transformedCrop);
     }
+
+    crop.left = transformedCrop.x;
+    crop.top = transformedCrop.y;
+    crop.right = transformedCrop.x + transformedCrop.w;
+    crop.bottom = transformedCrop.y + transformedCrop.h;
 }
 
 int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
@@ -1667,22 +1681,22 @@
         }
     }
 
-    setMdpFlags(layer, mdpFlags, downscale, transform);
+    setMdpFlags(ctx, layer, mdpFlags, downscale, transform);
 
-    if(isYuvBuffer(hnd) && //if 90 component or downscale, use rot
-            ((transform & HWC_TRANSFORM_ROT_90) || downscale)) {
+    //if 90 component or downscale, use rot
+    if((has90Transform(layer) && isRotationDoable(ctx, hnd)) || downscale) {
         *rot = ctx->mRotMgr->getNext();
         if(*rot == NULL) return -1;
         ctx->mLayerRotMap[dpy]->add(layer, *rot);
-        if(!dpy)
+        // BWC is not tested for other formats So enable it only for YUV format
+        if(!dpy && isYuvBuffer(hnd))
             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__);
             return -1;
         }
-        whf.format = (*rot)->getDstFormat();
-        updateSource(orient, whf, crop);
+        updateSource(orient, whf, crop, *rot);
         rotFlags |= ovutils::ROT_PREROTATED;
     }
 
@@ -1764,7 +1778,7 @@
        ActionSafe, and extorientation features. */
     calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
 
-    setMdpFlags(layer, mdpFlagsL, 0, transform);
+    setMdpFlags(ctx, layer, mdpFlagsL, 0, transform);
 
     if(lDest != OV_INVALID && rDest != OV_INVALID) {
         //Enable overfetch
@@ -1778,7 +1792,7 @@
         whf.format = wb->getOutputFormat();
     }
 
-    if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
+    if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
         (*rot) = ctx->mRotMgr->getNext();
         if((*rot) == NULL) return -1;
         ctx->mLayerRotMap[dpy]->add(layer, *rot);
@@ -1787,8 +1801,7 @@
             ALOGE("%s: configRotator failed!", __FUNCTION__);
             return -1;
         }
-        whf.format = (*rot)->getDstFormat();
-        updateSource(orient, whf, crop);
+        updateSource(orient, whf, crop, *rot);
         rotFlags |= ROT_PREROTATED;
     }
 
@@ -1800,14 +1813,17 @@
 
     const int lSplit = getLeftSplit(ctx, dpy);
 
-    if(lDest != OV_INVALID) {
+    // Calculate Left rects
+    if(dst.left < lSplit) {
         tmp_cropL = crop;
         tmp_dstL = dst;
         hwc_rect_t scissor = {0, 0, lSplit, hw_h };
         scissor = getIntersection(ctx->mViewFrame[dpy], scissor);
         qhwc::calculate_crop_rects(tmp_cropL, tmp_dstL, scissor, 0);
     }
-    if(rDest != OV_INVALID) {
+
+    // Calculate Right rects
+    if(dst.right > lSplit) {
         tmp_cropR = crop;
         tmp_dstR = dst;
         hwc_rect_t scissor = {lSplit, 0, hw_w, hw_h };
@@ -1820,8 +1836,8 @@
     //When buffer is H-flipped, contents of mixer config also needs to swapped
     //Not needed if the layer is confined to one half of the screen.
     //If rotator has been used then it has also done the flips, so ignore them.
-    if((orient & OVERLAY_TRANSFORM_FLIP_H) && lDest != OV_INVALID
-            && rDest != OV_INVALID && (*rot) == NULL) {
+    if((orient & OVERLAY_TRANSFORM_FLIP_H) && (dst.left < lSplit) &&
+            (dst.right > lSplit) && (*rot) == NULL) {
         hwc_rect_t new_cropR;
         new_cropR.left = tmp_cropL.left;
         new_cropR.right = new_cropR.left + (tmp_cropR.right - tmp_cropR.left);
@@ -1903,22 +1919,22 @@
        ActionSafe, and extorientation features. */
     calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
 
-    setMdpFlags(layer, mdpFlagsL, 0, transform);
+    setMdpFlags(ctx, layer, mdpFlagsL, 0, transform);
     trimLayer(ctx, dpy, transform, crop, dst);
 
-    if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
+    if(has90Transform(layer) && isRotationDoable(ctx, hnd)) {
         (*rot) = ctx->mRotMgr->getNext();
         if((*rot) == NULL) return -1;
         ctx->mLayerRotMap[dpy]->add(layer, *rot);
-        if(!dpy)
+        // BWC is not tested for other formats So enable it only for YUV format
+        if(!dpy && isYuvBuffer(hnd))
             BwcPM::setBwc(crop, dst, transform, mdpFlagsL);
         //Configure rotator for pre-rotation
         if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
             ALOGE("%s: configRotator failed!", __FUNCTION__);
             return -1;
         }
-        whf.format = (*rot)->getDstFormat();
-        updateSource(orient, whf, crop);
+        updateSource(orient, whf, crop, *rot);
         rotFlags |= ROT_PREROTATED;
     }
 
@@ -2024,12 +2040,12 @@
 }
 
 bool isDisplaySplit(hwc_context_t* ctx, int dpy) {
-    if(ctx->dpyAttr[dpy].xres > qdutils::MAX_DISPLAY_DIM) {
+    qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+    if(ctx->dpyAttr[dpy].xres > mdpHw.getMaxMixerWidth()) {
         return true;
     }
     //For testing we could split primary via device tree values
-    if(dpy == HWC_DISPLAY_PRIMARY &&
-        qdutils::MDPVersion::getInstance().getRightSplit()) {
+    if(dpy == HWC_DISPLAY_PRIMARY && mdpHw.getRightSplit()) {
         return true;
     }
     return false;
@@ -2048,30 +2064,22 @@
   return (ctx->enableABC && ctx->listStats[0].renderBufIndexforABC == 0);
 }
 
-/* Since we fake non-Hybrid WFD solution as external display, this
- * function helps us in determining the priority between external
- * (hdmi/non-Hybrid WFD display) and virtual display devices(SSD/
- * screenrecord). This can be removed once wfd-client migrates to
- * using virtual-display api's.
- */
-bool canUseMDPforVirtualDisplay(hwc_context_t* ctx,
-                                const hwc_display_contents_1_t *list) {
-
-    /* We rely on the fact that for pure virtual display solution
-     * list->outbuf will be a non-NULL handle.
-     *
-     * If there are three active displays (which means there is one
-     * primary, one external and one virtual active display)
-     * we give mdss/mdp hw resources(pipes,smp,etc) for external
-     * display(hdmi/non-Hybrid WFD display) rather than for virtual
-     * display(SSD/screenrecord)
-     */
-
-    if(list->outbuf and (ctx->numActiveDisplays == HWC_NUM_DISPLAY_TYPES)) {
-        return false;
+void dumpBuffer(private_handle_t *ohnd, char *bufferName) {
+    if (ohnd != NULL && ohnd->base) {
+        char dumpFilename[PATH_MAX];
+        bool bResult = false;
+        snprintf(dumpFilename, sizeof(dumpFilename), "/data/%s.%s.%dx%d.raw",
+            bufferName,
+            overlay::utils::getFormatString(utils::getMdpFormat(ohnd->format)),
+            getWidth(ohnd), getHeight(ohnd));
+        FILE* fp = fopen(dumpFilename, "w+");
+        if (NULL != fp) {
+            bResult = (bool) fwrite((void*)ohnd->base, ohnd->size, 1, fp);
+            fclose(fp);
+        }
+        ALOGD("Buffer[%s] Dump to %s: %s",
+        bufferName, dumpFilename, bResult ? "Success" : "Fail");
     }
-
-    return true;
 }
 
 bool isGLESComp(hwc_context_t *ctx,
@@ -2108,7 +2116,8 @@
         }
     }
     if(isGLESComp(ctx, list)) {
-        if(!gpuHint->mPrevCompositionGLES && !MDPComp::isIdleFallback()) {
+        if(gpuHint->mCompositionState != COMPOSITION_STATE_GPU
+            && !MDPComp::isIdleFallback()) {
             EGLint attr_list[] = {EGL_GPU_HINT_1,
                                   EGL_GPU_LEVEL_3,
                                   EGL_NONE };
@@ -2118,7 +2127,7 @@
                 ALOGW("eglGpuPerfHintQCOM failed for Built in display");
             } else {
                 gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_3;
-                gpuHint->mPrevCompositionGLES = true;
+                gpuHint->mCompositionState = COMPOSITION_STATE_GPU;
             }
         } else {
             EGLint attr_list[] = {EGL_GPU_HINT_1,
@@ -2131,6 +2140,9 @@
             } else {
                 gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_0;
             }
+            if(MDPComp::isIdleFallback()) {
+                gpuHint->mCompositionState = COMPOSITION_STATE_IDLE_FALLBACK;
+            }
         }
     } else {
         /* set the GPU hint flag to default for MDP composition */
@@ -2144,42 +2156,50 @@
         } else {
             gpuHint->mCurrGPUPerfMode = EGL_GPU_LEVEL_0;
         }
-        gpuHint->mPrevCompositionGLES = false;
+        gpuHint->mCompositionState = COMPOSITION_STATE_MDP;
     }
 #endif
 }
 
+bool isPeripheral(const hwc_rect_t& rect1, const hwc_rect_t& rect2) {
+    // To be peripheral, 3 boundaries should match.
+    uint8_t eqBounds = 0;
+    if (rect1.left == rect2.left)
+        eqBounds++;
+    if (rect1.top == rect2.top)
+        eqBounds++;
+    if (rect1.right == rect2.right)
+        eqBounds++;
+    if (rect1.bottom == rect2.bottom)
+        eqBounds++;
+    return (eqBounds == 3);
+}
+
 void BwcPM::setBwc(const hwc_rect_t& crop,
             const hwc_rect_t& dst, const int& transform,
             ovutils::eMdpFlags& mdpFlags) {
     //Target doesnt support Bwc
-    if(!qdutils::MDPVersion::getInstance().supportsBWC()) {
+    qdutils::MDPVersion& mdpHw = qdutils::MDPVersion::getInstance();
+    if(!mdpHw.supportsBWC()) {
         return;
     }
+    int src_w = crop.right - crop.left;
+    int src_h = crop.bottom - crop.top;
+    int dst_w = dst.right - dst.left;
+    int dst_h = dst.bottom - dst.top;
+    if(transform & HAL_TRANSFORM_ROT_90) {
+        swap(src_w, src_h);
+    }
     //src width > MAX mixer supported dim
-    if((crop.right - crop.left) > qdutils::MAX_DISPLAY_DIM) {
+    if(src_w > qdutils::MDPVersion::getInstance().getMaxMixerWidth()) {
         return;
     }
     //Decimation necessary, cannot use BWC. H/W requirement.
     if(qdutils::MDPVersion::getInstance().supportsDecimation()) {
-        int src_w = crop.right - crop.left;
-        int src_h = crop.bottom - crop.top;
-        int dst_w = dst.right - dst.left;
-        int dst_h = dst.bottom - dst.top;
-        if(transform & HAL_TRANSFORM_ROT_90) {
-            swap(src_w, src_h);
-        }
-        float horDscale = 0.0f;
-        float verDscale = 0.0f;
-        int horzDeci = 0;
-        int vertDeci = 0;
-        ovutils::getDecimationFactor(src_w, src_h, dst_w, dst_h, horDscale,
-                verDscale);
-        //TODO Use log2f once math.h has it
-        if((int)horDscale)
-            horzDeci = (int)(log(horDscale) / log(2));
-        if((int)verDscale)
-            vertDeci = (int)(log(verDscale) / log(2));
+        uint8_t horzDeci = 0;
+        uint8_t vertDeci = 0;
+        ovutils::getDecimationFactor(src_w, src_h, dst_w, dst_h, horzDeci,
+                vertDeci);
         if(horzDeci || vertDeci) return;
     }
     //Property
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index d7fa73d..dd55f8b 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -41,6 +41,8 @@
 #define MIN_DISPLAY_YRES 200
 #define HWC_WFDDISPSYNC_LOG 0
 #define STR(f) #f;
+// Max number of PTOR layers handled
+#define MAX_PTOR_LAYERS 2
 
 //Fwrd decls
 struct hwc_context_t;
@@ -131,6 +133,23 @@
     int  renderBufIndexforABC;
 };
 
+//PTOR Comp info
+struct PtorInfo {
+    int count;
+    int layerIndex[MAX_PTOR_LAYERS];
+    int mRenderBuffOffset[MAX_PTOR_LAYERS];
+    hwc_rect_t displayFrame[MAX_PTOR_LAYERS];
+    bool isActive() { return (count>0); }
+    int getPTORArrayIndex(int index) {
+        int idx = -1;
+        for(int i = 0; i < count; i++) {
+            if(index == layerIndex[i])
+                idx = i;
+        }
+        return idx;
+    }
+};
+
 struct LayerProp {
     uint32_t mFlags; //qcom specific layer flags
     LayerProp():mFlags(0){};
@@ -139,6 +158,7 @@
 struct VsyncState {
     bool enable;
     bool fakevsync;
+    bool debug;
 };
 
 struct BwcPM {
@@ -224,11 +244,6 @@
 // -----------------------------------------------------------------------------
 // Utility functions - implemented in hwc_utils.cpp
 void dumpLayer(hwc_layer_1_t const* l);
-
-// Calculate viewframe for external/primary display from primary resolution and
-// primary device orientation
-hwc_rect_t calculateDisplayViewFrame(hwc_context_t *ctx, int dpy);
-
 void setListStats(hwc_context_t *ctx, hwc_display_contents_1_t *list,
         int dpy);
 void initContext(hwc_context_t *ctx);
@@ -240,6 +255,10 @@
                               hwc_rect_t& nwr);
 bool isSecuring(hwc_context_t* ctx, hwc_layer_1_t const* layer);
 bool isSecureModePolicy(int mdpVersion);
+// Returns true, if the input layer format is supported by rotator
+bool isRotatorSupportedFormat(private_handle_t *hnd);
+//Returns true, if the layer is YUV or the layer has been rendered by CPU
+bool isRotationDoable(hwc_context_t *ctx, private_handle_t *hnd);
 bool isExternalActive(hwc_context_t* ctx);
 bool isAlphaScaled(hwc_layer_1_t const* layer);
 bool needsScaling(hwc_layer_1_t const* layer);
@@ -255,8 +274,7 @@
 void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers);
 bool isAbcInUse(hwc_context_t *ctx);
 
-bool canUseMDPforVirtualDisplay(hwc_context_t* ctx,
-                                const hwc_display_contents_1_t *list);
+void dumpBuffer(private_handle_t *ohnd, char *bufferName);
 
 //Helper function to dump logs
 void dumpsys_log(android::String8& buf, const char* fmt, ...);
@@ -319,7 +337,7 @@
         int fd);
 
 //Sets appropriate mdp flags for a layer.
-void setMdpFlags(hwc_layer_1_t *layer,
+void setMdpFlags(hwc_context_t *ctx, hwc_layer_1_t *layer,
         ovutils::eMdpFlags &mdpFlags,
         int rotDownscale, int transform);
 
@@ -337,7 +355,7 @@
         ovutils::eIsFg& isFg, const ovutils::eDest& dest);
 
 void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
-        hwc_rect_t& crop);
+        hwc_rect_t& crop, overlay::Rotator *rot);
 
 //Routine to configure low resolution panels (<= 2048 width)
 int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
@@ -376,6 +394,9 @@
 // due to idle fallback or MDP composition.
 void setGPUHint(hwc_context_t* ctx, hwc_display_contents_1_t* list);
 
+// Returns true if rect1 is peripheral to rect2, false otherwise.
+bool isPeripheral(const hwc_rect_t& rect1, const hwc_rect_t& rect2);
+
 // Inline utility functions
 static inline bool isSkipLayer(const hwc_layer_1_t* l) {
     return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
@@ -401,6 +422,10 @@
     return (hnd && (private_handle_t::PRIV_FLAGS_TILE_RENDERED & hnd->flags));
 }
 
+static inline bool isCPURendered(const private_handle_t* hnd) {
+    return (hnd && (private_handle_t::PRIV_FLAGS_CPU_RENDERED & hnd->flags));
+}
+
 //Return true if buffer is marked locked
 static inline bool isBufferLocked(const private_handle_t* hnd) {
     return (hnd && (private_handle_t::PRIV_FLAGS_HWC_LOCK & hnd->flags));
@@ -474,14 +499,20 @@
     ANIMATION_STARTED,
 };
 
+enum eCompositionState {
+    COMPOSITION_STATE_MDP = 0,        // Set if composition type is MDP
+    COMPOSITION_STATE_GPU,            // Set if composition type is GPU or MIXED
+    COMPOSITION_STATE_IDLE_FALLBACK,  // Set if it is idlefallback
+};
+
 // Structure holds the information about the GPU hint.
 struct gpu_hint_info {
     // system level flag to enable gpu_perf_mode
     bool mGpuPerfModeEnable;
     // Stores the current GPU performance mode DEFAULT/HIGH
     bool mCurrGPUPerfMode;
-    // true if previous composition used GPU
-    bool mPrevCompositionGLES;
+    // Stores the compositon state GPU, MDP or IDLE_FALLBACK
+    bool mCompositionState;
     // Stores the EGLContext of current process
     EGLContext mEGLContext;
     // Stores the EGLDisplay of current process
@@ -561,6 +592,8 @@
     struct gpu_hint_info mGPUHintInfo;
     //App Buffer Composition
     bool enableABC;
+    // PTOR Info
+    qhwc::PtorInfo mPtorInfo;
 };
 
 namespace qhwc {
@@ -572,7 +605,7 @@
     return  ctx->listStats[dpy].yuvCount;
 }
 
-static inline bool has90Transform(hwc_layer_1_t *layer) {
+static inline bool has90Transform(hwc_layer_1_t const* layer) {
     return ((layer->transform & HWC_TRANSFORM_ROT_90) &&
             !(layer->flags & HWC_COLOR_FILL));
 }
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
index 97b19ea..f8f3b45 100644
--- a/libhwcomposer/hwc_virtual.cpp
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -29,6 +29,7 @@
 #include "hwc_dump_layers.h"
 #include "hwc_copybit.h"
 #include "hwc_virtual.h"
+#include "sync/sync.h"
 
 #define HWCVIRTUAL_LOG 0
 
@@ -48,6 +49,16 @@
     }
 }
 
+HWCVirtualVDS::HWCVirtualVDS() {
+    char value[PROPERTY_VALUE_MAX];
+    mVDSDumpEnabled = false;
+    if((property_get("debug.hwc.enable_vds_dump", value, NULL) > 0)) {
+        if(atoi(value) != 0) {
+            mVDSDumpEnabled = true;
+        }
+    }
+}
+
 void HWCVirtualVDS::init(hwc_context_t *ctx) {
     const int dpy = HWC_DISPLAY_VIRTUAL;
     ctx->mFBUpdate[dpy] =
@@ -137,6 +148,7 @@
              * Mark all application layers as OVERLAY so that
              * GPU will not compose.
              */
+            Writeback::getInstance(); //Ensure that WB is active during pause
             for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
                 hwc_layer_1_t *layer = &list->hwLayers[i];
                 layer->compositionType = HWC_OVERLAY;
@@ -177,6 +189,10 @@
             int fd = -1; //FenceFD from the Copybit
             hwc_sync(ctx, list, dpy, fd);
 
+            // Dump the layers for virtual
+            if(ctx->mHwcDebug[dpy])
+                ctx->mHwcDebug[dpy]->dumpLayers(list);
+
             if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
                 ALOGE("%s: MDPComp draw failed", __FUNCTION__);
                 ret = -1;
@@ -200,6 +216,19 @@
                 ret = -1;
             }
 
+            if(mVDSDumpEnabled) {
+                char bufferName[128];
+                // Dumping frame buffer
+                sync_wait(fbLayer->acquireFenceFd, 1000);
+                snprintf(bufferName, sizeof(bufferName), "vds.fb");
+                dumpBuffer((private_handle_t *)fbLayer->handle, bufferName);
+                // Dumping WB output for non-secure session
+                if(!isSecureBuffer(ohnd)) {
+                    sync_wait(list->retireFenceFd, 1000);
+                    snprintf(bufferName, sizeof(bufferName), "vds.wb");
+                    dumpBuffer(ohnd, bufferName);
+                }
+            }
         } else if(list->outbufAcquireFenceFd >= 0) {
             //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
             //which will make sure, the framework waits on it and closes it.
@@ -224,6 +253,17 @@
     }
     usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
             * 2 / 1000);
+    // At this point all the pipes used by External have been
+    // marked as UNSET.
+    {
+        Locker::Autolock _l(ctx->mDrawLock);
+        // Perform commit to unstage the pipes.
+        if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+            ALOGE("%s: display commit fail! for %d dpy",
+                    __FUNCTION__, dpy);
+        }
+        ctx->proc->invalidate(ctx->proc);
+    }
     return;
 }
 
@@ -256,8 +296,7 @@
 
     if (LIKELY(list && list->numHwLayers > 1) &&
             ctx->dpyAttr[dpy].isActive &&
-            ctx->dpyAttr[dpy].connected &&
-            canUseMDPforVirtualDisplay(ctx,list)) {
+            ctx->dpyAttr[dpy].connected) {
         reset_layer_prop(ctx, dpy, (int)list->numHwLayers - 1);
         if(!ctx->dpyAttr[dpy].isPause) {
             ctx->dpyAttr[dpy].isConfiguring = false;
@@ -292,8 +331,7 @@
 
     if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
             ctx->dpyAttr[dpy].connected &&
-            (!ctx->dpyAttr[dpy].isPause) &&
-            canUseMDPforVirtualDisplay(ctx,list)) {
+            !ctx->dpyAttr[dpy].isPause) {
         uint32_t last = (uint32_t)list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         int fd = -1; //FenceFD from the Copybit(valid in async mode)
diff --git a/libhwcomposer/hwc_virtual.h b/libhwcomposer/hwc_virtual.h
index 87004c3..26d89c9 100644
--- a/libhwcomposer/hwc_virtual.h
+++ b/libhwcomposer/hwc_virtual.h
@@ -46,7 +46,7 @@
 
 class HWCVirtualVDS : public HWCVirtualBase {
 public:
-    explicit HWCVirtualVDS(){};
+    explicit HWCVirtualVDS();
     virtual ~HWCVirtualVDS(){};
     // Chooses composition type and configures pipe for each layer in virtual
     // display list
@@ -64,6 +64,12 @@
                        hwc_display_contents_1_t** displays);
     virtual void pause(hwc_context_t* ctx, int dpy);
     virtual void resume(hwc_context_t* ctx, int dpy);
+private:
+    // If WFD is enabled through VDS solution
+    // we can dump the frame buffer and WB
+    // output buffer by setting the property
+    // debug.hwc.enable_vds_dump
+    bool mVDSDumpEnabled;
 };
 
 class HWCVirtualV4L2 : public HWCVirtualBase {
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index 7bde83b..47f2229 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -40,7 +40,6 @@
 #define PANEL_ON_STR "panel_power_on ="
 #define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
 const int MAX_DATA = 64;
-bool logvsync = false;
 
 int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable)
 {
@@ -63,7 +62,7 @@
         timestamp = strtoull(data + strlen("VSYNC="), NULL, 0);
     }
     // send timestamp to SurfaceFlinger
-    ALOGD_IF (logvsync, "%s: timestamp %"PRIu64" sent to SF for dpy=%d",
+    ALOGD_IF (ctx->vstate.debug, "%s: timestamp %"PRIu64" sent to SF for dpy=%d",
             __FUNCTION__, timestamp, dpy);
     ctx->proc->vsync(ctx->proc, dpy, timestamp);
 }
@@ -71,8 +70,8 @@
 static void handle_blank_event(hwc_context_t* ctx, int dpy, char *data)
 {
     if (!strncmp(data, PANEL_ON_STR, strlen(PANEL_ON_STR))) {
-        uint32_t poweron = strtoul(data + strlen(PANEL_ON_STR), NULL, 0);
-        ALOGI("%s: dpy:%d panel power state: %d", __FUNCTION__, dpy, poweron);
+        unsigned long int poweron = strtoul(data + strlen(PANEL_ON_STR), NULL, 0);
+        ALOGI("%s: dpy:%d panel power state: %ld", __FUNCTION__, dpy, poweron);
         ctx->dpyAttr[dpy].isActive = poweron ? true: false;
     }
 }
@@ -110,11 +109,6 @@
             ctx->vstate.fakevsync = true;
     }
 
-    if(property_get("debug.hwc.logvsync", property, 0) > 0) {
-        if(atoi(property) == 1)
-            logvsync = true;
-    }
-
     char node_path[MAX_SYSFS_FILE_PATH];
 
     for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) {
@@ -151,7 +145,7 @@
 
     if (LIKELY(!ctx->vstate.fakevsync)) {
         do {
-            int err = poll(*pfd, num_displays * num_events, -1);
+            int err = poll(*pfd, (int)(num_displays * num_events), -1);
             if(err > 0) {
                 for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) {
                     for(size_t ev = 0; ev < num_events; ev++) {
diff --git a/liblight/lights.c b/liblight/lights.c
index 6fd1290..615ddd8 100644
--- a/liblight/lights.c
+++ b/liblight/lights.c
@@ -168,12 +168,18 @@
     }
 
     if (blink) {
-        if (red)
-            write_int(RED_BLINK_FILE, blink);
-        if (green)
-            write_int(GREEN_BLINK_FILE, blink);
-        if (blue)
-            write_int(BLUE_BLINK_FILE, blink);
+        if (red) {
+            if (write_int(RED_BLINK_FILE, blink))
+                write_int(RED_LED_FILE, 0);
+	}
+        if (green) {
+            if (write_int(GREEN_BLINK_FILE, blink))
+                write_int(GREEN_LED_FILE, 0);
+	}
+        if (blue) {
+            if (write_int(BLUE_BLINK_FILE, blink))
+                write_int(BLUE_LED_FILE, 0);
+	}
     } else {
         write_int(RED_LED_FILE, red);
         write_int(GREEN_LED_FILE, green);
@@ -194,6 +200,17 @@
 }
 
 static int
+set_light_battery(struct light_device_t* dev,
+        struct light_state_t const* state)
+{
+    pthread_mutex_lock(&g_lock);
+    g_battery = *state;
+    handle_speaker_battery_locked(dev);
+    pthread_mutex_unlock(&g_lock);
+    return 0;
+}
+
+static int
 set_light_notifications(struct light_device_t* dev,
         struct light_state_t const* state)
 {
@@ -259,6 +276,8 @@
 
     if (0 == strcmp(LIGHT_ID_BACKLIGHT, name))
         set_light = set_light_backlight;
+    else if (0 == strcmp(LIGHT_ID_BATTERY, name))
+        set_light = set_light_battery;
     else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
         set_light = set_light_notifications;
     else if (0 == strcmp(LIGHT_ID_BUTTONS, name))
diff --git a/libmemtrack/kgsl.c b/libmemtrack/kgsl.c
index 6194043..b644d73 100644
--- a/libmemtrack/kgsl.c
+++ b/libmemtrack/kgsl.c
@@ -87,7 +87,7 @@
          *  gpuaddr useraddr     size    id flags       type            usage sglen
          * 545ba000 545ba000     4096     1 ----pY     gpumem      arraybuffer     1
          */
-        ret = sscanf(line, "%*x %*lx %lu %*d %6s %6s %*s %*d\n",
+        ret = sscanf(line, "%*x %*x %lu %*d %6s %6s %*s %*d\n",
                      &size, flags, line_type);
         if (ret != 3) {
             continue;
diff --git a/liboverlay/mdpWrapper.h b/liboverlay/mdpWrapper.h
index 1bfa058..e24ad6a 100644
--- a/liboverlay/mdpWrapper.h
+++ b/liboverlay/mdpWrapper.h
@@ -30,6 +30,8 @@
 #ifndef MDP_WRAPPER_H
 #define MDP_WRAPPER_H
 
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
+
 /*
 * In order to make overlay::mdp_wrapper shorter, please do something like:
 * namespace mdpwrap = overlay::mdp_wrapper;
@@ -39,6 +41,7 @@
 #include <linux/msm_rotator.h>
 #include <sys/ioctl.h>
 #include <utils/Log.h>
+#include <utils/Trace.h>
 #include <errno.h>
 #include "overlayUtils.h"
 
@@ -80,9 +83,6 @@
 /* MSMFB_OVERLAY_PLAY */
 bool play(int fd, msmfb_overlay_data& od);
 
-/* MSMFB_OVERLAY_3D */
-bool set3D(int fd, msmfb_overlay_3d& ov);
-
 /* MSMFB_DISPLAY_COMMIT */
 bool displayCommit(int fd);
 
@@ -119,6 +119,7 @@
 //---------------Inlines -------------------------------------
 
 inline bool getFScreenInfo(int fd, fb_fix_screeninfo& finfo) {
+    ATRACE_CALL();
     if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) < 0) {
         ALOGE("Failed to call ioctl FBIOGET_FSCREENINFO err=%s",
                 strerror(errno));
@@ -128,6 +129,7 @@
 }
 
 inline bool getVScreenInfo(int fd, fb_var_screeninfo& vinfo) {
+    ATRACE_CALL();
     if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) < 0) {
         ALOGE("Failed to call ioctl FBIOGET_VSCREENINFO err=%s",
                 strerror(errno));
@@ -137,6 +139,7 @@
 }
 
 inline bool setVScreenInfo(int fd, fb_var_screeninfo& vinfo) {
+    ATRACE_CALL();
     if (ioctl(fd, FBIOPUT_VSCREENINFO, &vinfo) < 0) {
         ALOGE("Failed to call ioctl FBIOPUT_VSCREENINFO err=%s",
                 strerror(errno));
@@ -146,6 +149,7 @@
 }
 
 inline bool startRotator(int fd, msm_rotator_img_info& rot) {
+    ATRACE_CALL();
     if (ioctl(fd, MSM_ROTATOR_IOCTL_START, &rot) < 0){
         ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_START err=%s",
                 strerror(errno));
@@ -155,6 +159,7 @@
 }
 
 inline bool rotate(int fd, msm_rotator_data_info& rot) {
+    ATRACE_CALL();
     if (ioctl(fd, MSM_ROTATOR_IOCTL_ROTATE, &rot) < 0) {
         ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_ROTATE err=%s",
                 strerror(errno));
@@ -164,6 +169,7 @@
 }
 
 inline bool setOverlay(int fd, mdp_overlay& ov) {
+    ATRACE_CALL();
     if (ioctl(fd, MSMFB_OVERLAY_SET, &ov) < 0) {
         ALOGE("Failed to call ioctl MSMFB_OVERLAY_SET err=%s",
                 strerror(errno));
@@ -173,6 +179,7 @@
 }
 
 inline bool validateAndSet(const int& fd, mdp_overlay_list& list) {
+    ATRACE_CALL();
     if (ioctl(fd, MSMFB_OVERLAY_PREPARE, &list) < 0) {
         ALOGD_IF(IOCTL_DEBUG, "Failed to call ioctl MSMFB_OVERLAY_PREPARE "
                 "err=%s", strerror(errno));
@@ -182,6 +189,7 @@
 }
 
 inline bool endRotator(int fd, uint32_t sessionId) {
+    ATRACE_CALL();
     if (ioctl(fd, MSM_ROTATOR_IOCTL_FINISH, &sessionId) < 0) {
         ALOGE("Failed to call ioctl MSM_ROTATOR_IOCTL_FINISH err=%s",
                 strerror(errno));
@@ -191,6 +199,7 @@
 }
 
 inline bool unsetOverlay(int fd, int ovId) {
+    ATRACE_CALL();
     if (ioctl(fd, MSMFB_OVERLAY_UNSET, &ovId) < 0) {
         ALOGE("Failed to call ioctl MSMFB_OVERLAY_UNSET err=%s",
                 strerror(errno));
@@ -200,6 +209,7 @@
 }
 
 inline bool getOverlay(int fd, mdp_overlay& ov) {
+    ATRACE_CALL();
     if (ioctl(fd, MSMFB_OVERLAY_GET, &ov) < 0) {
         ALOGE("Failed to call ioctl MSMFB_OVERLAY_GET err=%s",
                 strerror(errno));
@@ -209,6 +219,7 @@
 }
 
 inline bool play(int fd, msmfb_overlay_data& od) {
+    ATRACE_CALL();
     if (ioctl(fd, MSMFB_OVERLAY_PLAY, &od) < 0) {
         ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY err=%s",
                 strerror(errno));
@@ -217,16 +228,8 @@
     return true;
 }
 
-inline bool set3D(int fd, msmfb_overlay_3d& ov) {
-    if (ioctl(fd, MSMFB_OVERLAY_3D, &ov) < 0) {
-        ALOGE("Failed to call ioctl MSMFB_OVERLAY_3D err=%s",
-                strerror(errno));
-        return false;
-    }
-    return true;
-}
-
 inline bool displayCommit(int fd, mdp_display_commit& info) {
+    ATRACE_CALL();
     if(ioctl(fd, MSMFB_DISPLAY_COMMIT, &info) == -1) {
         ALOGE("Failed to call ioctl MSMFB_DISPLAY_COMMIT err=%s",
                 strerror(errno));
@@ -236,6 +239,7 @@
 }
 
 inline bool wbInitStart(int fbfd) {
+    ATRACE_CALL();
     if(ioctl(fbfd, MSMFB_WRITEBACK_INIT, NULL) < 0) {
         ALOGE("Failed to call ioctl MSMFB_WRITEBACK_INIT err=%s",
                 strerror(errno));
@@ -250,6 +254,7 @@
 }
 
 inline bool wbStopTerminate(int fbfd) {
+    ATRACE_CALL();
     if(ioctl(fbfd, MSMFB_WRITEBACK_STOP, NULL) < 0) {
         ALOGE("Failed to call ioctl MSMFB_WRITEBACK_STOP err=%s",
                 strerror(errno));
@@ -264,6 +269,7 @@
 }
 
 inline bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData) {
+    ATRACE_CALL();
     if(ioctl(fbfd, MSMFB_WRITEBACK_QUEUE_BUFFER, &fbData) < 0) {
         ALOGE("Failed to call ioctl MSMFB_WRITEBACK_QUEUE_BUFFER err=%s",
                 strerror(errno));
@@ -273,6 +279,7 @@
 }
 
 inline bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData) {
+    ATRACE_CALL();
     if(ioctl(fbfd, MSMFB_WRITEBACK_DEQUEUE_BUFFER, &fbData) < 0) {
         ALOGE("Failed to call ioctl MSMFB_WRITEBACK_DEQUEUE_BUFFER err=%s",
                 strerror(errno));
diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h
index 5cadebd..2eec98c 100644
--- a/liboverlay/overlayCtrlData.h
+++ b/liboverlay/overlayCtrlData.h
@@ -77,8 +77,6 @@
     /* retrieve crop data */
     utils::Dim getCrop() const;
     utils::Dim getPosition() const;
-    /* Set downscale */
-    void setDownscale(int dscale_factor);
     /* Update the src format based on rotator's dest */
     void updateSrcFormat(const uint32_t& rotDstFormat);
     /* return pipe priority */
@@ -213,10 +211,6 @@
     return mMdp->getDstRectDim();
 }
 
-inline void Ctrl::setDownscale(int dscale_factor) {
-    mMdp->setDownscale(dscale_factor);
-}
-
 inline uint8_t Ctrl::getPriority() const {
     return mMdp->getPriority();
 }
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 4622d16..7f9f136 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -54,7 +54,6 @@
     utils::memset0(mOVInfo);
     mOVInfo.id = MSMFB_NEW_REQUEST;
     mOrientation = utils::OVERLAY_TRANSFORM_0;
-    mDownscale = 0;
     mDpy = 0;
 #ifdef USES_POST_PROCESSING
     memset(&mParams, 0, sizeof(struct compute_params));
@@ -147,39 +146,10 @@
 }
 
 void MdpCtrl::doDownscale() {
-    int mdpVersion = MDPVersion::getInstance().getMDPVersion();
-    if(mdpVersion < MDSS_V5) {
-        mOVInfo.src_rect.x >>= mDownscale;
-        mOVInfo.src_rect.y >>= mDownscale;
-        mOVInfo.src_rect.w >>= mDownscale;
-        mOVInfo.src_rect.h >>= mDownscale;
-    } else if(MDPVersion::getInstance().supportsDecimation()) {
-        //Decimation + MDP Downscale
-        mOVInfo.horz_deci = 0;
-        mOVInfo.vert_deci = 0;
-        int minHorDeci = 0;
-        if(mOVInfo.src_rect.w > 2048) {
-            //If the client sends us something > what a layer mixer supports
-            //then it means it doesn't want to use split-pipe but wants us to
-            //decimate. A minimum decimation of 2 will ensure that the width is
-            //always within layer mixer limits.
-            minHorDeci = 2;
-        }
-
-        float horDscale = 0.0f;
-        float verDscale = 0.0f;
-
+    if(MDPVersion::getInstance().supportsDecimation()) {
         utils::getDecimationFactor(mOVInfo.src_rect.w, mOVInfo.src_rect.h,
-                mOVInfo.dst_rect.w, mOVInfo.dst_rect.h, horDscale, verDscale);
-
-        if(horDscale < minHorDeci)
-            horDscale = minHorDeci;
-
-        if((int)horDscale)
-            mOVInfo.horz_deci = (int)log2f(horDscale);
-
-        if((int)verDscale)
-            mOVInfo.vert_deci = (int)log2f(verDscale);
+                mOVInfo.dst_rect.w, mOVInfo.dst_rect.h, mOVInfo.horz_deci,
+                mOVInfo.vert_deci);
     }
 }
 
@@ -247,12 +217,6 @@
     ovutils::getDump(buf, len, "Data", mOvData);
 }
 
-void MdpCtrl3D::dump() const {
-    ALOGE("== Dump MdpCtrl start ==");
-    mFd.dump();
-    ALOGE("== Dump MdpCtrl end ==");
-}
-
 bool MdpCtrl::setVisualParams(const MetaData_t& data) {
     ALOGD_IF(0, "In %s: data.operation = %d", __FUNCTION__, data.operation);
 #ifdef USES_POST_PROCESSING
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index f7d64f0..cb8e057 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -64,8 +64,6 @@
     void setPosition(const utils::Dim& dim);
     /* using user_data, sets/unsets roationvalue in mdp flags */
     void setRotationFlags();
-    /* Performs downscale calculations */
-    void setDownscale(int dscale_factor);
     /* Update the src format with rotator's dest*/
     void updateSrcFormat(const uint32_t& rotDstFormat);
     /* dump state of the object */
@@ -125,7 +123,6 @@
     mdp_overlay   mOVInfo;
     /* FD for the mdp fbnum */
     OvFD          mFd;
-    int mDownscale;
     int mDpy;
 
 #ifdef USES_POST_PROCESSING
@@ -134,31 +131,6 @@
 #endif
 };
 
-
-/* MDP 3D related ctrl */
-class MdpCtrl3D {
-public:
-    /* ctor reset data */
-    MdpCtrl3D();
-    /* calls MSMFB_OVERLAY_3D */
-    bool close();
-    /* set w/h. format is ignored*/
-    void setWh(const utils::Whf& whf);
-    /* set is_3d calls MSMFB_OVERLAY_3D */
-    bool useVirtualFB();
-    /* set fd to be used in ioctl */
-    void setFd(int fd);
-    /* dump */
-    void dump() const;
-private:
-    /* reset */
-    void reset();
-    /* actual MSM 3D info */
-    msmfb_overlay_3d m3DOVInfo;
-    /* FD for the mdp 3D */
-    OvFD mFd;
-};
-
 /* MDP data */
 class MdpData {
 public:
@@ -236,10 +208,6 @@
     mOVInfo.is_fg = isFg;
 }
 
-inline void MdpCtrl::setDownscale(int dscale) {
-    mDownscale = dscale;
-}
-
 inline void MdpCtrl::setPlaneAlpha(int planeAlpha) {
     mOVInfo.alpha = planeAlpha;
 }
@@ -312,46 +280,6 @@
     return mOVInfo.priority;
 }
 
-///////    MdpCtrl3D //////
-
-inline MdpCtrl3D::MdpCtrl3D() { reset(); }
-inline bool MdpCtrl3D::close() {
-    if (m3DOVInfo.is_3d) {
-        m3DOVInfo.is_3d = 0;
-        if(!mdp_wrapper::set3D(mFd.getFD(), m3DOVInfo)) {
-            ALOGE("MdpCtrl3D close failed set3D with 0");
-            return false;
-        }
-    }
-    reset();
-    return true;
-}
-inline void MdpCtrl3D::reset() {
-    utils::memset0(m3DOVInfo);
-}
-
-inline void MdpCtrl3D::setFd(int fd) {
-    mFd.copy(fd);
-    OVASSERT(mFd.valid(), "MdpCtrl3D setFd, FD should be valid");
-}
-
-inline void MdpCtrl3D::setWh(const utils::Whf& whf) {
-    // ignore fmt. Needed for useVirtualFB callflow
-    m3DOVInfo.width = whf.w;
-    m3DOVInfo.height = whf.h;
-}
-
-inline bool MdpCtrl3D::useVirtualFB() {
-    if(!m3DOVInfo.is_3d) {
-        m3DOVInfo.is_3d = 1;
-        if(!mdp_wrapper::set3D(mFd.getFD(), m3DOVInfo)) {
-            ALOGE("MdpCtrl3D close failed set3D with 0");
-            return false;
-        }
-    }
-    return true;
-}
-
 ///////    MdpData   //////
 
 inline MdpData::MdpData(const int& dpy) {
diff --git a/liboverlay/overlayMdpRot.cpp b/liboverlay/overlayMdpRot.cpp
index 38b0a92..bb985d7 100755
--- a/liboverlay/overlayMdpRot.cpp
+++ b/liboverlay/overlayMdpRot.cpp
@@ -19,6 +19,7 @@
 
 #include "overlayUtils.h"
 #include "overlayRotator.h"
+#include "gr.h"
 
 namespace ovutils = overlay::utils;
 
@@ -33,7 +34,7 @@
 
 bool MdpRot::enabled() const { return mRotImgInfo.enable; }
 
-void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = r; }
+void MdpRot::setRotations(uint32_t r) { mRotImgInfo.rotations = (uint8_t)r; }
 
 int MdpRot::getDstMemId() const {
     return mRotDataInfo.dst.memory_id;
@@ -47,6 +48,24 @@
     return mRotImgInfo.dst.format;
 }
 
+//Added for completeness. Not expected to be called.
+utils::Whf MdpRot::getDstWhf() const {
+    int alW = 0, alH = 0;
+    int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format);
+    getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height,
+            halFormat, alW, alH);
+    return utils::Whf(alW, alH, mRotImgInfo.dst.format);
+}
+
+//Added for completeness. Not expected to be called.
+utils::Dim MdpRot::getDstDimensions() const {
+    int alW = 0, alH = 0;
+    int halFormat = ovutils::getHALFormat(mRotImgInfo.dst.format);
+    getBufferSizeAndDimensions(mRotImgInfo.dst.width, mRotImgInfo.dst.height,
+            halFormat, alW, alH);
+    return utils::Dim(0, 0, alW, alH);
+}
+
 uint32_t MdpRot::getSessId() const { return mRotImgInfo.session_id; }
 
 void MdpRot::setDownscale(int ds) {
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index f7bc87a..5783dcb 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -63,6 +63,21 @@
     return mRotInfo.src.format;
 }
 
+utils::Whf MdssRot::getDstWhf() const {
+    //For Mdss dst_rect itself represents buffer dimensions. We ignore actual
+    //aligned values during buffer allocation. Also the driver overwrites the
+    //src.format field if destination format is different.
+    //This implementation detail makes it possible to retrieve w,h even before
+    //buffer allocation, which happens in queueBuffer.
+    return utils::Whf(mRotInfo.dst_rect.w, mRotInfo.dst_rect.h,
+            mRotInfo.src.format);
+}
+
+utils::Dim MdssRot::getDstDimensions() const {
+    return utils::Dim(mRotInfo.dst_rect.x, mRotInfo.dst_rect.y,
+            mRotInfo.dst_rect.w, mRotInfo.dst_rect.h);
+}
+
 uint32_t MdssRot::getSessId() const { return mRotInfo.id; }
 
 bool MdssRot::init() {
@@ -82,16 +97,10 @@
 }
 
 void MdssRot::setCrop(const utils::Dim& crop) {
-
     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*/) {
@@ -119,7 +128,22 @@
 }
 
 bool MdssRot::commit() {
+    if (utils::isYuv(mRotInfo.src.format)) {
+        utils::normalizeCrop(mRotInfo.src_rect.x, mRotInfo.src_rect.w);
+        utils::normalizeCrop(mRotInfo.src_rect.y, mRotInfo.src_rect.h);
+        // For interlaced, crop.h should be 4-aligned
+        if ((mRotInfo.flags & utils::OV_MDP_DEINTERLACE) and
+                (mRotInfo.src_rect.h % 4))
+            mRotInfo.src_rect.h = utils::aligndown(mRotInfo.src_rect.h, 4);
+    }
+
+    mRotInfo.dst_rect.x = 0;
+    mRotInfo.dst_rect.y = 0;
+    mRotInfo.dst_rect.w = mRotInfo.src_rect.w;
+    mRotInfo.dst_rect.h = mRotInfo.src_rect.h;
+
     doTransform();
+
     mRotInfo.flags |= MDSS_MDP_ROT_ONLY;
     mEnabled = true;
     if(!overlay::mdp_wrapper::setOverlay(mFd.getFD(), mRotInfo)) {
diff --git a/liboverlay/overlayRotator.cpp b/liboverlay/overlayRotator.cpp
index 0e5b0ec..0671b62 100644
--- a/liboverlay/overlayRotator.cpp
+++ b/liboverlay/overlayRotator.cpp
@@ -145,7 +145,7 @@
     //Return a rot object, creating one if necessary
     overlay::Rotator *rot = NULL;
     if(mUseCount >= MAX_ROT_SESS) {
-        ALOGE("%s, MAX rotator sessions reached", __func__);
+        ALOGW("%s, MAX rotator sessions reached, request rejected", __func__);
     } else {
         if(mRot[mUseCount] == NULL)
             mRot[mUseCount] = overlay::Rotator::getRotator();
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index 53c54e6..64387cd 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -74,9 +74,14 @@
     virtual void setTransform(const utils::eTransform& rot) = 0;
     virtual bool commit() = 0;
     virtual void setDownscale(int ds) = 0;
+    //Mem id and offset should be retrieved only after rotator kickoff
     virtual int getDstMemId() const = 0;
     virtual uint32_t getDstOffset() const = 0;
+    //Destination width, height, format, position should be retrieved only after
+    //rotator configuration is committed via commit API
     virtual uint32_t getDstFormat() const = 0;
+    virtual utils::Whf getDstWhf() const = 0;
+    virtual utils::Dim getDstDimensions() const = 0;
     virtual uint32_t getSessId() const = 0;
     virtual bool queueBuffer(int fd, uint32_t offset) = 0;
     virtual void dump() const = 0;
@@ -112,6 +117,8 @@
     virtual int getDstMemId() const;
     virtual uint32_t getDstOffset() const;
     virtual uint32_t getDstFormat() const;
+    virtual utils::Whf getDstWhf() const;
+    virtual utils::Dim getDstDimensions() const;
     virtual uint32_t getSessId() const;
     virtual bool queueBuffer(int fd, uint32_t offset);
     virtual void dump() const;
@@ -169,6 +176,8 @@
     virtual int getDstMemId() const;
     virtual uint32_t getDstOffset() const;
     virtual uint32_t getDstFormat() const;
+    virtual utils::Whf getDstWhf() const;
+    virtual utils::Dim getDstDimensions() const;
     virtual uint32_t getSessId() const;
     virtual bool queueBuffer(int fd, uint32_t offset);
     virtual void dump() const;
@@ -210,9 +219,10 @@
 // Holder of rotator objects. Manages lifetimes
 class RotMgr {
 public:
-    //Maximum sessions based on VG pipes, since rotator is used only for videos.
-    //Even though we can have 4 mixer stages, that much may be unnecessary.
-    enum { MAX_ROT_SESS = 3 };
+    //Virtually we can support as many rotator sessions as possible, However
+    // more number of rotator sessions leads to performance issues, so
+    // restricting the max rotator session to 4
+    enum { MAX_ROT_SESS = 4 };
 
     ~RotMgr();
     void configBegin();
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index 0b78e4d..0e063ab 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -74,12 +74,6 @@
 //----------From class Res ------------------------------
 const char* const Res::fbPath = "/dev/graphics/fb%u";
 const char* const Res::rotPath = "/dev/msm_rotator";
-const char* const Res::format3DFile =
-        "/sys/class/graphics/fb1/format_3d";
-const char* const Res::edid3dInfoFile =
-        "/sys/class/graphics/fb1/3d_present";
-const char* const Res::barrierFile =
-        "/sys/devices/platform/mipi_novatek.0/enable_3d_barrier";
 //--------------------------------------------------------
 
 
@@ -285,10 +279,12 @@
 }
 
 void getDecimationFactor(const int& src_w, const int& src_h,
-        const int& dst_w, const int& dst_h, float& horDscale,
-        float& verDscale) {
-    horDscale = ceilf((float)src_w / (float)dst_w);
-    verDscale = ceilf((float)src_h / (float)dst_h);
+        const int& dst_w, const int& dst_h, uint8_t& horzDeci,
+        uint8_t& vertDeci) {
+    horzDeci = 0;
+    vertDeci = 0;
+    float horDscale = ceilf((float)src_w / (float)dst_w);
+    float verDscale = ceilf((float)src_h / (float)dst_h);
 
     //Next power of 2, if not already
     horDscale = powf(2.0f, ceilf(log2f(horDscale)));
@@ -298,6 +294,21 @@
     //between decimator and MDP downscale
     horDscale /= 4.0f;
     verDscale /= 4.0f;
+
+    if((int)horDscale)
+        horzDeci = (uint8_t)log2f(horDscale);
+
+    if((int)verDscale)
+        vertDeci = (uint8_t)log2f(verDscale);
+
+    if(src_w > 2048) {
+        //If the client sends us something > what a layer mixer supports
+        //then it means it doesn't want to use split-pipe but wants us to
+        //decimate. A minimum decimation of 2 will ensure that the width is
+        //always within layer mixer limits.
+        if(horzDeci < 2)
+            horzDeci = 2;
+    }
 }
 
 static inline int compute(const uint32_t& x, const uint32_t& y,
@@ -323,86 +334,6 @@
     }
 }
 
-bool is3DTV() {
-    char is3DTV = '0';
-    IOFile fp(Res::edid3dInfoFile, "r");
-    (void)fp.read(is3DTV, 1);
-    ALOGI("3DTV EDID flag: %d", is3DTV);
-    return (is3DTV == '0') ? false : true;
-}
-
-bool isPanel3D() {
-    OvFD fd;
-    if(!overlay::open(fd, 0 /*fb*/, Res::fbPath)){
-        ALOGE("isPanel3D Can't open framebuffer 0");
-        return false;
-    }
-    fb_fix_screeninfo finfo;
-    if(!mdp_wrapper::getFScreenInfo(fd.getFD(), finfo)) {
-        ALOGE("isPanel3D read fb0 failed");
-    }
-    fd.close();
-    return (FB_TYPE_3D_PANEL == finfo.type) ? true : false;
-}
-
-bool usePanel3D() {
-    if(!isPanel3D())
-        return false;
-    char value[PROPERTY_VALUE_MAX];
-    property_get("persist.user.panel3D", value, "0");
-    int usePanel3D = atoi(value);
-    return usePanel3D ? true : false;
-}
-
-bool send3DInfoPacket (uint32_t format3D) {
-    IOFile fp(Res::format3DFile, "wb");
-    (void)fp.write("%d", format3D);
-    if(!fp.valid()) {
-        ALOGE("send3DInfoPacket: no sysfs entry for setting 3d mode");
-        return false;
-    }
-    return true;
-}
-
-bool enableBarrier (uint32_t orientation) {
-    IOFile fp(Res::barrierFile, "wb");
-    (void)fp.write("%d", orientation);
-    if(!fp.valid()) {
-        ALOGE("enableBarrier no sysfs entry for "
-                "enabling barriers on 3D panel");
-        return false;
-    }
-    return true;
-}
-
-uint32_t getS3DFormat(uint32_t fmt) {
-    // The S3D is part of the HAL_PIXEL_FORMAT_YV12 value. Add
-    // an explicit check for the format
-    if (fmt == HAL_PIXEL_FORMAT_YV12) {
-        return 0;
-    }
-    uint32_t fmt3D = format3D(fmt);
-    uint32_t fIn3D = format3DInput(fmt3D); // MSB 2 bytes - inp
-    uint32_t fOut3D = format3DOutput(fmt3D); // LSB 2 bytes - out
-    fmt3D = fIn3D | fOut3D;
-    if (!fIn3D) {
-        fmt3D |= fOut3D << SHIFT_TOT_3D; //Set the input format
-    }
-    if (!fOut3D) {
-        switch (fIn3D) {
-            case HAL_3D_IN_SIDE_BY_SIDE_L_R:
-            case HAL_3D_IN_SIDE_BY_SIDE_R_L:
-                // For all side by side formats, set the output
-                // format as Side-by-Side i.e 0x1
-                fmt3D |= HAL_3D_IN_SIDE_BY_SIDE_L_R >> SHIFT_TOT_3D;
-                break;
-            default:
-                fmt3D |= fIn3D >> SHIFT_TOT_3D; //Set the output format
-        }
-    }
-    return fmt3D;
-}
-
 void getDump(char *buf, size_t len, const char *prefix,
         const mdp_overlay& ov) {
     char str[256] = {'\0'};
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index c2649f3..530377b 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -120,40 +120,9 @@
     const NoCopy& operator=(const NoCopy&);
 };
 
-
-/* 3D related utils, defines etc...
- * The compound format passed to the overlay is
- * ABCCC where A is the input 3D format
- * B is the output 3D format
- * CCC is the color format e.g YCbCr420SP YCrCb420SP etc */
-enum { SHIFT_OUT_3D = 12,
-    SHIFT_TOT_3D = 16 };
-enum { INPUT_3D_MASK = 0xFFFF0000,
-    OUTPUT_3D_MASK = 0x0000FFFF };
-enum { BARRIER_LAND = 1,
-    BARRIER_PORT = 2 };
-
-inline uint32_t format3D(uint32_t x) { return x & 0xFF000; }
-inline uint32_t format3DOutput(uint32_t x) {
-    return (x & 0xF000) >> SHIFT_OUT_3D; }
-inline uint32_t format3DInput(uint32_t x) { return x & 0xF0000; }
-
-bool isHDMIConnected ();
-bool is3DTV();
-bool isPanel3D();
-bool usePanel3D();
-bool send3DInfoPacket (uint32_t fmt);
-bool enableBarrier (uint32_t orientation);
-uint32_t getS3DFormat(uint32_t fmt);
 bool isMdssRotator();
 void normalizeCrop(uint32_t& xy, uint32_t& wh);
 
-template <int CHAN>
-bool getPositionS3D(const Whf& whf, Dim& out);
-
-template <int CHAN>
-bool getCropS3D(const Dim& in, Dim& out, uint32_t fmt);
-
 template <class Type>
 void swapWidthHeight(Type& width, Type& height);
 
@@ -413,8 +382,8 @@
 int getDownscaleFactor(const int& src_w, const int& src_h,
         const int& dst_w, const int& dst_h);
 void getDecimationFactor(const int& src_w, const int& src_h,
-        const int& dst_w, const int& dst_h, float& horDscale,
-        float& verDscale);
+        const int& dst_w, const int& dst_h, uint8_t& horzDeci,
+        uint8_t& vertDeci);
 
 /* flip is upside down and such. V, H flip
  * rotation is 90, 180 etc
@@ -446,39 +415,6 @@
     return a ? ((value + (a-1)) & ~(a-1)) : value;
 }
 
-enum eRotOutFmt {
-    ROT_OUT_FMT_DEFAULT,
-    ROT_OUT_FMT_Y_CRCB_H2V2
-};
-
-template <int ROT_OUT_FMT> struct RotOutFmt;
-
-// FIXME, taken from gralloc_priv.h. Need to
-// put it back as soon as overlay takes place of the old one
-/* possible formats for 3D content*/
-enum {
-    HAL_NO_3D                         = 0x0000,
-    HAL_3D_IN_SIDE_BY_SIDE_L_R        = 0x10000,
-    HAL_3D_IN_TOP_BOTTOM              = 0x20000,
-    HAL_3D_IN_INTERLEAVE              = 0x40000,
-    HAL_3D_IN_SIDE_BY_SIDE_R_L        = 0x80000,
-    HAL_3D_OUT_SIDE_BY_SIDE           = 0x1000,
-    HAL_3D_OUT_TOP_BOTTOM             = 0x2000,
-    HAL_3D_OUT_INTERLEAVE             = 0x4000,
-    HAL_3D_OUT_MONOSCOPIC             = 0x8000
-};
-
-enum { HAL_3D_OUT_SBS_MASK =
-    HAL_3D_OUT_SIDE_BY_SIDE >> overlay::utils::SHIFT_OUT_3D,
-    HAL_3D_OUT_TOP_BOT_MASK =
-            HAL_3D_OUT_TOP_BOTTOM >> overlay::utils::SHIFT_OUT_3D,
-    HAL_3D_OUT_INTERL_MASK =
-            HAL_3D_OUT_INTERLEAVE >> overlay::utils::SHIFT_OUT_3D,
-    HAL_3D_OUT_MONOS_MASK =
-            HAL_3D_OUT_MONOSCOPIC >> overlay::utils::SHIFT_OUT_3D
-};
-
-
 inline bool isYuv(uint32_t format) {
     switch(format){
         case MDP_Y_CBCR_H2V1:
@@ -577,105 +513,6 @@
     ALOGE("== Dump Dim x=%d y=%d w=%d h=%d start/end ==", x, y, w, h);
 }
 
-// FB0
-template <int CHAN>
-inline Dim getPositionS3DImpl(const Whf& whf)
-{
-    switch (whf.format & OUTPUT_3D_MASK)
-    {
-        case HAL_3D_OUT_SBS_MASK:
-            // x, y, w, h
-            return Dim(0, 0, whf.w/2, whf.h);
-        case HAL_3D_OUT_TOP_BOT_MASK:
-            return Dim(0, 0, whf.w, whf.h/2);
-        case HAL_3D_OUT_MONOS_MASK:
-            return Dim();
-        case HAL_3D_OUT_INTERL_MASK:
-            // FIXME error?
-            ALOGE("%s HAL_3D_OUT_INTERLEAVE_MASK", __FUNCTION__);
-            return Dim();
-        default:
-            ALOGE("%s Unsupported 3D output format %d", __FUNCTION__,
-                    whf.format);
-    }
-    return Dim();
-}
-
-template <>
-inline Dim getPositionS3DImpl<utils::OV_RIGHT_SPLIT>(const Whf& whf)
-{
-    switch (whf.format & OUTPUT_3D_MASK)
-    {
-        case HAL_3D_OUT_SBS_MASK:
-            return Dim(whf.w/2, 0, whf.w/2, whf.h);
-        case HAL_3D_OUT_TOP_BOT_MASK:
-            return Dim(0, whf.h/2, whf.w, whf.h/2);
-        case HAL_3D_OUT_MONOS_MASK:
-            return Dim(0, 0, whf.w, whf.h);
-        case HAL_3D_OUT_INTERL_MASK:
-            // FIXME error?
-            ALOGE("%s HAL_3D_OUT_INTERLEAVE_MASK", __FUNCTION__);
-            return Dim();
-        default:
-            ALOGE("%s Unsupported 3D output format %d", __FUNCTION__,
-                    whf.format);
-    }
-    return Dim();
-}
-
-template <int CHAN>
-inline bool getPositionS3D(const Whf& whf, Dim& out) {
-    out = getPositionS3DImpl<CHAN>(whf);
-    return (out != Dim());
-}
-
-template <int CHAN>
-inline Dim getCropS3DImpl(const Dim& in, uint32_t fmt) {
-    switch (fmt & INPUT_3D_MASK)
-    {
-        case HAL_3D_IN_SIDE_BY_SIDE_L_R:
-            return Dim(0, 0, in.w/2, in.h);
-        case HAL_3D_IN_SIDE_BY_SIDE_R_L:
-            return Dim(in.w/2, 0, in.w/2, in.h);
-        case HAL_3D_IN_TOP_BOTTOM:
-            return Dim(0, 0, in.w, in.h/2);
-        case HAL_3D_IN_INTERLEAVE:
-            ALOGE("%s HAL_3D_IN_INTERLEAVE", __FUNCTION__);
-            break;
-        default:
-            ALOGE("%s Unsupported 3D format %d", __FUNCTION__, fmt);
-            break;
-    }
-    return Dim();
-}
-
-template <>
-inline Dim getCropS3DImpl<utils::OV_RIGHT_SPLIT>(const Dim& in, uint32_t fmt) {
-    switch (fmt & INPUT_3D_MASK)
-    {
-        case HAL_3D_IN_SIDE_BY_SIDE_L_R:
-            return Dim(in.w/2, 0, in.w/2, in.h);
-        case HAL_3D_IN_SIDE_BY_SIDE_R_L:
-            return Dim(0, 0, in.w/2, in.h);
-        case HAL_3D_IN_TOP_BOTTOM:
-            return Dim(0, in.h/2, in.w, in.h/2);
-        case HAL_3D_IN_INTERLEAVE:
-            ALOGE("%s HAL_3D_IN_INTERLEAVE", __FUNCTION__);
-            break;
-        default:
-            ALOGE("%s Unsupported 3D format %d", __FUNCTION__, fmt);
-            break;
-    }
-    return Dim();
-}
-
-template <int CHAN>
-inline bool getCropS3D(const Dim& in, Dim& out, uint32_t fmt)
-{
-    out = getCropS3DImpl<CHAN>(in, fmt);
-    return (out != Dim());
-}
-
 template <class Type>
 void swapWidthHeight(Type& width, Type& height) {
     Type tmp = width;
@@ -706,6 +543,14 @@
         value--;
 }
 
+/* Prerotation adjusts crop co-ordinates to the new transformed values within
+ * destination buffer. This is necessary only when the entire buffer is rotated
+ * irrespective of crop (A-family). If only the crop portion of the buffer is
+ * rotated into a destination buffer matching the size of crop, we don't need to
+ * use this helper (B-family).
+ * @Deprecated as of now, retained for the case where a full buffer needs
+ * transform and also as a reference.
+ */
 void preRotateSource(const eTransform& tr, Whf& whf, Dim& srcCrop);
 void getDump(char *buf, size_t len, const char *prefix, const mdp_overlay& ov);
 void getDump(char *buf, size_t len, const char *prefix, const msmfb_img& ov);
@@ -728,12 +573,6 @@
     static const char* const fbPath;
     // /dev/msm_rotator
     static const char* const rotPath;
-    // /sys/class/graphics/fb1/format_3d
-    static const char* const format3DFile;
-    // /sys/class/graphics/fb1/3d_present
-    static const char* const edid3dInfoFile;
-    // /sys/devices/platform/mipi_novatek.0/enable_3d_barrier
-    static const char* const barrierFile;
 };
 
 
diff --git a/liboverlay/pipes/overlay3DPipe.h b/liboverlay/pipes/overlay3DPipe.h
deleted file mode 100644
index 4e5630e..0000000
--- a/liboverlay/pipes/overlay3DPipe.h
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
-* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions are
-* met:
-*    * Redistributions of source code must retain the above copyright
-*      notice, this list of conditions and the following disclaimer.
-*    * Redistributions in binary form must reproduce the above
-*      copyright notice, this list of conditions and the following
-*      disclaimer in the documentation and/or other materials provided
-*      with the distribution.
-*    * Neither the name of The Linux Foundation nor the names of its
-*      contributors may be used to endorse or promote products derived
-*      from this software without specific prior written permission.
-*
-* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-* ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef OVERLAY_M3D_EXT_PIPE_H
-#define OVERLAY_M3D_EXT_PIPE_H
-
-#include "overlayGenPipe.h"
-#include "overlayUtils.h"
-
-namespace overlay {
-
-/////////////  M3DExt Pipe ////////////////////////////
-/**
-* A specific impl of GenericPipe for 3D.
-* Whenever needed to have a pass through - we do it.
-* If there is a special need for special/diff behavior
-* do it here
-* PANEL is always EXTERNAL for this pipe.
-* CHAN = 0,1 it's either Channel 1 or channel 2 needed for
-* 3D crop and position */
-template <int CHAN>
-class M3DExtPipe : utils::NoCopy {
-public:
-    /* Please look at overlayGenPipe.h for info */
-    explicit M3DExtPipe();
-    ~M3DExtPipe();
-    bool init(RotatorBase* rot);
-    bool close();
-    bool commit();
-    bool queueBuffer(int fd, uint32_t offset);
-    bool setCrop(const utils::Dim& d);
-    bool setPosition(const utils::Dim& dim);
-    bool setTransform(const utils::eTransform& param);
-    bool setSource(const utils::PipeArgs& args);
-    void dump() const;
-private:
-    overlay::GenericPipe<utils::EXTERNAL> mM3d;
-    // Cache the M3D format
-    uint32_t mM3Dfmt;
-};
-
-/////////////  M3DPrimary Pipe ////////////////////////////
-/**
-* A specific impl of GenericPipe for 3D.
-* Whenever needed to have a pass through - we do it.
-* If there is a special need for special/diff behavior
-* do it here
-* PANEL is always PRIMARY for this pipe.
-* CHAN = 0,1 it's either Channel 1 or channel 2 needed for
-* 3D crop and position */
-template <int CHAN>
-class M3DPrimaryPipe : utils::NoCopy {
-public:
-    /* Please look at overlayGenPipe.h for info */
-    explicit M3DPrimaryPipe();
-    ~M3DPrimaryPipe();
-    bool init(RotatorBase* rot);
-    bool close();
-    bool commit();
-    bool queueBuffer(int fd, uint32_t offset);
-    bool setCrop(const utils::Dim& d);
-    bool setPosition(const utils::Dim& dim);
-    bool setTransform(const utils::eTransform& param);
-    bool setSource(const utils::PipeArgs& args);
-    void dump() const;
-private:
-    overlay::GenericPipe<utils::PRIMARY> mM3d;
-    // Cache the M3D format
-    uint32_t mM3Dfmt;
-};
-
-/////////////  S3DExt Pipe ////////////////////////////////
-/**
-* A specific impl of GenericPipe for 3D.
-* Whenever needed to have a pass through - we do it.
-* If there is a special need for special/diff behavior
-* do it here.
-* PANEL is always EXTERNAL for this pipe.
-* CHAN = 0,1 it's either Channel 1 or channel 2 needed for
-* 3D crop and position */
-template <int CHAN>
-class S3DExtPipe : utils::NoCopy {
-public:
-    /* Please look at overlayGenPipe.h for info */
-    explicit S3DExtPipe();
-    ~S3DExtPipe();
-    bool init(RotatorBase* rot);
-    bool close();
-    bool commit();
-    bool queueBuffer(int fd, uint32_t offset);
-    bool setCrop(const utils::Dim& d);
-    bool setPosition(const utils::Dim& dim);
-    bool setTransform(const utils::eTransform& param);
-    bool setSource(const utils::PipeArgs& args);
-    void dump() const;
-private:
-    overlay::GenericPipe<utils::EXTERNAL> mS3d;
-    // Cache the 3D format
-    uint32_t mS3Dfmt;
-};
-
-/////////////  S3DPrimary Pipe ////////////////////////////
-/**
-* A specific impl of GenericPipe for 3D.
-* Whenever needed to have a pass through - we do it.
-* If there is a special need for special/diff behavior
-* do it here
-* PANEL is always PRIMARY for this pipe.
-* CHAN = 0,1 it's either Channel 1 or channel 2 needed for
-* 3D crop and position */
-template <int CHAN>
-class S3DPrimaryPipe : utils::NoCopy {
-public:
-    /* Please look at overlayGenPipe.h for info */
-    explicit S3DPrimaryPipe();
-    ~S3DPrimaryPipe();
-    bool init(RotatorBase* rot);
-    bool close();
-    bool commit();
-    bool queueBuffer(int fd, uint32_t offset);
-    bool setCrop(const utils::Dim& d);
-    bool setPosition(const utils::Dim& dim);
-    bool setTransform(const utils::eTransform& param);
-    bool setSource(const utils::PipeArgs& args);
-    void dump() const;
-private:
-    /* needed for 3D related IOCTL */
-    MdpCtrl3D mCtrl3D;
-    overlay::GenericPipe<utils::PRIMARY> mS3d;
-    // Cache the 3D format
-    uint32_t mS3Dfmt;
-};
-
-
-
-
-//------------------------Inlines and Templates--------------------------
-
-
-/////////////  M3DExt Pipe ////////////////////////////
-template <int CHAN>
-inline M3DExtPipe<CHAN>::M3DExtPipe() : mM3Dfmt(0) {}
-template <int CHAN>
-inline M3DExtPipe<CHAN>::~M3DExtPipe() { close(); }
-template <int CHAN>
-inline bool M3DExtPipe<CHAN>::init(RotatorBase* rot) {
-    ALOGE_IF(DEBUG_OVERLAY, "M3DExtPipe init");
-    if(!mM3d.init(rot)) {
-        ALOGE("3Dpipe failed to init");
-        return false;
-    }
-    return true;
-}
-template <int CHAN>
-inline bool M3DExtPipe<CHAN>::close() {
-    return mM3d.close();
-}
-template <int CHAN>
-inline bool M3DExtPipe<CHAN>::commit() { return mM3d.commit(); }
-template <int CHAN>
-inline bool M3DExtPipe<CHAN>::queueBuffer(int fd, uint32_t offset) {
-    return mM3d.queueBuffer(fd, offset);
-}
-template <int CHAN>
-inline bool M3DExtPipe<CHAN>::setCrop(const utils::Dim& d) {
-    utils::Dim _dim;
-    if(!utils::getCropS3D<CHAN>(d, _dim, mM3Dfmt)){
-        ALOGE("M3DExtPipe setCrop failed to getCropS3D");
-        _dim = d;
-    }
-    return mM3d.setCrop(_dim);
-}
-
-template <int CHAN>
-inline bool M3DExtPipe<CHAN>::setPosition(const utils::Dim& d) {
-    utils::Dim _dim;
-    // original setPositionHandleState has getPositionS3D(...,true)
-    // which means format is HAL_3D_OUT_SBS_MASK
-    // HAL_3D_OUT_SBS_MASK is 0x1000 >> 12 == 0x1 as the orig
-    // code suggets
-    utils::Whf _whf(mM3d.getScreenInfo().mFBWidth,
-            mM3d.getScreenInfo().mFBHeight,
-            mM3Dfmt);
-    if(!utils::getPositionS3D<CHAN>(_whf, _dim)) {
-        ALOGE("S3DPrimaryPipe setPosition err in getPositionS3D");
-        _dim = d;
-    }
-    return mM3d.setPosition(_dim);
-}
-template <int CHAN>
-inline bool M3DExtPipe<CHAN>::setTransform(const utils::eTransform& param) {
-    return mM3d.setTransform(param);
-}
-template <int CHAN>
-inline bool M3DExtPipe<CHAN>::setSource(const utils::PipeArgs& args)
-{
-    // extract 3D fmt
-    mM3Dfmt = utils::format3DInput(utils::getS3DFormat(args.whf.format)) |
-            utils::HAL_3D_OUT_MONOS_MASK;
-    return mM3d.setSource(args);
-}
-template <int CHAN>
-inline void M3DExtPipe<CHAN>::dump() const {
-    ALOGE("M3DExtPipe Pipe fmt=%d", mM3Dfmt);
-    mM3d.dump();
-}
-
-
-/////////////  M3DPrimary Pipe ////////////////////////////
-template <int CHAN>
-inline M3DPrimaryPipe<CHAN>::M3DPrimaryPipe() : mM3Dfmt(0) {}
-template <int CHAN>
-inline M3DPrimaryPipe<CHAN>::~M3DPrimaryPipe() { close(); }
-template <int CHAN>
-inline bool M3DPrimaryPipe<CHAN>::init(RotatorBase* rot) {
-    ALOGE_IF(DEBUG_OVERLAY, "M3DPrimaryPipe init");
-    if(!mM3d.init(rot)) {
-        ALOGE("3Dpipe failed to init");
-        return false;
-    }
-    return true;
-}
-template <int CHAN>
-inline bool M3DPrimaryPipe<CHAN>::close() {
-    return mM3d.close();
-}
-template <int CHAN>
-inline bool M3DPrimaryPipe<CHAN>::commit() { return mM3d.commit(); }
-template <int CHAN>
-inline bool M3DPrimaryPipe<CHAN>::queueBuffer(int fd, uint32_t offset) {
-    return mM3d.queueBuffer(fd, offset);
-}
-template <int CHAN>
-inline bool M3DPrimaryPipe<CHAN>::setCrop(const utils::Dim& d) {
-    utils::Dim _dim;
-    if(!utils::getCropS3D<CHAN>(d, _dim, mM3Dfmt)){
-        ALOGE("M3DPrimaryPipe setCrop failed to getCropS3D");
-        _dim = d;
-    }
-    return mM3d.setCrop(_dim);
-}
-template <int CHAN>
-inline bool M3DPrimaryPipe<CHAN>::setPosition(const utils::Dim& d) {
-    return mM3d.setPosition(d);
-}
-template <int CHAN>
-inline bool M3DPrimaryPipe<CHAN>::setTransform(const utils::eTransform& param) {
-    return mM3d.setTransform(param);
-}
-template <int CHAN>
-inline bool M3DPrimaryPipe<CHAN>::setSource(const utils::PipeArgs& args)
-{
-    // extract 3D fmt
-    mM3Dfmt = utils::format3DInput(utils::getS3DFormat(args.whf.format)) |
-            utils::HAL_3D_OUT_MONOS_MASK;
-    return mM3d.setSource(args);
-}
-template <int CHAN>
-inline void M3DPrimaryPipe<CHAN>::dump() const {
-    ALOGE("M3DPrimaryPipe Pipe fmt=%d", mM3Dfmt);
-    mM3d.dump();
-}
-
-/////////////  S3DExt Pipe ////////////////////////////////
-template <int CHAN>
-inline S3DExtPipe<CHAN>::S3DExtPipe() : mS3Dfmt(0) {}
-template <int CHAN>
-inline S3DExtPipe<CHAN>::~S3DExtPipe() { close(); }
-template <int CHAN>
-inline bool S3DExtPipe<CHAN>::init(RotatorBase* rot) {
-    ALOGE_IF(DEBUG_OVERLAY, "S3DExtPipe init");
-    if(!mS3d.init(rot)) {
-        ALOGE("3Dpipe failed to init");
-        return false;
-    }
-    return true;
-}
-template <int CHAN>
-inline bool S3DExtPipe<CHAN>::close() {
-    if(!utils::send3DInfoPacket(0)) {
-        ALOGE("S3DExtPipe close failed send3D info packet");
-    }
-    return mS3d.close();
-}
-template <int CHAN>
-inline bool S3DExtPipe<CHAN>::commit() { return mS3d.commit(); }
-template <int CHAN>
-inline bool S3DExtPipe<CHAN>::queueBuffer(int fd, uint32_t offset) {
-    return mS3d.queueBuffer(fd, offset);
-}
-template <int CHAN>
-inline bool S3DExtPipe<CHAN>::setCrop(const utils::Dim& d) {
-    utils::Dim _dim;
-    if(!utils::getCropS3D<CHAN>(d, _dim, mS3Dfmt)){
-        ALOGE("S3DExtPipe setCrop failed to getCropS3D");
-        _dim = d;
-    }
-    return mS3d.setCrop(_dim);
-}
-template <int CHAN>
-inline bool S3DExtPipe<CHAN>::setPosition(const utils::Dim& d)
-{
-    utils::Dim _dim;
-    utils::Whf _whf(mS3d.getScreenInfo().mFBWidth,
-            mS3d.getScreenInfo().mFBHeight,
-            mS3Dfmt);
-    if(!utils::getPositionS3D<CHAN>(_whf, _dim)) {
-        ALOGE("S3DExtPipe setPosition err in getPositionS3D");
-        _dim = d;
-    }
-    return mS3d.setPosition(_dim);
-}
-template <int CHAN>
-inline bool S3DExtPipe<CHAN>::setTransform(const utils::eTransform& param) {
-    return mS3d.setTransform(param);
-}
-template <int CHAN>
-inline bool S3DExtPipe<CHAN>::setSource(const utils::PipeArgs& args) {
-    mS3Dfmt = utils::getS3DFormat(args.whf.format);
-    return mS3d.setSource(args);
-}
-template <int CHAN>
-inline void S3DExtPipe<CHAN>::dump() const {
-    ALOGE("S3DExtPipe Pipe fmt=%d", mS3Dfmt);
-    mS3d.dump();
-}
-
-/////////////  S3DPrimary Pipe ////////////////////////////
-template <int CHAN>
-inline S3DPrimaryPipe<CHAN>::S3DPrimaryPipe() : mS3Dfmt(0) {}
-template <int CHAN>
-inline S3DPrimaryPipe<CHAN>::~S3DPrimaryPipe() { close(); }
-template <int CHAN>
-inline bool S3DPrimaryPipe<CHAN>::init(RotatorBase* rot) {
-    ALOGE_IF(DEBUG_OVERLAY, "S3DPrimaryPipe init");
-    if(!mS3d.init(rot)) {
-        ALOGE("3Dpipe failed to init");
-        return false;
-    }
-    // set the ctrl fd
-    mCtrl3D.setFd(mS3d.getCtrlFd());
-    return true;
-}
-template <int CHAN>
-inline bool S3DPrimaryPipe<CHAN>::close() {
-    if(!utils::enableBarrier(0)) {
-        ALOGE("S3DExtPipe close failed enable barrier");
-    }
-    mCtrl3D.close();
-    return mS3d.close();
-}
-
-template <int CHAN>
-inline bool S3DPrimaryPipe<CHAN>::commit() {
-    uint32_t fmt = mS3Dfmt & utils::OUTPUT_3D_MASK;
-    if(!utils::send3DInfoPacket(fmt)){
-        ALOGE("Error S3DExtPipe start error send3DInfoPacket %d", fmt);
-        return false;
-    }
-    return mS3d.commit();
-}
-template <int CHAN>
-inline bool S3DPrimaryPipe<CHAN>::queueBuffer(int fd, uint32_t offset) {
-    return mS3d.queueBuffer(fd, offset);
-}
-template <int CHAN>
-inline bool S3DPrimaryPipe<CHAN>::setCrop(const utils::Dim& d) {
-    utils::Dim _dim;
-    if(!utils::getCropS3D<CHAN>(d, _dim, mS3Dfmt)){
-        ALOGE("S3DPrimaryPipe setCrop failed to getCropS3D");
-        _dim = d;
-    }
-    return mS3d.setCrop(_dim);
-}
-template <int CHAN>
-inline bool S3DPrimaryPipe<CHAN>::setPosition(const utils::Dim& d)
-{
-    utils::Whf fbwhf(mS3d.getScreenInfo().mFBWidth,
-            mS3d.getScreenInfo().mFBHeight,
-            0 /* fmt dont care*/);
-    mCtrl3D.setWh(fbwhf);
-    if(!mCtrl3D.useVirtualFB()) {
-        ALOGE("Failed to use VFB on %d (non fatal)", utils::FB0);
-        return false;
-    }
-    utils::Dim _dim;
-    // original setPositionHandleState has getPositionS3D(...,true)
-    // which means format is HAL_3D_OUT_SBS_MASK
-    // HAL_3D_OUT_SBS_MASK is 0x1000 >> 12 == 0x1 as the orig
-    // code suggets
-    utils::Whf _whf(d.w, d.h, utils::HAL_3D_OUT_SBS_MASK);
-    if(!utils::getPositionS3D<CHAN>(_whf, _dim)) {
-        ALOGE("S3DPrimaryPipe setPosition err in getPositionS3D");
-        _dim = d;
-    }
-    return mS3d.setPosition(_dim);
-}
-
-/* for S3DPrimaryPipe, we need to have barriers once
-* So the easiest way to achieve it, is to make sure FB0 is having it before
-* setParam is running */
-template <>
-inline bool S3DPrimaryPipe<utils::OV_PIPE0>::setTransform(
-        const utils::eTransform& param) {
-    uint32_t barrier=0;
-    switch(param) {
-        case utils::OVERLAY_TRANSFORM_ROT_90:
-        case utils::OVERLAY_TRANSFORM_ROT_270:
-            barrier = utils::BARRIER_LAND;
-            break;
-        default:
-            barrier = utils::BARRIER_PORT;
-            break;
-    }
-    if(!utils::enableBarrier(barrier)) {
-        ALOGE("S3DPrimaryPipe setTransform failed to enable barrier");
-    }
-    return mS3d.setTransform(param);
-}
-
-template <int CHAN>
-inline bool S3DPrimaryPipe<CHAN>::setTransform(const utils::eTransform& param) {
-    return mS3d.setTransform(param);
-}
-template <int CHAN>
-inline bool S3DPrimaryPipe<CHAN>::setSource(const utils::PipeArgs& args)
-{
-    mS3Dfmt = utils::getS3DFormat(args.whf.format);
-    return mS3d.setSource(args);
-}
-template <int CHAN>
-inline void S3DPrimaryPipe<CHAN>::dump() const {
-    ALOGE("S3DPrimaryPipe Pipe fmt=%d", mS3Dfmt);
-    mS3d.dump();
-}
-
-} // overlay
-
-#endif // OVERLAY_M3D_EXT_PIPE_H
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 41cb271..aebaebf 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -32,18 +32,16 @@
 
 namespace overlay {
 
-GenericPipe::GenericPipe(const int& dpy) : mDpy(dpy), mRotDownscaleOpt(false),
-    pipeState(CLOSED), mCtrl(new Ctrl(dpy)), mData(new Data(dpy)) {
+GenericPipe::GenericPipe(const int& dpy) : mDpy(dpy),
+    mCtrl(new Ctrl(dpy)), mData(new Data(dpy)) {
 }
 
 GenericPipe::~GenericPipe() {
     delete mCtrl;
     delete mData;
-    setClosed();
 }
 
 void GenericPipe::setSource(const utils::PipeArgs& args) {
-    mRotDownscaleOpt = args.rotFlags & utils::ROT_DOWNSCALE_ENABLED;
     mCtrl->setSource(args);
 }
 
@@ -73,26 +71,10 @@
 }
 
 bool GenericPipe::commit() {
-    bool ret = false;
-    int downscale_factor = utils::ROT_DS_NONE;
-
-    if(mRotDownscaleOpt) {
-        ovutils::Dim src(mCtrl->getCrop());
-        ovutils::Dim dst(mCtrl->getPosition());
-        downscale_factor = ovutils::getDownscaleFactor(
-                src.w, src.h, dst.w, dst.h);
-    }
-
-    mCtrl->setDownscale(downscale_factor);
-    ret = mCtrl->commit();
-
-    pipeState = ret ? OPEN : CLOSED;
-    return ret;
+    return mCtrl->commit();
 }
 
 bool GenericPipe::queueBuffer(int fd, uint32_t offset) {
-    //TODO Move pipe-id transfer to CtrlData class. Make ctrl and data private.
-    OVASSERT(isOpen(), "State is closed, cannot queueBuffer");
     int pipeId = mCtrl->getPipeId();
     OVASSERT(-1 != pipeId, "Ctrl ID should not be -1");
     // set pipe id from ctrl to data
@@ -101,10 +83,6 @@
     return mData->queueBuffer(fd, offset);
 }
 
-int GenericPipe::getCtrlFd() const {
-    return mCtrl->getFd();
-}
-
 utils::Dim GenericPipe::getCrop() const
 {
     return mCtrl->getCrop();
@@ -117,7 +95,6 @@
 void GenericPipe::dump() const
 {
     ALOGE("== Dump Generic pipe start ==");
-    ALOGE("pipe state = %d", (int)pipeState);
     mCtrl->dump();
     mData->dump();
     ALOGE("== Dump Generic pipe end ==");
@@ -128,19 +105,6 @@
     mData->getDump(buf, len);
 }
 
-bool GenericPipe::isClosed() const  {
-    return (pipeState == CLOSED);
-}
-
-bool GenericPipe::isOpen() const  {
-    return (pipeState == OPEN);
-}
-
-bool GenericPipe::setClosed() {
-    pipeState = CLOSED;
-    return true;
-}
-
 int GenericPipe::getPipeId() {
     return mCtrl->getPipeId();
 }
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index c7e16f3..0a2639a 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -65,12 +65,6 @@
     const utils::PipeArgs& getArgs() const;
     /* retrieve cached crop data */
     utils::Dim getCrop() const;
-    /* is closed */
-    bool isClosed() const;
-    /* is open */
-    bool isOpen() const;
-    /* return Ctrl fd. Used for S3D */
-    int getCtrlFd() const;
     /* return pipe priority */
     uint8_t getPriority() const;
     /* dump the state of the object */
@@ -82,19 +76,7 @@
     static bool validateAndSet(GenericPipe* pipeArray[], const int& count,
             const int& fbFd);
 private:
-    /* set Closed pipe */
-    bool setClosed();
-
     int mDpy;
-    //Whether we will do downscale opt. This is just a request. If the frame is
-    //not a candidate, we might not do it.
-    bool mRotDownscaleOpt;
-    /* Pipe open or closed */
-    enum ePipeState {
-        CLOSED,
-        OPEN
-    };
-    ePipeState pipeState;
     Ctrl *mCtrl;
     Data *mData;
 };
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index 60f1f68..7ff106f 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -113,4 +113,25 @@
     return err;
 }
 
+int setViewFrame(int dpy, int l, int t, int r, int b) {
+    status_t err = (status_t) FAILED_TRANSACTION;
+    sp<IQService> binder = getBinder();
+    Parcel inParcel, outParcel;
+    inParcel.writeInt32(dpy);
+    inParcel.writeInt32(l);
+    inParcel.writeInt32(t);
+    inParcel.writeInt32(r);
+    inParcel.writeInt32(b);
+
+    if(binder != NULL) {
+        err = binder->dispatch(IQService::SET_VIEW_FRAME,
+                &inParcel, &outParcel);
+    }
+    if(err)
+        ALOGE("%s: Failed to set view frame for dpy %d err=%d",
+                            __FUNCTION__, dpy, err);
+
+    return err;
+}
+
 }; //namespace
diff --git a/libqdutils/display_config.h b/libqdutils/display_config.h
index 29edbef..a69265b 100644
--- a/libqdutils/display_config.h
+++ b/libqdutils/display_config.h
@@ -73,4 +73,7 @@
 // get the active visible region for the display
 // Returns 0 on success, negative values on errors
 int getDisplayVisibleRegion(int dpy, hwc_rect_t &rect);
+
+// set the view frame information in hwc context from surfaceflinger
+int setViewFrame(int dpy, int l, int t, int r, int b);
 }; //namespace
diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp
index d30375e..86191e9 100644
--- a/libqdutils/idle_invalidator.cpp
+++ b/libqdutils/idle_invalidator.cpp
@@ -103,7 +103,7 @@
             char data[64];
             // Consume the node by reading it
             ssize_t len = pread(pFd.fd, data, 64, 0);
-            ALOGD_IF(II_DEBUG, "IdleInvalidator::%s Idle Timeout fired len %zu",
+            ALOGD_IF(II_DEBUG, "IdleInvalidator::%s Idle Timeout fired len %zd",
                 __FUNCTION__, len);
             mHandler((void*)mHwcContext);
         }
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 96ed4d2..48f7cb7 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -37,6 +37,12 @@
 
 #define TOKEN_PARAMS_DELIM  "="
 
+// chip variants have same major number and minor numbers usually vary
+// for e.g., MDSS_MDP_HW_REV_101 is 0x10010000
+//                                    1001       -  major number
+//                                        0000   -  minor number
+// 8x26 v1 minor number is 0000
+//      v2 minor number is 0001 etc..
 #ifndef MDSS_MDP_HW_REV_100
 #define MDSS_MDP_HW_REV_100 0x10000000 //8974 v1
 #endif
@@ -53,7 +59,7 @@
 #define MDSS_MDP_HW_REV_104 0x10040000 //Next version
 #endif
 #ifndef MDSS_MDP_HW_REV_105
-#define MDSS_MDP_HW_REV_105 0x10050000 //Next version
+#define MDSS_MDP_HW_REV_105 0x10050000 //8994
 #endif
 #ifndef MDSS_MDP_HW_REV_106
 #define MDSS_MDP_HW_REV_106 0x10060000 //8x16
@@ -88,7 +94,13 @@
     mLowBw = 0;
     mHighBw = 0;
     mSourceSplit = false;
+    mSourceSplitAlways = false;
     mRGBHasNoScalar = false;
+    mRotDownscale = false;
+
+    // this is the default limit of mixer unless driver reports it.
+    // For resolutions beyond this, we use dual/split overlay pipes.
+    mMaxMixerWidth = 2048;
 
     updatePanelInfo();
 
@@ -136,7 +148,6 @@
     FILE *panelInfoNodeFP = NULL;
     const int MAX_FRAME_BUFFER_NAME_SIZE = 128;
     char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
-    char panelInfo[MAX_FRAME_BUFFER_NAME_SIZE];
     const char *strCmdPanel = "mipi dsi cmd panel";
     const char *strVideoPanel = "mipi dsi video panel";
     const char *strLVDSPanel = "lvds panel";
@@ -278,26 +289,29 @@
                 } else if(!strncmp(tokens[0], "max_bandwidth_high",
                         strlen("max_bandwidth_high"))) {
                     mHighBw = atol(tokens[1]);
+                } else if(!strncmp(tokens[0], "max_mixer_width",
+                        strlen("max_mixer_width"))) {
+                    mMaxMixerWidth = atoi(tokens[1]);
                 } else if(!strncmp(tokens[0], "features", strlen("features"))) {
                     for(int i=1; i<index;i++) {
                         if(!strncmp(tokens[i], "bwc", strlen("bwc"))) {
                            mFeatures |= MDP_BWC_EN;
-                        }
-                        else if(!strncmp(tokens[i], "decimation",
+                        } else if(!strncmp(tokens[i], "decimation",
                                     strlen("decimation"))) {
                            mFeatures |= MDP_DECIMATION_EN;
-                        }
-                        else if(!strncmp(tokens[i], "tile_format",
+                        } else if(!strncmp(tokens[i], "tile_format",
                                     strlen("tile_format"))) {
                            if(enableMacroTile)
                                mMacroTileEnabled = true;
                         } else if(!strncmp(tokens[i], "src_split",
                                     strlen("src_split"))) {
                             mSourceSplit = true;
-                        }
-                        else if(!strncmp(tokens[i], "non_scalar_rgb",
+                        } else if(!strncmp(tokens[i], "non_scalar_rgb",
                                     strlen("non_scalar_rgb"))) {
                             mRGBHasNoScalar = true;
+                        } else if(!strncmp(tokens[i], "rotator_downscale",
+                                    strlen("rotator_downscale"))) {
+                            mRotDownscale = true;
                         }
                     }
                 }
@@ -306,6 +320,30 @@
         free(line);
         fclose(sysfsFd);
     }
+
+    if(mSourceSplit) {
+        memset(sysfsPath, 0, sizeof(sysfsPath));
+        snprintf(sysfsPath , sizeof(sysfsPath),
+                "/sys/class/graphics/fb0/msm_fb_src_split_info");
+
+        sysfsFd = fopen(sysfsPath, "rb");
+        if (sysfsFd == NULL) {
+            ALOGE("%s: Opening file %s failed with error %s", __FUNCTION__,
+                    sysfsPath, strerror(errno));
+            return false;
+        } else {
+            line = (char *) malloc(len);
+            if((read = getline(&line, &len, sysfsFd)) != -1) {
+                if(!strncmp(line, "src_split_always",
+                        strlen("src_split_always"))) {
+                    mSourceSplitAlways = true;
+                }
+            }
+            free(line);
+            fclose(sysfsFd);
+        }
+    }
+
     ALOGD_IF(DEBUG, "%s: mMDPVersion: %d mMdpRev: %x mRGBPipes:%d,"
                     "mVGPipes:%d", __FUNCTION__, mMDPVersion, mMdpRev,
                     mRGBPipes, mVGPipes);
@@ -371,6 +409,10 @@
     return mSourceSplit;
 }
 
+bool MDPVersion::isSrcSplitAlways() const {
+    return mSourceSplitAlways;
+}
+
 bool MDPVersion::isRGBScalarSupported() const {
     return (!mRGBHasNoScalar);
 }
@@ -395,6 +437,11 @@
             mMdpRev < MDSS_MDP_HW_REV_206);
 }
 
+bool MDPVersion::is8994() {
+    return (mMdpRev >= MDSS_MDP_HW_REV_105 and
+            mMdpRev < MDSS_MDP_HW_REV_106);
+}
+
 bool MDPVersion::is8x16() {
     return (mMdpRev >= MDSS_MDP_HW_REV_106 and
             mMdpRev < MDSS_MDP_HW_REV_107);
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index e862d2d..ced414e 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -57,17 +57,6 @@
     MDSS_V5     = 500,
 };
 
-// chip variants have same major number and minor numbers usually vary
-// for e.g., MDSS_MDP_HW_REV_101 is 0x10010000
-//                                    1001       -  major number
-//                                        0000   -  minor number
-// 8x26 v1 minor number is 0000
-//      v2 minor number is 0001 etc..
-
-enum {
-    MAX_DISPLAY_DIM = 2048,
-};
-
 #define NO_PANEL         '0'
 #define MDDI_PANEL       '1'
 #define EBI2_PANEL       '2'
@@ -139,12 +128,16 @@
     bool needsROIMerge() { return mPanelInfo.mNeedsROIMerge; }
     unsigned long getLowBw() { return mLowBw; }
     unsigned long getHighBw() { return mHighBw; }
+    bool isRotDownscaleEnabled() { return mRotDownscale; }
+    int getMaxMixerWidth() const { return mMaxMixerWidth; }
     bool isSrcSplit() const;
+    bool isSrcSplitAlways() const;
     bool isRGBScalarSupported() const;
     bool is8x26();
     bool is8x74v2();
     bool is8084();
     bool is8092();
+    bool is8994();
     bool is8x16();
     bool is8x39();
 
@@ -170,7 +163,11 @@
     unsigned long mLowBw; //kbps
     unsigned long mHighBw; //kbps
     bool mSourceSplit;
+    //Additional property on top of source split
+    bool mSourceSplitAlways;
     bool mRGBHasNoScalar;
+    bool mRotDownscale;
+    uint32_t mMaxMixerWidth; //maximum x-res of a given mdss mixer.
 };
 }; //namespace qdutils
 #endif //INCLUDE_LIBQCOMUTILS_MDPVER
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 02f7341..c222eb9 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -51,6 +51,8 @@
         GET_DISPLAY_VISIBLE_REGION,  // Get the visibleRegion for dpy
         PAUSE_WFD,               // Pause/Resume WFD
         SET_WFD_STATUS,          // Set if wfd connection is on/off
+        SET_VIEW_FRAME,          // Set view frame of display
+        DYNAMIC_DEBUG,           // Enable more logging on the fly
         COMMAND_LIST_END = 400,
     };
 
@@ -59,6 +61,12 @@
         START,
     };
 
+    enum {
+        DEBUG_ALL,
+        DEBUG_MDPCOMP,
+        DEBUG_VSYNC,
+    };
+
     // Register a client that can be notified
     virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
     // Generic function to dispatch binder commands
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index e4af422..12dd995 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -28,6 +28,8 @@
  */
 
 #include <QService.h>
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
 
 #define QSERVICE_DEBUG 0
 
@@ -55,6 +57,10 @@
 status_t QService::dispatch(uint32_t command, const Parcel* inParcel,
         Parcel* outParcel) {
     status_t err = (status_t) FAILED_TRANSACTION;
+    IPCThreadState* ipc = IPCThreadState::self();
+    //Rewind parcel in case we're calling from the same process
+    if (ipc->getCallingPid() == getpid())
+        inParcel->setDataPosition(0);
     if (mClient.get()) {
         ALOGD_IF(QSERVICE_DEBUG, "Dispatching command: %d", command);
         err = mClient->notifyCallback(command, inParcel, outParcel);
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
index 1f8e70c..264d045 100644
--- a/libvirtual/virtual.cpp
+++ b/libvirtual/virtual.cpp
@@ -194,6 +194,13 @@
 
             setDownScaleMode(maxArea);
         }
+        //Initialize the display viewFrame info
+        mHwcContext->mViewFrame[HWC_DISPLAY_VIRTUAL].left = 0;
+        mHwcContext->mViewFrame[HWC_DISPLAY_VIRTUAL].top = 0;
+        mHwcContext->mViewFrame[HWC_DISPLAY_VIRTUAL].right =
+            (int)mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres;
+        mHwcContext->mViewFrame[HWC_DISPLAY_VIRTUAL].bottom =
+            (int)mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres;
         mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].vsync_period =
                 1000000000l /60;
         ALOGD_IF(DEBUG,"%s: Setting Virtual Attr: res(%d x %d)",__FUNCTION__,