Merge "hwc: Allow HWC to support Virtual Display"
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 883a39f..839d79a 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -168,11 +168,13 @@
 
 ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1),
     mCurrentMode(-1), mConnected(0), mConnectedFbNum(0), mModeCount(0),
-     mUnderscanSupported(false), mHwcContext(ctx), mHdmiFbNum(-1), mWfdFbNum(-1)
+    mUnderscanSupported(false), mHwcContext(ctx), mHdmiFbNum(-1),
+    mWfdFbNum(-1), mExtDpyNum(HWC_DISPLAY_EXTERNAL)
 {
     memset(&mVInfo, 0, sizeof(mVInfo));
     //Determine the fb index for external display devices.
     updateExtDispDevFbIndex();
+
 }
 
 void ExternalDisplay::setEDIDMode(int resMode) {
@@ -441,7 +443,7 @@
             ALOGE("%s: %s is not available", __FUNCTION__,
                                             msmFbDevicePath[fbNum-1]);
         if(mHwcContext) {
-            mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
+            mHwcContext->dpyAttr[mExtDpyNum].fd = mFd;
         }
     }
     return (mFd > 0);
@@ -455,7 +457,7 @@
         mFd = -1;
     }
     if(mHwcContext) {
-        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
+        mHwcContext->dpyAttr[mExtDpyNum].fd = mFd;
     }
     return (ret == 0);
 }
@@ -639,7 +641,7 @@
         // Store the external display
         mConnected = connected;
         mConnectedFbNum = extFbNum;
-        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = connected;
+        mHwcContext->dpyAttr[mExtDpyNum].connected = connected;
         // Update external fb number in Overlay context
         overlay::Overlay::getInstance()->setExtFbNum(extFbNum);
     }
