Merge "hwc: Verify handle is not NULL in bytes read calculation"
diff --git a/common.mk b/common.mk
index 13cd6ef..4aa56b2 100644
--- a/common.mk
+++ b/common.mk
@@ -10,7 +10,7 @@
 
 ifeq ($(TARGET_USES_POST_PROCESSING),true)
     common_flags     += -DUSES_POST_PROCESSING
-    common_includes += $(TARGET_OUT_HEADERS)/pp/inc
+    common_includes  += $(TARGET_OUT_HEADERS)/pp/inc
 endif
 
 common_header_export_path := qcom/display
@@ -36,6 +36,12 @@
     common_flags += -DMDSS_TARGET
 endif
 
+ifeq ($(call is-board-platform-in-list, mpq8092), true)
+    #XXX: Replace with check from MDP when available
+    common_flags += -DVPU_TARGET
+endif
+
+
 common_deps  :=
 kernel_includes :=
 
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index 1b3e934..ce15304 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -277,13 +277,6 @@
         return -EINVAL;
     size = (bufferSize >= size)? bufferSize : size;
 
-    // All buffers marked as protected or for external
-    // display need to go to overlay
-    if ((usage & GRALLOC_USAGE_EXTERNAL_DISP) ||
-        (usage & GRALLOC_USAGE_PROTECTED)) {
-        bufferType = BUFFER_TYPE_VIDEO;
-    }
-
     bool useFbMem = false;
     char property[PROPERTY_VALUE_MAX];
     if((usage & GRALLOC_USAGE_HW_FB) &&
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index d47e4b0..12b822a 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -25,4 +25,9 @@
                                  hwc_dump_layers.cpp \
                                  hwc_ad.cpp
 
+ifeq ($(call is-board-platform-in-list, mpq8092), true)
+    LOCAL_SRC_FILES += hwc_vpuclient.cpp
+endif
+
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 5fd7564..e970d4c 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -17,7 +17,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
 #include <fcntl.h>
 #include <errno.h>
 
@@ -38,6 +38,7 @@
 #include "hwc_copybit.h"
 #include "hwc_ad.h"
 #include "profiler.h"
+#include "hwc_vpuclient.h"
 
 using namespace qhwc;
 using namespace overlay;
@@ -67,12 +68,12 @@
     }
 };
 
-/* In case of proprietary WFD session, we are fooling SF by piggybacking on
+/* In case of non-hybrid WFD session, we are fooling SF by piggybacking on
  * HDMI display ID for virtual. This helper is needed to differentiate their
  * paths in HAL.
  * TODO: Not needed once we have WFD client working on top of Google API's */
 
