overlay: Add writeback support

Add explicit writeback display type, writeback ioctls, memory mgmt,
writeback class, writeback obj manager class to overlay.

Change-Id: I171e60cea5ed8f6649859e3eb189df37b39962f1
diff --git a/liboverlay/Android.mk b/liboverlay/Android.mk
index a375284..560b57f 100644
--- a/liboverlay/Android.mk
+++ b/liboverlay/Android.mk
@@ -16,6 +16,7 @@
       overlayRotator.cpp \
       overlayMdpRot.cpp \
       overlayMdssRot.cpp \
+      overlayWriteback.cpp \
       pipes/overlayGenPipe.cpp
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/liboverlay/mdpWrapper.h b/liboverlay/mdpWrapper.h
index 1f4a0be..d96317c 100644
--- a/liboverlay/mdpWrapper.h
+++ b/liboverlay/mdpWrapper.h
@@ -78,6 +78,21 @@
 /* MSMFB_OVERLAY_3D */
 bool set3D(int fd, msmfb_overlay_3d& ov);
 
+/* MSMFB_DISPLAY_COMMIT */
+bool displayCommit(int fd);
+
+/* MSMFB_WRITEBACK_INIT, MSMFB_WRITEBACK_START */
+bool wbInitStart(int fbfd);
+
+/* MSMFB_WRITEBACK_STOP, MSMFB_WRITEBACK_TERMINATE */
+bool wbStopTerminate(int fbfd);
+
+/* MSMFB_WRITEBACK_QUEUE_BUFFER */
+bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData);
+
+/* MSMFB_WRITEBACK_DEQUEUE_BUFFER */
+bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData);
+
 /* the following are helper functions for dumping
  * msm_mdp and friends*/
 void dump(const char* const s, const msmfb_overlay_data& ov);
@@ -197,6 +212,61 @@
     return true;
 }
 
