hwc: Add support for virtual displays

Add support for virtual displays in hwc.
The availability is detected when a valid list first appears.
Need a valid framebuffer handle to configure writeback based
on aligned dimensions.
Force full GLES virtual layers to go through HWC based on
boardconfig flag.

b/8316155 - Implement HWComposer 1.3 w/ virtual display support
Change-Id: Ice26d47022c8582a6d30503cfa5c918057046320
Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/msm8974/common.mk b/msm8974/common.mk
index 10f6653..0cea0e2 100644
--- a/msm8974/common.mk
+++ b/msm8974/common.mk
@@ -25,6 +25,10 @@
     common_flags += -DMDSS_TARGET
 endif
 
+ifeq ($(TARGET_FORCE_HWC_FOR_VIRTUAL_DISPLAYS), true)
+    common_flags += -DFORCE_HWC_FOR_VIRTUAL_DISPLAYS
+endif
+
 common_deps  :=
 kernel_includes :=
 
diff --git a/msm8974/libhwcomposer/hwc.cpp b/msm8974/libhwcomposer/hwc.cpp
index 5593989..989edb2 100644
--- a/msm8974/libhwcomposer/hwc.cpp
+++ b/msm8974/libhwcomposer/hwc.cpp
@@ -104,6 +104,8 @@
 
         if(ctx->mFBUpdate[i])
             ctx->mFBUpdate[i]->reset();
+        if(ctx->mMDPComp[i])
+            ctx->mMDPComp[i]->reset();
         if(ctx->mCopyBit[i])
             ctx->mCopyBit[i]->reset();
         if(ctx->mLayerRotMap[i])
@@ -173,10 +175,11 @@
 }
 
 static int hwc_prepare_external(hwc_composer_device_1 *dev,
-        hwc_display_contents_1_t *list, int dpy) {
+        hwc_display_contents_1_t *list) {
 
     ATRACE_CALL();
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+    const int dpy = HWC_DISPLAY_EXTERNAL;
 
     if (LIKELY(list && list->numHwLayers > 1) &&
             ctx->dpyAttr[dpy].isActive &&
@@ -213,9 +216,36 @@
 }
 
 static int hwc_prepare_virtual(hwc_composer_device_1 *dev,
-                               hwc_display_contents_1_t *list, int dpy) {
+        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->numHwLayers > 1) {
+        reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
+        uint32_t last = list->numHwLayers - 1;
+        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+        if(fbLayer->handle) {
+            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;
+                setupSecondaryObjs(ctx, dpy);
+            }
+
+            ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
+            Writeback::getInstance()->configureDpyInfo(fbWidth, fbHeight);
+            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;
 }
 
@@ -234,6 +264,14 @@
 
     Overlay::setDMAMode(Overlay::DMA_LINE_MODE);
 
+    //Cleanup virtual display objs, since there is no explicit disconnect
+    if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected &&
+        (numDisplays <= HWC_NUM_PHYSICAL_DISPLAY_TYPES ||
+        displays[HWC_DISPLAY_VIRTUAL] == NULL)) {
+        ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false;
+        clearSecondaryObjs(ctx, HWC_DISPLAY_VIRTUAL);
+    }
+
     for (int32_t i = numDisplays - 1; i >= 0; i--) {
         hwc_display_contents_1_t *list = displays[i];
         switch(i) {
@@ -241,10 +279,10 @@
                 ret = hwc_prepare_primary(dev, list);
                 break;
             case HWC_DISPLAY_EXTERNAL:
-                ret = hwc_prepare_external(dev, list, i);
+                ret = hwc_prepare_external(dev, list);
                 break;
             case HWC_DISPLAY_VIRTUAL:
-                ret = hwc_prepare_virtual(dev, list, i);
+                ret = hwc_prepare_virtual(dev, list);
                 break;
             default:
                 ret = -EINVAL;
@@ -320,8 +358,8 @@
                 // so that any pipe unsets gets committed
                 if (display_commit(ctx, dpy) < 0) {
                     ret = -1;
-                    ALOGE("%s:post failed for external display !! ",
-                          __FUNCTION__);
+                    ALOGE("%s:post failed for dpy %d",
+                          __FUNCTION__, dpy);
                 }
             } else {
             }
@@ -353,9 +391,12 @@
         // Not supported for now
         value[0] = 0;
         break;
-    case HWC_DISPLAY_TYPES_SUPPORTED:
-        if(ctx->mMDP.hasOverlay)
-            supported |= HWC_DISPLAY_EXTERNAL_BIT;
+    case HWC_DISPLAY_TYPES_SUPPORTED: //Unused by f/w
+        if(ctx->mMDP.hasOverlay) {
+            supported |= HWC_DISPLAY_VIRTUAL_BIT;
+            if(!qdutils::MDPVersion::getInstance().is8x26())
+                supported |= HWC_DISPLAY_EXTERNAL_BIT;
+        }
         value[0] = supported;
         break;
     default:
@@ -406,15 +447,16 @@
         }
     }
 
