display: External display refactor

- cleans up external library
- add separate library for virtual display
- process virtual updates in its separate path
  in hwc.
- Acquire blank mutex lock for one complete drawing
  cycle

Change-Id: Ib984c578464a131ecdb27ee48960f58d68b7a5a7
diff --git a/Android.mk b/Android.mk
index b62e45b..afc4e4f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,5 +1,6 @@
-display-hals := libgralloc libgenlock libcopybit liblight
+display-hals := libgralloc libgenlock libcopybit liblight libvirtual
 display-hals += libhwcomposer liboverlay libqdutils libexternal libqservice
+
 ifeq ($(call is-vendor-board-platform,QCOM),true)
     include $(call all-named-subdir-makefiles,$(display-hals))
 else
diff --git a/common.mk b/common.mk
index e8a50c1..13cd6ef 100644
--- a/common.mk
+++ b/common.mk
@@ -6,6 +6,7 @@
 common_includes += hardware/qcom/display/libhwcomposer
 common_includes += hardware/qcom/display/libexternal
 common_includes += hardware/qcom/display/libqservice
+common_includes += hardware/qcom/display/libvirtual
 
 ifeq ($(TARGET_USES_POST_PROCESSING),true)
     common_flags     += -DUSES_POST_PROCESSING
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 97f031d..b247dfb 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -21,8 +21,6 @@
 #define DEBUG 0
 #include <ctype.h>
 #include <fcntl.h>
-#include <media/IAudioPolicyService.h>
-#include <media/AudioSystem.h>
 #include <utils/threads.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
@@ -31,8 +29,6 @@
 #include <video/msm_hdmi_modes.h>
 #include <linux/fb.h>
 #include <sys/ioctl.h>
-#include <sys/poll.h>
-#include <sys/resource.h>
 #include <cutils/properties.h>
 #include "hwc_utils.h"
 #include "external.h"
@@ -42,53 +38,15 @@
 using namespace android;
 
 namespace qhwc {
-
-#define MAX_FRAME_BUFFER_NAME_SIZE      (80)
-#define MAX_DISPLAY_DEVICES             (3)
 #define MAX_SYSFS_FILE_PATH             255
 #define UNKNOWN_STRING                  "unknown"
 #define SPD_NAME_LENGTH                 16
 
-const char* msmFbDevicePath[] = {  "/dev/graphics/fb1",
-                                   "/dev/graphics/fb2"};
-
-/*
- * Updates extDeviceFbIndex Array with the correct frame buffer indices
- * of avaiable external devices
- *
- */
-void ExternalDisplay::updateExtDispDevFbIndex()
-{
-    FILE *displayDeviceFP = NULL;
-    char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
-    char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
-
-    for(int j = 1; j < MAX_DISPLAY_DEVICES; j++) {
-        snprintf (msmFbTypePath, sizeof(msmFbTypePath),
-                  "/sys/class/graphics/fb%d/msm_fb_type", j);
-        displayDeviceFP = fopen(msmFbTypePath, "r");
-        if(displayDeviceFP){
-            fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
-                    displayDeviceFP);
-            if(strncmp(fbType, "dtv panel", strlen("dtv panel")) == 0){
-                ALOGD_IF(DEBUG,"hdmi framebuffer index is %d",j);
-                mHdmiFbNum = j;
-            } else if(strncmp(fbType, "writeback panel",
-                                    strlen("writeback panel")) == 0){
-                ALOGD_IF(DEBUG,"wfd framebuffer index is %d",j);
-                mWfdFbNum = j;
-            }
-            fclose(displayDeviceFP);
-        }
-    }
-    ALOGD_IF(DEBUG,"%s: mHdmiFbNum: %d mWfdFbNum: %d ",__FUNCTION__,
-                                                       mHdmiFbNum, mWfdFbNum);
-}
-
-int ExternalDisplay::configureHDMIDisplay() {
-    openFrameBuffer(mHdmiFbNum);
-    if(mFd == -1)
+int ExternalDisplay::configure() {
+    if(!openFrameBuffer()) {
+        ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum);
         return -1;
+    }
     readCEUnderscanInfo();
     readResolution();
     // TODO: Move this to activate
@@ -101,82 +59,33 @@
         mode = getBestMode();
     }
     setResolution(mode);
-    setDpyHdmiAttr();
-    setExternalDisplay(true, mHdmiFbNum);
+    setAttributes();
     // set system property
     property_set("hw.hdmiON", "1");
     return 0;
 }
 
-int ExternalDisplay::configureWFDDisplay() {
-    int ret = 0;
-    if(mConnectedFbNum == mHdmiFbNum) {
-        ALOGE("%s: Cannot process WFD connection while HDMI is active",
-                     __FUNCTION__);
-        return -1;
-    }
-    openFrameBuffer(mWfdFbNum);
-    if(mFd == -1)
-        return -1;
-    ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
-    if(ret < 0) {
-        ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
-                strerror(errno));
-    }
-    setDpyWfdAttr();
-    setExternalDisplay(true, mWfdFbNum);
+int ExternalDisplay::teardown() {
+    closeFrameBuffer();
+    resetInfo();
+    // unset system property
+    property_set("hw.hdmiON", "0");
     return 0;
 }
 
-int ExternalDisplay::teardownHDMIDisplay() {
-    if(mConnectedFbNum == mHdmiFbNum) {
-        // hdmi offline event..!
-        closeFrameBuffer();
-        resetInfo();
-        setExternalDisplay(false);
-        // unset system property
-        property_set("hw.hdmiON", "0");
-    }
-    return 0;
-}
-
-int ExternalDisplay::teardownWFDDisplay() {
-    if(mConnectedFbNum == mWfdFbNum) {
-        // wfd offline event..!
-        closeFrameBuffer();
-        memset(&mVInfo, 0, sizeof(mVInfo));
-        setExternalDisplay(false);
-    }
-    return 0;
-}
-
-int ExternalDisplay::ignoreRequest(const char *str) {
-    const char *s1 = str + strlen("change@/devices/virtual/switch/");
-    if(!strncmp(s1,"wfd",strlen(s1))) {
-        if(mConnectedFbNum == mHdmiFbNum) {
-            ALOGE("Ignore wfd event when HDMI is active");
-            return true;
-        }
-    }
-    return false;
-}
-
-
 ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1),