+inline bool displayCommit(int fd, mdp_display_commit& info) {
+    if(ioctl(fd, MSMFB_DISPLAY_COMMIT, &info) == -1) {
+        ALOGE("Failed to call ioctl MSMFB_DISPLAY_COMMIT err=%s",
+                strerror(errno));
+        return false;
+    }
+    return true;
+}
+
+inline bool wbInitStart(int fbfd) {
+    if(ioctl(fbfd, MSMFB_WRITEBACK_INIT, NULL) < 0) {
+        ALOGE("Failed to call ioctl MSMFB_WRITEBACK_INIT err=%s",
+                strerror(errno));
+        return false;
+    }
+    if(ioctl(fbfd, MSMFB_WRITEBACK_START, NULL) < 0) {
+        ALOGE("Failed to call ioctl MSMFB_WRITEBACK_START err=%s",
+                strerror(errno));
+        return false;
+    }
+    return true;
+}
+
+inline bool wbStopTerminate(int fbfd) {
+    if(ioctl(fbfd, MSMFB_WRITEBACK_STOP, NULL) < 0) {
+        ALOGE("Failed to call ioctl MSMFB_WRITEBACK_STOP err=%s",
+                strerror(errno));
+        return false;
+    }
+    if(ioctl(fbfd, MSMFB_WRITEBACK_TERMINATE, NULL) < 0) {
+        ALOGE("Failed to call ioctl MSMFB_WRITEBACK_TERMINATE err=%s",
+                strerror(errno));
+        return false;
+    }
+    return true;
+}
+
+inline bool wbQueueBuffer(int fbfd, struct msmfb_data& fbData) {
+    if(ioctl(fbfd, MSMFB_WRITEBACK_QUEUE_BUFFER, &fbData) < 0) {
+        ALOGE("Failed to call ioctl MSMFB_WRITEBACK_QUEUE_BUFFER err=%s",
+                strerror(errno));
+        return false;
+    }
+    return true;
+}
+
+inline bool wbDequeueBuffer(int fbfd, struct msmfb_data& fbData) {
+    if(ioctl(fbfd, MSMFB_WRITEBACK_DEQUEUE_BUFFER, &fbData) < 0) {
+        ALOGE("Failed to call ioctl MSMFB_WRITEBACK_DEQUEUE_BUFFER err=%s",
+                strerror(errno));
+        return false;
+    }
+    return true;
+}
+
 /* dump funcs */
 inline void dump(const char* const s, const msmfb_overlay_data& ov) {
     ALOGE("%s msmfb_overlay_data id=%d",
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index a15d0a8..f449c78 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -89,7 +89,7 @@
         if(type == OV_MDP_PIPE_ANY || type == PipeBook::getPipeType((eDest)i)) {
             //If the pipe is not allocated to any display or used by the
             //requesting display already in previous round.
-            if((mPipeBook[i].mDisplay == PipeBook::DPY_UNUSED ||
+            if((mPipeBook[i].mDisplay == DPY_UNUSED ||
                     mPipeBook[i].mDisplay == dpy) &&
                     PipeBook::isNotAllocated(i)) {
                 //In block mode we don't allow line operations
@@ -127,7 +127,7 @@
 bool Overlay::isPipeTypeAttached(eMdpPipeType type) {
     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
         if(type == PipeBook::getPipeType((eDest)i) &&
-                mPipeBook[i].mDisplay != PipeBook::DPY_UNUSED) {
+                mPipeBook[i].mDisplay != DPY_UNUSED) {
             return true;
         }
     }
@@ -252,7 +252,7 @@
         mdp_mixer_info *minfo = NULL;
         char name[64];
         int fd = -1;
-        for(int i = 0; i < NUM_FB_DEVICES; i++) {
+        for(int i = 0; i < MAX_FB_DEVICES; i++) {
             snprintf(name, 64, FB_DEVICE_TEMPLATE, i);
             ALOGD("initoverlay:: opening the device:: %s", name);
             fd = ::open(name, O_RDWR, 0);
@@ -288,9 +288,48 @@
             fd = -1;
         }
     }
+
+    FILE *displayDeviceFP = NULL;
+    const int MAX_FRAME_BUFFER_NAME_SIZE = 128;
+    char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
+    char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
+    const char *strDtvPanel = "dtv panel";
+    const char *strWbPanel = "writeback panel";
+
+    for(int num = 1; num < MAX_FB_DEVICES; num++) {
+        snprintf (msmFbTypePath, sizeof(msmFbTypePath),
+                "/sys/class/graphics/fb%d/msm_fb_type", num);
+        displayDeviceFP = fopen(msmFbTypePath, "r");
+
+        if(displayDeviceFP){
+            fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
+                    displayDeviceFP);
+
+            if(strncmp(fbType, strDtvPanel, strlen(strDtvPanel)) == 0) {
+                sDpyFbMap[DPY_EXTERNAL] = num;
+            } else if(strncmp(fbType, strWbPanel, strlen(strWbPanel)) == 0) {
+                sDpyFbMap[DPY_WRITEBACK] = num;
+            }
+
+            fclose(displayDeviceFP);
+        }
+    }
+
     return 0;
 }
 
+bool Overlay::displayCommit(const int& fd) {
+    //Commit
+    struct mdp_display_commit info;
+    memset(&info, 0, sizeof(struct mdp_display_commit));
+    info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
+    if(!mdp_wrapper::displayCommit(fd, info)) {
+       ALOGE("%s: commit failed", __func__);
+       return false;
+    }
+    return true;
+}
+
 void Overlay::dump() const {
     if(strlen(mDumpStr)) { //dump only on state change
         ALOGD_IF(PIPE_DEBUG, "%s\n", mDumpStr);
@@ -343,6 +382,7 @@
 
 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;
 int Overlay::PipeBook::sPipeUsageBitmap = 0;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index cfceaff..62cc000 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -41,6 +41,12 @@
 class Overlay : utils::NoCopy {
 public:
     enum { DMA_BLOCK_MODE, DMA_LINE_MODE };
+    //Abstract Display types. Each backed by a LayerMixer,
+    //represented by a fb node.
+    //High res panels can be backed by 2 layer mixers and a single fb node.
+    enum { DPY_PRIMARY, DPY_EXTERNAL, DPY_WRITEBACK, DPY_UNUSED };
+    enum { DPY_MAX = DPY_UNUSED };
+    enum { MAX_FB_DEVICES = DPY_MAX };
 
     /* dtor close */
     ~Overlay();
@@ -85,6 +91,7 @@
     /* 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.
@@ -94,6 +101,9 @@
     void clear(int dpy);
     static void setDMAMode(const int& mode);
     static int getDMAMode();
+    /* Returns the framebuffer node backing up the display */
+    static int getFbForDpy(const int& dpy);
+    static bool displayCommit(const int& fd);
 
 private:
     /* Ctor setup */
@@ -104,8 +114,6 @@
 
     /* Just like a Facebook for pipes, but much less profile info */
     struct PipeBook {
-        enum { DPY_PRIMARY, DPY_EXTERNAL, DPY_UNUSED };
-
         void init();
         void destroy();
         /* Check if pipe exists and return true, false otherwise */
@@ -157,7 +165,9 @@
 
     /* Singleton Instance*/
     static Overlay *sInstance;
+    //TODO Deprecate
     static int sExtFbIndex;
+    static int sDpyFbMap[DPY_MAX];
     static int sDMAMode;
 };
 
@@ -171,7 +181,7 @@
 inline int Overlay::availablePipes(int dpy) {
      int avail = 0;
      for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
-       if((mPipeBook[i].mDisplay == PipeBook::DPY_UNUSED ||
+       if((mPipeBook[i].mDisplay == DPY_UNUSED ||
            mPipeBook[i].mDisplay == dpy) && PipeBook::isNotAllocated(i)) {
                 avail++;
         }
@@ -196,6 +206,11 @@
     return sDMAMode;
 }
 
+inline int Overlay::getFbForDpy(const int& dpy) {
+    OVASSERT(dpy >= 0 && dpy < DPY_MAX, "Invalid dpy %d", dpy);
+    return sDpyFbMap[dpy];
+}
+
 inline bool Overlay::PipeBook::valid() {
     return (mPipe != NULL);
 }
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index 4bb2151..b543018 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -78,7 +78,6 @@
 #endif
 
 #define FB_DEVICE_TEMPLATE "/dev/graphics/fb%u"
-#define NUM_FB_DEVICES 3
 
 namespace overlay {
 
@@ -368,15 +367,8 @@
     f = static_cast<eMdpFlags>(clrBit(f, v));
 }
 
-// fb 0/1/2
 enum { FB0, FB1, FB2 };
 
-//Panels could be categorized as primary and external
-enum { PRIMARY, EXTERNAL };
-
-// 2 for rgb0/1 double bufs
-enum { RGB_PIPE_NUM_BUFS = 2 };
-
 struct ScreenInfo {
     ScreenInfo() : mFBWidth(0),
     mFBHeight(0),
diff --git a/liboverlay/overlayWriteback.cpp b/liboverlay/overlayWriteback.cpp
new file mode 100644
index 0000000..b6ed53c
--- /dev/null
+++ b/liboverlay/overlayWriteback.cpp
@@ -0,0 +1,215 @@
+/*
+* 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.
+*/
+
+#include "overlay.h"
+#include "overlayWriteback.h"
+#include "mdpWrapper.h"
+
+namespace overlay {
+
+//=========== class WritebackMem ==============================================
+bool WritebackMem::manageMem(uint32_t size, bool isSecure) {
+    if(mBuf.bufSz() == size) {
+        return true;
+    }
+    if(mBuf.valid()) {
+        if(!mBuf.close()) {
+            ALOGE("%s error closing mem", __func__);
+            return false;
+        }
+    }
+    return alloc(size, isSecure);
+}
+
+bool WritebackMem::alloc(uint32_t size, bool isSecure) {
+    if(!mBuf.open(NUM_BUFS, size, isSecure)){
+        ALOGE("%s: Failed to open", __func__);
+        mBuf.close();
+        return false;
+    }
+
+    OVASSERT(MAP_FAILED != mBuf.addr(), "MAP failed");
+    OVASSERT(mBuf.getFD() != -1, "getFd is -1");
+
+    mCurrOffsetIndex = 0;
+    for (uint32_t i = 0; i < NUM_BUFS; i++) {
+        mOffsets[i] = i * size;
+    }
+    return true;
+}
+
+bool WritebackMem::dealloc() {
+    bool ret = true;
+    if(mBuf.valid()) {
+        ret = mBuf.close();
+    }
+    return ret;
+}
+
+//=========== class Writeback =================================================
+Writeback::Writeback() : mXres(0), mYres(0) {
+    int fbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+    if(!utils::openDev(mFd, fbNum, Res::fbPath, O_RDWR)) {
+        ALOGE("%s failed to init %s", __func__, Res::fbPath);
+        return;
+    }
+    startSession();
+}
+
+Writeback::~Writeback() {
+    stopSession();
+    if (!mFd.close()) {
+        ALOGE("%s error closing fd", __func__);
+    }
+}
+
+bool Writeback::startSession() {
+    if(!mdp_wrapper::wbInitStart(mFd.getFD())) {
+        ALOGE("%s failed", __func__);
+        return false;
+    }
+    return true;
+}
+
+bool Writeback::stopSession() {
+    if(mFd.valid()) {
+        if(!mdp_wrapper::wbStopTerminate(mFd.getFD())) {
+            ALOGE("%s failed", __func__);
+            return false;
+        }
+    } else {
+        ALOGE("%s Invalid fd", __func__);
+        return false;
+    }
+    return true;
+}
+
+bool Writeback::configureDpyInfo(int xres, int yres) {
+    if(mXres != xres || mYres != yres) {
+        fb_var_screeninfo vinfo;
+        memset(&vinfo, 0, sizeof(fb_var_screeninfo));
+        if(!mdp_wrapper::getVScreenInfo(mFd.getFD(), vinfo)) {
+            ALOGE("%s failed", __func__);
+            return false;
+        }
+        vinfo.xres = xres;
+        vinfo.yres = yres;
+        vinfo.xres_virtual = xres;
+        vinfo.yres_virtual = yres;
+        vinfo.xoffset = 0;
+        vinfo.yoffset = 0;
+        if(!mdp_wrapper::setVScreenInfo(mFd.getFD(), vinfo)) {
+            ALOGE("%s failed", __func__);
+            return false;
+        }
+        mXres = xres;
+        mYres = yres;
+    }
+    return true;
+}
+
+bool Writeback::configureMemory(uint32_t size, bool isSecure) {
+    if(!mWbMem.manageMem(size, isSecure)) {
+        ALOGE("%s failed, memory failure", __func__);
+        return false;
+    }
+    return true;
+}
+
+bool Writeback::queueBuffer(int opFd, uint32_t opOffset) {
+    memset(&mFbData, 0, sizeof(struct msmfb_data));
+    //Queue
+    mFbData.offset = opOffset;
+    mFbData.memory_id = opFd;
+    mFbData.id = 0;
+    mFbData.flags = 0;
+    if(!mdp_wrapper::wbQueueBuffer(mFd.getFD(), mFbData)) {
+        ALOGE("%s: queuebuffer failed", __func__);
+        return false;
+    }
+    return true;
+}
+
+bool Writeback::dequeueBuffer() {
+    //Dequeue
+    mFbData.flags = MSMFB_WRITEBACK_DEQUEUE_BLOCKING;
+    if(!mdp_wrapper::wbDequeueBuffer(mFd.getFD(), mFbData)) {
+        ALOGE("%s: dequeuebuffer failed", __func__);
+        return false;
+    }
+    return true;
+}
+
+bool Writeback::writeSync(int opFd, uint32_t opOffset) {
+    if(!queueBuffer(opFd, opOffset)) {
+        return false;
+    }
+    if(!Overlay::displayCommit(mFd.getFD())) {
+        return false;
+    }
+    if(!dequeueBuffer()) {
+        return false;
+    }
+    return true;
+}
+
+bool Writeback::writeSync() {
+    mWbMem.useNextBuffer();
+    return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
+}
+
+//static
+
+Writeback *Writeback::getInstance() {
+    if(sWb == NULL) {
+        sWb = new Writeback();
+    }
+    sUsed = true;
+    return sWb;
+}
+
+void Writeback::configDone() {
+    if(sUsed == false && sWb) {
+        delete sWb;
+        sWb = NULL;
+    }
+}
+
+void Writeback::clear() {
+    sUsed = false;
+    if(sWb) {
+        delete sWb;
+        sWb = NULL;
+    }
+}
+
+Writeback *Writeback::sWb = 0;
+bool Writeback::sUsed = false;
+
+} //namespace overlay
diff --git a/liboverlay/overlayWriteback.h b/liboverlay/overlayWriteback.h
new file mode 100644
index 0000000..fbfd889
--- /dev/null
+++ b/liboverlay/overlayWriteback.h
@@ -0,0 +1,108 @@
+/*
+* 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 OVERLAY_WRITEBACK_H
+#define OVERLAY_WRITEBACK_H
+
+#include "overlayMem.h"
+
+namespace overlay {
+
+class WritebackMgr;
+
+class WritebackMem {
+public:
+    explicit WritebackMem() : mCurrOffsetIndex(0) {
+        memset(&mOffsets, 0, sizeof(mOffsets));
+    }
+    ~WritebackMem() { dealloc(); }
+    bool manageMem(uint32_t size, bool isSecure);
+    void useNextBuffer() {
+            mCurrOffsetIndex = (mCurrOffsetIndex + 1) % NUM_BUFS;
+    }
+    uint32_t getOffset() const { return mOffsets[mCurrOffsetIndex]; }
+    int getDstFd() const { return mBuf.getFD(); }
+private:
+    bool alloc(uint32_t size, bool isSecure);
+    bool dealloc();
+    enum { NUM_BUFS = 2 };
+    OvMem mBuf;
+    uint32_t mOffsets[NUM_BUFS];
+    uint32_t mCurrOffsetIndex;
+};
+
+//Abstracts the WB2 interface of MDP
+//Has modes to either manage memory or work with memory allocated elsewhere
+class Writeback {
+public:
+    ~Writeback();
+    bool configureDpyInfo(int xres, int yres);
+    bool configureMemory(uint32_t size, bool isSecure);
+    /* Blocking write. (queue, commit, dequeue)
+     * This class will do writeback memory management.
+     * This class will call display-commit on writeback mixer.
+     */
+    bool writeSync();
+    /* Blocking write. (queue, commit, dequeue)
+     * Client must do writeback memory management.
+     * Client must not call display-commit on writeback mixer.
+     */
+    bool writeSync(int opFd, uint32_t opOffset);
+    /* Async queue. (Does not write)
+     * Client must do writeback memory management.
+     * Client must call display-commit on their own.
+     * Client must use sync mechanism e.g sync pt.
+     */
+    bool queueBuffer(int opFd, uint32_t opOffset);
+    uint32_t getOffset() const { return mWbMem.getOffset(); }
+    int getDstFd() const { return mWbMem.getDstFd(); }
+
+    static Writeback* getInstance();
+    static void configBegin() { sUsed = false; }
+    static void configDone();
+    static void clear();
+
+private:
+    explicit Writeback();
+    bool startSession();
+    bool stopSession();
+    //Actually block_until_write_done for the usage here.
+    bool dequeueBuffer();
+    OvFD mFd;
+    WritebackMem mWbMem;
+    struct msmfb_data mFbData;
+    int mXres;
+    int mYres;
+
+    static bool sUsed;
+    static Writeback *sWb;
+};
+
+}
+
+#endif
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 3ab0d19..0de7129 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -33,7 +33,7 @@
 
 namespace overlay {
 
-GenericPipe::GenericPipe(int dpy) : mFbNum(dpy), mRotDownscaleOpt(false),
+GenericPipe::GenericPipe(int dpy) : mDpy(dpy), mRotDownscaleOpt(false),
     pipeState(CLOSED) {
     init();
 }
@@ -46,17 +46,24 @@
 {
     ALOGE_IF(DEBUG_OVERLAY, "GenericPipe init");
     mRotDownscaleOpt = false;
-    if(mFbNum)
-        mFbNum = Overlay::getInstance()->getExtFbNum();
 
-    ALOGD_IF(DEBUG_OVERLAY,"%s: mFbNum:%d",__FUNCTION__, mFbNum);
+    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);
+    }
 
-    if(!mCtrlData.ctrl.init(mFbNum)) {
+    ALOGD_IF(DEBUG_OVERLAY,"%s: mFbNum:%d",__FUNCTION__, fbNum);
+
+    if(!mCtrlData.ctrl.init(fbNum)) {
         ALOGE("GenericPipe failed to init ctrl");
         return false;
     }
 
-    if(!mCtrlData.data.init(mFbNum)) {
+    if(!mCtrlData.data.init(fbNum)) {
         ALOGE("GenericPipe failed to init data");
         return false;
     }
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index 9a66632..2472f4e 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -82,7 +82,7 @@
     /* set Closed pipe */
     bool setClosed();
 
-    int mFbNum;
+    int mDpy;
     /* Ctrl/Data aggregator */
     CtrlData mCtrlData;
     //Whether we will do downscale opt. This is just a request. If the frame is