-    closeAcquireFds(list);
+    closeAcquireFds(list, dpy);
     return ret;
 }
 
 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].isPause &&
@@ -452,23 +494,64 @@
         }
     }
 
-    closeAcquireFds(list);
+    closeAcquireFds(list, dpy);
     return ret;
 }
 
 static int hwc_set_virtual(hwc_context_t *ctx,
-                           hwc_display_contents_1_t* list, int dpy)
-{
-    //XXX: Implement set.
-    closeAcquireFds(list);
-    if (list) {
-        // 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;
+        hwc_display_contents_1_t* list) {
+    ATRACE_CALL();
+    int ret = 0;
+    const int dpy = HWC_DISPLAY_VIRTUAL;
+
+    if (list && list->outbuf && list->numHwLayers > 1) {
+        uint32_t last = list->numHwLayers - 1;
+        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+
+        if(fbLayer->handle && ctx->dpyAttr[dpy].connected
+#ifndef FORCE_HWC_FOR_VIRTUAL_DISPLAYS
+                //XXX: If we're not forcing virtual via HWC,
+                //full GLES compositions will not be routed through here.
+                && !isGLESOnlyComp(ctx, dpy)
+#endif
+        ) {
+
+            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 (display_commit(ctx, dpy) < 0) {
+                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);
+        }
     }
-    return 0;
+
+    closeAcquireFds(list, dpy);
+    return ret;
 }
 
 
@@ -485,10 +568,10 @@
                 ret = hwc_set_primary(ctx, list);
                 break;
             case HWC_DISPLAY_EXTERNAL:
-                ret = hwc_set_external(ctx, list, i);
+                ret = hwc_set_external(ctx, list);
                 break;
             case HWC_DISPLAY_VIRTUAL:
-                ret = hwc_set_virtual(ctx, list, i);
+                ret = hwc_set_virtual(ctx, list);
                 break;
             default:
                 ret = -EINVAL;
diff --git a/msm8974/libhwcomposer/hwc_ad.cpp b/msm8974/libhwcomposer/hwc_ad.cpp
index c469d8e..037f931 100644
--- a/msm8974/libhwcomposer/hwc_ad.cpp
+++ b/msm8974/libhwcomposer/hwc_ad.cpp
@@ -34,7 +34,6 @@
 #include <mdp_version.h>
 #include "hwc_ad.h"
 #include "hwc_utils.h"
-#include "external.h"
 
 #define DEBUG 0
 using namespace overlay;
@@ -143,7 +142,7 @@
         const hwc_display_contents_1_t* list) {
     mDoable = false;
     if(mFeatureEnabled &&
-        !ctx->mExtDisplay->isExternalConnected() &&
+        !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/msm8974/libhwcomposer/hwc_mdpcomp.cpp b/msm8974/libhwcomposer/hwc_mdpcomp.cpp
index bbf4a73..53096cc 100644
--- a/msm8974/libhwcomposer/hwc_mdpcomp.cpp
+++ b/msm8974/libhwcomposer/hwc_mdpcomp.cpp
@@ -19,7 +19,6 @@
 #include <math.h>
 #include "hwc_mdpcomp.h"
 #include <sys/ioctl.h>
-#include "external.h"
 #include "qdMetaData.h"
 #include "mdp_version.h"
 #include "hwc_fbupdate.h"
@@ -347,7 +346,7 @@
         ret = false;
     } else if(qdutils::MDPVersion::getInstance().is8x26() &&
             ctx->mVideoTransFlag &&
-            ctx->mExtDisplay->isExternalConnected()) {
+            isSecondaryConnected(ctx)) {
         //1 Padding round to shift pipes across mixers
         ALOGD_IF(isDebug(),"%s: MDP Comp. video transition padding round",
                 __FUNCTION__);
diff --git a/msm8974/libhwcomposer/hwc_mdpcomp.h b/msm8974/libhwcomposer/hwc_mdpcomp.h
index e028cd9..ab8fe48 100644
--- a/msm8974/libhwcomposer/hwc_mdpcomp.h
+++ b/msm8974/libhwcomposer/hwc_mdpcomp.h
@@ -45,6 +45,8 @@
     virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list) = 0;
     /* dumpsys */
     void dump(android::String8& buf);
+    void reset() { mCurrentFrame.reset(0); }
+    int getMDPCompCount() { return mCurrentFrame.mdpCount; }
 
     static MDPComp* getObject(const int& width, const int& rightSplit,
             const int& dpy);
diff --git a/msm8974/libhwcomposer/hwc_utils.cpp b/msm8974/libhwcomposer/hwc_utils.cpp
index 030e28a..d9b3e2a 100644
--- a/msm8974/libhwcomposer/hwc_utils.cpp
+++ b/msm8974/libhwcomposer/hwc_utils.cpp
@@ -583,12 +583,7 @@
 
 }
 