-    mCurrentMode(-1), mConnected(0), mConnectedFbNum(0), mModeCount(0),
-    mUnderscanSupported(false), mHwcContext(ctx), mHdmiFbNum(-1),
-    mWfdFbNum(-1), mExtDpyNum(HWC_DISPLAY_EXTERNAL)
+    mCurrentMode(-1), mModeCount(0),
+    mUnderscanSupported(false), mHwcContext(ctx)
 {
     memset(&mVInfo, 0, sizeof(mVInfo));
-    //Determine the fb index for external display devices.
-    updateExtDispDevFbIndex();
+    mFbNum = overlay::Overlay::getInstance()->getFbForDpy(HWC_DISPLAY_EXTERNAL);
     // disable HPD at start, it will be enabled later
     // when the display powers on
     // This helps for framework reboot or adb shell stop/start
     writeHPDOption(0);
 
     // for HDMI - retreive all the modes supported by the driver
-    if(mHdmiFbNum != -1) {
+    if(mFbNum != -1) {
         supported_video_mode_lut =
                         new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX];
         // Populate the mode table for supported modes
@@ -201,7 +110,7 @@
     memset(sysFsSPDFilePath, 0, sizeof(sysFsSPDFilePath));
     snprintf(sysFsSPDFilePath , sizeof(sysFsSPDFilePath),
                  "/sys/devices/virtual/graphics/fb%d/%s",
-                 mHdmiFbNum, node);
+                 mFbNum, node);
     int spdFile = open(sysFsSPDFilePath, O_RDWR, 0);
     if (spdFile < 0) {
         ALOGE("%s: file '%s' not found : ret = %d"
@@ -225,17 +134,6 @@
     }
 }
 
-void ExternalDisplay::setEDIDMode(int resMode) {
-    ALOGD_IF(DEBUG,"resMode=%d ", resMode);
-    {
-        Mutex::Autolock lock(mExtDispLock);
-        setExternalDisplay(false);
-        openFrameBuffer(mHdmiFbNum);
-        setResolution(resMode);
-    }
-    setExternalDisplay(true, mHdmiFbNum);
-}
-
 void ExternalDisplay::setHPD(uint32_t startEnd) {
     ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd);
     writeHPDOption(startEnd);
@@ -243,24 +141,20 @@
 
 void ExternalDisplay::setActionSafeDimension(int w, int h) {
     ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
-    Mutex::Autolock lock(mExtDispLock);
     char actionsafeWidth[PROPERTY_VALUE_MAX];
     char actionsafeHeight[PROPERTY_VALUE_MAX];
     snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w);
     property_set("persist.sys.actionsafe.width", actionsafeWidth);
     snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h);
     property_set("persist.sys.actionsafe.height", actionsafeHeight);
-    setExternalDisplay(true, mHdmiFbNum);
 }
 
 int ExternalDisplay::getModeCount() const {
     ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
-    Mutex::Autolock lock(mExtDispLock);
     return mModeCount;
 }
 
 void ExternalDisplay::getEDIDModes(int *out) const {
-    Mutex::Autolock lock(mExtDispLock);
     for(int i = 0;i < mModeCount;i++) {
         out[i] = mEDIDModes[i];
     }
@@ -277,7 +171,7 @@
     char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH];
     snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath),
             "/sys/devices/virtual/graphics/fb%d/"
-                                   "scan_info", mHdmiFbNum);
+                                   "scan_info", mFbNum);
 
     memset(scanInfo, 0, sizeof(scanInfo));
     hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0);
@@ -397,7 +291,7 @@
 {
     char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH];
     snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath),
-            "/sys/devices/virtual/graphics/fb%d/edid_modes", mHdmiFbNum);
+            "/sys/devices/virtual/graphics/fb%d/edid_modes", mFbNum);
 
     int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0);
     int len = -1;
@@ -431,16 +325,15 @@
     return (strlen(mEDIDs) > 0);
 }
 
-bool ExternalDisplay::openFrameBuffer(int fbNum)
+bool ExternalDisplay::openFrameBuffer()
 {
     if (mFd == -1) {
-        mFd = open(msmFbDevicePath[fbNum-1], O_RDWR);
+        char strDevPath[MAX_SYSFS_FILE_PATH];
+        snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum);
+        mFd = open(strDevPath, O_RDWR);
         if (mFd < 0)
-            ALOGE("%s: %s is not available", __FUNCTION__,
-                                            msmFbDevicePath[fbNum-1]);
-        if(mHwcContext) {
-            mHwcContext->dpyAttr[mExtDpyNum].fd = mFd;
-        }
+            ALOGE("%s: %s is not available", __FUNCTION__, strDevPath);
+        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
     }
     return (mFd > 0);
 }
@@ -452,9 +345,7 @@
         ret = close(mFd);
         mFd = -1;
     }
-    if(mHwcContext) {
-        mHwcContext->dpyAttr[mExtDpyNum].fd = mFd;
-    }
+    mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
     return (ret == 0);
 }
 
@@ -547,7 +438,6 @@
 int ExternalDisplay::getBestMode() {
     int bestOrder = 0;
     int bestMode = HDMI_VFRMT_640x480p60_4_3;
-    Mutex::Autolock lock(mExtDispLock);
     // for all the edid read, get the best mode
     for(int i = 0; i < mModeCount; i++) {
         int mode = mEDIDModes[i];
@@ -644,40 +534,17 @@
     }
 }
 
