hwc: vds: Add support to dump layers, FB and WB output buffer

1. Add hook to dump the layers going to VDS based virtual display.

2. Furthermore, add utility function to dump the frame buffer and
   WB output buffer. This will be enabled via a system property

   debug.hwc.enable_vds_dump

   Once dumping is enabled, the dumps can be extracted from

   /data/vds.fb.FORMAT.XRESxYRES.raw
   /data/vds.wb.FORMAT.XRESxYRES.raw

   e.g. vds.fb.MDP_RGBA_8888.1152x1920.raw

Change-Id: I2435c5507961a52929411206892c005492d5c193
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 4708368..59e39bb 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -2080,6 +2080,24 @@
     return true;
 }
 
+void dumpBuffer(private_handle_t *ohnd, char *bufferName) {
+    if (ohnd != NULL && ohnd->base) {
+        char dumpFilename[PATH_MAX];
+        bool bResult = false;
+        snprintf(dumpFilename, sizeof(dumpFilename), "/data/%s.%s.%dx%d.raw",
+            bufferName,
+            overlay::utils::getFormatString(utils::getMdpFormat(ohnd->format)),
+            getWidth(ohnd), getHeight(ohnd));
+        FILE* fp = fopen(dumpFilename, "w+");
+        if (NULL != fp) {
+            bResult = (bool) fwrite((void*)ohnd->base, ohnd->size, 1, fp);
+            fclose(fp);
+        }
+        ALOGD("Buffer[%s] Dump to %s: %s",
+        bufferName, dumpFilename, bResult ? "Success" : "Fail");
+    }
+}
+
 bool isGLESComp(hwc_context_t *ctx,
                      hwc_display_contents_1_t* list) {
     int numAppLayers = ctx->listStats[HWC_DISPLAY_PRIMARY].numAppLayers;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index c7b7ded..5086d72 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -257,6 +257,7 @@
 
 bool canUseMDPforVirtualDisplay(hwc_context_t* ctx,
                                 const hwc_display_contents_1_t *list);
+void dumpBuffer(private_handle_t *ohnd, char *bufferName);
 
 //Helper function to dump logs
 void dumpsys_log(android::String8& buf, const char* fmt, ...);
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
index adda35b..01c0873 100644
--- a/libhwcomposer/hwc_virtual.cpp
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -29,6 +29,7 @@
 #include "hwc_dump_layers.h"
 #include "hwc_copybit.h"
 #include "hwc_virtual.h"
+#include "sync/sync.h"
 
 #define HWCVIRTUAL_LOG 0
 
@@ -48,6 +49,16 @@
     }
 }
 
+HWCVirtualVDS::HWCVirtualVDS() {
+    char value[PROPERTY_VALUE_MAX];
+    mVDSDumpEnabled = false;
+    if((property_get("debug.hwc.enable_vds_dump", value, NULL) > 0)) {
+        if(atoi(value) != 0) {
+            mVDSDumpEnabled = true;
+        }
+    }
+}
+
 void HWCVirtualVDS::init(hwc_context_t *ctx) {
     const int dpy = HWC_DISPLAY_VIRTUAL;
     ctx->mFBUpdate[dpy] =
@@ -178,6 +189,10 @@
             int fd = -1; //FenceFD from the Copybit
             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;
@@ -201,6 +216,19 @@
                 ret = -1;
             }
 
+            if(mVDSDumpEnabled) {
+                char bufferName[128];
+                // Dumping frame buffer
+                sync_wait(fbLayer->acquireFenceFd, 1000);
+                snprintf(bufferName, sizeof(bufferName), "vds.fb");
+                dumpBuffer((private_handle_t *)fbLayer->handle, bufferName);
+                // Dumping WB output for non-secure session
+                if(!isSecureBuffer(ohnd)) {
+                    sync_wait(list->retireFenceFd, 1000);
+                    snprintf(bufferName, sizeof(bufferName), "vds.wb");
+                    dumpBuffer(ohnd, bufferName);
+                }
+            }
         } 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.
diff --git a/libhwcomposer/hwc_virtual.h b/libhwcomposer/hwc_virtual.h
index 87004c3..26d89c9 100644
--- a/libhwcomposer/hwc_virtual.h
+++ b/libhwcomposer/hwc_virtual.h
@@ -46,7 +46,7 @@
 
 class HWCVirtualVDS : public HWCVirtualBase {
 public:
-    explicit HWCVirtualVDS(){};
+    explicit HWCVirtualVDS();
     virtual ~HWCVirtualVDS(){};
     // Chooses composition type and configures pipe for each layer in virtual
     // display list
@@ -64,6 +64,12 @@
                        hwc_display_contents_1_t** displays);
     virtual void pause(hwc_context_t* ctx, int dpy);
     virtual void resume(hwc_context_t* ctx, int dpy);
+private:
+    // If WFD is enabled through VDS solution
+    // we can dump the frame buffer and WB
+    // output buffer by setting the property
+    // debug.hwc.enable_vds_dump
+    bool mVDSDumpEnabled;
 };
 
 class HWCVirtualV4L2 : public HWCVirtualBase {