Merge "hwcomposer: Fix a crash with MDP composition."
diff --git a/common.mk b/common.mk
index cefe060..e8a50c1 100644
--- a/common.mk
+++ b/common.mk
@@ -12,6 +12,8 @@
     common_includes += $(TARGET_OUT_HEADERS)/pp/inc
 endif
 
+common_header_export_path := qcom/display
+
 #Common libraries external to display HAL
 common_libs := liblog libutils libcutils libhardware
 
@@ -27,7 +29,8 @@
     common_flags += -D__ARM_HAVE_NEON
 endif
 
-ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610 apq8084), true)
+ifeq ($(call is-board-platform-in-list, msm8974 msm8226 msm8610 apq8084 \
+        mpq8092), true)
     common_flags += -DVENUS_COLOR_FORMAT
     common_flags += -DMDSS_TARGET
 endif
@@ -39,10 +42,10 @@
 ifeq ($(TARGET_USES_QCOM_BSP),true)
 # Enable QCOM Display features
     common_flags += -DQCOM_BSP
+endif
 ifneq ($(call is-platform-sdk-version-at-least,18),true)
     common_flags += -DANDROID_JELLYBEAN_MR1=1
 endif
-endif
 ifeq ($(call is-vendor-board-platform,QCOM),true)
 # This check is to pick the kernel headers from the right location.
 # If the macro above is defined, we make the assumption that we have the kernel
diff --git a/libcopybit/Android.mk b/libcopybit/Android.mk
index b125f11..b3d4249 100644
--- a/libcopybit/Android.mk
+++ b/libcopybit/Android.mk
@@ -16,6 +16,11 @@
 include $(LOCAL_PATH)/../common.mk
 include $(CLEAR_VARS)
 
+LOCAL_COPY_HEADERS_TO         := $(common_header_export_path)
+LOCAL_COPY_HEADERS            := copybit.h copybit_priv.h
+#Copy the headers regardless of whether copybit is built
+include $(BUILD_COPY_HEADERS)
+
 LOCAL_MODULE                  := copybit.$(TARGET_BOARD_PLATFORM)
 LOCAL_MODULE_PATH             := $(TARGET_OUT_SHARED_LIBRARIES)/hw
 LOCAL_MODULE_TAGS             := optional
diff --git a/libexternal/external.h b/libexternal/external.h
index d35490f..7ab7c3f 100644
--- a/libexternal/external.h
+++ b/libexternal/external.h
@@ -58,6 +58,7 @@
     int  configureWFDDisplay();
     int  teardownHDMIDisplay();
     int  teardownWFDDisplay();
+    int getHDMIIndex() { return mHdmiFbNum; }
 
 private:
     void setSPDInfo(const char* node, const char* property);
diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk
index fb2b0df..a879c5c 100644
--- a/libgralloc/Android.mk
+++ b/libgralloc/Android.mk
@@ -25,7 +25,9 @@
 LOCAL_SHARED_LIBRARIES        += libqdutils libGLESv1_CM
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdgralloc\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
-LOCAL_SRC_FILES               :=  gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp
+LOCAL_SRC_FILES               := gpu.cpp gralloc.cpp framebuffer.cpp mapper.cpp
+LOCAL_COPY_HEADERS_TO         := $(common_header_export_path)
+LOCAL_COPY_HEADERS            := gralloc_priv.h
 
 include $(BUILD_SHARED_LIBRARY)
 
