Merge "hwc: Manipulate external display position for split and src split"
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 982146e..d12d9f0 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -37,14 +37,11 @@
 #include "qd_utils.h"
 
 using namespace android;
+using namespace qdutils;
 
 namespace qhwc {
-#define MAX_SYSFS_FILE_PATH             255
 #define UNKNOWN_STRING                  "unknown"
 #define SPD_NAME_LENGTH                 16
-/* Max. resolution assignable to when downscale */
-#define SUPPORTED_DOWNSCALE_EXT_AREA    (1920*1080)
-
 
 int ExternalDisplay::configure() {
     if(!openFrameBuffer()) {
@@ -594,7 +591,7 @@
             // downscale mode
             // Restrict this upto 1080p resolution max
             if(((priW * priH) > (width * height)) &&
-               ((priW * priH) <= SUPPORTED_DOWNSCALE_EXT_AREA)) {
+               ((priW * priH) <= SUPPORTED_DOWNSCALE_AREA)) {
                 // tmpW and tmpH will hold the primary dimensions before we
                 // update the aspect ratio if necessary.
                 int tmpW = priW;
@@ -611,7 +608,7 @@
                 // We get around this by calculating a new resolution by
                 // keeping aspect ratio intact.
                 hwc_rect r = {0, 0, 0, 0};
-                getAspectRatioPosition(tmpW, tmpH, width, height, r);
+                qdutils::getAspectRatioPosition(tmpW, tmpH, width, height, r);
                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres =
                                                               r.right - r.left;
                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres =
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 7255391..0e80843 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -592,7 +592,7 @@
         //Planar
         case HAL_PIXEL_FORMAT_YV12:
             ystride = hnd->width;
-            cstride = hnd->width/2;
+            cstride = ALIGN(hnd->width/2, 16);
             ycbcr->y  = (void*)hnd->base;
             ycbcr->cr = (void*)(hnd->base + ystride * hnd->height);
             ycbcr->cb = (void*)(hnd->base + ystride * hnd->height +
diff --git a/libgralloc/fb_priv.h b/libgralloc/fb_priv.h
index 191aa2a..e2eba6a 100644
--- a/libgralloc/fb_priv.h
+++ b/libgralloc/fb_priv.h
@@ -43,9 +43,7 @@
     uint32_t numBuffers;
     uint32_t bufferMask;
     pthread_mutex_t lock;
-    private_handle_t *currentBuffer;
     struct fb_var_screeninfo info;
-    struct mdp_display_commit commit;
     struct fb_fix_screeninfo finfo;
     float xdpi;
     float ydpi;
diff --git a/libgralloc/framebuffer.cpp b/libgralloc/framebuffer.cpp
index ca11bea..0ebc3db 100644
--- a/libgralloc/framebuffer.cpp
+++ b/libgralloc/framebuffer.cpp
@@ -58,9 +58,10 @@
 
 struct fb_context_t {
     framebuffer_device_t  device;
+    //fd - which is returned on open
+    int fbFd;
 };
 
-
 static int fb_setSwapInterval(struct framebuffer_device_t* dev,
                               int interval)
 {
@@ -87,11 +88,12 @@
         reinterpret_cast<private_module_t*>(dev->common.module);
     private_handle_t *hnd = static_cast<private_handle_t*>
         (const_cast<native_handle_t*>(buffer));
+    fb_context_t *ctx = reinterpret_cast<fb_context_t*>(dev);
     const unsigned int offset = (unsigned int) (hnd->base -
             m->framebuffer->base);
     m->info.activate = FB_ACTIVATE_VBL;
     m->info.yoffset = (int)(offset / m->finfo.line_length);
-    if (ioctl(m->framebuffer->fd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
+    if (ioctl(ctx->fbFd, FBIOPUT_VSCREENINFO, &m->info) == -1) {
         ALOGE("%s: FBIOPUT_VSCREENINFO for primary failed, str: %s",
                 __FUNCTION__, strerror(errno));
         return -errno;
@@ -110,8 +112,11 @@
     return 0;
 }
 
-int mapFrameBufferLocked(struct private_module_t* module)
+int mapFrameBufferLocked(framebuffer_device_t *dev)
 {
+    private_module_t* module =
+        reinterpret_cast<private_module_t*>(dev->common.module);
+    fb_context_t *ctx = reinterpret_cast<fb_context_t*>(dev);
     // already initialized...
     if (module->framebuffer) {
         return 0;
@@ -134,8 +139,6 @@
     if (fd < 0)
         return -errno;
 
-    memset(&module->commit, 0, sizeof(struct mdp_display_commit));
-
     struct fb_fix_screeninfo finfo;
     if (ioctl(fd, FBIOGET_FSCREENINFO, &finfo) == -1) {
         close(fd);
@@ -329,34 +332,55 @@
     //adreno needs page aligned offsets. Align the fbsize to pagesize.
     unsigned int fbSize = roundUpToPageSize(finfo.line_length * info.yres)*
                     module->numBuffers;
-    module->framebuffer = new private_handle_t(fd, fbSize,
-                                        private_handle_t::PRIV_FLAGS_USES_ION,
-                                        BUFFER_TYPE_UI,
-                                        module->fbFormat, info.xres, info.yres);
     void* vaddr = mmap(0, fbSize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
     if (vaddr == MAP_FAILED) {
         ALOGE("Error mapping the framebuffer (%s)", strerror(errno));
         close(fd);
         return -errno;
     }
+    //store the framebuffer fd in the ctx
+    ctx->fbFd = fd;
+#ifdef MSMFB_METADATA_GET
+    memset(&metadata, 0 , sizeof(metadata));
+    metadata.op = metadata_op_get_ion_fd;
+    // get the ION fd for the framebuffer, as GPU needs ION fd
+    if (ioctl(fd, MSMFB_METADATA_GET, &metadata) == -1) {
+        ALOGE("Error getting ION fd (%s)", strerror(errno));
+        close(fd);
+        return -errno;
+    }
+    if(metadata.data.fbmem_ionfd < 0) {
+        ALOGE("Error: Ioctl returned invalid ION fd = %d",
+                                        metadata.data.fbmem_ionfd);
+        close(fd);
+        return -errno;
+    }
+    fd = metadata.data.fbmem_ionfd;
+#endif
+    // Create framebuffer handle using the ION fd
+    module->framebuffer = new private_handle_t(fd, fbSize,
+                                        private_handle_t::PRIV_FLAGS_USES_ION,
+                                        BUFFER_TYPE_UI,
+                                        module->fbFormat, info.xres, info.yres);
     module->framebuffer->base = uint64_t(vaddr);
     memset(vaddr, 0, fbSize);
     //Enable vsync
     int enable = 1;
-    ioctl(module->framebuffer->fd, MSMFB_OVERLAY_VSYNC_CTRL,
-             &enable);
+    ioctl(ctx->fbFd, MSMFB_OVERLAY_VSYNC_CTRL, &enable);
     return 0;
 }
 
-static int mapFrameBuffer(struct private_module_t* module)
+static int mapFrameBuffer(framebuffer_device_t *dev)
 {
     int err = -1;
     char property[PROPERTY_VALUE_MAX];
     if((property_get("debug.gralloc.map_fb_memory", property, NULL) > 0) &&
        (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
         (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+        private_module_t* module =
+            reinterpret_cast<private_module_t*>(dev->common.module);
         pthread_mutex_lock(&module->lock);
-        err = mapFrameBufferLocked(module);
+        err = mapFrameBufferLocked(dev);
         pthread_mutex_unlock(&module->lock);
     }
     return err;
@@ -368,6 +392,11 @@
 {
     fb_context_t* ctx = (fb_context_t*)dev;
     if (ctx) {
+#ifdef MSMFB_METADATA_GET
+        if(ctx->fbFd >=0) {
+            close(ctx->fbFd);
+        }
+#endif
         //Hack until fbdev is removed. Framework could close this causing hwc a
         //pain.
         //free(ctx);
@@ -403,8 +432,8 @@
         dev->device.setUpdateRect   = 0;
         dev->device.compositionComplete = fb_compositionComplete;
 
-        private_module_t* m = (private_module_t*)module;
-        status = mapFrameBuffer(m);
+        status = mapFrameBuffer((framebuffer_device_t*)dev);
+        private_module_t* m = (private_module_t*)dev->device.common.module;
         if (status >= 0) {
             int stride = m->finfo.line_length / (m->info.bits_per_pixel >> 3);
             const_cast<uint32_t&>(dev->device.flags) = 0;
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index 4067050..9b98f1b 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -224,9 +224,11 @@
 
     // create a "fake" handle for it
     uint64_t vaddr = uint64_t(m->framebuffer->base);
+    // As GPU needs ION FD, the private handle is created
+    // using ION fd and ION flags are set
     private_handle_t* hnd = new private_handle_t(
         dup(m->framebuffer->fd), bufferSize,
-        private_handle_t::PRIV_FLAGS_USES_PMEM |
+        private_handle_t::PRIV_FLAGS_USES_ION |
         private_handle_t::PRIV_FLAGS_FRAMEBUFFER,
         BUFFER_TYPE_UI, m->fbFormat, m->info.xres,
         m->info.yres);
diff --git a/libgralloc/gralloc.cpp b/libgralloc/gralloc.cpp
index c1c61aa..c0aa8cb 100644
--- a/libgralloc/gralloc.cpp
+++ b/libgralloc/gralloc.cpp
@@ -91,7 +91,6 @@
     numBuffers: 0,
     bufferMask: 0,
     lock: PTHREAD_MUTEX_INITIALIZER,
-    currentBuffer: 0,
 };
 
 // Open Gralloc device
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 3d3d138..3b480e8 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -226,8 +226,7 @@
     }
 
     ctx->mAD->reset();
-    if(ctx->mHWCVirtual)
-        ctx->mHWCVirtual->destroy(ctx, numDisplays, displays);
+
 }
 
 static void scaleDisplayFrame(hwc_context_t *ctx, int dpy,
@@ -348,6 +347,7 @@
     for (int32_t i = ((int32_t)numDisplays-1); i >=0 ; i--) {
         hwc_display_contents_1_t *list = displays[i];
         int dpy = getDpyforExternalDisplay(ctx, i);
+        resetROI(ctx, dpy);
         switch(dpy) {
             case HWC_DISPLAY_PRIMARY:
                 ret = hwc_prepare_primary(dev, list);
@@ -367,6 +367,11 @@
     ctx->mOverlay->configDone();
     ctx->mRotMgr->configDone();
     overlay::Writeback::configDone();
+    // If VD list is deleted, mdp overlay pipe objects and writeback object
+    // are deleted as part of configDone functions.
+    // Proceed with HWCVirtualVDS object deletion.
+    if(ctx->mHWCVirtual)
+        ctx->mHWCVirtual->destroy(ctx, numDisplays, displays);
 
     return ret;
 }
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index 9f23bb8..f849450 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -214,7 +214,7 @@
                 ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
     }
 
-    PipeArgs parg(mdpFlags, whf, ZORDER_0, IS_FG_OFF,
+    PipeArgs parg(mdpFlags, whf, ZORDER_0,
             ROT_FLAGS_NONE);
     hwc_rect_t dst = crop; //input same as output
 
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index aef5d08..7d00d9c 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -159,7 +159,6 @@
         }
 
         ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
-        ovutils::eIsFg isFg = ovutils::IS_FG_OFF;
         ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
 
         hwc_rect_t sourceCrop = integerizeSourceCrop(layer->sourceCropf);
@@ -187,9 +186,8 @@
         // Dont do wormhole calculation when extDownscale is enabled on External
         if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
             sourceCrop = layer->displayFrame;
-        } else if((!mDpy ||
-                  (mDpy && !extOrient
-                  && !ctx->dpyAttr[mDpy].mDownScaleMode))) {
+        } else if((mDpy && !extOrient
+                  && !ctx->dpyAttr[mDpy].mDownScaleMode)) {
             if(ctx->mOverlay->isUIScalingOnExternalSupported() &&
                 !ctx->dpyAttr[mDpy].customFBSize) {
                 getNonWormholeRegion(list, sourceCrop);
@@ -211,7 +209,7 @@
         //For the mdp, since either we are pre-rotating or MDP does flips
         orient = ovutils::OVERLAY_TRANSFORM_0;
         transform = 0;
-        ovutils::PipeArgs parg(mdpFlags, info, zOrder, isFg,
+        ovutils::PipeArgs parg(mdpFlags, info, zOrder,
                                static_cast<ovutils::eRotFlags>(rotFlags),
                                ovutils::DEFAULT_PLANE_ALPHA,
                                (ovutils::eBlending)
@@ -349,7 +347,6 @@
             ovutils::PipeArgs pargL(mdpFlags,
                                     info,
                                     zOrder,
-                                    ovutils::IS_FG_OFF,
                                     ovutils::ROT_FLAGS_NONE,
                                     ovutils::DEFAULT_PLANE_ALPHA,
                                     (ovutils::eBlending)
@@ -385,7 +382,6 @@
             ovutils::PipeArgs pargR(mdpFlagsR,
                                     info,
                                     zOrder,
-                                    ovutils::IS_FG_OFF,
                                     ovutils::ROT_FLAGS_NONE,
                                     ovutils::DEFAULT_PLANE_ALPHA,
                                     (ovutils::eBlending)
@@ -453,7 +449,6 @@
     ovutils::PipeArgs parg(mdpFlags,
             info,
             zOrder,
-            ovutils::IS_FG_OFF,
             ovutils::ROT_FLAGS_NONE,
             ovutils::DEFAULT_PLANE_ALPHA,
             (ovutils::eBlending)
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 6084d8d..0d968c8 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -238,11 +238,12 @@
 }
 
 MDPComp::FrameInfo::FrameInfo() {
+    memset(&mdpToLayer, 0, sizeof(mdpToLayer));
     reset(0);
 }
 
 void MDPComp::FrameInfo::reset(const int& numLayers) {
-    for(int i = 0 ; i < MAX_PIPES_PER_MIXER && numLayers; i++ ) {
+    for(int i = 0; i < MAX_PIPES_PER_MIXER; i++) {
         if(mdpToLayer[i].pipeInfo) {
             delete mdpToLayer[i].pipeInfo;
             mdpToLayer[i].pipeInfo = NULL;
@@ -677,7 +678,9 @@
     const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
     int priDispW = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
 
-    if(sIdleFallBack && !ctx->listStats[mDpy].secureUI) {
+    // No Idle fall back, if secure display or secure RGB layers are present
+    if(sIdleFallBack && (!ctx->listStats[mDpy].secureUI &&
+                    !ctx->listStats[mDpy].secureRGBCount)) {
         ALOGD_IF(isDebug(), "%s: Idle fallback dpy %d",__FUNCTION__, mDpy);
         return false;
     }
@@ -1047,6 +1050,8 @@
     }
 
     updateYUV(ctx, list, false /*secure only*/);
+    /* mark secure RGB layers for MDP comp */
+    updateSecureRGB(ctx, list);
     bool ret = markLayersForCaching(ctx, list); //sets up fbZ also
     if(!ret) {
         ALOGD_IF(isDebug(),"%s: batching failed, dpy %d",__FUNCTION__, mDpy);
@@ -1237,6 +1242,64 @@
     return true;
 }
 
+/* if tryFullFrame fails, try to push all video and secure RGB layers to MDP */
+bool MDPComp::tryMDPOnlyLayers(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
+    const bool secureOnly = true;
+    return mdpOnlyLayersComp(ctx, list, not secureOnly) or
+            mdpOnlyLayersComp(ctx, list, secureOnly);
+
+}
+
+bool MDPComp::mdpOnlyLayersComp(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list, bool secureOnly) {
+
+    if(sSimulationFlags & MDPCOMP_AVOID_MDP_ONLY_LAYERS)
+        return false;
+
+    /* Bail out if we are processing only secured video layers
+     * and we dont have any */
+    if(!isSecurePresent(ctx, mDpy) && secureOnly){
+        reset(ctx);
+        return false;
+    }
+
+    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
+    mCurrentFrame.reset(numAppLayers);
+    mCurrentFrame.fbCount -= mCurrentFrame.dropCount;
+
+    updateYUV(ctx, list, secureOnly);
+    /* mark secure RGB layers for MDP comp */
+    updateSecureRGB(ctx, list);
+
+    if(mCurrentFrame.mdpCount == 0) {
+        reset(ctx);
+        return false;
+    }
+
+    /* find the maximum batch of layers to be marked for framebuffer */
+    bool ret = markLayersForCaching(ctx, list); //sets up fbZ also
+    if(!ret) {
+        ALOGD_IF(isDebug(),"%s: batching failed, dpy %d",__FUNCTION__, mDpy);
+        reset(ctx);
+        return false;
+    }
+
+    if(sEnableYUVsplit){
+        adjustForSourceSplit(ctx, list);
+    }
+
+    if(!postHeuristicsHandling(ctx, list)) {
+        ALOGD_IF(isDebug(), "post heuristic handling failed");
+        reset(ctx);
+        return false;
+    }
+
+    ALOGD_IF(sSimulationFlags,"%s: MDP_ONLY_LAYERS_COMP SUCCEEDED",
+             __FUNCTION__);
+    return true;
+}
+
 /* Checks for conditions where YUV layers cannot be bypassed */
 bool MDPComp::isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer) {
     if(isSkipLayer(layer)) {
@@ -1270,6 +1333,27 @@
     return true;
 }
 
+/* Checks for conditions where Secure RGB layers cannot be bypassed */
+bool MDPComp::isSecureRGBDoable(hwc_context_t* ctx, hwc_layer_1_t* layer) {
+    if(isSkipLayer(layer)) {
+        ALOGD_IF(isDebug(), "%s: Secure RGB layer marked SKIP dpy %d",
+            __FUNCTION__, mDpy);
+        return false;
+    }
+
+    if(isSecuring(ctx, layer)) {
+        ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__);
+        return false;
+    }
+
+    if(not isSupportedForMDPComp(ctx, layer)) {
+        ALOGD_IF(isDebug(), "%s: Unsupported secure RGB layer",
+            __FUNCTION__);
+        return false;
+    }
+    return true;
+}
+
 /* starts at fromIndex and check for each layer to find
  * if it it has overlapping with any Updating layer above it in zorder
  * till the end of the batch. returns true if it finds any intersection */
@@ -1487,6 +1571,32 @@
              mCurrentFrame.fbCount);
 }
 
+void MDPComp::updateSecureRGB(hwc_context_t* ctx,
+    hwc_display_contents_1_t* list) {
+    int nSecureRGBCount = ctx->listStats[mDpy].secureRGBCount;
+    for(int index = 0;index < nSecureRGBCount; index++){
+        int nSecureRGBIndex = ctx->listStats[mDpy].secureRGBIndices[index];
+        hwc_layer_1_t* layer = &list->hwLayers[nSecureRGBIndex];
+
+        if(!isSecureRGBDoable(ctx, layer)) {
+            if(!mCurrentFrame.isFBComposed[nSecureRGBIndex]) {
+                mCurrentFrame.isFBComposed[nSecureRGBIndex] = true;
+                mCurrentFrame.fbCount++;
+            }
+        } else {
+            if(mCurrentFrame.isFBComposed[nSecureRGBIndex]) {
+                mCurrentFrame.isFBComposed[nSecureRGBIndex] = false;
+                mCurrentFrame.fbCount--;
+            }
+        }
+    }
+
+    mCurrentFrame.mdpCount = mCurrentFrame.layerCount -
+            mCurrentFrame.fbCount - mCurrentFrame.dropCount;
+    ALOGD_IF(isDebug(),"%s: fb count: %d",__FUNCTION__,
+             mCurrentFrame.fbCount);
+}
+
 hwc_rect_t MDPComp::getUpdatingFBRect(hwc_context_t *ctx,
         hwc_display_contents_1_t* list){
     hwc_rect_t fbRect = (struct hwc_rect){0, 0, 0, 0};
@@ -1708,7 +1818,10 @@
     if(isFrameDoable(ctx)) {
         generateROI(ctx, list);
 
-        mModeOn = tryFullFrame(ctx, list) || tryVideoOnly(ctx, list);
+        // if tryFullFrame fails, try to push all video and secure RGB layers
+        // to MDP for composition.
+        mModeOn = tryFullFrame(ctx, list) || tryMDPOnlyLayers(ctx, list) ||
+                  tryVideoOnly(ctx, list);
         if(mModeOn) {
             setMDPCompLayerFlags(ctx, list);
         } else {
@@ -1822,13 +1935,12 @@
         *(static_cast<MdpPipeInfoNonSplit*>(PipeLayerPair.pipeInfo));
     eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
     eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
-    eIsFg isFg = IS_FG_OFF;
     eDest dest = mdp_info.index;
 
     ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipe: %d",
              __FUNCTION__, layer, zOrder, dest);
 
-    return configureNonSplit(ctx, layer, mDpy, mdpFlags, zOrder, isFg, dest,
+    return configureNonSplit(ctx, layer, mDpy, mdpFlags, zOrder, dest,
                            &PipeLayerPair.rot);
 }
 
@@ -1877,12 +1989,11 @@
     MdpYUVPipeInfo& mdp_info =
             *(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo));
     eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
-    eIsFg isFg = IS_FG_OFF;
     eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
     eDest lDest = mdp_info.lIndex;
     eDest rDest = mdp_info.rIndex;
 
-    return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg,
+    return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder,
             lDest, rDest, &PipeLayerPair.rot);
 }
 
@@ -2110,12 +2221,11 @@
         MdpYUVPipeInfo& mdp_info =
                 *(static_cast<MdpYUVPipeInfo*>(PipeLayerPair.pipeInfo));
         eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
-        eIsFg isFg = IS_FG_OFF;
         eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
         eDest lDest = mdp_info.lIndex;
         eDest rDest = mdp_info.rIndex;
 
-        return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg,
+        return configureSourceSplit(ctx, layer, mDpy, mdpFlagsL, zOrder,
                 lDest, rDest, &PipeLayerPair.rot);
     }
     else{
@@ -2131,7 +2241,6 @@
     MdpPipeInfoSplit& mdp_info =
         *(static_cast<MdpPipeInfoSplit*>(PipeLayerPair.pipeInfo));
     eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
-    eIsFg isFg = IS_FG_OFF;
     eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
     eDest lDest = mdp_info.lIndex;
     eDest rDest = mdp_info.rIndex;
@@ -2139,7 +2248,7 @@
     ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
              "dest_pipeR: %d",__FUNCTION__, layer, zOrder, lDest, rDest);
 
-    return configureSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg, lDest,
+    return configureSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, lDest,
                             rDest, &PipeLayerPair.rot);
 }
 
@@ -2349,7 +2458,6 @@
         *(static_cast<MdpPipeInfoSplit*>(PipeLayerPair.pipeInfo));
     Rotator **rot = &PipeLayerPair.rot;
     eZorder z = static_cast<eZorder>(mdp_info.zOrder);
-    eIsFg isFg = IS_FG_OFF;
     eDest lDest = mdp_info.lIndex;
     eDest rDest = mdp_info.rIndex;
     hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
@@ -2407,14 +2515,24 @@
         cropR.left = cropL.right;
         sanitizeSourceCrop(cropL, cropR, hnd);
 
+        bool cropSwap = false;
         //Swap crops on H flip since 2 pipes are being used
         if((orient & OVERLAY_TRANSFORM_FLIP_H) && (*rot) == NULL) {
             hwc_rect_t tmp = cropL;
             cropL = cropR;
             cropR = tmp;
+            cropSwap = true;
         }
 
-        dstL.right = (dst.right + dst.left) / 2;
+        //cropSwap trick: If the src and dst widths are both odd, let us say
+        //2507, then splitting both into half would cause left width to be 1253
+        //and right 1254. If crop is swapped because of H flip, this will cause
+        //left crop width to be 1254, whereas left dst width remains 1253, thus
+        //inducing a scaling that is unaccounted for. To overcome that we add 1
+        //to the dst width if there is a cropSwap. So if the original width was
+        //2507, the left dst width will be 1254. Even if the original width was
+        //even for ex: 2508, the left dst width will still remain 1254.
+        dstL.right = (dst.right + dst.left + cropSwap) / 2;
         dstR.left = dstL.right;
     }
 
@@ -2424,7 +2542,7 @@
 
     //configure left pipe
     if(lDest != OV_INVALID) {
-        PipeArgs pargL(mdpFlags, whf, z, isFg,
+        PipeArgs pargL(mdpFlags, whf, z,
                 static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
                 (ovutils::eBlending) getBlending(layer->blending));
 
@@ -2437,7 +2555,7 @@
 
     //configure right pipe
     if(rDest != OV_INVALID) {
-        PipeArgs pargR(mdpFlags, whf, z, isFg,
+        PipeArgs pargR(mdpFlags, whf, z,
                 static_cast<eRotFlags>(rotFlags),
                 layer->planeAlpha,
                 (ovutils::eBlending) getBlending(layer->blending));
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 5214ac6..8c833c2 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -74,6 +74,7 @@
         MDPCOMP_AVOID_CACHE_MDP = 0x002,
         MDPCOMP_AVOID_LOAD_MDP = 0x004,
         MDPCOMP_AVOID_VIDEO_ONLY = 0x008,
+        MDPCOMP_AVOID_MDP_ONLY_LAYERS = 0x010,
     };
 
     /* mdp pipe data */
@@ -190,8 +191,14 @@
     bool tryVideoOnly(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     bool videoOnlyComp(hwc_context_t *ctx, hwc_display_contents_1_t* list,
             bool secureOnly);
+    /* checks for conditions where only secure RGB and video can be bypassed */
+    bool tryMDPOnlyLayers(hwc_context_t *ctx, hwc_display_contents_1_t* list);
+    bool mdpOnlyLayersComp(hwc_context_t *ctx, hwc_display_contents_1_t* list,
+            bool secureOnly);
     /* checks for conditions where YUV layers cannot be bypassed */
     bool isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
+    /* checks for conditions where Secure RGB layers cannot be bypassed */
+    bool isSecureRGBDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
     /* checks if MDP/MDSS can process current list w.r.to HW limitations
      * All peculiar HW limitations should go here */
     bool hwLimitationsCheck(hwc_context_t* ctx, hwc_display_contents_1_t* list);
@@ -217,6 +224,9 @@
         /* updates cache map with YUV info */
     void updateYUV(hwc_context_t* ctx, hwc_display_contents_1_t* list,
             bool secureOnly);
+    /* updates cache map with secure RGB info */
+    void updateSecureRGB(hwc_context_t* ctx,
+            hwc_display_contents_1_t* list);
     /* Validates if the GPU/MDP layer split chosen by a strategy is supported
      * by MDP.
      * Sets up MDP comp data structures to reflect covnversion from layers to
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 892e9c0..efe6e16 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -32,6 +32,7 @@
 #include <hwc_utils.h>
 #include <mdp_version.h>
 #include <hwc_mdpcomp.h>
+#include <hwc_virtual.h>
 
 #define QCLIENT_DEBUG 0
 
@@ -231,6 +232,10 @@
             ctx->vstate.debug = enable;
             if (debug_type != IQService::DEBUG_ALL)
                 break;
+        case IQService::DEBUG_VD:
+            HWCVirtualBase::dynamicDebug(enable);
+            if (debug_type != IQService::DEBUG_ALL)
+                break;
     }
 }
 
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 94191b7..f887ccc 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -235,22 +235,42 @@
                    * 2 / 1000);
 
             if(dpy == HWC_DISPLAY_EXTERNAL) {
-                if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
-                    // Triple Display is supported on 8084 target
-                    // WFD can be initiated by Wfd-client or Settings app
-                    // 1. wfd-client use hdmi hotplug mechanism.
-                    //    If wfd is connected via wfd-client and if HDMI is
-                    //    connected, we have to teardown wfd session.
-                    //    (as SF support only one active External display
-                    //     at a given time).
-                    //    (ToDo: Once wfd-client migrates using virtual display
-                    //     apis, second condition is redundant).
-                    // 2. Settings app use virtual display mechanism.
-                    //    In this approach, there is no limitation of supporting
-                    //    triple display.
-                    if(!(qdutils::MDPVersion::getInstance().is8084() &&
-                                !ctx->mVirtualonExtActive)) {
-                        teardownWfd(ctx);
+                if(isVDConnected(ctx)) {
+                    // Do not initiate WFD teardown if WFD architecture is based
+                    // on VDS mechanism.
+                    // WFD Stack listens to HDMI intent and initiates virtual
+                    // display teardown.
+                    // ToDo: Currently non-WFD Virtual display clients do not
+                    // involve HWC. If there is a change, we need to come up
+                    // with mechanism of how to address non-WFD Virtual display
+                    // clients + HDMI
+                    if(isVDSEnabled(ctx)) {
+                        ctx->mWfdSyncLock.lock();
+                        ALOGD_IF(HWC_WFDDISPSYNC_LOG,
+                                "%s: Waiting for wfd-teardown to be signalled",
+                                __FUNCTION__);
+                        ctx->mWfdSyncLock.wait();
+                        ALOGD_IF(HWC_WFDDISPSYNC_LOG,
+                                "%s: Teardown signalled. Completed waiting in"
+                                "uevent thread", __FUNCTION__);
+                        ctx->mWfdSyncLock.unlock();
+                    } else {
+                        // Triple Display is supported on 8084 target
+                        // WFD can be initiated by Wfd-client or Settings app
+                        // 1. wfd-client use hdmi hotplug mechanism.
+                        //    If wfd is connected via wfd-client and if HDMI is
+                        //    connected, we have to teardown wfd session.
+                        //    (as SF support only one active External display
+                        //     at a given time).
+                        //    (ToDo: Once wfd-client migrates using virtual
+                        //     display apis, second condition is redundant).
+                        // 2. Settings app use virtual display mechanism.
+                        //    In this approach, there is no limitation of
+                        //    supporting triple display.
+                        if(!(qdutils::MDPVersion::getInstance().is8084() &&
+                                    !ctx->mVirtualonExtActive)) {
+                            teardownWfd(ctx);
+                        }
                     }
                 }
                 ctx->mExtDisplay->configure();
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index e71d84d..e57e573 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -488,8 +488,8 @@
     if(extOrientation & HAL_TRANSFORM_ROT_90) {
         // Swap width/height for input position
         swapWidthHeight(actualWidth, actualHeight);
-        getAspectRatioPosition((int)fbWidth, (int)fbHeight, (int)actualWidth,
-                               (int)actualHeight, rect);
+        qdutils::getAspectRatioPosition((int)fbWidth, (int)fbHeight,
+                                (int)actualWidth, (int)actualHeight, rect);
         xPos = rect.left;
         yPos = rect.top;
         width = float(rect.right - rect.left);
@@ -520,7 +520,7 @@
         xRatio = (float)(outPos.x - xPos)/width;
         // GetaspectRatio -- tricky to get the correct aspect ratio
         // But we need to do this.
-        getAspectRatioPosition((int)width, (int)height,
+        qdutils::getAspectRatioPosition((int)width, (int)height,
                                (int)width,(int)height, r);
         xPos = r.left;
         yPos = r.top;
@@ -603,7 +603,7 @@
                 if(!isPrimaryPortrait(ctx)) {
                     swap(srcWidth, srcHeight);
                 }                    // Get Aspect Ratio for external
-                getAspectRatioPosition(dstWidth, dstHeight, srcWidth,
+                qdutils::getAspectRatioPosition(dstWidth, dstHeight, srcWidth,
                                     srcHeight, displayFrame);
                 // Crop - this is needed, because for sidesync, the dest fb will
                 // be in portrait orientation, so update the crop to not show the
@@ -840,6 +840,7 @@
     ctx->listStats[dpy].yuv4k2kCount = 0;
     ctx->dpyAttr[dpy].mActionSafePresent = isActionSafePresent(ctx, dpy);
     ctx->listStats[dpy].renderBufIndexforABC = -1;
+    ctx->listStats[dpy].secureRGBCount = 0;
 
     resetROI(ctx, dpy);
 
@@ -867,6 +868,12 @@
 
         if (isSecureBuffer(hnd)) {
             ctx->listStats[dpy].isSecurePresent = true;
+            if(not isYuvBuffer(hnd)) {
+                // cache secureRGB layer parameters like we cache for YUV layers
+                int& secureRGBCount = ctx->listStats[dpy].secureRGBCount;
+                ctx->listStats[dpy].secureRGBIndices[secureRGBCount] = (int)i;
+                secureRGBCount++;
+            }
         }
 
         if (isSkipLayer(&list->hwLayers[i])) {
@@ -1472,22 +1479,20 @@
                 ovutils::OV_MDP_BLEND_FG_PREMULT);
     }
 
-    if(isYuvBuffer(hnd)) {
-        if(isSecureBuffer(hnd)) {
-            ovutils::setMdpFlags(mdpFlags,
-                    ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
-        }
-        if(metadata && (metadata->operation & PP_PARAM_INTERLACED) &&
-                metadata->interlaced) {
-            ovutils::setMdpFlags(mdpFlags,
-                    ovutils::OV_MDP_DEINTERLACE);
-        }
+    if(metadata && (metadata->operation & PP_PARAM_INTERLACED) &&
+            metadata->interlaced) {
+        ovutils::setMdpFlags(mdpFlags,
+                ovutils::OV_MDP_DEINTERLACE);
+    }
+
+    // Mark MDP flags with SECURE_OVERLAY_SESSION for driver
+    if(isSecureBuffer(hnd)) {
+        ovutils::setMdpFlags(mdpFlags,
+                ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
     }
 
     if(isSecureDisplayBuffer(hnd)) {
-        // Secure display needs both SECURE_OVERLAY and SECURE_DISPLAY_OV
-        ovutils::setMdpFlags(mdpFlags,
-                             ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
+        // Mark MDP flags with SECURE_DISPLAY_OVERLAY_SESSION for driver
         ovutils::setMdpFlags(mdpFlags,
                              ovutils::OV_MDP_SECURE_DISPLAY_OVERLAY_SESSION);
     }
@@ -1571,7 +1576,7 @@
 
 int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
-        eIsFg& isFg, const eDest& dest) {
+        const eDest& dest) {
 
     hwc_rect_t dst = layer->displayFrame;
     trimLayer(ctx, dpy, 0, dst, dst);
@@ -1587,7 +1592,7 @@
     if (layer->blending == HWC_BLENDING_PREMULT)
         ovutils::setMdpFlags(mdpFlags, ovutils::OV_MDP_BLEND_FG_PREMULT);
 
-    PipeArgs parg(mdpFlags, whf, z, isFg, static_cast<eRotFlags>(0),
+    PipeArgs parg(mdpFlags, whf, z, static_cast<eRotFlags>(0),
                   layer->planeAlpha,
                   (ovutils::eBlending) getBlending(layer->blending));
 
@@ -1673,14 +1678,14 @@
 
 int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
-        eIsFg& isFg, const eDest& dest, Rotator **rot) {
+        const eDest& dest, Rotator **rot) {
 
     private_handle_t *hnd = (private_handle_t *)layer->handle;
 
     if(!hnd) {
         if (layer->flags & HWC_COLOR_FILL) {
             // Configure Color layer
-            return configColorLayer(ctx, layer, dpy, mdpFlags, z, isFg, dest);
+            return configColorLayer(ctx, layer, dpy, mdpFlags, z, dest);
         }
         ALOGE("%s: layer handle is NULL", __FUNCTION__);
         return -1;
@@ -1728,7 +1733,7 @@
     //For the mdp, since either we are pre-rotating or MDP does flips
     orient = OVERLAY_TRANSFORM_0;
     transform = 0;
-    PipeArgs parg(mdpFlags, whf, z, isFg,
+    PipeArgs parg(mdpFlags, whf, z,
                   static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
                   (ovutils::eBlending) getBlending(layer->blending));
 
@@ -1770,7 +1775,7 @@
 
 int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
-        eIsFg& isFg, const eDest& lDest, const eDest& rDest,
+        const eDest& lDest, const eDest& rDest,
         Rotator **rot) {
     private_handle_t *hnd = (private_handle_t *)layer->handle;
     if(!hnd) {
@@ -1884,7 +1889,7 @@
 
     //configure left mixer
     if(lDest != OV_INVALID) {
-        PipeArgs pargL(mdpFlagsL, whf, z, isFg,
+        PipeArgs pargL(mdpFlagsL, whf, z,
                        static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
                        (ovutils::eBlending) getBlending(layer->blending));
 
@@ -1897,7 +1902,7 @@
 
     //configure right mixer
     if(rDest != OV_INVALID) {
-        PipeArgs pargR(mdpFlagsR, whf, z, isFg,
+        PipeArgs pargR(mdpFlagsR, whf, z,
                        static_cast<eRotFlags>(rotFlags),
                        layer->planeAlpha,
                        (ovutils::eBlending) getBlending(layer->blending));
@@ -1915,7 +1920,7 @@
 
 int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
-        eIsFg& isFg, const eDest& lDest, const eDest& rDest,
+        const eDest& lDest, const eDest& rDest,
         Rotator **rot) {
     private_handle_t *hnd = (private_handle_t *)layer->handle;
     if(!hnd) {
@@ -2010,7 +2015,7 @@
 
     //configure left half
     if(lDest != OV_INVALID) {
-        PipeArgs pargL(mdpFlagsL, whf, lz, isFg,
+        PipeArgs pargL(mdpFlagsL, whf, lz,
                 static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
                 (ovutils::eBlending) getBlending(layer->blending));
 
@@ -2023,7 +2028,7 @@
 
     //configure right half
     if(rDest != OV_INVALID) {
-        PipeArgs pargR(mdpFlagsR, whf, rz, isFg,
+        PipeArgs pargR(mdpFlagsR, whf, rz,
                 static_cast<eRotFlags>(rotFlags),
                 layer->planeAlpha,
                 (ovutils::eBlending) getBlending(layer->blending));
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index f6c3c1b..98e53a6 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -132,6 +132,9 @@
     hwc_rect_t rRoi;  //right ROI. Unused in single DSI panels.
     //App Buffer Composition index
     int  renderBufIndexforABC;
+    // Secure RGB specific
+    int secureRGBCount;
+    int secureRGBIndices[MAX_NUM_APP_LAYERS];
 };
 
 //PTOR Comp info
@@ -352,7 +355,7 @@
 
 int configColorLayer(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
         ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
-        ovutils::eIsFg& isFg, const ovutils::eDest& dest);
+        const ovutils::eDest& dest);
 
 void updateSource(ovutils::eTransform& orient, ovutils::Whf& whf,
         hwc_rect_t& crop, overlay::Rotator *rot);
@@ -360,20 +363,20 @@
 //Routine to configure low resolution panels (<= 2048 width)
 int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
         ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
-        ovutils::eIsFg& isFg, const ovutils::eDest& dest,
+        const ovutils::eDest& dest,
         overlay::Rotator **rot);
 
 //Routine to configure high resolution panels (> 2048 width)
 int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
         ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
-        ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
+        const ovutils::eDest& lDest,
         const ovutils::eDest& rDest, overlay::Rotator **rot);
 
 //Routine to split and configure high resolution YUV layer (> 2048 width)
 int configureSourceSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy,
         ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
-        ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
+        const ovutils::eDest& lDest,
         const ovutils::eDest& rDest, overlay::Rotator **rot);
 
 //On certain targets DMA pipes are used for rotation and they won't be available
@@ -624,6 +627,16 @@
             ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected);
 }
 
+/* Return true if HWC supports VirtualDisplaySurface mechanism */
+static inline bool isVDSEnabled(hwc_context_t* ctx) {
+    return ctx->mVDSEnabled;
+}
+
+/* Return Virtual Display connection status */
+static inline bool isVDConnected(hwc_context_t* ctx) {
+    return ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected;
+}
+
 };
 
 #endif //HWC_UTILS_H
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
index db43435..a3a7612 100644
--- a/libhwcomposer/hwc_virtual.cpp
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -36,6 +36,7 @@
 using namespace qhwc;
 using namespace overlay;
 
+bool HWCVirtualBase::sVDDumpEnabled = false;
 HWCVirtualBase* HWCVirtualBase::getObject(bool isVDSEnabled) {
 
     if(isVDSEnabled) {
@@ -49,16 +50,6 @@
     }
 }
 
-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] =
@@ -88,11 +79,7 @@
             delete ctx->mMDPComp[dpy];
             ctx->mMDPComp[dpy] = NULL;
         }
-        // We reset the WB session to non-secure when the virtual display
-        // has been disconnected.
-        if(!Writeback::getInstance()->setSecure(false)) {
-            ALOGE("Failure while attempting to reset WB session.");
-        }
+        // signal synclock to indicate successful wfd teardown
         ctx->mWfdSyncLock.lock();
         ctx->mWfdSyncLock.signal();
         ctx->mWfdSyncLock.unlock();
@@ -177,13 +164,12 @@
             Writeback::getInstance()->setOutputFormat(
                                     utils::getMdpFormat(format));
 
-            // Configure WB as secure if the output buffer handle is secure.
-            if(isSecureBuffer(ohnd)){
-                if(! Writeback::getInstance()->setSecure(true))
-                {
-                    ALOGE("Failed to set WB as secure for virtual display");
-                    return false;
-                }
+            // Configure WB secure mode based on output buffer handle
+            if(! Writeback::getInstance()->setSecure(isSecureBuffer(ohnd)))
+            {
+                ALOGE("Failed to set WB secure mode: %d for virtual display",
+                    isSecureBuffer(ohnd));
+                return false;
             }
 
             int fd = -1; //FenceFD from the Copybit
@@ -216,7 +202,7 @@
                 ret = -1;
             }
 
-            if(mVDSDumpEnabled) {
+            if(sVDDumpEnabled) {
                 char bufferName[128];
                 // Dumping frame buffer
                 sync_wait(fbLayer->acquireFenceFd, 1000);
diff --git a/libhwcomposer/hwc_virtual.h b/libhwcomposer/hwc_virtual.h
index 26d89c9..5f7b20f 100644
--- a/libhwcomposer/hwc_virtual.h
+++ b/libhwcomposer/hwc_virtual.h
@@ -42,11 +42,17 @@
                        hwc_display_contents_1_t** displays) = 0;
     virtual void pause(hwc_context_t* ctx, int dpy) = 0;
     virtual void resume(hwc_context_t* ctx, int dpy) = 0;
+    // We can dump the frame buffer and WB
+    // output buffer by dynamically enabling
+    // dumping via a binder call:
+    // adb shell service call display.qservice 15 i32 3 i32 1
+    static bool sVDDumpEnabled;
+    static void dynamicDebug(bool enable) {sVDDumpEnabled = enable;};
 };
 
 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,12 +70,6 @@
                        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 6c6ba63..66988f7 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -27,16 +27,17 @@
 #include <sys/prctl.h>
 #include <poll.h>
 #include "hwc_utils.h"
+#include "qd_utils.h"
 #include "string.h"
 #include "external.h"
 #include "overlay.h"
 #define __STDC_FORMAT_MACROS 1
 #include <inttypes.h>
 
+using namespace qdutils;
 namespace qhwc {
 
 #define HWC_VSYNC_THREAD_NAME "hwcVsyncThread"
-#define MAX_SYSFS_FILE_PATH             255
 #define PANEL_ON_STR "panel_power_on ="
 #define ARRAY_LENGTH(array) (sizeof((array))/sizeof((array)[0]))
 #define MAX_THERMAL_LEVEL 3
diff --git a/liboverlay/mdpWrapper.h b/liboverlay/mdpWrapper.h
index e24ad6a..60e972f 100644
--- a/liboverlay/mdpWrapper.h
+++ b/liboverlay/mdpWrapper.h
@@ -103,7 +103,6 @@
 void dump(const char* const s, const msmfb_overlay_data& ov);
 void dump(const char* const s, const msmfb_data& ov);
 void dump(const char* const s, const mdp_overlay& ov);
-void dump(const char* const s, const msmfb_overlay_3d& ov);
 void dump(const char* const s, const uint32_t u[], uint32_t cnt);
 void dump(const char* const s, const msmfb_img& ov);
 void dump(const char* const s, const mdp_rect& ov);
@@ -299,8 +298,8 @@
             s, ov.offset, ov.memory_id, ov.id, ov.flags, ov.priv);
 }
 inline void dump(const char* const s, const mdp_overlay& ov) {
-    ALOGE("%s mdp_overlay z=%d fg=%d alpha=%d mask=%d flags=0x%x id=%d",
-            s, ov.z_order, ov.is_fg, ov.alpha,
+    ALOGE("%s mdp_overlay z=%d alpha=%d mask=%d flags=0x%x id=%d",
+            s, ov.z_order, ov.alpha,
             ov.transp_mask, ov.flags, ov.id);
     dump("src", ov.src);
     dump("src_rect", ov.src_rect);
@@ -322,11 +321,6 @@
             s, ov.x, ov.y, ov.w, ov.h);
 }
 
-inline void dump(const char* const s, const msmfb_overlay_3d& ov) {
-    ALOGE("%s msmfb_overlay_3d 3d=%d w=%d h=%d",
-            s, ov.is_3d, ov.width, ov.height);
-
-}
 inline void dump(const char* const s, const uint32_t u[], uint32_t cnt) {
     ALOGE("%s user_data cnt=%d", s, cnt);
     for(uint32_t i=0; i < cnt; ++i) {
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index 26c8845..c016d3d 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -32,6 +32,7 @@
 #include "pipes/overlayGenPipe.h"
 #include "mdp_version.h"
 #include "qdMetaData.h"
+#include "qd_utils.h"
 
 #define PIPE_DEBUG 0
 
@@ -452,7 +453,6 @@
     }
 
     FILE *displayDeviceFP = NULL;
-    const int MAX_FRAME_BUFFER_NAME_SIZE = 128;
     char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
     char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
     const char *strDtvPanel = "dtv panel";
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 7f9f136..ddc40ee 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -96,7 +96,6 @@
     //TODO These calls should ideally be a part of setPipeParams API
     setFlags(args.mdpFlags);
     setZ(args.zorder);
-    setIsFg(args.isFg);
     setPlaneAlpha(args.planeAlpha);
     setBlending(args.blending);
 }
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index cb8e057..d415b9d 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -99,8 +99,6 @@
     void setFlags(int f);
     /* set z order */
     void setZ(utils::eZorder z);
-    /* set isFg flag */
-    void setIsFg(utils::eIsFg isFg);
     /* return a copy of src whf*/
     utils::Whf getSrcWhf() const;
     /* set plane alpha */
@@ -204,10 +202,6 @@
     mOVInfo.z_order = z;
 }
 
-inline void MdpCtrl::setIsFg(overlay::utils::eIsFg isFg) {
-    mOVInfo.is_fg = isFg;
-}
-
 inline void MdpCtrl::setPlaneAlpha(int planeAlpha) {
     mOVInfo.alpha = planeAlpha;
 }
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index 86e9349..f9ee326 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -309,9 +309,9 @@
         const mdp_overlay& ov) {
     char str[256] = {'\0'};
     snprintf(str, 256,
-            "%s id=%d z=%d fg=%d alpha=%d mask=%d flags=0x%x H.Deci=%d,"
+            "%s id=%d z=%d alpha=%d mask=%d flags=0x%x H.Deci=%d,"
             "V.Deci=%d\n",
-            prefix, ov.id, ov.z_order, ov.is_fg, ov.alpha,
+            prefix, ov.id, ov.z_order, ov.alpha,
             ov.transp_mask, ov.flags, ov.horz_deci, ov.vert_deci);
     strlcat(buf, str, len);
     getDump(buf, len, "\tsrc", ov.src);
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index 4a989f6..2b8e303 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -210,15 +210,6 @@
     ROT_DS_EIGHTH = 3,
 };
 
-/* The values for is_fg flag for control alpha and transp
- * IS_FG_OFF means is_fg = 0
- * IS_FG_SET means is_fg = 1
- */
-enum eIsFg {
-    IS_FG_OFF = 0,
-    IS_FG_SET = 1
-};
-
 /*
  * Various mdp flags like PIPE SHARE, DEINTERLACE etc...
  * kernel/common/linux/msm_mdp.h
@@ -321,19 +312,17 @@
 struct PipeArgs {
     PipeArgs() : mdpFlags(OV_MDP_FLAGS_NONE),
         zorder(Z_SYSTEM_ALLOC),
-        isFg(IS_FG_OFF),
         rotFlags(ROT_FLAGS_NONE),
         planeAlpha(DEFAULT_PLANE_ALPHA),
         blending(OVERLAY_BLENDING_COVERAGE){
     }
 
     PipeArgs(eMdpFlags f, Whf _whf,
-            eZorder z, eIsFg fg, eRotFlags r,
+            eZorder z, eRotFlags r,
             int pA = DEFAULT_PLANE_ALPHA, eBlending b = OVERLAY_BLENDING_COVERAGE) :
         mdpFlags(f),
         whf(_whf),
         zorder(z),
-        isFg(fg),
         rotFlags(r),
         planeAlpha(pA),
         blending(b){
@@ -342,7 +331,6 @@
     eMdpFlags mdpFlags; // for mdp_overlay flags
     Whf whf;
     eZorder zorder; // stage number
-    eIsFg isFg; // control alpha & transp
     eRotFlags rotFlags;
     int planeAlpha;
     eBlending blending;
diff --git a/liboverlay/overlayWriteback.cpp b/liboverlay/overlayWriteback.cpp
index 08af00f..de18e55 100644
--- a/liboverlay/overlayWriteback.cpp
+++ b/liboverlay/overlayWriteback.cpp
@@ -101,8 +101,12 @@
 
 bool Writeback::stopSession() {
     if(mFd.valid()) {
+        if(!Overlay::displayCommit(mFd.getFD())) {
+            ALOGE("%s: displayCommit failed", __func__);
+            return false;
+        }
         if(!mdp_wrapper::wbStopTerminate(mFd.getFD())) {
-            ALOGE("%s failed", __func__);
+            ALOGE("%s: wbStopTerminate failed", __func__);
             return false;
         }
     } else {
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index be7c2aa..108313b 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -29,6 +29,7 @@
 #include <cutils/log.h>
 #include <linux/msm_mdp.h>
 #include "mdp_version.h"
+#include "qd_utils.h"
 
 #define DEBUG 0
 
@@ -146,7 +147,6 @@
 void  MDPVersion::updatePanelInfo() {
     FILE *displayDeviceFP = NULL;
     FILE *panelInfoNodeFP = NULL;
-    const int MAX_FRAME_BUFFER_NAME_SIZE = 128;
     char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
     const char *strCmdPanel = "mipi dsi cmd panel";
     const char *strVideoPanel = "mipi dsi video panel";
diff --git a/libqdutils/qd_utils.cpp b/libqdutils/qd_utils.cpp
index f67de52..5726202 100644
--- a/libqdutils/qd_utils.cpp
+++ b/libqdutils/qd_utils.cpp
@@ -28,11 +28,10 @@
  */
 
 #include "qd_utils.h"
-
-
-#define MAX_FRAME_BUFFER_NAME_SIZE      (80)
 #define QD_UTILS_DEBUG 0
 
+namespace qdutils {
+
 int getHDMINode(void)
 {
     FILE *displayDeviceFP = NULL;
@@ -121,3 +120,4 @@
     rect.bottom = srcHeight + rect.top;
 }
 
+}; //namespace qdutils
diff --git a/libqdutils/qd_utils.h b/libqdutils/qd_utils.h
index a35f255..2124c38 100644
--- a/libqdutils/qd_utils.h
+++ b/libqdutils/qd_utils.h
@@ -44,11 +44,18 @@
 #include <cutils/properties.h>
 #include <hardware/hwcomposer.h>
 
-#define EDID_RAW_DATA_SIZE 640
+namespace qdutils {
+#define EDID_RAW_DATA_SIZE              640
+
+enum qd_utils {
+    MAX_FRAME_BUFFER_NAME_SIZE = 128,
+    MAX_SYSFS_FILE_PATH = 255,
+    SUPPORTED_DOWNSCALE_AREA = (1920*1080)
+};
 
 int getEdidRawData(char *buffer);
 
 void getAspectRatioPosition(int destWidth, int destHeight, int srcWidth,
                                 int srcHeight, hwc_rect_t& rect);
-
+}; //namespace qdutils
 #endif
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index c222eb9..9be04b2 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -65,6 +65,7 @@
         DEBUG_ALL,
         DEBUG_MDPCOMP,
         DEBUG_VSYNC,
+        DEBUG_VD
     };
 
     // Register a client that can be notified
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
index 264d045..44d0603 100644
--- a/libvirtual/virtual.cpp
+++ b/libvirtual/virtual.cpp
@@ -50,14 +50,10 @@
 #include "qd_utils.h"
 
 using namespace android;
+using namespace qdutils;
 
 namespace qhwc {
 
-#define MAX_SYSFS_FILE_PATH             255
-
-/* Max. resolution assignable to virtual display. */
-#define SUPPORTED_VIRTUAL_AREA          (1920*1080)
-
 int VirtualDisplay::configure() {
     if(!openFrameBuffer())
         return -1;
@@ -124,9 +120,9 @@
     // for eg., primary in 1600p and WFD in 1080p
     // we wont use downscale feature because MAX MDP
     // writeback resolution supported is 1080p (tracked
-    // by SUPPORTED_VIRTUAL_AREA).
+    // by SUPPORTED_DOWNSCALE_AREA).
     if((maxArea == (priW * priH))
-        && (maxArea <= SUPPORTED_VIRTUAL_AREA)) {
+        && (maxArea <= SUPPORTED_DOWNSCALE_AREA)) {
         // tmpW and tmpH will hold the primary dimensions before we
         // update the aspect ratio if necessary.
         uint32_t tmpW = priW;
@@ -143,7 +139,7 @@
         // We get around this by calculating a new resolution by
         // keeping aspect ratio intact.
         hwc_rect r = {0, 0, 0, 0};
-        getAspectRatioPosition(tmpW, tmpH, extW, extH, r);
+        qdutils::getAspectRatioPosition(tmpW, tmpH, extW, extH, r);
         extW = r.right - r.left;
         extH = r.bottom - r.top;
     }
@@ -156,13 +152,13 @@
    2. WFD down scale path i.e. when WFD resolution is lower than
       primary resolution.
    Furthermore, downscale mode is only valid when downscaling from
-   SUPPORTED_VIRTUAL_AREA to a lower resolution.
-   (SUPPORTED_VIRTUAL_AREA represents the maximum resolution that
+   SUPPORTED_DOWNSCALE_AREA to a lower resolution.
+   (SUPPORTED_DOWNSCALE_AREA represents the maximum resolution that
    we can configure to the virtual display)
 */
 void VirtualDisplay::setDownScaleMode(uint32_t maxArea) {
     if((maxArea > (mVInfo.xres * mVInfo.yres))
-        && (maxArea <= SUPPORTED_VIRTUAL_AREA)) {
+        && (maxArea <= SUPPORTED_DOWNSCALE_AREA)) {
         mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = true;
     }else {
         mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = false;
@@ -214,7 +210,7 @@
         int fbNum = overlay::Overlay::getInstance()->
                                    getFbForDpy(HWC_DISPLAY_VIRTUAL);
 
-        char strDevPath[MAX_SYSFS_FILE_PATH];
+        char strDevPath[qdutils::MAX_SYSFS_FILE_PATH];
         snprintf(strDevPath,sizeof(strDevPath), "/dev/graphics/fb%d", fbNum);
 
         mFd = open(strDevPath, O_RDWR);