-void ExternalDisplay::setExternalDisplay(bool connected, int extFbNum)
-{
-    hwc_context_t* ctx = mHwcContext;
-    if(ctx) {
-        ALOGD_IF(DEBUG, "%s: connected = %d", __FUNCTION__, connected);
-        // Store the external display
-        mConnected = connected;
-        mConnectedFbNum = extFbNum;
-        mHwcContext->dpyAttr[mExtDpyNum].connected = connected;
-        // Update external fb number in Overlay context
-        overlay::Overlay::getInstance()->setExtFbNum(extFbNum);
-    }
-}
-
-int ExternalDisplay::getExtFbNum(int &fbNum) {
-    int ret = -1;
-    if(mConnected) {
-        fbNum = mConnectedFbNum;
-        ret = 0;
-    }
-    return ret;
-}
-
 bool ExternalDisplay::writeHPDOption(int userOption) const
 {
     bool ret = true;
-    if(mHdmiFbNum != -1) {
+    if(mFbNum != -1) {
         char sysFsHPDFilePath[MAX_SYSFS_FILE_PATH];
         snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath),
-                 "/sys/devices/virtual/graphics/fb%d/hpd", mHdmiFbNum);
+                 "/sys/devices/virtual/graphics/fb%d/hpd", mFbNum);
         int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0);
         if (hdmiHPDFile < 0) {
-            ALOGE("%s: state file '%s' not found : ret%d err str: %s", __FUNCTION__,
-                  sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
+            ALOGE("%s: state file '%s' not found : ret%d err str: %s",
+                  __FUNCTION__, sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
             ret = false;
         } else {
             int err = -1;
@@ -687,7 +554,8 @@
             else
                 err = write(hdmiHPDFile, "0" , 2);
             if (err <= 0) {
-                ALOGE("%s: file write failed '%s'", __FUNCTION__, sysFsHPDFilePath);
+                ALOGE("%s: file write failed '%s'", __FUNCTION__,
+                      sysFsHPDFilePath);
                 ret = false;
             }
             close(hdmiHPDFile);
@@ -696,26 +564,15 @@
     return ret;
 }
 
-void ExternalDisplay::setDpyWfdAttr() {
-    if(mHwcContext) {
-        mHwcContext->dpyAttr[mExtDpyNum].xres = mVInfo.xres;
-        mHwcContext->dpyAttr[mExtDpyNum].yres = mVInfo.yres;
-        mHwcContext->dpyAttr[mExtDpyNum].vsync_period =
-                1000000000l /60;
-        ALOGD_IF(DEBUG,"%s: wfd...connected..!",__FUNCTION__);
-    }
-}
-
-void ExternalDisplay::setDpyHdmiAttr() {
+void ExternalDisplay::setAttributes() {
     int width = 0, height = 0, fps = 0;
     getAttrForMode(width, height, fps);
-    if(mHwcContext) {
-        ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
-        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
-        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
-        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
-            1000000000l / fps;
-    }
+
+    ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
+    mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
+    mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
+    mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
+        1000000000l / fps;
 }
 
 void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) {
diff --git a/libexternal/external.h b/libexternal/external.h
index 7ab7c3f..2fbb027 100644
--- a/libexternal/external.h
+++ b/libexternal/external.h
@@ -21,7 +21,6 @@
 #ifndef HWC_EXTERNAL_DISPLAY_H
 #define HWC_EXTERNAL_DISPLAY_H
 
-#include <utils/threads.h>
 #include <linux/fb.h>
 
 struct hwc_context_t;
@@ -42,61 +41,45 @@
 public:
     ExternalDisplay(hwc_context_t* ctx);
     ~ExternalDisplay();
-    int getModeCount() const;
-    void getEDIDModes(int *out) const;
-    bool isCEUnderscanSupported() { return mUnderscanSupported; }
-    void setExternalDisplay(bool connected, int extFbNum = 0);
-    bool isExternalConnected() { return mConnected;};
-    void  setExtDpyNum(int extDpyNum) { mExtDpyNum = extDpyNum;};
-    int  getExternalType() {return mConnectedFbNum;};
-    bool isWFDActive() {return (mConnectedFbNum == mWfdFbNum);};
     void setHPD(uint32_t startEnd);
-    void setEDIDMode(int resMode);
     void setActionSafeDimension(int w, int h);
-    int ignoreRequest(const char *str);
-    int  configureHDMIDisplay();
-    int  configureWFDDisplay();
-    int  teardownHDMIDisplay();
-    int  teardownWFDDisplay();
-    int getHDMIIndex() { return mHdmiFbNum; }
+    bool isCEUnderscanSupported() { return mUnderscanSupported; }
+    int configure();
+    int teardown();
+    bool isConnected() {
+        return  mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].connected;
+    }
 
 private:
+    int getModeCount() const;
+    void getEDIDModes(int *out) const;
+    void setEDIDMode(int resMode);
     void setSPDInfo(const char* node, const char* property);
     void readCEUnderscanInfo();
     bool readResolution();
     int  parseResolution(char* edidStr, int* edidModes);
     void setResolution(int ID);
-    bool openFrameBuffer(int fbNum);
+    bool openFrameBuffer();
     bool closeFrameBuffer();
     bool writeHPDOption(int userOption) const;
     bool isValidMode(int ID);
-    void handleUEvent(char* str, int len);
     int  getModeOrder(int mode);
     int  getUserMode();
     int  getBestMode();
     bool isInterlacedMode(int mode);
     void resetInfo();
-    void setDpyHdmiAttr();
-    void setDpyWfdAttr();
+    void setAttributes();
     void getAttrForMode(int& width, int& height, int& fps);
-    void updateExtDispDevFbIndex();
-    int  getExtFbNum(int &fbNum);
 
-    mutable android::Mutex mExtDispLock;
     int mFd;
+    int mFbNum;
     int mCurrentMode;
-    int mConnected;
-    int mConnectedFbNum;
-    int mResolutionMode;
     char mEDIDs[128];
     int mEDIDModes[64];
     int mModeCount;
     bool mUnderscanSupported;
     hwc_context_t *mHwcContext;
     fb_var_screeninfo mVInfo;
-    int mHdmiFbNum;
-    int mWfdFbNum;
-    int mExtDpyNum;
     // Holds all the HDMI modes and timing info supported by driver
     msm_hdmi_mode_timing_info* supported_video_mode_lut;
 };
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 87a7815..d47e4b0 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_SHARED_LIBRARIES        := $(common_libs) libEGL liboverlay \
                                  libexternal libqdutils libhardware_legacy \
                                  libdl libmemalloc libqservice libsync \
-                                 libbinder libmedia libskia
+                                 libbinder libmedia libskia libvirtual
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdhwcomposer\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
 LOCAL_SRC_FILES               := hwc.cpp          \
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 09fef80..558cc29 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -67,6 +67,17 @@
     }
 };
 
+/* In case of proprietary 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) {
+    if(dpy == HWC_DISPLAY_EXTERNAL && ctx->mVirtualonExtActive)
+        return HWC_DISPLAY_VIRTUAL;
+    return dpy;
+}
+
 /*
  * Save callback functions registered to HWC
  */
@@ -125,9 +136,10 @@
     struct mdp_display_commit commit_info;
     memset(&commit_info, 0, sizeof(struct mdp_display_commit));
     commit_info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
-    if(ioctl(ctx->dpyAttr[dpy].fd, MSMFB_DISPLAY_COMMIT, &commit_info) == -1) {
-       ALOGE("%s: MSMFB_DISPLAY_COMMIT for dpy %d failed", __FUNCTION__,dpy);
-       return -errno;
+    if(ioctl(ctx->dpyAttr[dpy].fd, MSMFB_DISPLAY_COMMIT, &commit_info) < 0){
+        ALOGE("%s: MSMFB_DISPLAY_COMMIT for dpy %d failed", __FUNCTION__,
+              dpy);
+        return -errno;
     }
     return 0;
 }
@@ -157,9 +169,9 @@
 }
 
 static int hwc_prepare_external(hwc_composer_device_1 *dev,
-        hwc_display_contents_1_t *list, int dpy) {
-
+        hwc_display_contents_1_t *list) {
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+    const int dpy = HWC_DISPLAY_EXTERNAL;
 
     if (LIKELY(list && list->numHwLayers > 1) &&
             ctx->dpyAttr[dpy].isActive &&
@@ -169,19 +181,13 @@
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         if(!ctx->dpyAttr[dpy].isPause) {
             if(fbLayer->handle) {
-                ctx->mExtDispConfiguring = false;
+                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);
                 }
 
-                /* Temporarily commenting out C2D until we support partial
-                   copybit composition for mixed mode MDP
-
-                if((fbZOrder >= 0) && ctx->mCopyBit[dpy])
-                    ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
-                */
                 if(ctx->listStats[dpy].isDisplayAnimating) {
                     // Mark all app layers as HWC_OVERLAY for external during
                     // animation, so that SF doesnt draw it on FB
@@ -202,12 +208,54 @@
     return 0;
 }
 
+static int hwc_prepare_virtual(hwc_composer_device_1 *dev,
+        hwc_display_contents_1_t *list) {
+
+    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);
+        uint32_t last = list->numHwLayers - 1;
+        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+        if(!ctx->dpyAttr[dpy].isPause) {
+            if(fbLayer->handle) {
+                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);
+                }
+
+                if(ctx->listStats[dpy].isDisplayAnimating) {
+                    // Mark all app layers as HWC_OVERLAY for virtual during
+                    // animation, so that SF doesnt draw it on FB
+                    for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) {
+                        hwc_layer_1_t *layer = &list->hwLayers[i];
+                        layer->compositionType = HWC_OVERLAY;
+                    }
+                }
+            }
+        } else {
+            // Virtual Display is in Pause state.
+            // ToDo:
+            // Mark all application layers as OVERLAY so that
+            // GPU will not compose. This is done for power
+            // optimization
+        }
+    }
+    return 0;
+}
+
+
 static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
                        hwc_display_contents_1_t** displays)
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    Locker::Autolock _bl(ctx->mBlankLock);
+    ctx->mBlankLock.lock();
     //Will be unlocked at the end of set
     ctx->mExtLock.lock();
     reset(ctx, numDisplays, displays);