@@ -38,6 +40,6 @@
 LOCAL_SHARED_LIBRARIES        := $(common_libs) libqdutils libdl
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdmemalloc\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
-LOCAL_SRC_FILES               :=  ionalloc.cpp alloc_controller.cpp
+LOCAL_SRC_FILES               := ionalloc.cpp alloc_controller.cpp
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libgralloc/framebuffer.cpp b/libgralloc/framebuffer.cpp
index 1851196..3109303 100644
--- a/libgralloc/framebuffer.cpp
+++ b/libgralloc/framebuffer.cpp
@@ -336,7 +336,7 @@
 
 static int mapFrameBuffer(struct private_module_t* module)
 {
-    int err = 0;
+    int err = -1;
     char property[PROPERTY_VALUE_MAX];
     if((property_get("debug.gralloc.map_fb_memory", property, NULL) > 0) &&
        (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp
index 46c7cb8..fd3abbc 100644
--- a/libgralloc/ionalloc.cpp
+++ b/libgralloc/ionalloc.cpp
@@ -109,10 +109,6 @@
             ioctl(mIonFd, ION_IOC_FREE, &handle_data);
             return err;
         }
-        memset(base, 0, ionAllocData.len);
-        // Clean cache after memset
-        clean_buffer(base, data.size, data.offset, fd_data.fd,
-                     CACHE_CLEAN_AND_INVALIDATE);
     }
 
     data.base = base;
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index e322357..3879f11 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -28,6 +28,7 @@
 #include <sys/ioctl.h>
 #include <overlay.h>
 #include <overlayRotator.h>
+#include <overlayWriteback.h>
 #include <mdp_version.h>
 #include "hwc_utils.h"
 #include "hwc_fbupdate.h"
@@ -158,7 +159,6 @@
         hwc_display_contents_1_t *list, int dpy) {
 
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    Locker::Autolock _l(ctx->mExtLock);
 
     if (LIKELY(list && list->numHwLayers > 1) &&
             ctx->dpyAttr[dpy].isActive &&
@@ -209,11 +209,14 @@
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    Locker::Autolock _l(ctx->mBlankLock);
+    Locker::Autolock _bl(ctx->mBlankLock);
+    Locker::Autolock _el(ctx->mExtLock);
     reset(ctx, numDisplays, displays);
 
     ctx->mOverlay->configBegin();
     ctx->mRotMgr->configBegin();
+    overlay::Writeback::configBegin();
+
     Overlay::setDMAMode(Overlay::DMA_LINE_MODE);
 
     for (int32_t i = numDisplays; i >= 0; i--) {
@@ -233,6 +236,7 @@
 
     ctx->mOverlay->configDone();
     ctx->mRotMgr->configDone();
+    overlay::Writeback::configDone();
 
     return ret;
 }
@@ -242,7 +246,6 @@
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    Locker::Autolock _l(ctx->mBlankLock);
     switch(event) {
         case HWC_EVENT_VSYNC:
             if (ctx->vstate.enable == enable)
@@ -256,6 +259,7 @@
 #ifdef QCOM_BSP
         case  HWC_EVENT_ORIENTATION:
             if(dpy == HWC_DISPLAY_PRIMARY) {
+                Locker::Autolock _l(ctx->mBlankLock);
                 // store the primary display orientation
                 // will be used in hwc_video::configure to disable
                 // rotation animation on external display
@@ -285,6 +289,7 @@
         ctx->mOverlay->configBegin();
         ctx->mOverlay->configDone();
         ctx->mRotMgr->clear();
+        overlay::Writeback::clear();
     }
     switch(dpy) {
         case HWC_DISPLAY_PRIMARY:
@@ -417,7 +422,6 @@
 {
     ATRACE_CALL();
     int ret = 0;
-    Locker::Autolock _l(ctx->mExtLock);
 
     if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
         ctx->dpyAttr[dpy].connected) {
@@ -477,7 +481,8 @@
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    Locker::Autolock _l(ctx->mBlankLock);
+    Locker::Autolock _bl(ctx->mBlankLock);
+    Locker::Autolock _el(ctx->mExtLock);
     for (uint32_t i = 0; i <= numDisplays; i++) {
         hwc_display_contents_1_t* list = displays[i];
         switch(i) {
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 28b1849..abca20b 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -206,6 +206,7 @@
         case EXTERNAL_PAUSE:
             {   // pause case
                 ALOGD("%s Received Pause event",__FUNCTION__);
+                Locker::Autolock _l(ctx->mExtLock);
                 ctx->dpyAttr[dpy].isActive = true;
                 ctx->dpyAttr[dpy].isPause = true;
                 break;
@@ -214,9 +215,11 @@
             {  // resume case
                 ALOGD("%s Received resume event",__FUNCTION__);
                 // treat Resume as Online event
+                Locker::Autolock _l(ctx->mExtLock);
                 ctx->mExtDispConfiguring = true;
                 ctx->dpyAttr[dpy].isActive = true;
                 ctx->dpyAttr[dpy].isPause = false;
+                ctx->proc->invalidate(ctx->proc);
                 break;
             }
         default:
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 90038f2..552b526 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -478,8 +478,8 @@
 }
 
 
-static void calc_cut(float& leftCutRatio, float& topCutRatio,
-        float& rightCutRatio, float& bottomCutRatio, int orient) {
+static void calc_cut(double& leftCutRatio, double& topCutRatio,
+        double& rightCutRatio, double& bottomCutRatio, int orient) {
     if(orient & HAL_TRANSFORM_FLIP_H) {
         swap(leftCutRatio, rightCutRatio);
     }
@@ -488,7 +488,7 @@
     }
     if(orient & HAL_TRANSFORM_ROT_90) {
         //Anti clock swapping
-        float tmpCutRatio = leftCutRatio;
+        double tmpCutRatio = leftCutRatio;
         leftCutRatio = topCutRatio;
         topCutRatio = rightCutRatio;
         rightCutRatio = bottomCutRatio;
@@ -553,26 +553,26 @@
     int sci_w = abs(sci_r - sci_l);
     int sci_h = abs(sci_b - sci_t);
 
-    float leftCutRatio = 0.0f, rightCutRatio = 0.0f, topCutRatio = 0.0f,
-            bottomCutRatio = 0.0f;
+    double leftCutRatio = 0.0, rightCutRatio = 0.0, topCutRatio = 0.0,
+            bottomCutRatio = 0.0;
 
     if(dst_l < sci_l) {
-        leftCutRatio = (float)(sci_l - dst_l) / (float)dst_w;
+        leftCutRatio = (double)(sci_l - dst_l) / (double)dst_w;
         dst_l = sci_l;
     }
 
     if(dst_r > sci_r) {
-        rightCutRatio = (float)(dst_r - sci_r) / (float)dst_w;
+        rightCutRatio = (double)(dst_r - sci_r) / (double)dst_w;
         dst_r = sci_r;
     }
 
     if(dst_t < sci_t) {
-        topCutRatio = (float)(sci_t - dst_t) / (float)dst_h;
+        topCutRatio = (double)(sci_t - dst_t) / (double)dst_h;
         dst_t = sci_t;
     }
 
     if(dst_b > sci_b) {
-        bottomCutRatio = (float)(dst_b - sci_b) / (float)dst_h;
+        bottomCutRatio = (double)(dst_b - sci_b) / (double)dst_h;
         dst_b = sci_b;
     }
 
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index 2f4475e..e4da4f7 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -33,6 +33,7 @@
 namespace qhwc {
 
 #define HWC_VSYNC_THREAD_NAME "hwcVsyncThread"
+#define MAX_SYSFS_FILE_PATH             255
 
 int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable)
 {
@@ -49,10 +50,6 @@
 
 static void *vsync_loop(void *param)
 {
-    const char* vsync_timestamp_fb0 = "/sys/class/graphics/fb0/vsync_event";
-    const char* vsync_timestamp_fb1 = "/sys/class/graphics/fb1/vsync_event";
-    int dpy = HWC_DISPLAY_PRIMARY;
-
     hwc_context_t * ctx = reinterpret_cast<hwc_context_t *>(param);
 
     char thread_name[64] = HWC_VSYNC_THREAD_NAME;
@@ -61,16 +58,14 @@
                 android::PRIORITY_MORE_FAVORABLE);
 
     const int MAX_DATA = 64;
-    static char vdata[MAX_DATA];
-    struct pollfd pfd;
-
-    uint64_t cur_timestamp=0;
-    ssize_t len = -1;
-    int fb0_fd = -1;
-    int ret = 0;
-    bool fb1_vsync = false;
+    char vdata[MAX_DATA];
     bool logvsync = false;
 
+    struct pollfd pfd[2];
+    int fb_fd[2];
+    uint64_t timestamp[2];
+    int num_displays;
+
     char property[PROPERTY_VALUE_MAX];
     if(property_get("debug.hwc.fakevsync", property, NULL) > 0) {
         if(atoi(property) == 1)
@@ -82,62 +77,91 @@
             logvsync = true;
     }
 
-    /* Currently read vsync timestamp from drivers
-       e.g. VSYNC=41800875994
-       */
-    fb0_fd = open(vsync_timestamp_fb0, O_RDONLY);
-    pfd.fd = fb0_fd;
-    pfd.events = POLLPRI | POLLERR;
+    if (ctx->mExtDisplay->getHDMIIndex() > 0)
+        num_displays = 2;
+    else
+        num_displays = 1;
 
-    if (fb0_fd < 0) {
-        // Make sure fb device is opened before starting this thread so this
-        // never happens.
-        ALOGE ("FATAL:%s:not able to open file:%s, %s",  __FUNCTION__,
-               (fb1_vsync) ? vsync_timestamp_fb1 : vsync_timestamp_fb0,
-               strerror(errno));
-        ctx->vstate.fakevsync = true;
+    char vsync_node_path[MAX_SYSFS_FILE_PATH];
+    for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) {
+        snprintf(vsync_node_path, sizeof(vsync_node_path),
+                "/sys/class/graphics/fb%d/vsync_event",
+                dpy == HWC_DISPLAY_PRIMARY ? 0 :
+                ctx->mExtDisplay->getHDMIIndex());
+        ALOGI("%s: Reading vsync for dpy=%d from %s", __FUNCTION__, dpy,
+                vsync_node_path);
+        fb_fd[dpy] = open(vsync_node_path, O_RDONLY);
+
+        if (fb_fd[dpy] < 0) {
+            // Make sure fb device is opened before starting this thread so this
+            // never happens.
+            ALOGE ("%s:not able to open vsync node for dpy=%d, %s",
+                    __FUNCTION__, dpy, strerror(errno));
+            if (dpy == HWC_DISPLAY_PRIMARY) {
+                ctx->vstate.fakevsync = true;
+                break;
+            }
+        }
+
+        pfd[dpy].fd = fb_fd[dpy];
+        if (pfd[dpy].fd >= 0)
+            pfd[dpy].events = POLLPRI | POLLERR;
     }
 
-    do {
-        if (LIKELY(!ctx->vstate.fakevsync)) {
-            int err = poll(&pfd, 1, -1);
+    if (LIKELY(!ctx->vstate.fakevsync)) {
+        do {
+            int err = poll(pfd, num_displays, -1);
             if(err > 0) {
-                if (pfd.revents & POLLPRI) {
-                    len = pread(fb0_fd, vdata, MAX_DATA, 0);
-                    if (UNLIKELY(len < 0)) {
-                        // If the read was just interrupted - it is not a fatal
-                        // error. Just continue in this case
-                        ALOGE ("FATAL:%s:not able to read file:%s, %s",
-                               __FUNCTION__,
-                               vsync_timestamp_fb0, strerror(errno));
-                        continue;
-                    }
-                    // extract timestamp
-                    const char *str = vdata;
-                    if (!strncmp(str, "VSYNC=", strlen("VSYNC="))) {
-                        cur_timestamp = strtoull(str + strlen("VSYNC="),
-                                                 NULL, 0);
+                for (int dpy = HWC_DISPLAY_PRIMARY; dpy < num_displays; dpy++) {
+                    if (pfd[dpy].revents & POLLPRI) {
+                        int len = pread(pfd[dpy].fd, vdata, MAX_DATA, 0);
+                        if (UNLIKELY(len < 0)) {
+                            // If the read was just interrupted - it is not a
+                            // fatal error. Just continue in this case
+                            ALOGE ("%s:Unable to read vsync for dpy=%d :%s",
+                                    __FUNCTION__, dpy, strerror(errno));
+                            continue;
+                        }
+                        // extract timestamp
+                        if (!strncmp(vdata, "VSYNC=", strlen("VSYNC="))) {
+                            timestamp[dpy] = strtoull(vdata + strlen("VSYNC="),
+                                    NULL, 0);
+                        }
+                        // send timestamp to SurfaceFlinger
+                        ALOGD_IF (logvsync,
+                                "%s: timestamp %llu sent to SF for dpy=%d",
+                                __FUNCTION__, timestamp[dpy], dpy);
+                        ctx->proc->vsync(ctx->proc, dpy, timestamp[dpy]);
                     }
                 }
+
             } else {
                 ALOGE("%s: vsync poll failed errno: %s", __FUNCTION__,
-                      strerror(errno));
+                        strerror(errno));
                 continue;
             }
-        } else {
-            usleep(16666);
-            cur_timestamp = systemTime();
-        }
-        // send timestamp to HAL
-        if(ctx->vstate.enable) {
-            ALOGD_IF (logvsync, "%s: timestamp %llu sent to HWC for %s",
-                      __FUNCTION__, cur_timestamp, "fb0");
-            ctx->proc->vsync(ctx->proc, dpy, cur_timestamp);
-        }
+        } while (true);
 
-    } while (true);
-    if(fb0_fd >= 0)
-        close (fb0_fd);
+    } else {
+
+        //Fake vsync is used only when set explicitly through a property or when
+        //the vsync timestamp node cannot be opened at bootup. There is no
+        //fallback to fake vsync from the true vsync loop, ever, as the
+        //condition can easily escape detection.
+        //Also, fake vsync is delivered only for the primary display.
+        do {
+            usleep(16666);
+            timestamp[HWC_DISPLAY_PRIMARY] = systemTime();
+            ctx->proc->vsync(ctx->proc, HWC_DISPLAY_PRIMARY,
+                    timestamp[HWC_DISPLAY_PRIMARY]);
+
+        } while (true);
+    }
+
+    for (int dpy = HWC_DISPLAY_PRIMARY; dpy <= HWC_DISPLAY_EXTERNAL; dpy++ ) {
+        if(fb_fd[dpy] >= 0)
+            close (fb_fd[dpy]);
+    }
 
     return NULL;
 }
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..5115a5b 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -70,9 +70,11 @@
             //fds
             if(mPipeBook[i].valid()) {
                 char str[32];
-                sprintf(str, "Unset pipe=%s dpy=%d; ",
+                sprintf(str, "Unset=%s dpy=%d; ",
                         PipeBook::getDestStr((eDest)i), mPipeBook[i].mDisplay);
+#if PIPE_DEBUG
                 strncat(mDumpStr, str, strlen(str));
+#endif
             }
             mPipeBook[i].destroy();
         }
@@ -89,7 +91,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
@@ -112,9 +114,11 @@
         if(not mPipeBook[index].valid()) {
             mPipeBook[index].mPipe = new GenericPipe(dpy);
             char str[32];
-            snprintf(str, 32, "Set pipe=%s dpy=%d; ",
+            snprintf(str, 32, "Set=%s dpy=%d; ",
                      PipeBook::getDestStr(dest), dpy);
+#if PIPE_DEBUG
             strncat(mDumpStr, str, strlen(str));
+#endif
         }
     } else {
         ALOGD_IF(PIPE_DEBUG, "Pipe unavailable type=%d display=%d",
@@ -127,7 +131,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 +256,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,13 +292,54 @@
             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;
 }
 
-void Overlay::dump() const {
-    if(strlen(mDumpStr)) { //dump only on state change
-        ALOGD_IF(PIPE_DEBUG, "%s\n", mDumpStr);
+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 PIPE_DEBUG
+    if(strlen(mDumpStr)) { //dump only on state change
+        ALOGD("%s\n", mDumpStr);
+    }
+#endif
 }
 
 void Overlay::getDump(char *buf, size_t len) {
@@ -343,6 +388,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..10ae10d 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 */
@@ -153,11 +161,13 @@
     PipeBook mPipeBook[utils::OV_INVALID]; //Used as max
 
     /* Dump string */
-    char mDumpStr[256];
+    char mDumpStr[1024];
 
     /* 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/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index 30d7ccd..b8a2417 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -279,7 +279,7 @@
     int aHeight = ovutils::align(mRotInfo.src_rect.h, 4);
     int rau_cnt = aWidth/64;
     int stride0 = (64 * 4 * rau_cnt) + rau_cnt/8;
-    int stride1 = (64 * 2 * rau_cnt) + rau_cnt/8;
+    int stride1 = ((64 * 2 * rau_cnt) + rau_cnt/8) * 2;
     int stride0_off = (aHeight/4);
     int stride1_off = (aHeight/2);
 
diff --git a/liboverlay/overlayMem.h b/liboverlay/overlayMem.h
index 5fbe91b..061d197 100644
--- a/liboverlay/overlayMem.h
+++ b/liboverlay/overlayMem.h
@@ -121,8 +121,9 @@
     if(isSecure) {
         allocFlags = GRALLOC_USAGE_PRIVATE_MM_HEAP;
         allocFlags |= GRALLOC_USAGE_PROTECTED;
-        allocFlags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
     }
+    // Allocate uncached rotator buffers
+    allocFlags |= GRALLOC_USAGE_PRIVATE_UNCACHED;
 
     int err = 0;
     OVASSERT(numbufs && bufSz, "numbufs=%d bufSz=%d", numbufs, bufSz);
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
diff --git a/libqdutils/Android.mk b/libqdutils/Android.mk
index eb04afb..459f548 100644
--- a/libqdutils/Android.mk
+++ b/libqdutils/Android.mk
@@ -15,7 +15,7 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_COPY_HEADERS_TO           := qcom/display
+LOCAL_COPY_HEADERS_TO           := $(common_header_export_path)
 LOCAL_COPY_HEADERS              := qdMetaData.h
 LOCAL_MODULE_PATH               := $(TARGET_OUT_SHARED_LIBRARIES)
 LOCAL_SHARED_LIBRARIES          := liblog libcutils
diff --git a/libqdutils/idle_invalidator.cpp b/libqdutils/idle_invalidator.cpp
index 4f03968..97176a4 100644
--- a/libqdutils/idle_invalidator.cpp
+++ b/libqdutils/idle_invalidator.cpp
@@ -45,6 +45,7 @@
                           unsigned int idleSleepTime) {
     ALOGD_IF(II_DEBUG, "%s", __func__);
 
+    Locker::Autolock _l(mLock);
     /* store registered handler */
     mHandler = reg_handler;
     mHwcContext = user_data;
@@ -55,6 +56,8 @@
 bool IdleInvalidator::threadLoop() {
     ALOGD_IF(II_DEBUG, "%s", __func__);
     usleep(mSleepTime * 500);
+
+    Locker::Autolock _l(mLock);
     if(mSleepAgain) {
         //We need to sleep again!
         mSleepAgain = false;
@@ -75,6 +78,7 @@
 }
 
 void IdleInvalidator::markForSleep() {
+    Locker::Autolock _l(mLock);
     mSleepAgain = true;
     //Triggers the threadLoop to run, if not already running.
     run(threadName, android::PRIORITY_AUDIO);
diff --git a/libqdutils/idle_invalidator.h b/libqdutils/idle_invalidator.h
index 82b1ac0..abd9b29 100644
--- a/libqdutils/idle_invalidator.h
+++ b/libqdutils/idle_invalidator.h
@@ -32,6 +32,7 @@
 
 #include <cutils/log.h>
 #include <utils/threads.h>
+#include <gr.h>
 
 typedef void (*InvalidatorHandler)(void*);
 
@@ -41,6 +42,7 @@
     unsigned int mSleepTime;
     static InvalidatorHandler mHandler;
     static android::sp<IdleInvalidator> sInstance;
+    mutable Locker mLock;
 
     public:
     IdleInvalidator();
diff --git a/libqservice/Android.mk b/libqservice/Android.mk
index e1585e4..17b2eda 100644
--- a/libqservice/Android.mk
+++ b/libqservice/Android.mk
@@ -12,5 +12,9 @@
 LOCAL_SRC_FILES               := QService.cpp \
                                  IQService.cpp \
                                  IQClient.cpp
+LOCAL_COPY_HEADERS_TO         := $(common_header_export_path)
+LOCAL_COPY_HEADERS            := IQService.h \
+                                 IQClient.h
+
 
 include $(BUILD_SHARED_LIBRARY)