-static int getHWCDpy(hwc_context_t *ctx, int dpy) {
+static int getDpyforExternalDisplay(hwc_context_t *ctx, int dpy) {
     if(dpy == HWC_DISPLAY_EXTERNAL && ctx->mVirtualonExtActive)
         return HWC_DISPLAY_VIRTUAL;
     return dpy;
@@ -144,6 +145,7 @@
 
 static int hwc_prepare_primary(hwc_composer_device_1 *dev,
         hwc_display_contents_1_t *list) {
+    ATRACE_CALL();
     hwc_context_t* ctx = (hwc_context_t*)(dev);
     const int dpy = HWC_DISPLAY_PRIMARY;
     if (LIKELY(list && list->numHwLayers > 1) &&
@@ -154,6 +156,9 @@
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         if(fbLayer->handle) {
             setListStats(ctx, list, dpy);
+#ifdef VPU_TARGET
+            ctx->mVPUClient->prepare(ctx, list);
+#endif
             if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
                 const int fbZ = 0;
                 ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
@@ -169,6 +174,7 @@
 
 static int hwc_prepare_external(hwc_composer_device_1 *dev,
         hwc_display_contents_1_t *list) {
+    ATRACE_CALL();
     hwc_context_t* ctx = (hwc_context_t*)(dev);
     const int dpy = HWC_DISPLAY_EXTERNAL;
 
@@ -210,6 +216,7 @@
 
 static int hwc_prepare_virtual(hwc_composer_device_1 *dev,
         hwc_display_contents_1_t *list) {
+    ATRACE_CALL();
 
     hwc_context_t* ctx = (hwc_context_t*)(dev);
     const int dpy = HWC_DISPLAY_VIRTUAL;
@@ -268,7 +275,7 @@
 
     for (int32_t i = numDisplays; i >= 0; i--) {
         hwc_display_contents_1_t *list = displays[i];
-        int dpy = getHWCDpy(ctx, i);
+        int dpy = getDpyforExternalDisplay(ctx, i);
         switch(dpy) {
             case HWC_DISPLAY_PRIMARY:
                 ret = hwc_prepare_primary(dev, list);
@@ -294,6 +301,7 @@
 static int hwc_eventControl(struct hwc_composer_device_1* dev, int dpy,
                              int event, int enable)
 {
+    ATRACE_CALL();
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
     switch(event) {
@@ -330,6 +338,14 @@
 
     Locker::Autolock _l(ctx->mDrawLock);
     int ret = 0, value = 0;
+
+    /* In case of non-hybrid WFD session, we are fooling SF by
+     * piggybacking on HDMI display ID for virtual.
+     * TODO: Not needed once we have WFD client working on top
+     * of Google API's.
+     */
+    dpy = getDpyforExternalDisplay(ctx,dpy);
+
     ALOGD_IF(BLANK_DEBUG, "%s: %s display: %d", __FUNCTION__,
           blank==1 ? "Blanking":"Unblanking", dpy);
     if(blank) {
@@ -356,13 +372,37 @@
             ctx->mExtDisplay->setHPD(1);
         }
 
-        /* Since SF is not aware of VIRTUAL DISPLAY being handle by HWC,
-         * it wont send blank / unblank events for it. We piggyback on
-         * PRIMARY DISPLAY events to release mdp pips and
-         * activate/deactive VIRTUAL DISPLAY */
+        ctx->dpyAttr[dpy].isActive = !blank;
+
+        if(ctx->mVirtualonExtActive) {
+            /* if mVirtualonExtActive is true, display hal will
+             * receive unblank calls for non-hybrid WFD solution
+             * since we piggyback on HDMI.
+             * TODO: Not needed once we have WFD client working on top
+             of Google API's */
+            break;
+        }
+    case HWC_DISPLAY_VIRTUAL:
+        /* There are two ways to reach this block of code.
+
+         * Display hal has received unblank call on HWC_DISPLAY_EXTERNAL
+         and ctx->mVirtualonExtActive is true. In this case, non-hybrid
+         WFD is active. If so, getDpyforExternalDisplay will return dpy
+         as HWC_DISPLAY_VIRTUAL.
+
+         * Display hal has received unblank call on HWC_DISPLAY_PRIMARY
+         and since SF is not aware of VIRTUAL DISPLAY being handle by HWC,
+         it wont send blank / unblank events for it. We piggyback on
+         PRIMARY DISPLAY events to release mdp pipes and
+         activate/deactivate VIRTUAL DISPLAY.
+
+         * TODO: This separate case statement is not needed once we have
+         WFD client working on top of Google API's.
+
+         */
 
         if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
-            if(blank) {
+            if(blank and (!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause)) {
                 int dpy = HWC_DISPLAY_VIRTUAL;
                 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
                     ALOGE("%s: display commit fail for virtual!", __FUNCTION__);
@@ -379,13 +419,12 @@
                 ret = -1;
             }
         }
+        ctx->dpyAttr[dpy].isActive = !blank;
         break;
     default:
         return -EINVAL;
     }
 
-    ctx->dpyAttr[dpy].isActive = !blank;
-
     ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__,
           blank ? "blanking":"unblanking", dpy);
     return ret;
@@ -437,6 +476,9 @@
             ALOGE("%s: MDPComp draw failed", __FUNCTION__);
             ret = -1;
         }
+#ifdef VPU_TARGET
+        ctx->mVPUClient->draw(ctx, list);
+#endif
 
         //TODO We dont check for SKIP flag on this layer because we need PAN
         //always. Last layer is always FB
@@ -526,47 +568,48 @@
 {
     ATRACE_CALL();
     int ret = 0;
+
     const int dpy = HWC_DISPLAY_VIRTUAL;
 
-    if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
-                           ctx->dpyAttr[dpy].connected) {
-        if(!ctx->dpyAttr[dpy].isPause) {
-            uint32_t last = list->numHwLayers - 1;
-            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(list->numHwLayers > 1)
-                hwc_sync(ctx, list, dpy, fd);
+    if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
+            ctx->dpyAttr[dpy].connected &&
+            !ctx->dpyAttr[dpy].isPause) {
+        uint32_t last = list->numHwLayers - 1;
+        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(list->numHwLayers > 1)
+            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__);
+        if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+            ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+            ret = -1;
+        }
+
+        int extOnlyLayerIndex =
+            ctx->listStats[dpy].extOnlyLayerIndex;
+
+        private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
+        if(extOnlyLayerIndex!= -1) {
+            hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
+            hnd = (private_handle_t *)extLayer->handle;
+        } else if(copybitDone) {
+            hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
+        }
+
+        if(hnd && !isYuvBuffer(hnd)) {
+            if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
+                ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
                 ret = -1;
             }
-
-            int extOnlyLayerIndex =
-                    ctx->listStats[dpy].extOnlyLayerIndex;
-
-            private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
-            if(extOnlyLayerIndex!= -1) {
-                hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
-                hnd = (private_handle_t *)extLayer->handle;
-            } else if(copybitDone) {
-                hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
-            }
-
-            if(hnd && !isYuvBuffer(hnd)) {
-                if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
-                    ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
-                    ret = -1;
-                }
-            }
         }
 
         if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
@@ -597,7 +640,7 @@
     hwc_context_t* ctx = (hwc_context_t*)(dev);
     for (uint32_t i = 0; i <= numDisplays; i++) {
         hwc_display_contents_1_t* list = displays[i];
-        int dpy = getHWCDpy(ctx, i);
+        int dpy = getDpyforExternalDisplay(ctx, i);
         switch(dpy) {
             case HWC_DISPLAY_PRIMARY:
                 ret = hwc_set_primary(ctx, list);
@@ -626,7 +669,7 @@
         uint32_t* configs, size_t* numConfigs) {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    disp = getHWCDpy(ctx, disp);
+    disp = getDpyforExternalDisplay(ctx, disp);
     //in 1.1 there is no way to choose a config, report as config id # 0
     //This config is passed to getDisplayAttributes. Ignore for now.
     switch(disp) {
@@ -656,7 +699,7 @@
         uint32_t config, const uint32_t* attributes, int32_t* values) {
 
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    disp = getHWCDpy(ctx, disp);
+    disp = getDpyforExternalDisplay(ctx, disp);
     //If hotpluggable displays(i.e, HDMI, WFD) are inactive return error
     if( (disp != HWC_DISPLAY_PRIMARY) && !ctx->dpyAttr[disp].connected) {
         return -1;
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 565865a..d388ebb 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -100,10 +100,6 @@
        (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
         (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
         sEnabled = true;
-        if(!setupBasePipe(ctx)) {
-            ALOGE("%s: Failed to setup primary base pipe", __FUNCTION__);
-            return false;
-        }
     }
 
     sEnableMixedMode = true;
@@ -188,7 +184,6 @@
             layerProp[index].mFlags |= HWC_MDPCOMP;
             layer->compositionType = HWC_OVERLAY;
             layer->hints |= HWC_HINT_CLEAR_FB;
-            mCachedFrame.hnd[index] = NULL;
         } else {
             if(!mCurrentFrame.needsRedraw)
                 layer->compositionType = HWC_OVERLAY;
@@ -196,45 +191,6 @@
     }
 }
 
-/*
- * Sets up BORDERFILL as default base pipe and detaches RGB0.
- * Framebuffer is always updated using PLAY ioctl.
- */
-bool MDPComp::setupBasePipe(hwc_context_t *ctx) {
-    const int dpy = HWC_DISPLAY_PRIMARY;
-    int fb_stride = ctx->dpyAttr[dpy].stride;
-    int fb_width = ctx->dpyAttr[dpy].xres;
-    int fb_height = ctx->dpyAttr[dpy].yres;
-    int fb_fd = ctx->dpyAttr[dpy].fd;
-
-    mdp_overlay ovInfo;
-    msmfb_overlay_data ovData;
-    memset(&ovInfo, 0, sizeof(mdp_overlay));
-    memset(&ovData, 0, sizeof(msmfb_overlay_data));
-
-    ovInfo.src.format = MDP_RGB_BORDERFILL;
-    ovInfo.src.width  = fb_width;
-    ovInfo.src.height = fb_height;
-    ovInfo.src_rect.w = fb_width;
-    ovInfo.src_rect.h = fb_height;
-    ovInfo.dst_rect.w = fb_width;
-    ovInfo.dst_rect.h = fb_height;
-    ovInfo.id = MSMFB_NEW_REQUEST;
-
-    if (ioctl(fb_fd, MSMFB_OVERLAY_SET, &ovInfo) < 0) {
-        ALOGE("Failed to call ioctl MSMFB_OVERLAY_SET err=%s",
-              strerror(errno));
-        return false;
-    }
-
-    ovData.id = ovInfo.id;
-    if (ioctl(fb_fd, MSMFB_OVERLAY_PLAY, &ovData) < 0) {
-        ALOGE("Failed to call ioctl MSMFB_OVERLAY_PLAY err=%s",
-              strerror(errno));
-        return false;
-    }
-    return true;
-}
 MDPComp::FrameInfo::FrameInfo() {
     reset(0);
 }
@@ -1108,6 +1064,7 @@
 bool MDPCompSplit::arePipesAvailable(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
     overlay::Overlay& ov = *ctx->mOverlay;
+    int totalPipesNeeded = 0;
 
     for(int i = 0; i < Overlay::MIXER_MAX; i++) {
         int numPipesNeeded = pipesNeeded(ctx, list, i);
@@ -1115,8 +1072,11 @@
 
         //Reserve pipe(s)for FB
         if(mCurrentFrame.fbCount)
-            availPipes -= 1;
+            numPipesNeeded += 1;
 
+        totalPipesNeeded += numPipesNeeded;
+
+        //Per mixer check.
         if(numPipesNeeded > availPipes) {
             ALOGD_IF(isDebug(), "%s: Insufficient pipes for "
                      "dpy %d mixer %d needed %d, avail %d",
@@ -1124,6 +1084,16 @@
             return false;
         }
     }
+
+    //Per display check, since unused pipes can get counted twice.
+    int totalPipesAvailable = ov.availablePipes(mDpy);
+    if(totalPipesNeeded > totalPipesAvailable) {
+        ALOGD_IF(isDebug(), "%s: Insufficient pipes for "
+                "dpy %d needed %d, avail %d",
+                __FUNCTION__, mDpy, totalPipesNeeded, totalPipesAvailable);
+        return false;
+    }
+
     return true;
 }
 
@@ -1169,7 +1139,7 @@
 
         if(isYuvBuffer(hnd)) {
             type = MDPCOMP_OV_VG;
-        } else if(!qhwc::needsScaling(ctx, layer, mDpy)
+        } else if(!qhwc::needsScalingWithSplit(ctx, layer, mDpy)
             && Overlay::getDMAMode() != Overlay::DMA_BLOCK_MODE
             && ctx->mMDP.version >= qdutils::MDSS_V5) {
             type = MDPCOMP_OV_DMA;
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 869eee7..da4b330 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -148,8 +148,6 @@
     /* checks if the required bandwidth exceeds a certain max */
     bool bandwidthCheck(hwc_context_t *ctx, const uint32_t& size);
 
-    /* set up Border fill as Base pipe */
-    static bool setupBasePipe(hwc_context_t*);
     /* Is debug enabled */
     static bool isDebug() { return sDebugLogs ? true : false; };
     /* Is feature enabled */
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 12a9f32..a17565b 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -30,6 +30,7 @@
 #include <hwc_qclient.h>
 #include <IQService.h>
 #include <hwc_utils.h>
+#include <hwc_vpuclient.h>
 
 #define QCLIENT_DEBUG 0
 
@@ -51,6 +52,12 @@
 }
 
 status_t QClient::notifyCallback(uint32_t msg, uint32_t value) {
+
+    if (msg > IQService::VPU_COMMAND_LIST_START &&
+        msg < IQService::VPU_COMMAND_LIST_END) {
+        return vpuCommand(msg, value);
+    }
+
     switch(msg) {
         case IQService::SECURING:
             securing(value);
@@ -117,6 +124,16 @@
     return result;
 }
 
+android::status_t QClient::vpuCommand(uint32_t command, uint32_t setting) {
+    status_t result = NO_INIT;
+#ifdef QCOM_BSP
+#ifdef VPU_TARGET
+    result = mHwcContext->mVPUClient->processCommand(command, setting);
+#endif
+#endif
+    return result;
+}
+
 void QClient::setExtOrientation(uint32_t orientation) {
     mHwcContext->mExtOrientation = orientation;
 }
diff --git a/libhwcomposer/hwc_qclient.h b/libhwcomposer/hwc_qclient.h
index 848d8d2..fa1d6b0 100644
--- a/libhwcomposer/hwc_qclient.h
+++ b/libhwcomposer/hwc_qclient.h
@@ -62,6 +62,7 @@
     android::status_t screenRefresh();
     void setExtOrientation(uint32_t orientation);
     void setBufferMirrorMode(uint32_t enable);
+    android::status_t vpuCommand(uint32_t command, uint32_t setting);
 
     hwc_context_t *mHwcContext;
     const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index a44924b..8c3d00d 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -223,20 +223,20 @@
             ctx->dpyAttr[dpy].connected = true;
             ctx->dpyAttr[dpy].isConfiguring = true;
 
-            if(dpy == HWC_DISPLAY_VIRTUAL) {
+            if(dpy == HWC_DISPLAY_EXTERNAL ||
+               ctx->mVirtualonExtActive) {
+                /* External display is HDMI or non-hybrid WFD solution */
+                ALOGE_IF(UEVENT_DEBUG, "%s: Sending EXTERNAL_OFFLINE ONLINE"
+                         "hotplug event", __FUNCTION__);
+                ctx->proc->hotplug(ctx->proc,HWC_DISPLAY_EXTERNAL,
+                                   EXTERNAL_ONLINE);
+            } else {
                 /* We wont be getting unblank for VIRTUAL DISPLAY and its
                  * always guaranteed from WFD stack that CONNECT uevent for
                  * VIRTUAL DISPLAY will be triggered before creating
                  * surface for the same. */
                 ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = true;
             }
-            if(dpy == HWC_DISPLAY_EXTERNAL ||
-               ctx->mVirtualonExtActive) {
-                ALOGE_IF(UEVENT_DEBUG, "%s: Sending EXTERNAL_OFFLINE ONLINE"
-                         "hotplug event", __FUNCTION__);
-                ctx->proc->hotplug(ctx->proc,HWC_DISPLAY_EXTERNAL,
-                                   EXTERNAL_ONLINE);
-            }
             break;
         }
         case EXTERNAL_PAUSE:
@@ -270,6 +270,15 @@
                 //its pipes; we don't allow inter-mixer pipe transfers.
                 {
                     Locker::Autolock _l(ctx->mDrawLock);
+
+                    // A dynamic resolution change (DRC) can be made for a WiFi
+                    // display. In order to support the resolution change, we
+                    // need to reconfigure the corresponding display attributes.
+                    // Since DRC is only on WiFi display, we only need to call
+                    // configure() on the VirtualDisplay device.
+                    if(dpy == HWC_DISPLAY_VIRTUAL)
+                        ctx->mVirtualDisplay->configure();
+
                     ctx->dpyAttr[dpy].isConfiguring = true;
                     ctx->dpyAttr[dpy].isActive = true;
                     ctx->proc->invalidate(ctx->proc);
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 5ea79b5..9837bd1 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -17,6 +17,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL)
 #define HWC_UTILS_DEBUG 0
 #include <math.h>
 #include <sys/ioctl.h>
@@ -24,6 +25,7 @@
 #include <binder/IServiceManager.h>
 #include <EGL/egl.h>
 #include <cutils/properties.h>
+#include <utils/Trace.h>
 #include <gralloc_priv.h>
 #include <overlay.h>
 #include <overlayRotator.h>
@@ -35,6 +37,7 @@
 #include "mdp_version.h"
 #include "hwc_copybit.h"
 #include "hwc_dump_layers.h"
+#include "hwc_vpuclient.h"
 #include "external.h"
 #include "virtual.h"
 #include "hwc_qclient.h"
@@ -192,8 +195,10 @@
     ctx->mPrevDestVideo.left = ctx->mPrevDestVideo.top =
         ctx->mPrevDestVideo.right = ctx->mPrevDestVideo.bottom = 0;
     ctx->mPrevTransformVideo = 0;
-
     ctx->mBufferMirrorMode = false;
+#ifdef VPU_TARGET
+    ctx->mVPUClient = new VPUClient();
+#endif
 
     ALOGI("Initializing Qualcomm Hardware Composer");
     ALOGI("MDP version: %d", ctx->mMDP.version);
@@ -228,6 +233,12 @@
         ctx->mExtDisplay = NULL;
     }
 
+#ifdef VPU_TARGET
+    if(ctx->mVPUClient) {
+        delete ctx->mVPUClient;
+    }
+#endif
+
     for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
         if(ctx->mFBUpdate[i]) {
             delete ctx->mFBUpdate[i];
@@ -608,6 +619,59 @@
     return false;
 }
 
+// Checks if layer needs scaling with split
+bool needsScalingWithSplit(hwc_context_t* ctx, hwc_layer_1_t const* layer,
+        const int& dpy) {
+
+    int src_width_l, src_height_l;
+    int src_width_r, src_height_r;
+    int dst_width_l, dst_height_l;
+    int dst_width_r, dst_height_r;
+    int hw_w = ctx->dpyAttr[dpy].xres;
+    int hw_h = ctx->dpyAttr[dpy].yres;
+    hwc_rect_t cropL, dstL, cropR, dstR;
+    const int lSplit = getLeftSplit(ctx, dpy);
+    hwc_rect_t sourceCrop = layer->sourceCrop;
+    hwc_rect_t displayFrame  = layer->displayFrame;
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+    trimLayer(ctx, dpy, layer->transform, sourceCrop, displayFrame);
+
+    cropL = sourceCrop;
+    dstL = displayFrame;
+    hwc_rect_t scissorL = { 0, 0, lSplit, hw_h };
+    qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0);
+
+    cropR = sourceCrop;
+    dstR = displayFrame;
+    hwc_rect_t scissorR = { lSplit, 0, hw_w, hw_h };
+    qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0);
+
+    // Sanitize Crop to stitch
+    sanitizeSourceCrop(cropL, cropR, hnd);
+
+    // Calculate the left dst
+    dst_width_l = dstL.right - dstL.left;
+    dst_height_l = dstL.bottom - dstL.top;
+    src_width_l = cropL.right - cropL.left;
+    src_height_l = cropL.bottom - cropL.top;
+
+    // check if there is any scaling on the left
+    if(((src_width_l != dst_width_l) || (src_height_l != dst_height_l)))
+        return true;
+
+    // Calculate the right dst
+    dst_width_r = dstR.right - dstR.left;
+    dst_height_r = dstR.bottom - dstR.top;
+    src_width_r = cropR.right - cropR.left;
+    src_height_r = cropR.bottom - cropR.top;
+
+    // check if there is any scaling on the right
+    if(((src_width_r != dst_width_r) || (src_height_r != dst_height_r)))
+        return true;
+
+    return false;
+}
+
 bool isAlphaScaled(hwc_context_t* ctx, hwc_layer_1_t const* layer,
         const int& dpy) {
     if(needsScaling(ctx, layer, dpy) && isAlphaPresent(layer)) {
@@ -895,21 +959,17 @@
 
 int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
         int fd) {
+    ATRACE_CALL();
     int ret = 0;
     int acquireFd[MAX_NUM_APP_LAYERS];
     int count = 0;
     int releaseFd = -1;
     int fbFd = -1;
-    int rotFd = -1;
     bool swapzero = false;
     int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
 
     struct mdp_buf_sync data;
     memset(&data, 0, sizeof(data));
-    //Until B-family supports sync for rotator
-#ifdef MDSS_TARGET
-    data.flags = MDP_BUF_SYNC_FLAG_WAIT;
-#endif
     data.acq_fen_fd = acquireFd;
     data.rel_fen_fd = &releaseFd;
 
@@ -918,34 +978,37 @@
         if(atoi(property) == 0)
             swapzero = true;
     }
+
     bool isExtAnimating = false;
     if(dpy)
        isExtAnimating = ctx->listStats[dpy].isDisplayAnimating;
 
     //Send acquireFenceFds to rotator
-#ifdef MDSS_TARGET
-    //TODO B-family
-#else
-    //A-family
-    int rotFd = ctx->mRotMgr->getRotDevFd();
-    struct msm_rotator_buf_sync rotData;
-
     for(uint32_t i = 0; i < ctx->mLayerRotMap[dpy]->getCount(); i++) {
+        int rotFd = ctx->mRotMgr->getRotDevFd();
+        int rotReleaseFd = -1;
+        struct mdp_buf_sync rotData;
         memset(&rotData, 0, sizeof(rotData));
-        int& acquireFenceFd =
-                ctx->mLayerRotMap[dpy]->getLayer(i)->acquireFenceFd;
-        rotData.acq_fen_fd = acquireFenceFd;
+        rotData.acq_fen_fd =
+                &ctx->mLayerRotMap[dpy]->getLayer(i)->acquireFenceFd;
+        rotData.rel_fen_fd = &rotReleaseFd; //driver to populate this
         rotData.session_id = ctx->mLayerRotMap[dpy]->getRot(i)->getSessId();
-        ioctl(rotFd, MSM_ROTATOR_IOCTL_BUFFER_SYNC, &rotData);
-        close(acquireFenceFd);
-        //For MDP to wait on.
-        acquireFenceFd = dup(rotData.rel_fen_fd);
-        //A buffer is free to be used by producer as soon as its copied to
-        //rotator.
-        ctx->mLayerRotMap[dpy]->getLayer(i)->releaseFenceFd =
-                rotData.rel_fen_fd;
+        int ret = 0;
+        ret = ioctl(rotFd, MSMFB_BUFFER_SYNC, &rotData);
+        if(ret < 0) {
+            ALOGE("%s: ioctl MSMFB_BUFFER_SYNC failed for rot sync, err=%s",
+                    __FUNCTION__, strerror(errno));
+        } else {
+            close(ctx->mLayerRotMap[dpy]->getLayer(i)->acquireFenceFd);
+            //For MDP to wait on.
+            ctx->mLayerRotMap[dpy]->getLayer(i)->acquireFenceFd =
+                    dup(rotReleaseFd);
+            //A buffer is free to be used by producer as soon as its copied to
+            //rotator
+            ctx->mLayerRotMap[dpy]->getLayer(i)->releaseFenceFd =
+                    rotReleaseFd;
+        }
     }
-#endif
 
     //Accumulate acquireFenceFds for MDP
     for(uint32_t i = 0; i < list->numHwLayers; i++) {
@@ -1019,14 +1082,8 @@
     if (ctx->mCopyBit[dpy])
         ctx->mCopyBit[dpy]->setReleaseFd(releaseFd);
 
-#ifdef MDSS_TARGET
-    //TODO When B is implemented remove #ifdefs from here
-    //The API called applies to RotMem buffers
-#else
-    //A-family
     //Signals when MDP finishes reading rotator buffers.
     ctx->mLayerRotMap[dpy]->setReleaseFd(releaseFd);
-#endif
 
     // if external is animating, close the relaseFd
     if(isExtAnimating) {
@@ -1282,7 +1339,7 @@
 }
 
 //Helper to 1) Ensure crops dont have gaps 2) Ensure L and W are even
-static void sanitizeSourceCrop(hwc_rect_t& cropL, hwc_rect_t& cropR,
+void sanitizeSourceCrop(hwc_rect_t& cropL, hwc_rect_t& cropR,
         private_handle_t *hnd) {
     if(cropL.right - cropL.left) {
         if(isYuvBuffer(hnd)) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index d77673b..cb6d091 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -57,6 +57,7 @@
 class CopyBit;
 class HwcDebug;
 class AssertiveDisplay;
+class VPUClient;
 
 
 struct MDPInfo {
@@ -169,7 +170,12 @@
 bool isSecuring(hwc_context_t* ctx, hwc_layer_1_t const* layer);
 bool isSecureModePolicy(int mdpVersion);
 bool isExternalActive(hwc_context_t* ctx);
-bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer, const int& dpy);
+bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer,
+                  const int& dpy);
+bool needsScalingWithSplit(hwc_context_t* ctx, hwc_layer_1_t const* layer,
+                           const int& dpy);
+void sanitizeSourceCrop(hwc_rect_t& cropL, hwc_rect_t& cropR,
+                        private_handle_t *hnd);
 bool isAlphaPresent(hwc_layer_1_t const* layer);
 int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable);
 int getBlending(int blending);
@@ -351,6 +357,7 @@
     qhwc::MDPComp *mMDPComp[HWC_NUM_DISPLAY_TYPES];
     qhwc::HwcDebug *mHwcDebug[HWC_NUM_DISPLAY_TYPES];
     qhwc::AssertiveDisplay *mAD;
+    qhwc::VPUClient *mVPUClient;
 
     // No animation on External display feature
     // Notifies hwcomposer about the device orientation before animation.
diff --git a/libhwcomposer/hwc_vpuclient.cpp b/libhwcomposer/hwc_vpuclient.cpp
new file mode 100644
index 0000000..bdfeae5
--- /dev/null
+++ b/libhwcomposer/hwc_vpuclient.cpp
@@ -0,0 +1,88 @@
+/*
+* Copyright (c) 2013 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.
+*/
+
+#include <dlfcn.h>
+#include "hwc_vpuclient.h"
+#include "hwc_utils.h"
+#include <vpu/vpu.h>
+
+
+using namespace vpu;
+namespace qhwc {
+
+VPUClient::VPUClient()
+{
+    mVPULib = dlopen("libvpu.so", RTLD_NOW);
+    VPU* (*init)();
+    *(void **) &init =  dlsym(mVPULib, "getObject");
+    if(init)
+        mVPU = init();
+    else
+        mVPU = NULL;
+}
+
+VPUClient::~VPUClient()
+{
+    void (*destroy) (VPU*);
+    *(void **) &destroy = dlsym(mVPULib, "deleteObject");
+    dlclose(mVPULib);
+}
+
+int VPUClient::prepare(hwc_context_t *ctx,
+                                hwc_display_contents_1_t* list)
+{
+    int err = 0;
+    if(!mVPU)
+        return err;
+    // * Check VPU status
+    // * Check session availability
+    // * Other individual checks
+    // Do not pass hwc context/list
+    // Mark buffers to be drawn for VPU
+    return err;
+}
+
+int VPUClient::draw(hwc_context_t *ctx,
+                             hwc_display_contents_1_t* list)
+{
+    int err = 0;
+    if(!mVPU)
+        return err;
+    // Queue buffers to VPU
+    return err;
+}
+
+int VPUClient::processCommand(uint32_t command, uint32_t setting)
+{
+    if(!mVPU)
+        return 0;
+    return mVPU->processCommand(command, setting);
+}
+
+}; // namespace qhwc
diff --git a/libhwcomposer/hwc_vpuclient.h b/libhwcomposer/hwc_vpuclient.h
new file mode 100644
index 0000000..8cc7137
--- /dev/null
+++ b/libhwcomposer/hwc_vpuclient.h
@@ -0,0 +1,63 @@
+/*
+* Copyright (c) 2013 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 HWC_VPU_H
+#define HWC_VPU_H
+
+#include <sys/types.h>
+
+//Forward declarations
+struct hwc_display_contents_1;
+typedef struct hwc_display_contents_1 hwc_display_contents_1_t;
+struct hwc_context_t;
+namespace vpu {
+class VPU;
+};
+
+namespace qhwc {
+
+class VPUClient {
+public:
+    VPUClient();
+
+    ~VPUClient();
+
+    int prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+
+    int draw(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+
+    int processCommand(uint32_t command, uint32_t setting);
+
+private:
+    vpu::VPU *mVPU;
+    void* mVPULib;
+
+}; // class VPU
+}; // namespace qhwc
+#endif /* end of include guard: HWC_VPU_H */
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 280223c..4b91038 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -84,6 +84,8 @@
 
     /* Returns available ("unallocated") pipes for a display's mixer */
     int availablePipes(int dpy, int mixer);
+    /* Returns available ("unallocated") pipes for a display */
+    int availablePipes(int dpy);
     /* Returns if any of the requested pipe type is attached to any of the
      * displays
      */
@@ -198,6 +200,21 @@
     return avail;
 }
 
+inline int Overlay::availablePipes(int dpy) {
+    int avail = 0;
+    for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+        if( (mPipeBook[i].mDisplay == DPY_UNUSED ||
+             mPipeBook[i].mDisplay == dpy) &&
+            PipeBook::isNotAllocated(i) &&
+            !(Overlay::getDMAMode() == Overlay::DMA_BLOCK_MODE &&
+              PipeBook::getPipeType((utils::eDest)i) ==
+              utils::OV_MDP_PIPE_DMA)) {
+            avail++;
+        }
+    }
+    return avail;
+}
+
 inline void Overlay::setDMAMode(const int& mode) {
     if(mode == DMA_LINE_MODE || mode == DMA_BLOCK_MODE)
         sDMAMode = mode;
diff --git a/liboverlay/overlayRotator.cpp b/liboverlay/overlayRotator.cpp
index 2995580..84a9818 100644
--- a/liboverlay/overlayRotator.cpp
+++ b/liboverlay/overlayRotator.cpp
@@ -174,11 +174,10 @@
 }
 
 int RotMgr::getRotDevFd() {
-    //2nd check just in case
-    if(mRotDevFd < 0 && Rotator::getRotatorHwType() == Rotator::TYPE_MDP) {
-        mRotDevFd = ::open("/dev/msm_rotator", O_RDWR, 0);
+    if(mRotDevFd < 0 && Rotator::getRotatorHwType() == Rotator::TYPE_MDSS) {
+        mRotDevFd = ::open("/dev/graphics/fb0", O_RDWR, 0);
         if(mRotDevFd < 0) {
-            ALOGE("%s failed to open rotator device", __FUNCTION__);
+            ALOGE("%s failed to open fb0", __FUNCTION__);
         }
     }
     return mRotDevFd;
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index a600732..f551f1d 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -237,11 +237,11 @@
      * Expects a NULL terminated buffer of big enough size.
      */
     void getDump(char *buf, size_t len);
-    int getRotDevFd(); //Called on A-fam only
+    int getRotDevFd();
 private:
     overlay::Rotator *mRot[MAX_ROT_SESS];
     int mUseCount;
-    int mRotDevFd; //A-fam
+    int mRotDevFd;
 };
 
 
diff --git a/liboverlay/overlayWriteback.cpp b/liboverlay/overlayWriteback.cpp
index f711ca6..f1f0eb5 100644
--- a/liboverlay/overlayWriteback.cpp
+++ b/liboverlay/overlayWriteback.cpp
@@ -31,10 +31,15 @@
 #include "overlayWriteback.h"
 #include "mdpWrapper.h"
 
+#define SIZE_1M 0x00100000
+
 namespace overlay {
 
 //=========== class WritebackMem ==============================================
 bool WritebackMem::manageMem(uint32_t size, bool isSecure) {
+    if(isSecure) {
+        size = utils::align(size, SIZE_1M);
+    }
     if(mBuf.bufSz() == size) {
         return true;
     }
@@ -79,7 +84,6 @@
         ALOGE("%s failed to init %s", __func__, Res::fbPath);
         return;
     }
-    queryOutputFormat();
     startSession();
 }
 
@@ -185,15 +189,33 @@
     return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
 }
 
-void Writeback::queryOutputFormat() {
-    struct msmfb_metadata metadata;
-    memset(&metadata, 0 , sizeof(metadata));
-    metadata.op = metadata_op_wb_format;
-    if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) {
-        ALOGE("Error retrieving MDP Writeback format");
-        return;
+bool Writeback::setOutputFormat(int mdpFormat) {
+    if(mdpFormat != mOpFmt) {
+        struct msmfb_metadata metadata;
+        memset(&metadata, 0 , sizeof(metadata));
+        metadata.op = metadata_op_wb_format;
+        metadata.data.mixer_cfg.writeback_format = mdpFormat;
+        if (ioctl(mFd.getFD(), MSMFB_METADATA_SET, &metadata) < 0) {
+            ALOGE("Error setting MDP Writeback format");
+            return false;
+        }
+        mOpFmt = mdpFormat;
     }
-    mOpFmt = metadata.data.mixer_cfg.writeback_format;
+    return true;
+}
+
+int Writeback::getOutputFormat() {
+    if(mOpFmt < 0) {
+        struct msmfb_metadata metadata;
+        memset(&metadata, 0 , sizeof(metadata));
+        metadata.op = metadata_op_wb_format;
+        if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) {
+            ALOGE("Error retrieving MDP Writeback format");
+            return -1;
+        }
+        mOpFmt =  metadata.data.mixer_cfg.writeback_format;
+    }
+    return mOpFmt;
 }
 
 //static
diff --git a/liboverlay/overlayWriteback.h b/liboverlay/overlayWriteback.h
index 6280391..8c0c52a 100644
--- a/liboverlay/overlayWriteback.h
+++ b/liboverlay/overlayWriteback.h
@@ -81,7 +81,12 @@
     bool queueBuffer(int opFd, uint32_t opOffset);
     uint32_t getOffset() const { return mWbMem.getOffset(); }
     int getDstFd() const { return mWbMem.getDstFd(); }
-    int getOutputFormat() const { return mOpFmt; }
+    /* Subject to GC if writeback isnt used for a drawing round.
+     * Get always if caching the value.
+     */
+    int getFbFd() const { return mFd.getFD(); }
+    int getOutputFormat();
+    bool setOutputFormat(int mdpFormat);
 
     static Writeback* getInstance();
     static void configBegin() { sUsed = false; }
@@ -94,7 +99,6 @@
     bool stopSession();
     //Actually block_until_write_done for the usage here.
     bool dequeueBuffer();
-    void queryOutputFormat();
     OvFD mFd;
     WritebackMem mWbMem;
     struct msmfb_data mFbData;
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index e45f42e..33f79c6 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -85,6 +85,15 @@
         data.writeInt32(enable);
         remote()->transact(BUFFER_MIRRORMODE, data, &reply);
     }
+
+    virtual status_t vpuCommand(uint32_t command, uint32_t setting) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IQService::getInterfaceDescriptor());
+        data.writeInt32(setting);
+        remote()->transact(command, data, &reply);
+        status_t result = reply.readInt32();
+        return result;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(QService, "android.display.IQService");
@@ -107,6 +116,18 @@
 
     const bool permission = (callerUid == AID_MEDIA);
 
+    if (code > VPU_COMMAND_LIST_START && code < VPU_COMMAND_LIST_END) {
+        if(callerUid != AID_SYSTEM && callerUid != AID_ROOT) {
+            ALOGE("display.qservice VPU command access denied: \
+                  pid=%d uid=%d process=%s",callerPid,
+                  callerUid, callingProcName);
+            return PERMISSION_DENIED;
+        }
+        CHECK_INTERFACE(IQService, data, reply);
+        int32_t setting = data.readInt32();
+        return vpuCommand(code, setting);
+    }
+
     switch(code) {
         case SECURING: {
             if(!permission) {
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index 149cd8b..9cd122e 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -43,6 +43,9 @@
         SCREEN_REFRESH,
         EXTERNAL_ORIENTATION,
         BUFFER_MIRRORMODE,
+        //VPU command codes - list is defined in vpu.h
+        VPU_COMMAND_LIST_START = 100,
+        VPU_COMMAND_LIST_END = 200,
     };
     enum {
         END = 0,
@@ -54,6 +57,7 @@
     virtual android::status_t screenRefresh() = 0;
     virtual void setExtOrientation(uint32_t orientation) = 0;
     virtual void setBufferMirrorMode(uint32_t enable) = 0;
+    virtual android::status_t vpuCommand(uint32_t command, uint32_t setting) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index a8c5dca..327888c 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -71,6 +71,15 @@
     return result;
 }
 
+android::status_t QService::vpuCommand(uint32_t command, uint32_t setting ) {
+    status_t result = NO_ERROR;
+    if(mClient.get()) {
+        result = mClient->notifyCallback(command, setting);
+    }
+    return result;
+}
+
+
 void QService::setExtOrientation(uint32_t orientation) {
     if(mClient.get()) {
         mClient->notifyCallback(EXTERNAL_ORIENTATION, orientation);
diff --git a/libqservice/QService.h b/libqservice/QService.h
index a241d44..de18b59 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -51,6 +51,7 @@
     virtual android::status_t screenRefresh();
     virtual void setExtOrientation(uint32_t orientation);
     virtual void setBufferMirrorMode(uint32_t enable);
+    virtual android::status_t vpuCommand(uint32_t command, uint32_t setting);
     static void init();
 private:
     QService();
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
index 8e96a56..c94a5c6 100644
--- a/libvirtual/virtual.cpp
+++ b/libvirtual/virtual.cpp
@@ -76,6 +76,10 @@
 int VirtualDisplay::teardown() {
     closeFrameBuffer();
     memset(&mVInfo, 0, sizeof(mVInfo));
+    // Reset the resolution when we close the fb for this device. We need
+    // this to distinguish between an ONLINE and RESUME event.
+    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = 0;
+    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = 0;
     return 0;
 }
 
@@ -92,24 +96,41 @@
 
 void VirtualDisplay::setAttributes() {
     if(mHwcContext) {
-        // Always set dpyAttr res to mVInfo res
-        mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = mVInfo.xres;
-        mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = mVInfo.yres;
+        unsigned int &w = mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres;
+        unsigned int &h = mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres;
+
+        // Always set dpyAttr res to mVInfo res, only on an ONLINE event. Keep
+        // the original configuration to cater for DRC initiated RESUME events
+        if(w == 0 || h == 0){
+            w = mVInfo.xres;
+            h = mVInfo.yres;
+        }
         mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = false;
+
         if(!qdutils::MDPVersion::getInstance().is8x26()) {
             uint32_t priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
             uint32_t priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
-            // if primary resolution is more than the wfd resolution
+
+            // Find the maximum resolution between primary and virtual
+            uint32_t maxArea = max((w * h), (priW * priH));
+
+            // If primary resolution is more than the wfd resolution
             // configure dpy attr to primary resolution and set
-            // downscale mode
-            if((priW * priH) > (mVInfo.xres * mVInfo.yres)) {
-                mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = priW;
-                mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = priH;
-                // WFD is always in landscape, so always assign the higher
-                // dimension to wfd's xres
-                if(priH > priW) {
-                    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = priH;
-                    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = priW;
+            // downscale mode.
+            // DRC is only valid when the original resolution on the WiFi
+            // display is greater than the new resolution in mVInfo.
+            if(maxArea > (mVInfo.xres * mVInfo.yres)) {
+                if(maxArea == (priW * priH)) {
+                    // Here we account for the case when primary resolution is
+                    // greater than that of the WiFi display
+                    w = priW;
+                    h = priH;
+                    // WFD is always in landscape, so always assign the higher
+                    // dimension to wfd's xres
+                    if(priH > priW) {
+                        w = priH;
+                        h = priW;
+                    }
                 }
                 // Set External Display MDP Downscale mode indicator
                 mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = true;