Merge "hwc: disable MDP composition on Secondary display"
diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk
index a879c5c..ef10f54 100644
--- a/libgralloc/Android.mk
+++ b/libgralloc/Android.mk
@@ -27,7 +27,7 @@
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
 LOCAL_SRC_FILES               := gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp
 LOCAL_COPY_HEADERS_TO         := $(common_header_export_path)
-LOCAL_COPY_HEADERS            := gralloc_priv.h
+LOCAL_COPY_HEADERS            := gralloc_priv.h gr.h
 
 include $(BUILD_SHARED_LIBRARY)
 
@@ -41,5 +41,6 @@
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdmemalloc\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
 LOCAL_SRC_FILES               := ionalloc.cpp alloc_controller.cpp
+LOCAL_COPY_HEADERS            := alloc_controller.h memalloc.h
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index f4192c4..da179f9 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -177,6 +177,9 @@
 {
     *bufferType = BUFFER_TYPE_VIDEO;
 
+    if (inputFormat == HAL_PIXEL_FORMAT_RGB_888)
+        return;
+
     if (inputFormat <= HAL_PIXEL_FORMAT_sRGB_X_8888) {
         // RGB formats
         *bufferType = BUFFER_TYPE_UI;
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 7b2092d..72e064e 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -23,7 +23,8 @@
                                  hwc_copybit.cpp  \
                                  hwc_qclient.cpp  \
                                  hwc_dump_layers.cpp \
-                                 hwc_ad.cpp
+                                 hwc_ad.cpp \
+                                 hwc_virtual.cpp
 
 ifeq ($(call is-board-platform-in-list, mpq8092 msm_bronze msm8916), true)
     LOCAL_SRC_FILES += hwc_vpuclient.cpp
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index eb999f7..dcad00b 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -39,6 +39,7 @@
 #include "hwc_ad.h"
 #include "profiler.h"
 #include "hwc_vpuclient.h"
+#include "hwc_virtual.h"
 
 using namespace qhwc;
 using namespace overlay;
@@ -127,15 +128,8 @@
 
     ctx->mAD->reset();
     MDPComp::reset();
-}
-
-//clear prev layer prop flags and realloc for current frame
-static void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) {
-    if(ctx->layerProp[dpy]) {
-       delete[] ctx->layerProp[dpy];
-       ctx->layerProp[dpy] = NULL;
-    }
-    ctx->layerProp[dpy] = new LayerProp[numAppLayers];
+    if(ctx->mHWCVirtual)
+        ctx->mHWCVirtual->destroy(ctx, numDisplays, displays);
 }
 
 static int hwc_prepare_primary(hwc_composer_device_1 *dev,
@@ -193,39 +187,6 @@
     return 0;
 }
 
-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;
-
-    if (LIKELY(list && list->numHwLayers > 1) &&
-            ctx->dpyAttr[dpy].isActive &&
-            ctx->dpyAttr[dpy].connected) {
-        reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
-        if(!ctx->dpyAttr[dpy].isPause) {
-            ctx->dpyAttr[dpy].isConfiguring = false;
-            setListStats(ctx, list, dpy);
-            if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
-                const int fbZ = 0;
-                ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
-            }
-        } else {
-            /* Virtual Display is in Pause state.
-             * Mark all application layers as OVERLAY so that
-             * GPU will not compose.
-             */
-            for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
-                hwc_layer_1_t *layer = &list->hwLayers[i];
-                layer->compositionType = HWC_OVERLAY;
-            }
-        }
-    }
-    return 0;
-}
-
-
 static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
                        hwc_display_contents_1_t** displays)
 {
@@ -256,7 +217,8 @@
                 ret = hwc_prepare_external(dev, list);
                 break;
             case HWC_DISPLAY_VIRTUAL:
-                ret = hwc_prepare_virtual(dev, list);
+                if(ctx->mHWCVirtual)
+                    ret = ctx->mHWCVirtual->prepare(dev, list);
                 break;
             default:
                 ret = -EINVAL;
@@ -439,8 +401,11 @@
         value[0] = 0;
         break;
     case HWC_DISPLAY_TYPES_SUPPORTED:
-        if(ctx->mMDP.hasOverlay)
-            supported |= HWC_DISPLAY_EXTERNAL_BIT;
+        if(ctx->mMDP.hasOverlay) {
+            supported |= HWC_DISPLAY_VIRTUAL_BIT;
+            if(!qdutils::MDPVersion::getInstance().is8x26())
+                supported |= HWC_DISPLAY_EXTERNAL_BIT;
+        }
         value[0] = supported;
         break;
     case HWC_FORMAT_RB_SWAP:
@@ -567,75 +532,6 @@
     return ret;
 }
 