@@ -688,6 +690,7 @@
 {
     if(mFd == -1)
         return false;
+
     struct mdp_display_commit ext_commit;
     memset(&ext_commit, 0, sizeof(struct mdp_display_commit));
     ext_commit.flags = MDP_DISPLAY_COMMIT_OVERLAY;
@@ -701,9 +704,9 @@
 
 void ExternalDisplay::setDpyWfdAttr() {
     if(mHwcContext) {
-        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = mVInfo.xres;
-        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = mVInfo.yres;
-        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
+        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__);
     }
diff --git a/libexternal/external.h b/libexternal/external.h
index baf3598..39f8645 100644
--- a/libexternal/external.h
+++ b/libexternal/external.h
@@ -46,6 +46,7 @@
     bool isCEUnderscanSupported() { return mUnderscanSupported; }
     void setExternalDisplay(bool connected, int extFbNum = 0);
     bool isExternalConnected() { return mConnected;};
+    void  setExtDpyNum(int extDpyNum) { mExtDpyNum = extDpyNum;};
     bool post();
     void setHPD(uint32_t startEnd);
     void setEDIDMode(int resMode);
@@ -92,6 +93,7 @@
     fb_var_screeninfo mVInfo;
     int mHdmiFbNum;
     int mWfdFbNum;
+    int mExtDpyNum;
 };
 
 }; //qhwc
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 187ec4a..519126f 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -84,7 +84,7 @@
 static void reset(hwc_context_t *ctx, int numDisplays,
                   hwc_display_contents_1_t** displays) {
     memset(ctx->listStats, 0, sizeof(ctx->listStats));
-    for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++){
+    for(int i = 0; i < MAX_DISPLAYS; i++) {
         hwc_display_contents_1_t *list = displays[i];
         // XXX:SurfaceFlinger no longer guarantees that this
         // value is reset on every prepare. However, for the layer
@@ -148,25 +148,31 @@
 }
 
 static int hwc_prepare_external(hwc_composer_device_1 *dev,
-        hwc_display_contents_1_t *list) {
+        hwc_display_contents_1_t *list, int dpy) {
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    const int dpy = HWC_DISPLAY_EXTERNAL;
 
     if (LIKELY(list && list->numHwLayers > 1) &&
         ctx->dpyAttr[dpy].isActive &&
         ctx->dpyAttr[dpy].connected) {
-
         uint32_t last = list->numHwLayers - 1;
-        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
-        if(fbLayer->handle) {
-            setListStats(ctx, list, dpy);
-            reset_layer_prop(ctx, dpy);
-            VideoOverlay::prepare(ctx, list, dpy);
-            ctx->mFBUpdate[dpy]->prepare(ctx, fbLayer);
-            ctx->mLayerCache[dpy]->updateLayerCache(list);
-            if(ctx->mCopyBit[dpy])
-                ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
-            ctx->mExtDispConfiguring = false;
+        if(!ctx->dpyAttr[dpy].isPause) {
+            hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+            if(fbLayer->handle) {
+                setListStats(ctx, list, dpy);
+                reset_layer_prop(ctx, dpy);
+                VideoOverlay::prepare(ctx, list, dpy);
+                ctx->mFBUpdate[dpy]->prepare(ctx, fbLayer);
+                ctx->mLayerCache[dpy]->updateLayerCache(list);
+                if(ctx->mCopyBit[dpy])
+                    ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
+                ctx->mExtDispConfiguring = false;
+            }
+        } else {
+            // External 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;
@@ -182,14 +188,15 @@
 
     ctx->mOverlay->configBegin();
 
-    for (int32_t i = numDisplays - 1; i >= 0; i--) {
+    for (int32_t i = numDisplays; i >= 0; i--) {
         hwc_display_contents_1_t *list = displays[i];
         switch(i) {
             case HWC_DISPLAY_PRIMARY:
                 ret = hwc_prepare_primary(dev, list);
                 break;
             case HWC_DISPLAY_EXTERNAL:
-                ret = hwc_prepare_external(dev, list);
+            case HWC_DISPLAY_VIRTUAL:
+                ret = hwc_prepare_external(dev, list, i);
                 break;
             default:
                 ret = -EINVAL;
@@ -244,8 +251,9 @@
             }
             break;
         case HWC_DISPLAY_EXTERNAL:
+        case HWC_DISPLAY_VIRTUAL:
             if(blank) {
-                // External Display post commits the changes to display
+                // External/Virtual Display post commits the changes to display
                 // Call this on blank, so that any pipe unsets gets committed
                 if (!ctx->mExtDisplay->post()) {
                     ret = -1;
@@ -342,13 +350,12 @@
 }
 
 static int hwc_set_external(hwc_context_t *ctx,
-        hwc_display_contents_1_t* list) {
+        hwc_display_contents_1_t* list, int dpy) {
     int ret = 0;
-    const int dpy = HWC_DISPLAY_EXTERNAL;
-
     Locker::Autolock _l(ctx->mExtSetLock);
 
     if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
+        !ctx->dpyAttr[dpy].isPause &&
         ctx->dpyAttr[dpy].connected) {
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
@@ -388,14 +395,19 @@
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
     Locker::Autolock _l(ctx->mBlankLock);
-    for (uint32_t i = 0; i < numDisplays; i++) {
+    for (uint32_t i = 0; i <= numDisplays; i++) {
         hwc_display_contents_1_t* list = displays[i];
         switch(i) {
             case HWC_DISPLAY_PRIMARY:
                 ret = hwc_set_primary(ctx, list);
                 break;
             case HWC_DISPLAY_EXTERNAL:
-                ret = hwc_set_external(ctx, list);
+            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);
                 break;
             default:
                 ret = -EINVAL;
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 6b8f4e3..752aaa2 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -35,6 +35,21 @@
 
 #define HWC_UEVENT_THREAD_NAME "hwcUeventThread"
 
+/* External Display states */
+enum {
+    EXTERNAL_OFFLINE = 0,
+    EXTERNAL_ONLINE,
+    EXTERNAL_PAUSE,
+    EXTERNAL_RESUME
+};
+
+static bool isHDMI(const char* str)
+{
+    if(strcasestr("change@/devices/virtual/switch/hdmi", str))
+        return true;
+    return false;
+}
+
 static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
 {
     int vsync = 0;
@@ -48,7 +63,6 @@
                            qdutils::COMPOSITION_TYPE_MDP |
                            qdutils::COMPOSITION_TYPE_C2D)) {
         usecopybit = true;
-
     }
 
     if(!strcasestr("change@/devices/virtual/switch/hdmi", str) &&
@@ -56,19 +70,35 @@
         ALOGD_IF(UEVENT_DEBUG, "%s: Not Ext 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 dpy = isHDMI(str) ? HWC_DISPLAY_EXTERNAL : extDpyNum;
+
+    // update extDpyNum
+    ctx->mExtDisplay->setExtDpyNum(dpy);
+
     // 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;
@@ -76,32 +106,63 @@
             break;
     }
 
-    if(connected != -1) { //either we got switch_state connected or disconnect
-        ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = connected;
-        if (connected) {
-            ctx->mExtDispConfiguring = true;
-            ctx->mExtDisplay->processUEventOnline(udata);
-            ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL] =
-                IFBUpdate::getObject(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].xres,
-                HWC_DISPLAY_EXTERNAL);
-            if(usecopybit)
-                ctx->mCopyBit[HWC_DISPLAY_EXTERNAL] = new CopyBit();
-        } else {
-            ctx->mExtDisplay->processUEventOffline(udata);
-            if(ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL]) {
+    switch(connected) {
+        case EXTERNAL_OFFLINE:
+            {   // disconnect event
+                ctx->mExtDisplay->processUEventOffline(udata);
+                if(ctx->mFBUpdate[dpy]) {
+                    Locker::Autolock _l(ctx->mExtSetLock);
+                    delete ctx->mFBUpdate[dpy];
+                    ctx->mFBUpdate[dpy] = NULL;
+                }
+                if(ctx->mCopyBit[dpy]){
+                    Locker::Autolock _l(ctx->mExtSetLock);
+                    delete ctx->mCopyBit[dpy];
+                    ctx->mCopyBit[dpy] = NULL;
+                }
+                ALOGD("%s sending hotplug: connected = %d and dpy:%d",
+                      __FUNCTION__, connected, dpy);
+                ctx->dpyAttr[dpy].connected = false;
                 Locker::Autolock _l(ctx->mExtSetLock);
-                delete ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL];
-                ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL] = NULL;
+                //hwc comp could be on
+                ctx->proc->hotplug(ctx->proc, dpy, connected);
+                break;
             }
-            if(ctx->mCopyBit[HWC_DISPLAY_EXTERNAL]){
-                Locker::Autolock _l(ctx->mExtSetLock);
-                delete ctx->mCopyBit[HWC_DISPLAY_EXTERNAL];
-                ctx->mCopyBit[HWC_DISPLAY_EXTERNAL] = NULL;
+        case EXTERNAL_ONLINE:
+            {   // connect case
+                ctx->mExtDispConfiguring = true;
+                ctx->mExtDisplay->processUEventOnline(udata);
+                ctx->mFBUpdate[dpy] =
+                        IFBUpdate::getObject(ctx->dpyAttr[dpy].xres, dpy);
+                ctx->dpyAttr[dpy].isPause = false;
+                if(usecopybit)
+                    ctx->mCopyBit[dpy] = new CopyBit();
+                ALOGD("%s sending hotplug: connected = %d", __FUNCTION__,
+                        connected);
+                ctx->dpyAttr[dpy].connected = true;
+                Locker::Autolock _l(ctx->mExtSetLock); //hwc comp could be on
+                ctx->proc->hotplug(ctx->proc, dpy, connected);
+                break;
             }
-        }
-        ALOGD("%s sending hotplug: connected = %d", __FUNCTION__, connected);
-        Locker::Autolock _l(ctx->mExtSetLock); //hwc comp could be on
-        ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL, connected);
+        case EXTERNAL_PAUSE:
+            {   // pause case
+                ALOGD("%s Received Pause event",__FUNCTION__);
+                ctx->dpyAttr[dpy].isActive = true;
+                ctx->dpyAttr[dpy].isPause = true;
+                break;
+            }
+        case EXTERNAL_RESUME:
+            {  // resume case
+                ALOGD("%s Received resume event",__FUNCTION__);
+                ctx->dpyAttr[dpy].isActive = true;
+                ctx->dpyAttr[dpy].isPause = false;
+                break;
+            }
+        default:
+            {
+                ALOGE("ignore event and connected:%d",connected);
+                break;
+            }
     }
 }
 
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index e7c60d6..fe3401b 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -90,7 +90,7 @@
     }
 
     ctx->mExtDisplay = new ExternalDisplay(ctx);
-    for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++)
+    for (uint32_t i = 0; i < MAX_DISPLAYS; i++)
         ctx->mLayerCache[i] = new LayerCache();
     ctx->mMDPComp = MDPComp::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres);
     MDPComp::init(ctx);
@@ -119,7 +119,7 @@
         ctx->mOverlay = NULL;
     }
 
-    for(int i = 0; i< HWC_NUM_DISPLAY_TYPES; i++) {
+    for(int i = 0; i < MAX_DISPLAYS; i++) {
         if(ctx->mCopyBit[i]) {
             delete ctx->mCopyBit[i];
             ctx->mCopyBit[i] = NULL;
@@ -138,7 +138,7 @@
         ctx->mExtDisplay = NULL;
     }
 
-    for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+    for(int i = 0; i < MAX_DISPLAYS; i++) {
         if(ctx->mFBUpdate[i]) {
             delete ctx->mFBUpdate[i];
             ctx->mFBUpdate[i] = NULL;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 525fd75..045ef7f 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -36,6 +36,10 @@
 #define MAX_NUM_LAYERS 32
 #define MAX_DISPLAY_DIM 2048
 
+// For support of virtual displays
+#define HWC_DISPLAY_VIRTUAL     (HWC_DISPLAY_EXTERNAL+1)
+#define MAX_DISPLAYS            (HWC_NUM_DISPLAY_TYPES+1)
+
 //Fwrd decls
 struct hwc_context_t;
 struct framebuffer_device_t;
@@ -70,6 +74,9 @@
     //Connected does not mean it ready to use.
     //It should be active also. (UNBLANKED)
     bool isActive;
+    // In pause state, composition is bypassed
+    // used for WFD displays only
+    bool isPause;
 };
 
 struct ListStats {
@@ -221,20 +228,20 @@
     framebuffer_device_t *mFbDev;
 
     //CopyBit objects
-    qhwc::CopyBit *mCopyBit[HWC_NUM_DISPLAY_TYPES];
+    qhwc::CopyBit *mCopyBit[MAX_DISPLAYS];
 
     //Overlay object - NULL for non overlay devices
     overlay::Overlay *mOverlay;
 
     //Primary and external FB updater
-    qhwc::IFBUpdate *mFBUpdate[HWC_NUM_DISPLAY_TYPES];
+    qhwc::IFBUpdate *mFBUpdate[MAX_DISPLAYS];
     // External display related information
     qhwc::ExternalDisplay *mExtDisplay;
     qhwc::MDPInfo mMDP;
-    qhwc::DisplayAttributes dpyAttr[HWC_NUM_DISPLAY_TYPES];
-    qhwc::ListStats listStats[HWC_NUM_DISPLAY_TYPES];
-    qhwc::LayerCache *mLayerCache[HWC_NUM_DISPLAY_TYPES];
-    qhwc::LayerProp *layerProp[HWC_NUM_DISPLAY_TYPES];
+    qhwc::DisplayAttributes dpyAttr[MAX_DISPLAYS];
+    qhwc::ListStats listStats[MAX_DISPLAYS];
+    qhwc::LayerCache *mLayerCache[MAX_DISPLAYS];
+    qhwc::LayerProp *layerProp[MAX_DISPLAYS];
     qhwc::MDPComp *mMDPComp;
 
     //Securing in progress indicator
diff --git a/libhwcomposer/hwc_video.h b/libhwcomposer/hwc_video.h
index 3612018..93cdaa5 100644
--- a/libhwcomposer/hwc_video.h
+++ b/libhwcomposer/hwc_video.h
@@ -45,12 +45,12 @@
     //Marks layer flags if this feature is used
     static void markFlags(hwc_layer_1_t *yuvLayer);
     //Flags if this feature is on.
-    static bool sIsModeOn[HWC_NUM_DISPLAY_TYPES];
-    static ovutils::eDest sDest[HWC_NUM_DISPLAY_TYPES];
+    static bool sIsModeOn[MAX_DISPLAYS];
+    static ovutils::eDest sDest[MAX_DISPLAYS];
 };
 
 inline void VideoOverlay::reset() {
-    for(uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+    for(uint32_t i = 0; i < MAX_DISPLAYS; i++) {
         sIsModeOn[i] = false;
         sDest[i] = ovutils::OV_INVALID;
     }