@@ -220,13 +268,16 @@
 
     for (int32_t i = numDisplays; i >= 0; i--) {
         hwc_display_contents_1_t *list = displays[i];
-        switch(i) {
+        int dpy = getHWCDpy(ctx, i);
+        switch(dpy) {
             case HWC_DISPLAY_PRIMARY:
                 ret = hwc_prepare_primary(dev, list);
                 break;
             case HWC_DISPLAY_EXTERNAL:
+                ret = hwc_prepare_external(dev, list);
+                break;
             case HWC_DISPLAY_VIRTUAL:
-                ret = hwc_prepare_external(dev, list, i);
+                ret = hwc_prepare_virtual(dev, list);
                 break;
             default:
                 ret = -EINVAL;
@@ -278,7 +329,7 @@
     hwc_context_t* ctx = (hwc_context_t*)(dev);
 
     Locker::Autolock _l(ctx->mBlankLock);
-    int ret = 0;
+    int ret = 0, value = 0;
     ALOGD_IF(BLANK_DEBUG, "%s: %s display: %d", __FUNCTION__,
           blank==1 ? "Blanking":"Unblanking", dpy);
     if(blank) {
@@ -291,57 +342,44 @@
         overlay::Writeback::clear();
     }
     switch(dpy) {
-        case HWC_DISPLAY_PRIMARY:
-            if(blank) {
-                ret = ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK,FB_BLANK_POWERDOWN);
+    case HWC_DISPLAY_PRIMARY:
+        value = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK;
+        if(ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, value) < 0 ) {
+            ALOGE("%s: Failed to handle blank event(%d) for Primary!!",
+                  __FUNCTION__, blank );
+            return -1;
+        }
 
-                if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected == true) {
-                    // Surfaceflinger does not send Blank/unblank event to hwc
-                    // for virtual display, handle it explicitly when blank for
-                    // primary is invoked, so that any pipes unset get committed
-                    if (display_commit(ctx, HWC_DISPLAY_VIRTUAL) < 0) {
-                        ret = -1;
-                        ALOGE("%s:post failed for virtual display !!",
-                                                            __FUNCTION__);
-                    } else {
-                        ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
-                    }
-                }
-            } else {
-                ret = ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, FB_BLANK_UNBLANK);
-                if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected == true) {
-                    ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
-                }
-            }
-            break;
-        case HWC_DISPLAY_EXTERNAL:
-            if(blank) {
-                // call external framebuffer commit on blank,
-                // so that any pipe unsets gets committed
-                if (display_commit(ctx, dpy) < 0) {
-                    ret = -1;
-                    ALOGE("%s:post failed for external display !! ",
-                          __FUNCTION__);
-                }
-            } else {
-            }
-            break;
-        default:
-            return -EINVAL;
+        if(!blank) {
+            // Enable HPD here, as during bootup unblank is called
+            // when SF is completely initialized
+            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 */
+
+        if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
+            if(blank)
+                display_commit(ctx, HWC_DISPLAY_VIRTUAL);
+            ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
+        }
+        break;
+    case HWC_DISPLAY_EXTERNAL:
+        if(blank) {
+            display_commit(ctx, HWC_DISPLAY_EXTERNAL);
+        }
+        break;
+    default:
+        return -EINVAL;
     }
-    // Enable HPD here, as during bootup unblank is called
-    // when SF is completely initialized
-    ctx->mExtDisplay->setHPD(1);
-    if(ret == 0){
-        ctx->dpyAttr[dpy].isActive = !blank;
-    } else {
-        ALOGE("%s: Failed in %s display: %d error:%s", __FUNCTION__,
-              blank==1 ? "blanking":"unblanking", dpy, strerror(errno));
-        return ret;
-    }
+
+    ctx->dpyAttr[dpy].isActive = !blank;
 
     ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__,
-          blank==1 ? "blanking":"unblanking", dpy);
+          blank ? "blanking":"unblanking", dpy);
     return 0;
 }
 