-static int hwc_set_virtual(hwc_context_t *ctx,
-                            hwc_display_contents_1_t* list)
-{
-    ATRACE_CALL();
-    int ret = 0;
-
-    const int dpy = HWC_DISPLAY_VIRTUAL;
-
-
-    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__);
-            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)) {
-            ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
-            ret = -1;
-        }
-    }
-
-    closeAcquireFds(list);
-
-    if (list && !ctx->mVirtualonExtActive && (list->retireFenceFd < 0) ) {
-        // SF assumes HWC waits for the acquire fence and returns a new fence
-        // that signals when we're done. Since we don't wait, and also don't
-        // touch the buffer, we can just handle the acquire fence back to SF
-        // as the retire fence.
-        list->retireFenceFd = list->outbufAcquireFenceFd;
-    }
-
-    return ret;
-}
-
-
 static int hwc_set(hwc_composer_device_1 *dev,
                    size_t numDisplays,
                    hwc_display_contents_1_t** displays)
@@ -653,7 +549,8 @@
                 ret = hwc_set_external(ctx, list);
                 break;
             case HWC_DISPLAY_VIRTUAL:
-                ret = hwc_set_virtual(ctx, list);
+                if(ctx->mHWCVirtual)
+                    ret = ctx->mHWCVirtual->set(ctx, list);
                 break;
             default:
                 ret = -EINVAL;
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index 104ffce..929ccc4 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -157,7 +157,7 @@
         const hwc_display_contents_1_t* list) {
     mDoable = false;
     if(mFeatureEnabled &&
-        !ctx->mExtDisplay->isConnected() &&
+        !isSecondaryConnected(ctx) &&
         ctx->listStats[HWC_DISPLAY_PRIMARY].yuvCount == 1) {
         int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndices[0];
         const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 4600e9d..e84b345 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -413,13 +413,13 @@
         ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
         ret = false;
     } else if(qdutils::MDPVersion::getInstance().is8x26() &&
-            ctx->mVideoTransFlag && ctx->mVirtualDisplay->isConnected()) {
+            ctx->mVideoTransFlag &&
+            isSecondaryConnected(ctx)) {
         //1 Padding round to shift pipes across mixers
         ALOGD_IF(isDebug(),"%s: MDP Comp. video transition padding round",
                 __FUNCTION__);
         ret = false;
-    } else if(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
-              ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring) {
+    } else if(isSecondaryConfiguring(ctx)) {
         ALOGD_IF( isDebug(),"%s: External Display connection is pending",
                   __FUNCTION__);
         ret = false;
@@ -987,11 +987,13 @@
         int& maxBatchCount) {
     int i = 0;
     int fbZOrder =-1;
+    int droppedLayerCt = 0;
     while (i < mCurrentFrame.layerCount) {
         int batchCount = 0;
         int batchStart = i;
         int batchEnd = i;
-        int fbZ = batchStart;
+        /* Adjust batch Z order with the dropped layers so far */
+        int fbZ = batchStart - droppedLayerCt;
         int firstZReverseIndex = -1;
         int updatingLayersAbove = 0;//Updating layer count in middle of batch
         while(i < mCurrentFrame.layerCount) {
@@ -1006,6 +1008,7 @@
             } else {
                 if(mCurrentFrame.drop[i]) {
                     i++;
+                    droppedLayerCt++;
                     continue;
                 } else if(updatingLayersAbove <= 0) {
                     batchCount++;
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 512a120..bc41bd9 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -45,7 +45,7 @@
     virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;
     /* dumpsys */
     void dump(android::String8& buf);
-
+    bool isGLESOnlyComp() { return (mCurrentFrame.mdpCount == 0); }
     static MDPComp* getObject(hwc_context_t *ctx, const int& dpy);
     /* Handler to invoke frame redraw on Idle Timer expiry */
     static void timeout_handler(void *udata);
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index fa021cc..d47e120 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -43,6 +43,7 @@
 #include "hwc_qclient.h"
 #include "QService.h"
 #include "comptype.h"
+#include "hwc_virtual.h"
 
 using namespace qClient;
 using namespace qService;
@@ -170,6 +171,7 @@
     ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
          MDPComp::getObject(ctx, HWC_DISPLAY_PRIMARY);
     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
+    ctx->mHWCVirtual = HWCVirtualBase::getObject();
 
     for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
         ctx->mHwcDebug[i] = new HwcDebug(i);
@@ -259,6 +261,10 @@
             ctx->mLayerRotMap[i] = NULL;
         }
     }
+    if(ctx->mHWCVirtual) {
+        delete ctx->mHWCVirtual;
+        ctx->mHWCVirtual = NULL;
+    }
     if(ctx->mAD) {
         delete ctx->mAD;
         ctx->mAD = NULL;
@@ -1143,12 +1149,19 @@
 }
 
 void closeAcquireFds(hwc_display_contents_1_t* list) {
-    for(uint32_t i = 0; list && i < list->numHwLayers; i++) {
-        //Close the acquireFenceFds
-        //HWC_FRAMEBUFFER are -1 already by SF, rest we close.
-        if(list->hwLayers[i].acquireFenceFd >= 0) {
-            close(list->hwLayers[i].acquireFenceFd);
-            list->hwLayers[i].acquireFenceFd = -1;
+    if(LIKELY(list)) {
+        for(uint32_t i = 0; i < list->numHwLayers; i++) {
+            //Close the acquireFenceFds
+            //HWC_FRAMEBUFFER are -1 already by SF, rest we close.
+            if(list->hwLayers[i].acquireFenceFd >= 0) {
+                close(list->hwLayers[i].acquireFenceFd);
+                list->hwLayers[i].acquireFenceFd = -1;
+            }
+        }
+        //Writeback
+        if(list->outbufAcquireFenceFd >= 0) {
+            close(list->outbufAcquireFenceFd);
+            list->outbufAcquireFenceFd = -1;
         }
     }
 }
@@ -1160,6 +1173,7 @@
     int acquireFd[MAX_NUM_APP_LAYERS];
     int count = 0;
     int releaseFd = -1;
+    int retireFd = -1;
     int fbFd = -1;
     bool swapzero = false;
     int mdpVersion = qdutils::MDPVersion::getInstance().getMDPVersion();
@@ -1168,6 +1182,8 @@
     memset(&data, 0, sizeof(data));
     data.acq_fen_fd = acquireFd;
     data.rel_fen_fd = &releaseFd;
+    data.retire_fen_fd = &retireFd;
+    data.flags = MDP_BUF_SYNC_FLAG_RETIRE_FENCE;
 
     char property[PROPERTY_VALUE_MAX];
     if(property_get("debug.egl.swapinterval", property, "1") > 0) {
@@ -1207,6 +1223,11 @@
     }
 
     //Accumulate acquireFenceFds for MDP
+    if(list->outbufAcquireFenceFd >= 0) {
+        //Writeback output buffer
+        acquireFd[count++] = list->outbufAcquireFenceFd;
+    }
+
     for(uint32_t i = 0; i < list->numHwLayers; i++) {
         if((list->hwLayers[i].compositionType == HWC_OVERLAY  ||
                         list->hwLayers[i].compositionType == HWC_BLIT) &&
@@ -1277,20 +1298,14 @@
 
     //Signals when MDP finishes reading rotator buffers.
     ctx->mLayerRotMap[dpy]->setReleaseFd(releaseFd);
+    close(releaseFd);
+    releaseFd = -1;
 
-    // if external is animating, close the relaseFd
-    if(isExtAnimating) {
-        close(releaseFd);
-        releaseFd = -1;
-    }
-
-    if(UNLIKELY(swapzero)){
+    if(UNLIKELY(swapzero)) {
         list->retireFenceFd = -1;
-        close(releaseFd);
     } else {
-        list->retireFenceFd = releaseFd;
+        list->retireFenceFd = retireFd;
     }
-
     return ret;
 }
 
@@ -1847,7 +1862,7 @@
 
 bool canUseRotator(hwc_context_t *ctx, int dpy) {
     if(qdutils::MDPVersion::getInstance().is8x26() &&
-            ctx->mVirtualDisplay->isConnected() &&
+            isSecondaryConnected(ctx) &&
             !ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) {
         /* 8x26 mdss driver supports multiplexing of DMA pipe
          * in LINE and BLOCK modes for writeback panels.
@@ -1883,6 +1898,15 @@
     return false;
 }
 
+//clear prev layer prop flags and realloc for current frame
+void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers) {
+    if(ctx->layerProp[dpy]) {
+       delete[] ctx->layerProp[dpy];
+       ctx->layerProp[dpy] = NULL;
+    }
+    ctx->layerProp[dpy] = new LayerProp[numAppLayers];
+}
+
 void BwcPM::setBwc(hwc_context_t *ctx, const hwc_rect_t& crop,
             const hwc_rect_t& dst, const int& transform,
             ovutils::eMdpFlags& mdpFlags) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 4a20d47..e64f89c 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -59,6 +59,7 @@
 class HwcDebug;
 class AssertiveDisplay;
 class VPUClient;
+class HWCVirtualBase;
 
 
 struct MDPInfo {
@@ -221,6 +222,8 @@
 bool isAlphaPresent(hwc_layer_1_t const* layer);
 int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable);
 int getBlending(int blending);
+bool isGLESOnlyComp(hwc_context_t *ctx, const int& dpy);
+void reset_layer_prop(hwc_context_t* ctx, int dpy, int numAppLayers);
 
 //Helper function to dump logs
 void dumpsys_log(android::String8& buf, const char* fmt, ...);
@@ -465,6 +468,7 @@
     qhwc::AssertiveDisplay *mAD;
     qhwc::VPUClient *mVPUClient;
     eAnimationState mAnimationState[HWC_NUM_DISPLAY_TYPES];
+    qhwc::HWCVirtualBase *mHWCVirtual;
 
     // stores the primary device orientation
     int deviceOrientation;
@@ -511,6 +515,16 @@
     return ctx->listStats[dpy].isSecurePresent;
 }
 
+static inline bool isSecondaryConfiguring(hwc_context_t* ctx) {
+    return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
+            ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring);
+}
+
+static inline bool isSecondaryConnected(hwc_context_t* ctx) {
+    return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected ||
+            ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected);
+}
+
 };
 
 #endif //HWC_UTILS_H
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
new file mode 100644
index 0000000..51ade32
--- /dev/null
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <fcntl.h>
+#include <errno.h>
+
+#include <cutils/log.h>
+#include <utils/Trace.h>
+#include <overlayWriteback.h>
+#include "hwc_utils.h"
+#include "hwc_fbupdate.h"
+#include "hwc_mdpcomp.h"
+#include "hwc_dump_layers.h"
+#include "hwc_copybit.h"
+#include "hwc_virtual.h"
+
+#define HWCVIRTUAL_LOG 0
+
+using namespace qhwc;
+using namespace overlay;
+
+HWCVirtualBase* HWCVirtualBase::getObject() {
+    char property[PROPERTY_VALUE_MAX];
+
+    if((property_get("persist.hwc.enable_vds", property, NULL) > 0)) {
+        if(atoi(property) != 0) {
+            ALOGD_IF(HWCVIRTUAL_LOG, "%s: VDS is enabled for Virtual display",
+                __FUNCTION__);
+            return new HWCVirtualVDS();
+        }
+    }
+    ALOGD_IF(HWCVIRTUAL_LOG, "%s: V4L2 is enabled for Virtual display",
+            __FUNCTION__);
+    return new HWCVirtualV4L2();
+}
+
+void HWCVirtualVDS::init(hwc_context_t *ctx) {
+    const int dpy = HWC_DISPLAY_VIRTUAL;
+    ctx->mFBUpdate[dpy] =
+            IFBUpdate::getObject(ctx, dpy);
+    ctx->mMDPComp[dpy] =  MDPComp::getObject(ctx, dpy);
+
+    if(ctx->mFBUpdate[dpy])
+        ctx->mFBUpdate[dpy]->reset();
+    if(ctx->mMDPComp[dpy])
+        ctx->mMDPComp[dpy]->reset();
+}
+
+void HWCVirtualVDS::destroy(hwc_context_t *ctx, size_t numDisplays,
+                       hwc_display_contents_1_t** displays) {
+    int dpy = HWC_DISPLAY_VIRTUAL;
+
+    //Cleanup virtual display objs, since there is no explicit disconnect
+    if(ctx->dpyAttr[dpy].connected &&
+        (numDisplays <= HWC_NUM_PHYSICAL_DISPLAY_TYPES ||
+        displays[dpy] == NULL)) {
+        ctx->dpyAttr[dpy].connected = false;
+
+        if(ctx->mFBUpdate[dpy]) {
+            delete ctx->mFBUpdate[dpy];
+            ctx->mFBUpdate[dpy] = NULL;
+        }
+        if(ctx->mMDPComp[dpy]) {
+            delete ctx->mMDPComp[dpy];
+            ctx->mMDPComp[dpy] = NULL;
+        }
+    }
+}
+
+int HWCVirtualVDS::prepare(hwc_composer_device_1 *dev,
+        hwc_display_contents_1_t *list) {
+    ATRACE_CALL();
+    //XXX: Fix when framework support is added
+    hwc_context_t* ctx = (hwc_context_t*)(dev);
+    const int dpy = HWC_DISPLAY_VIRTUAL;
+
+    if (list && list->outbuf && list->numHwLayers > 0) {
+        reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
+        uint32_t last = list->numHwLayers - 1;
+        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+        int fbWidth = 0, fbHeight = 0;
+        getLayerResolution(fbLayer, fbWidth, fbHeight);
+        ctx->dpyAttr[dpy].xres = fbWidth;
+        ctx->dpyAttr[dpy].yres = fbHeight;
+
+        if(ctx->dpyAttr[dpy].connected == false) {
+            ctx->dpyAttr[dpy].connected = true;
+            init(ctx);
+            //First round, just setup and return so primary can free pipes
+            return 0;
+        }
+
+        ctx->dpyAttr[dpy].isConfiguring = false;
+        ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
+        private_handle_t *ohnd = (private_handle_t *)list->outbuf;
+        Writeback::getInstance()->configureDpyInfo(ohnd->width, ohnd->height);
+        setListStats(ctx, list, dpy);
+
+        if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+            const int fbZ = 0;
+            ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
+        }
+    }
+    return 0;
+}
+
+int HWCVirtualVDS::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
+    ATRACE_CALL();
+    int ret = 0;
+    const int dpy = HWC_DISPLAY_VIRTUAL;
+
+    if (list && list->outbuf && list->numHwLayers > 0) {
+        uint32_t last = list->numHwLayers - 1;
+        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+
+        if(fbLayer->handle && !isSecondaryConfiguring(ctx) &&
+                !ctx->mMDPComp[dpy]->isGLESOnlyComp()) {
+            private_handle_t *ohnd = (private_handle_t *)list->outbuf;
+            Writeback::getInstance()->setOutputFormat(
+                                    utils::getMdpFormat(ohnd->format));
+
+            int fd = -1; //FenceFD from the Copybit
+            hwc_sync(ctx, list, dpy, fd);
+
+            if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+                ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+                ret = -1;
+            }
+            if (!ctx->mFBUpdate[dpy]->draw(ctx,
+                        (private_handle_t *)fbLayer->handle)) {
+                ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
+                ret = -1;
+            }
+
+            Writeback::getInstance()->queueBuffer(ohnd->fd, ohnd->offset);
+            if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+                ALOGE("%s: display commit fail!", __FUNCTION__);
+                ret = -1;
+            }
+
+        } else if(list->outbufAcquireFenceFd >= 0) {
+            //If we dont handle the frame, set retireFenceFd to outbufFenceFd,
+            //which will make sure, the framework waits on it and closes it.
+            //The other way is to wait on outbufFenceFd ourselves, close it and
+            //set retireFenceFd to -1. Since we want hwc to be async, choosing
+            //the former.
+            //Also dup because, the closeAcquireFds() will close the outbufFence
+            list->retireFenceFd = dup(list->outbufAcquireFenceFd);
+        }
+    }
+
+    closeAcquireFds(list);
+    return ret;
+}
+
+/* Implementation for HWCVirtualV4L2 class */
+
+int HWCVirtualV4L2::prepare(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;
+
+    if (LIKELY(list && list->numHwLayers > 1) &&
+            ctx->dpyAttr[dpy].isActive &&
+            ctx->dpyAttr[dpy].connected) {
+        reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
+        if(!ctx->dpyAttr[dpy].isPause) {
+            ctx->dpyAttr[dpy].isConfiguring = false;
+            setListStats(ctx, list, dpy);
+            if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+                const int fbZ = 0;
+                ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
+            }
+        } else {
+            /* Virtual Display is in Pause state.
+             * Mark all application layers as OVERLAY so that
+             * GPU will not compose.
+             */
+            for(size_t i = 0 ;i < (size_t)(list->numHwLayers - 1); i++) {
+                hwc_layer_1_t *layer = &list->hwLayers[i];
+                layer->compositionType = HWC_OVERLAY;
+            }
+        }
+    }
+    return 0;
+}
+
+int HWCVirtualV4L2::set(hwc_context_t *ctx, hwc_display_contents_1_t *list) {
+    ATRACE_CALL();
+    int ret = 0;
+
+    const int dpy = HWC_DISPLAY_VIRTUAL;
+
+    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__);
+            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)) {
+            ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
+            ret = -1;
+        }
+    }
+
+    closeAcquireFds(list);
+
+    if (list && !ctx->mVirtualonExtActive && (list->retireFenceFd < 0) ) {
+        // SF assumes HWC waits for the acquire fence and returns a new fence
+        // that signals when we're done. Since we don't wait, and also don't
+        // touch the buffer, we can just handle the acquire fence back to SF
+        // as the retire fence.
+        list->retireFenceFd = list->outbufAcquireFenceFd;
+    }
+
+    return ret;
+}
diff --git a/libhwcomposer/hwc_virtual.h b/libhwcomposer/hwc_virtual.h
new file mode 100644
index 0000000..502aa3b
--- /dev/null
+++ b/libhwcomposer/hwc_virtual.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * Not a Contribution, Apache license notifications and license are retained
+ * for attribution purposes only.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef HWC_VIRTUAL
+#define HWC_VIRTUAL
+
+#include <hwc_utils.h>
+
+namespace qhwc {
+namespace ovutils = overlay::utils;
+
+// Base and abstract class for VDS and V4L2 wfd design.
+class HWCVirtualBase {
+public:
+    explicit HWCVirtualBase(){};
+    virtual ~HWCVirtualBase(){};
+    // instantiates and returns the pointer to VDS or V4L2 object.
+    static HWCVirtualBase* getObject();
+    virtual int prepare(hwc_composer_device_1 *dev,
+                          hwc_display_contents_1_t* list) = 0;
+    virtual int set(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;
+    virtual void init(hwc_context_t *ctx) = 0;
+    virtual void destroy(hwc_context_t *ctx, size_t numDisplays,
+                       hwc_display_contents_1_t** displays) = 0;
+};
+
+class HWCVirtualVDS : public HWCVirtualBase {
+public:
+    explicit HWCVirtualVDS(){};
+    virtual ~HWCVirtualVDS(){};
+    // Chooses composition type and configures pipe for each layer in virtual
+    // display list
+    virtual int prepare(hwc_composer_device_1 *dev,
+                          hwc_display_contents_1_t* list);
+    // Queues the buffer for each layer in virtual display list and call display
+    // commit.
+    virtual int set(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+    // instantiates mdpcomp, copybit and fbupdate objects and initialize those
+    // objects for virtual display during virtual display connect.
+    virtual void init(hwc_context_t *ctx);
+    // Destroys mdpcomp, copybit and fbupdate objects and for virtual display
+    // during virtual display disconnect.
+    virtual void destroy(hwc_context_t *ctx, size_t numDisplays,
+                       hwc_display_contents_1_t** displays);
+};
+
+class HWCVirtualV4L2 : public HWCVirtualBase {
+public:
+    explicit HWCVirtualV4L2(){};
+    virtual ~HWCVirtualV4L2(){};
+    // Chooses composition type and configures pipe for each layer in virtual
+    // display list
+    virtual int prepare(hwc_composer_device_1 *dev,
+                         hwc_display_contents_1_t* list);
+    // Queues the buffer for each layer in virtual display list and call
+    // display commit.
+    virtual int set(hwc_context_t *ctx, hwc_display_contents_1_t *list);
+    // instantiates mdpcomp, copybit and fbupdate objects and initialize those
+    // objects for virtual display during virtual display connect. This function
+    // is no-op for V4L2 design
+    virtual void init(hwc_context_t *ctx) {};
+    // Destroys mdpcomp, copybit and fbupdate objects and for virtual display
+    // during virtual display disconnect. This function is no-op for V4L2 design
+    virtual void destroy(hwc_context_t *ctx, size_t numDisplays,
+                       hwc_display_contents_1_t** displays){};
+};
+
+}; //namespace
+#endif