hwc: Extend pause/resume functionality to VDS displays

Add support to handle pause/resume for virtual displays connected
either using VDS approach.

Change-Id: Iabd01c5597f2399ccc7f83712bda1a2c1103788d
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
index cc29d45..37d87e2 100644
--- a/libhwcomposer/hwc_virtual.cpp
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -69,6 +69,7 @@
     //Cleanup virtual display objs, since there is no explicit disconnect
     if(ctx->dpyAttr[dpy].connected && (displays[dpy] == NULL)) {
         ctx->dpyAttr[dpy].connected = false;
+        ctx->dpyAttr[dpy].isPause = false;
 
         if(ctx->mFBUpdate[dpy]) {
             delete ctx->mFBUpdate[dpy];
@@ -104,6 +105,7 @@
 
         if(ctx->dpyAttr[dpy].connected == false) {
             ctx->dpyAttr[dpy].connected = true;
+            ctx->dpyAttr[dpy].isPause = false;
             // We set the vsync period to the primary refresh rate, leaving
             // it up to the consumer to decide how fast to consume frames.
             ctx->dpyAttr[dpy].vsync_period
@@ -113,16 +115,27 @@
             // allow one padding round to free up resources but this breaks
             // certain use cases.
         }
+        if(!ctx->dpyAttr[dpy].isPause) {
+            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);
 
-        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]->prepareAndValidate(ctx, list, fbZ);
+            if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+                const int fbZ = 0;
+                ctx->mFBUpdate[dpy]->prepareAndValidate(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;
@@ -137,7 +150,9 @@
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
 
-        if(ctx->dpyAttr[dpy].connected) {
+        if(ctx->dpyAttr[dpy].connected
+                && (!ctx->dpyAttr[dpy].isPause))
+        {
             private_handle_t *ohnd = (private_handle_t *)list->outbuf;
             int format = ohnd->format;
             if (format == HAL_PIXEL_FORMAT_RGBA_8888)
@@ -194,6 +209,36 @@
     return ret;
 }
 
+void HWCVirtualVDS::pause(hwc_context_t* ctx, int dpy) {
+    {
+        Locker::Autolock _l(ctx->mDrawLock);
+        ctx->dpyAttr[dpy].isActive = true;
+        ctx->dpyAttr[dpy].isPause = true;
+        ctx->proc->invalidate(ctx->proc);
+    }
+    usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+            * 2 / 1000);
+    return;
+}
+
+void HWCVirtualVDS::resume(hwc_context_t* ctx, int dpy) {
+    {
+        Locker::Autolock _l(ctx->mDrawLock);
+        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->mDrawLock);
+        ctx->dpyAttr[dpy].isPause = false;
+        ctx->proc->invalidate(ctx->proc);
+    }
+    return;
+}
+
 /* Implementation for HWCVirtualV4L2 class */
 
 int HWCVirtualV4L2::prepare(hwc_composer_device_1 *dev,
@@ -294,3 +339,56 @@
 
     return ret;
 }
+
+void HWCVirtualV4L2::pause(hwc_context_t* ctx, int dpy) {
+    {
+        Locker::Autolock _l(ctx->mDrawLock);
+        ctx->dpyAttr[dpy].isActive = true;
+        ctx->dpyAttr[dpy].isPause = true;
+        ctx->proc->invalidate(ctx->proc);
+    }
+    usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+            * 2 / 1000);
+    // At this point all the pipes used by External have been
+    // marked as UNSET.
+    {
+        Locker::Autolock _l(ctx->mDrawLock);
+        // Perform commit to unstage the pipes.
+        if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+            ALOGE("%s: display commit fail! for %d dpy",
+                    __FUNCTION__, dpy);
+        }
+    }
+    return;
+}
+
+void HWCVirtualV4L2::resume(hwc_context_t* ctx, int dpy){
+    //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->mDrawLock);
+
+        // A dynamic resolution change (DRC) can be made for a WiFi
+        // display. In order to support the resolution change, we
+        // need to reconfigure the corresponding display attributes.
+        // Since DRC is only on WiFi display, we only need to call
+        // configure() on the VirtualDisplay device.
+        //TODO: clean up
+        if(dpy == HWC_DISPLAY_VIRTUAL)
+            ctx->mVirtualDisplay->configure();
+
+        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->mDrawLock);
+        ctx->dpyAttr[dpy].isPause = false;
+        ctx->proc->invalidate(ctx->proc);
+    }
+    return;
+}