-bool isSecondaryConfiguring(hwc_context_t* ctx) {
-    return (ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring |
-            ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring);
-}
-
-void closeAcquireFds(hwc_display_contents_1_t* list) {
+void closeAcquireFds(hwc_display_contents_1_t* list, int dpy) {
     if(LIKELY(list)) {
         for(uint32_t i = 0; i < list->numHwLayers; i++) {
             //Close the acquireFenceFds
@@ -598,6 +593,12 @@
                 list->hwLayers[i].acquireFenceFd = -1;
             }
         }
+
+        //Writeback
+        if(dpy > HWC_DISPLAY_EXTERNAL && list->outbufAcquireFenceFd >= 0) {
+            close(list->outbufAcquireFenceFd);
+            list->outbufAcquireFenceFd = -1;
+        }
     }
 }
 
@@ -656,6 +657,11 @@
     }
 
     //Accumulate acquireFenceFds for MDP
+    if(dpy > HWC_DISPLAY_EXTERNAL && 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].acquireFenceFd >= 0) {
@@ -1088,7 +1094,7 @@
 
 bool canUseRotator(hwc_context_t *ctx, int dpy) {
     if(qdutils::MDPVersion::getInstance().is8x26() &&
-            ctx->mExtDisplay->isExternalConnected()) {
+            isSecondaryConnected(ctx)) {
         return false;
     }
     if(ctx->mMDP.version == qdutils::MDP_V3_0_4)
@@ -1121,6 +1127,13 @@
                            qdutils::COMPOSITION_TYPE_C2D)) {
         ctx->mCopyBit[dpy] = new CopyBit();
     }
+
+    if(ctx->mFBUpdate[dpy])
+        ctx->mFBUpdate[dpy]->reset();
+    if(ctx->mMDPComp[dpy])
+        ctx->mMDPComp[dpy]->reset();
+    if(ctx->mCopyBit[dpy])
+        ctx->mCopyBit[dpy]->reset();
 }
 
 void clearSecondaryObjs(hwc_context_t *ctx, const int& dpy) {
@@ -1138,6 +1151,13 @@
     }
 }
 
+bool isGLESOnlyComp(hwc_context_t *ctx, const int& dpy) {
+    if(ctx->mMDPComp[dpy]) {
+        return (ctx->mMDPComp[dpy]->getMDPCompCount() == 0);
+    }
+    return true;
+}
+
 void BwcPM::setBwc(hwc_context_t *ctx, const hwc_rect_t& crop,
             const hwc_rect_t& dst, const int& transform,
             ovutils::eMdpFlags& mdpFlags) {
@@ -1149,8 +1169,8 @@
     if((crop.right - crop.left) > qdutils::MAX_DISPLAY_DIM) {
         return;
     }
-    //External connected
-    if(ctx->mExtDisplay->isExternalConnected()) {
+    //Secondary display connected
+    if(isSecondaryConnected(ctx)) {
         return;
     }
     //Decimation necessary, cannot use BWC. H/W requirement.
diff --git a/msm8974/libhwcomposer/hwc_utils.h b/msm8974/libhwcomposer/hwc_utils.h
index 65b3098..03575a7 100644
--- a/msm8974/libhwcomposer/hwc_utils.h
+++ b/msm8974/libhwcomposer/hwc_utils.h
@@ -186,13 +186,11 @@
                               hwc_rect_t& nwr);
 bool isSecuring(hwc_context_t* ctx, hwc_layer_1_t const* layer);
 bool isSecureModePolicy(int mdpVersion);
-//Secondary display hasnt acquired any pipes yet.
-//Secondary stands for external as well as virtual
-bool isSecondaryConfiguring(hwc_context_t* ctx);
 bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer, const int& dpy);
 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);
 
 //Helper function to dump logs
 void dumpsys_log(android::String8& buf, const char* fmt, ...);
@@ -202,7 +200,7 @@
                                         uint32_t& y, uint32_t& w, uint32_t& h);
 
 //Close acquireFenceFds of all layers of incoming list
-void closeAcquireFds(hwc_display_contents_1_t* list);
+void closeAcquireFds(hwc_display_contents_1_t* list, int dpy);
 
 //Sync point impl.
 int hwc_sync(hwc_context_t *ctx, hwc_display_contents_1_t* list, int dpy,
@@ -406,6 +404,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