@@ -417,11 +455,14 @@
 }
 
 static int hwc_set_external(hwc_context_t *ctx,
-                            hwc_display_contents_1_t* list, int dpy)
+                            hwc_display_contents_1_t* list)
 {
     ATRACE_CALL();
     int ret = 0;
 
+    const int dpy = HWC_DISPLAY_EXTERNAL;
+
+
     if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
         ctx->dpyAttr[dpy].connected) {
 
@@ -474,26 +515,92 @@
     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) {
+        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);
+
+            // 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 (display_commit(ctx, dpy) < 0) {
+            ALOGE("%s: display commit fail!", __FUNCTION__);
+            ret = -1;
+        }
+    }
+
+    closeAcquireFds(list);
+
+    if (list && !ctx->mVirtualonExtActive) {
+        // 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)
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    Locker::Autolock _bl(ctx->mBlankLock);
     for (uint32_t i = 0; i <= numDisplays; i++) {
         hwc_display_contents_1_t* list = displays[i];
-        switch(i) {
+        int dpy = getHWCDpy(ctx, i);
+        switch(dpy) {
             case HWC_DISPLAY_PRIMARY:
                 ret = hwc_set_primary(ctx, list);
                 break;
             case HWC_DISPLAY_EXTERNAL:
+                ret = hwc_set_external(ctx, list);
+                break;
             case HWC_DISPLAY_VIRTUAL:
-            /* ToDo: We are using hwc_set_external path for both External and
-                     Virtual displays on HWC1.1. Eventually, we will have
-                     separate functions when we move to HWC1.2
-            */
-                ret = hwc_set_external(ctx, list, i);
+                ret = hwc_set_virtual(ctx, list);
                 break;
             default:
                 ret = -EINVAL;
@@ -506,6 +613,7 @@
     ctx->mVideoTransFlag = false;
     //Was locked at the beginning of prepare
     ctx->mExtLock.unlock();
+    ctx->mBlankLock.unlock();
     return ret;
 }
 
@@ -513,6 +621,7 @@
         uint32_t* configs, size_t* numConfigs) {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+    disp = getHWCDpy(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) {
@@ -542,8 +651,9 @@
         uint32_t config, const uint32_t* attributes, int32_t* values) {
 
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+    disp = getHWCDpy(ctx, disp);
     //If hotpluggable displays(i.e, HDMI, WFD) are inactive return error
-    if( (disp >= HWC_DISPLAY_EXTERNAL) && !ctx->dpyAttr[disp].connected) {
+    if( (disp != HWC_DISPLAY_PRIMARY) && !ctx->dpyAttr[disp].connected) {
         return -1;
     }
 
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index ef5980c..9ac8958 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -143,7 +143,7 @@
         const hwc_display_contents_1_t* list) {
     mDoable = false;
     if(mFeatureEnabled &&
-        !ctx->mExtDisplay->isExternalConnected() &&
+        !ctx->mExtDisplay->isConnected() &&
         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 31b9645..5c0ad4d 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -20,6 +20,7 @@
 #include "hwc_mdpcomp.h"
 #include <sys/ioctl.h>
 #include "external.h"
+#include "virtual.h"
 #include "qdMetaData.h"
 #include "mdp_version.h"
 #include "hwc_fbupdate.h"
@@ -56,7 +57,8 @@
 {
     Locker::Autolock _l(mMdpCompLock);
     dumpsys_log(buf,"HWC Map for Dpy: %s \n",
-                mDpy ? "\"EXTERNAL\"" : "\"PRIMARY\"");
+                (mDpy == 0) ? "\"PRIMARY\"" :
+                (mDpy == 1) ? "\"EXTERNAL\"" : "\"VIRTUAL\"");
     dumpsys_log(buf,"PREV_FRAME: layerCount:%2d    mdpCount:%2d \
                 cacheCount:%2d \n", mCachedFrame.layerCount,
                 mCachedFrame.mdpCount, mCachedFrame.cacheCount);
@@ -378,13 +380,13 @@
         ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
         ret = false;
     } else if(qdutils::MDPVersion::getInstance().is8x26() &&
-            ctx->mVideoTransFlag &&
-            ctx->mExtDisplay->isExternalConnected()) {
+            ctx->mVideoTransFlag && ctx->mVirtualDisplay->isConnected()) {
         //1 Padding round to shift pipes across mixers
         ALOGD_IF(isDebug(),"%s: MDP Comp. video transition padding round",
                 __FUNCTION__);
         ret = false;
-    } else if(ctx->mExtDispConfiguring) {
+    } else if(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
+              ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring) {
         ALOGD_IF( isDebug(),"%s: External Display connection is pending",
                   __FUNCTION__);
         ret = false;
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index c658224..1d127f0 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -31,6 +31,7 @@
 #include "hwc_copybit.h"
 #include "comptype.h"
 #include "external.h"
+#include "virtual.h"
 #include "mdp_version.h"
 
 namespace qhwc {
@@ -45,22 +46,20 @@
     EXTERNAL_RESUME
 };
 
-static bool isHDMI(const char* str)
-{
-    if(strcasestr("change@/devices/virtual/switch/hdmi", str))
-        return true;
-    return false;
-}
-
-static void setup(hwc_context_t* ctx, int dpy, bool usecopybit)
+static void setup(hwc_context_t* ctx, int dpy)
 {
     const int rSplit = 0; //Even split for external if at all
     ctx->mFBUpdate[dpy] = IFBUpdate::getObject(ctx->dpyAttr[dpy].xres,
             rSplit, dpy);
     ctx->mMDPComp[dpy] =  MDPComp::getObject(ctx->dpyAttr[dpy].xres,
             rSplit, dpy);
-    if(usecopybit)
+    int compositionType =
+                qdutils::QCCompositionType::getInstance().getCompositionType();
+    if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
+                           qdutils::COMPOSITION_TYPE_MDP |
+                           qdutils::COMPOSITION_TYPE_C2D)) {
         ctx->mCopyBit[dpy] = new CopyBit();
+    }
 }
 
 static void clear(hwc_context_t* ctx, int dpy)
@@ -79,183 +78,203 @@
     }
 }
 
+/* Parse uevent data for devices which we are interested */
+static int getConnectedDisplay(const char* strUdata)
+{
+    if(strcasestr("change@/devices/virtual/switch/hdmi", strUdata))
+        return HWC_DISPLAY_EXTERNAL;
+    if(strcasestr("change@/devices/virtual/switch/wfd", strUdata))
+        return HWC_DISPLAY_VIRTUAL;
+    return -1;
+}
+
+/* Parse uevent data for action requested for the display */
+static int getConnectedState(const char* strUdata, int len)
+{
+    const char* iter_str = strUdata;
+    while(((iter_str - strUdata) <= len) && (*iter_str)) {
+        char* pstr = strstr(iter_str, "SWITCH_STATE=");
+        if (pstr != NULL) {
+            return (atoi(pstr + strlen("SWITCH_STATE=")));
+        }
+        iter_str += strlen(iter_str)+1;
+    }
+    return -1;
+}
+
 static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
 {
-    int vsync = 0;
-    int64_t timestamp = 0;
-    const char *str = udata;
-    bool usecopybit = false;
-    int compositionType =
-        qdutils::QCCompositionType::getInstance().getCompositionType();
-
-    if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
-                           qdutils::COMPOSITION_TYPE_MDP |
-                           qdutils::COMPOSITION_TYPE_C2D)) {
-        usecopybit = true;
-    }
-    if(!strcasestr("change@/devices/virtual/switch/hdmi", str) &&
-       !strcasestr("change@/devices/virtual/switch/wfd", str)) {
-        ALOGD_IF(UEVENT_DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__);
+    int dpy = getConnectedDisplay(udata);
+    if(dpy < 0) {
+        ALOGD_IF(UEVENT_DEBUG, "%s: Not disp Event ", __FUNCTION__);
         return;
     }
-    int connected = -1; // initial value - will be set to  1/0 based on hotplug
-    int extDpyNum = HWC_DISPLAY_EXTERNAL;
-    char property[PROPERTY_VALUE_MAX];
-    if((property_get("persist.sys.wfd.virtual", property, NULL) > 0) &&
-            (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
-             (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
-        // This means we are using Google API to trigger WFD Display
-        extDpyNum = HWC_DISPLAY_VIRTUAL;
 
-    }
+    int switch_state = getConnectedState(udata, len);
 
-    int dpy = isHDMI(str) ? HWC_DISPLAY_EXTERNAL : extDpyNum;
+    ALOGE_IF(UEVENT_DEBUG,"%s: uevent recieved: %s switch state: %d",
+             __FUNCTION__,udata, switch_state);
 
-    // parse HDMI/WFD switch state for connect/disconnect
-    // for HDMI:
-    // The event will be of the form:
-    // change@/devices/virtual/switch/hdmi ACTION=change
-    // SWITCH_STATE=1 or SWITCH_STATE=0
-    while(*str) {
-        if (!strncmp(str, "SWITCH_STATE=", strlen("SWITCH_STATE="))) {
-            connected = atoi(str + strlen("SWITCH_STATE="));
-            //Disabled until SF calls unblank
-            ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
-            //Ignored for Virtual Displays
-            //ToDo: we can do this in a much better way
-            ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = true;
-            break;
-        }
-        str += strlen(str) + 1;
-        if (str - udata >= len)
-            break;
-    }
-    ALOGD_IF(UEVENT_DEBUG, "Received str:%s",udata);
-
-    if(connected != EXTERNAL_ONLINE) {
-        if(ctx->mExtDisplay->ignoreRequest(udata)) {
-            ALOGD_IF(UEVENT_DEBUG,"No need to process this connection request"
-                                  "str:%s",udata);
-           ctx->dpyAttr[dpy].isActive = true;
-           return;
-        }
-    }
-
-    // update extDpyNum
-    ctx->mExtDisplay->setExtDpyNum(dpy);
-    switch(connected) {
-        case EXTERNAL_OFFLINE:
-            {   // disconnect event
-                const char *s1 = udata + strlen(HWC_UEVENT_SWITCH_STR);
-                if(!strncmp(s1,"hdmi",strlen(s1))) {
-                    ctx->mExtDisplay->teardownHDMIDisplay();
-                }else if(!strncmp(s1,"wfd",strlen(s1))) {
-                    ctx->mExtDisplay->teardownWFDDisplay();
-                }
-                Locker::Autolock _l(ctx->mExtLock);
-                clear(ctx, dpy);
-                ALOGD("%s sending hotplug: connected = %d and dpy:%d",
-                      __FUNCTION__, connected, dpy);
-                ctx->dpyAttr[dpy].connected = false;
-                //hwc comp could be on
-                ctx->proc->hotplug(ctx->proc, dpy, connected);
+    switch(switch_state) {
+    case EXTERNAL_OFFLINE:
+        {
+            /* Display not connected */
+            if(!ctx->dpyAttr[dpy].connected){
+                ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_OFFLINE event"
+                         "for display: %d", __FUNCTION__, dpy);
                 break;
             }
-        case EXTERNAL_ONLINE:
-            {   // connect case
-                {
-                    //Force composition to give up resources like pipes and
-                    //close fb. For example if assertive display is going on,
-                    //fb2 could be open, thus connecting Layer Mixer#0 to
-                    //WriteBack module. If HDMI attempts to open fb1, the driver
-                    //will try to attach Layer Mixer#0 to HDMI INT, which will
-                    //fail, since Layer Mixer#0 is still connected to WriteBack.
-                    //This block will force composition to close fb2 in above
-                    //example.
-                    Locker::Autolock _l(ctx->mExtLock);
-                    ctx->mExtDispConfiguring = true;
-                    ctx->dpyAttr[dpy].connected = false;
-                    ctx->proc->invalidate(ctx->proc);
-                }
-                //2 cycles for slower content
-                usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
-                        * 2 / 1000);
-                const char *s1 = udata + strlen(HWC_UEVENT_SWITCH_STR);
-                if(!strncmp(s1,"hdmi",strlen(s1))) {
-                    // hdmi online event..!
-                    // check if WFD is configured
-                    if(ctx->mExtDisplay->isWFDActive()) {
-                        ALOGD_IF(UEVENT_DEBUG,"Received HDMI connection request"
-                                "when WFD is active");
-                        // teardown Active WFD Display
-                        ctx->mExtDisplay->teardownWFDDisplay();
+
+            Locker::Autolock _l(ctx->mExtLock);
+            clear(ctx, dpy);
+            ctx->dpyAttr[dpy].connected = false;
+            ctx->dpyAttr[dpy].isActive = false;
+
+            if(dpy == HWC_DISPLAY_EXTERNAL) {
+                ctx->mExtDisplay->teardown();
+            } else {
+                ctx->mVirtualDisplay->teardown();
+            }
+
+            /* We need to send hotplug to SF only when we are disconnecting
+             * (1) HDMI OR (2) proprietary WFD session */
+            if(dpy == HWC_DISPLAY_EXTERNAL ||
+               ctx->mVirtualonExtActive) {
+                ALOGE_IF(UEVENT_DEBUG,"%s:Sending EXTERNAL OFFLINE hotplug"
+                         "event", __FUNCTION__);
+                ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL,
+                                   EXTERNAL_OFFLINE);
+            }
+            break;
+        }
+    case EXTERNAL_ONLINE:
+        {
+            /* Display already connected */
+            if(ctx->dpyAttr[dpy].connected) {
+                ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_ONLINE event"
+                         "for display: %d", __FUNCTION__, dpy);
+                break;
+            }
+            {
+                //Force composition to give up resources like pipes and
+                //close fb. For example if assertive display is going on,
+                //fb2 could be open, thus connecting Layer Mixer#0 to
+                //WriteBack module. If HDMI attempts to open fb1, the driver
+                //will try to attach Layer Mixer#0 to HDMI INT, which will
+                //fail, since Layer Mixer#0 is still connected to WriteBack.
+                //This block will force composition to close fb2 in above
+                //example.
+                Locker::Autolock _l(ctx->mExtLock);
+                ctx->dpyAttr[dpy].isConfiguring = true;
+                ctx->proc->invalidate(ctx->proc);
+            }
+            //2 cycles for slower content
+            usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+                   * 2 / 1000);
+
+            if(dpy == HWC_DISPLAY_EXTERNAL) {
+                if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
+                    ALOGD_IF(UEVENT_DEBUG,"Received HDMI connection request"
+                             "when WFD is active");
+                    {
+                        Locker::Autolock _l(ctx->mExtLock);
+                        clear(ctx, HWC_DISPLAY_VIRTUAL);
+                        ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false;
+                        ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = false;
+                    }
+
+                    ctx->mVirtualDisplay->teardown();
+
+                    /* Need to send hotplug only when connected WFD in
+                     * proprietary path */
+                    if(ctx->mVirtualonExtActive) {
+                        ALOGE_IF(UEVENT_DEBUG,"%s: Sending EXTERNAL OFFLINE"
+                                 "hotplug event", __FUNCTION__);
+                        ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL,
+                                           EXTERNAL_OFFLINE);
                         {
                             Locker::Autolock _l(ctx->mExtLock);
-                            clear(ctx, dpy);
-                            //send hotplug disconnect event
-                            ALOGD_IF(UEVENT_DEBUG, "sending hotplug: disconnect"
-                                    "for WFD");
-                            // hwc comp could be on
-                            ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_OFFLINE);
+                            ctx->mVirtualonExtActive = false;
                         }
-                        //Invalidate
-                        ctx->proc->invalidate(ctx->proc);
-                        //wait for 1 second
-                        ALOGE_IF(UEVENT_DEBUG, "wait for 1 second -- padding"
-                                "round");
-                        sleep(1);
                     }
-                    ctx->mExtDisplay->configureHDMIDisplay();
-                } else if(!strncmp(s1,"wfd",strlen(s1))) {
-                    // wfd online event..!
-                    ctx->mExtDisplay->configureWFDDisplay();
+                    /* Wait for few frames for SF to tear down
+                     * the WFD session. */
+                    usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+                           * 2 / 1000);
                 }
+                ctx->mExtDisplay->configure();
+            } else {
                 {
                     Locker::Autolock _l(ctx->mExtLock);
-                    ctx->dpyAttr[dpy].isPause = false;
-                    setup(ctx, dpy, usecopybit);
-                    ALOGD("%s sending hotplug: connected = %d", __FUNCTION__,
-                            connected);
-                    ctx->dpyAttr[dpy].connected = true;
-                    ctx->proc->hotplug(ctx->proc, dpy, connected);
+                    /* TRUE only when we are on proprietary WFD session */
+                    ctx->mVirtualonExtActive = true;
+                    char property[PROPERTY_VALUE_MAX];
+                    if((property_get("persist.sys.wfd.virtual",
+                                                  property, NULL) > 0) &&
+                       (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+                       (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+                        // This means we are on Google's WFD session
+                        ctx->mVirtualonExtActive = false;
+                    }
                 }
-                break;
+                ctx->mVirtualDisplay->configure();
             }
-        case EXTERNAL_PAUSE:
-            {   // pause case
-                ALOGD("%s Received Pause event",__FUNCTION__);
-                Locker::Autolock _l(ctx->mExtLock);
-                ctx->dpyAttr[dpy].isActive = true;
-                ctx->dpyAttr[dpy].isPause = true;
-                break;
+
+            Locker::Autolock _l(ctx->mExtLock);
+            setup(ctx, dpy);
+            ctx->dpyAttr[dpy].isPause = false;
+            ctx->dpyAttr[dpy].connected = true;
+            ctx->dpyAttr[dpy].isConfiguring = true;
+
+            if(dpy == HWC_DISPLAY_VIRTUAL) {
+                /* 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;
             }
-        case EXTERNAL_RESUME:
-            {  // resume case
-                ALOGD("%s Received resume event",__FUNCTION__);
-                //Treat Resume as Online event
-                //Since external didnt have any pipes, force primary to give up
-                //its pipes; we don't allow inter-mixer pipe transfers.
-                {
-                    Locker::Autolock _l(ctx->mExtLock);
-                    ctx->mExtDispConfiguring = true;
-                    ctx->dpyAttr[dpy].isActive = true;
-                    ctx->proc->invalidate(ctx->proc);
-                }
-                usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
-                        * 2 / 1000);
-                //At this point external has all the pipes it would need.
-                {
-                    Locker::Autolock _l(ctx->mExtLock);
-                    ctx->dpyAttr[dpy].isPause = false;
-                    ctx->proc->invalidate(ctx->proc);
-                }
-                break;
+
+            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);
             }
-        default:
+            break;
+        }
+    case EXTERNAL_PAUSE:
+        {
+            ctx->dpyAttr[dpy].isActive = true;
+            ctx->dpyAttr[dpy].isPause = true;
+            break;
+        }
+    case EXTERNAL_RESUME:
+        {
+            //Treat Resume as Online event
+            //Since external didnt have any pipes, force primary to give up
+            //its pipes; we don't allow inter-mixer pipe transfers.
             {
-                ALOGE("ignore event and connected:%d",connected);
-                break;
+                Locker::Autolock _l(ctx->mExtLock);
+                ctx->dpyAttr[dpy].isConfiguring = true;
+                ctx->dpyAttr[dpy].isActive = true;
+                ctx->proc->invalidate(ctx->proc);
             }
+            usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+                   * 2 / 1000);
+            {
+                //At this point external has all the pipes it  would need.
+                Locker::Autolock _l(ctx->mExtLock);
+                ctx->dpyAttr[dpy].isPause = false;
+                ctx->proc->invalidate(ctx->proc);
+            }
+            break;
+        }
+    default:
+        {
+            ALOGE("%s: Invalid state to swtich:%d", __FUNCTION__, switch_state);
+            break;
+        }
     }
 }
 
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 2c02e5b..0e2eb2e 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -36,6 +36,7 @@
 #include "hwc_copybit.h"
 #include "hwc_dump_layers.h"
 #include "external.h"
+#include "virtual.h"
 #include "hwc_qclient.h"
 #include "QService.h"
 #include "comptype.h"
@@ -152,10 +153,17 @@
     }
 
     ctx->mExtDisplay = new ExternalDisplay(ctx);
+    ctx->mVirtualDisplay = new VirtualDisplay(ctx);
+    ctx->mVirtualonExtActive = false;
+    ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
+    ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = false;
+    ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = false;
+    ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false;
 
     ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
          MDPComp::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres,
                 rightSplit, HWC_DISPLAY_PRIMARY);
+    ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
 
     for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
         ctx->mHwcDebug[i] = new HwcDebug(i);
@@ -167,7 +175,6 @@
 
     ctx->vstate.enable = false;
     ctx->vstate.fakevsync = false;
-    ctx->mExtDispConfiguring = false;
     ctx->mExtOrientation = 0;
 
     //Right now hwc starts the service but anybody could do it, or it could be
@@ -1183,7 +1190,7 @@
 
 bool canUseRotator(hwc_context_t *ctx) {
     if(qdutils::MDPVersion::getInstance().is8x26() &&
-            ctx->mExtDisplay->isExternalConnected()) {
+                       ctx->mVirtualDisplay->isConnected()) {
         return false;
     }
     if(ctx->mMDP.version == qdutils::MDP_V3_0_4)
@@ -1214,7 +1221,7 @@
         return;
     }
     //External connected
-    if(ctx->mExtDisplay->isExternalConnected()) {
+    if(ctx->mExtDisplay->isConnected()|| ctx->mVirtualDisplay->isConnected()) {
         return;
     }
     //Decimation necessary, cannot use BWC. H/W requirement.
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index c4fd345..9a7ef0d 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -50,6 +50,7 @@
 //fwrd decl
 class QueuedBufferStore;
 class ExternalDisplay;
+class VirtualDisplay;
 class IFBUpdate;
 class IVideoOverlay;
 class MDPComp;
@@ -79,6 +80,9 @@
     // In pause state, composition is bypassed
     // used for WFD displays only
     bool isPause;
+    // To trigger padding round to clean up mdp
+    // pipes
+    bool isConfiguring;
 };
 
 struct ListStats {
@@ -315,6 +319,7 @@
     qhwc::IFBUpdate *mFBUpdate[HWC_NUM_DISPLAY_TYPES];
     // External display related information
     qhwc::ExternalDisplay *mExtDisplay;
+    qhwc::VirtualDisplay *mVirtualDisplay;
     qhwc::MDPInfo mMDP;
     qhwc::VsyncState vstate;
     qhwc::DisplayAttributes dpyAttr[HWC_NUM_DISPLAY_TYPES];
@@ -333,8 +338,8 @@
     int mPrevTransformVideo;
     //Securing in progress indicator
     bool mSecuring;
-    //External Display configuring progress indicator
-    bool mExtDispConfiguring;
+    //WFD on proprietary stack
+    bool mVirtualonExtActive;
     //Display in secure mode indicator
     bool mSecureMode;
     //Lock to prevent set from being called while blanking
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index e4da4f7..7189a01 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -29,6 +29,7 @@
 #include "hwc_utils.h"
 #include "string.h"
 #include "external.h"
+#include "overlay.h"
 
 namespace qhwc {
 
@@ -63,7 +64,7 @@
 
     struct pollfd pfd[2];
     int fb_fd[2];
-    uint64_t timestamp[2];
+    uint64_t timestamp[2] = {0,0};
     int num_displays;
 
     char property[PROPERTY_VALUE_MAX];
@@ -77,7 +78,7 @@
             logvsync = true;
     }
 
-    if (ctx->mExtDisplay->getHDMIIndex() > 0)
+    if (ctx->mExtDisplay->isConnected())
         num_displays = 2;
     else
         num_displays = 1;
@@ -87,7 +88,8 @@
         snprintf(vsync_node_path, sizeof(vsync_node_path),
                 "/sys/class/graphics/fb%d/vsync_event",
                 dpy == HWC_DISPLAY_PRIMARY ? 0 :
-                ctx->mExtDisplay->getHDMIIndex());
+                overlay::Overlay::getInstance()->
+                                getFbForDpy(HWC_DISPLAY_EXTERNAL));
         ALOGI("%s: Reading vsync for dpy=%d from %s", __FUNCTION__, dpy,
                 vsync_node_path);
         fb_fd[dpy] = open(vsync_node_path, O_RDONLY);
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index fac0c49..ecd66a6 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -385,7 +385,6 @@
 }
 
 Overlay* Overlay::sInstance = 0;
-int Overlay::sExtFbIndex = 1;
 int Overlay::sDpyFbMap[DPY_MAX] = {0, -1, -1};
 int Overlay::sDMAMode = DMA_LINE_MODE;
 int Overlay::PipeBook::NUM_PIPES = 0;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index 63f5bf1..fea50b3 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -92,11 +92,6 @@
      * displays
      */
     bool isPipeTypeAttached(utils::eMdpPipeType type);
-    /* set the framebuffer index for external display */
-    void setExtFbNum(int fbNum);
-    /* Returns framebuffer index of the current external display */
-    /* TODO Deprecate */
-    int getExtFbNum();
     /* Returns pipe dump. Expects a NULL terminated buffer of big enough size
      * to populate.
      */
@@ -171,8 +166,6 @@
 
     /* Singleton Instance*/
     static Overlay *sInstance;
-    //TODO Deprecate
-    static int sExtFbIndex;
     static int sDpyFbMap[DPY_MAX];
     static int sDMAMode;
 };
@@ -201,14 +194,6 @@
     return avail;
 }
 
-inline void Overlay::setExtFbNum(int fbNum) {
-    sExtFbIndex = fbNum;
-}
-
-inline int Overlay::getExtFbNum() {
-    return sExtFbIndex;
-}
-
 inline void Overlay::setDMAMode(const int& mode) {
     if(mode == DMA_LINE_MODE || mode == DMA_BLOCK_MODE)
         sDMAMode = mode;
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 0de7129..35f686c 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -47,13 +47,10 @@
     ALOGE_IF(DEBUG_OVERLAY, "GenericPipe init");
     mRotDownscaleOpt = false;
 
-    int fbNum = 0;
-    //TODO Remove the if block. What's in else block should be the standard way
-    //EXTERNAL's meaning has been overloaded in hwc to mean WFD also!
-    if(mDpy == Overlay::DPY_EXTERNAL) {
-        fbNum = Overlay::getInstance()->getExtFbNum();
-    } else if(mDpy == Overlay::DPY_WRITEBACK) {
-        fbNum = Overlay::getFbForDpy(mDpy);
+    int fbNum = Overlay::getFbForDpy(mDpy);
+    if( fbNum < 0 ) {
+        ALOGE("%s: Invalid FB for the display: %d",__FUNCTION__, mDpy);
+        return false;
     }
 
     ALOGD_IF(DEBUG_OVERLAY,"%s: mFbNum:%d",__FUNCTION__, fbNum);
diff --git a/libvirtual/Android.mk b/libvirtual/Android.mk
new file mode 100644
index 0000000..1231f8d
--- /dev/null
+++ b/libvirtual/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_MODULE                  := libvirtual
+LOCAL_MODULE_PATH             := $(TARGET_OUT_SHARED_LIBRARIES)
+LOCAL_MODULE_TAGS             := optional
+LOCAL_C_INCLUDES              := $(common_includes) $(kernel_includes)
+LOCAL_SHARED_LIBRARIES        := $(common_libs) liboverlay
+LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdvirtual\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_SRC_FILES               := virtual.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
new file mode 100644
index 0000000..e2f239a
--- /dev/null
+++ b/libvirtual/virtual.cpp
@@ -0,0 +1,128 @@
+/*
+* 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.
+*/
+
+
+#define DEBUG 0
+#include <ctype.h>
+#include <fcntl.h>
+#include <media/IAudioPolicyService.h>
+#include <media/AudioSystem.h>
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <linux/msm_mdp.h>
+#include <linux/fb.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/resource.h>
+#include <cutils/properties.h>
+#include "hwc_utils.h"
+#include "virtual.h"
+#include "overlayUtils.h"
+#include "overlay.h"
+
+using namespace android;
+
+namespace qhwc {
+
+#define MAX_SYSFS_FILE_PATH             255
+
+int VirtualDisplay::configure() {
+    if(!openFrameBuffer())
+        return -1;
+
+    if(ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo) < 0) {
+        ALOGD("%s: FBIOGET_VSCREENINFO failed with %s", __FUNCTION__,
+                strerror(errno));
+        return -1;
+    }
+    setAttributes();
+    return 0;
+}
+
+int VirtualDisplay::teardown() {
+    closeFrameBuffer();
+    memset(&mVInfo, 0, sizeof(mVInfo));
+    return 0;
+}
+
+VirtualDisplay::VirtualDisplay(hwc_context_t* ctx):mFd(-1),
+     mHwcContext(ctx)
+{
+    memset(&mVInfo, 0, sizeof(mVInfo));
+}
+
+VirtualDisplay::~VirtualDisplay()
+{
+    closeFrameBuffer();
+}
+
+void VirtualDisplay::setAttributes() {
+    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = mVInfo.xres;
+    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = mVInfo.yres;
+    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].vsync_period =
+        1000000000l /60;
+    ALOGD_IF(DEBUG,"%s: Setting Virtual Attr: res(%d x %d)",__FUNCTION__,
+             mVInfo.xres, mVInfo.yres);
+}
+
+bool VirtualDisplay::openFrameBuffer()
+{
+    if (mFd == -1) {
+        int fbNum = overlay::Overlay::getInstance()->
+                                   getFbForDpy(HWC_DISPLAY_VIRTUAL);
+
+        char strDevPath[MAX_SYSFS_FILE_PATH];
+        sprintf(strDevPath,"/dev/graphics/fb%d", fbNum);
+
+        mFd = open(strDevPath, O_RDWR);
+        if(mFd < 0) {
+            ALOGE("%s: Unable to open %s ", __FUNCTION__,strDevPath);
+            return -1;
+        }
+
+        mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].fd = mFd;
+    }
+    return 1;
+}
+
+bool VirtualDisplay::closeFrameBuffer()
+{
+    if(mFd >= 0) {
+        if(close(mFd) < 0 ) {
+            ALOGE("%s: Unable to close FD(%d)", __FUNCTION__, mFd);
+            return -1;
+        }
+        mFd = -1;
+        mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].fd = mFd;
+    }
+    return 1;
+}
+};
diff --git a/libvirtual/virtual.h b/libvirtual/virtual.h
new file mode 100644
index 0000000..cd0e7da
--- /dev/null
+++ b/libvirtual/virtual.h
@@ -0,0 +1,61 @@
+/*
+* 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_VIRTUAL_DISPLAY_H
+#define HWC_VIRTUAL_DISPLAY_H
+
+#include <linux/fb.h>
+
+struct hwc_context_t;
+
+namespace qhwc {
+
+class VirtualDisplay
+{
+public:
+    VirtualDisplay(hwc_context_t* ctx);
+    ~VirtualDisplay();
+    int  configure();
+    int  teardown();
+    bool isConnected() {
+        return  mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].connected;
+    }
+private:
+    bool openFrameBuffer();
+    bool closeFrameBuffer();
+    void setAttributes();
+
+    int mFd;
+    hwc_context_t *mHwcContext;
+    fb_var_screeninfo mVInfo;
+};
+}; //qhwc
+// ---------------------------------------------------------------------------
+#endif //HWC_VIRTUAL_DISPLAY_H