Merge "hwc: Handle ext display device conn/disconn requests"
diff --git a/libcopybit/Android.mk b/libcopybit/Android.mk
index 55d421b..73bfa86 100644
--- a/libcopybit/Android.mk
+++ b/libcopybit/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2012 The Android Open Source Project
+# Copyright (C) 2008 The Android Open Source Project
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 823c1ae..669ea08 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -235,6 +235,11 @@
             alignedh = height;
             size = ALIGN(alignedw * alignedh * 2, 4096);
             break;
+        case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+            alignedw = VENUS_Y_STRIDE(COLOR_FMT_NV12, width);
+            alignedh = VENUS_Y_SCANLINES(COLOR_FMT_NV12, height);
+            size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
+            break;
         default:
             ALOGE("unrecognized pixel format: 0x%x", format);
             return -EINVAL;
diff --git a/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index 59fbd30..4f6445d 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -96,6 +96,7 @@
 enum {
     /* OEM specific HAL formats */
     HAL_PIXEL_FORMAT_NV12_ENCODEABLE        = 0x102,
+    HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS     = 0x7FA30C04,
     HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED     = 0x7FA30C03,
     HAL_PIXEL_FORMAT_YCbCr_420_SP           = 0x109,
     HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO    = 0x7FA30C01,
diff --git a/libgralloc/ionalloc.cpp b/libgralloc/ionalloc.cpp
index b9b9717..8cee7fd 100644
--- a/libgralloc/ionalloc.cpp
+++ b/libgralloc/ionalloc.cpp
@@ -69,14 +69,18 @@
     struct ion_handle_data handle_data;
     struct ion_fd_data fd_data;
     struct ion_allocation_data ionAllocData;
-
     void *base = 0;
 
     ionAllocData.len = data.size;
     ionAllocData.align = data.align;
-    ionAllocData.heap_mask = data.flags;
+    ionAllocData.heap_mask = data.flags & ~ION_SECURE;
     ionAllocData.flags = data.uncached ? 0 : ION_FLAG_CACHED;
 
+    // ToDo: replace usage of alloc data structure with
+    //  ionallocdata structure.
+    if (data.flags & ION_SECURE)
+        ionAllocData.flags |= ION_SECURE;
+
     err = open_device();
     if (err)
         return err;
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index a0a0c82..c8410c9 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -93,9 +93,11 @@
                     list->hwLayers[j].compositionType = HWC_FRAMEBUFFER;
             }
         }
+
+        if(ctx->mFBUpdate[i])
+            ctx->mFBUpdate[i]->reset();
     }
     VideoOverlay::reset();
-    FBUpdate::reset();
 }
 
 //clear prev layer prop flags and realloc for current frame
@@ -115,20 +117,21 @@
 static int hwc_prepare_primary(hwc_composer_device_1 *dev,
         hwc_display_contents_1_t *list) {
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+    const int dpy = HWC_DISPLAY_PRIMARY;
 
     if (LIKELY(list && list->numHwLayers > 1) &&
-        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isActive) {
+        ctx->dpyAttr[dpy].isActive) {
 
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         if(fbLayer->handle) {
-            setListStats(ctx, list, HWC_DISPLAY_PRIMARY);
-            reset_layer_prop(ctx, HWC_DISPLAY_PRIMARY);
+            setListStats(ctx, list, dpy);
+            reset_layer_prop(ctx, dpy);
             if(!MDPComp::configure(ctx, list)) {
-                VideoOverlay::prepare(ctx, list, HWC_DISPLAY_PRIMARY);
-                FBUpdate::prepare(ctx, fbLayer, HWC_DISPLAY_PRIMARY);
+                VideoOverlay::prepare(ctx, list, dpy);
+                ctx->mFBUpdate[dpy]->prepare(ctx, fbLayer);
             }
-            ctx->mLayerCache[HWC_DISPLAY_PRIMARY]->updateLayerCache(list);
+            ctx->mLayerCache[dpy]->updateLayerCache(list);
         }
     }
     return 0;
@@ -137,20 +140,20 @@
 static int hwc_prepare_external(hwc_composer_device_1 *dev,
         hwc_display_contents_1_t *list) {
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+    const int dpy = HWC_DISPLAY_EXTERNAL;
 
     if (LIKELY(list && list->numHwLayers > 1) &&
-        ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive &&
-        ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected) {
+        ctx->dpyAttr[dpy].isActive &&
+        ctx->dpyAttr[dpy].connected) {
 
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         if(fbLayer->handle) {
-            setListStats(ctx, list, HWC_DISPLAY_EXTERNAL);
-            reset_layer_prop(ctx, HWC_DISPLAY_EXTERNAL);
-
-            VideoOverlay::prepare(ctx, list, HWC_DISPLAY_EXTERNAL);
-            FBUpdate::prepare(ctx, fbLayer, HWC_DISPLAY_EXTERNAL);
-            ctx->mLayerCache[HWC_DISPLAY_EXTERNAL]->updateLayerCache(list);
+            setListStats(ctx, list, dpy);
+            reset_layer_prop(ctx, dpy);
+            VideoOverlay::prepare(ctx, list, dpy);
+            ctx->mFBUpdate[dpy]->prepare(ctx, fbLayer);
+            ctx->mLayerCache[dpy]->updateLayerCache(list);
         }
     }
     return 0;
@@ -173,15 +176,14 @@
                 ret = hwc_prepare_primary(dev, list);
                 break;
             case HWC_DISPLAY_EXTERNAL:
-
                 ret = hwc_prepare_external(dev, list);
                 break;
             default:
                 ret = -EINVAL;
         }
     }
-    ctx->mOverlay->configDone();
 
+    ctx->mOverlay->configDone();
     return ret;
 }
 
@@ -282,14 +284,15 @@
 
 static int hwc_set_primary(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     int ret = 0;
+    const int dpy = HWC_DISPLAY_PRIMARY;
 
     if (LIKELY(list && list->numHwLayers > 1) &&
-        ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isActive) {
+        ctx->dpyAttr[dpy].isActive) {
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
 
-        hwc_sync(ctx, list, HWC_DISPLAY_PRIMARY);
-        if (!VideoOverlay::draw(ctx, list, HWC_DISPLAY_PRIMARY)) {
+        hwc_sync(ctx, list, dpy);
+        if (!VideoOverlay::draw(ctx, list, dpy)) {
             ALOGE("%s: VideoOverlay::draw fail!", __FUNCTION__);
             ret = -1;
         }
@@ -303,7 +306,7 @@
         private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
         if(fbLayer->compositionType == HWC_FRAMEBUFFER_TARGET && hnd) {
             if(!(fbLayer->flags & HWC_SKIP_LAYER)) {
-                if (!FBUpdate::draw(ctx, fbLayer, HWC_DISPLAY_PRIMARY)) {
+                if (!ctx->mFBUpdate[dpy]->draw(ctx, fbLayer)) {
                     ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
                     ret = -1;
                 }
@@ -320,17 +323,19 @@
 static int hwc_set_external(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
     int ret = 0;
+    const int dpy = HWC_DISPLAY_EXTERNAL;
+
     Locker::Autolock _l(ctx->mExtSetLock);
 
     if (LIKELY(list && list->numHwLayers > 1) &&
-        ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive &&
-        ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected) {
+        ctx->dpyAttr[dpy].isActive &&
+        ctx->dpyAttr[dpy].connected) {
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
 
-        hwc_sync(ctx, list, HWC_DISPLAY_EXTERNAL);
+        hwc_sync(ctx, list, dpy);
 
-        if (!VideoOverlay::draw(ctx, list, HWC_DISPLAY_EXTERNAL)) {
+        if (!VideoOverlay::draw(ctx, list, dpy)) {
             ALOGE("%s: VideoOverlay::draw fail!", __FUNCTION__);
             ret = -1;
         }
@@ -338,7 +343,7 @@
         private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
         if(fbLayer->compositionType == HWC_FRAMEBUFFER_TARGET &&
                 !(fbLayer->flags & HWC_SKIP_LAYER) && hnd) {
-            if (!FBUpdate::draw(ctx, fbLayer, HWC_DISPLAY_EXTERNAL)) {
+            if (!ctx->mFBUpdate[dpy]->draw(ctx, fbLayer)) {
                 ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
                 ret = -1;
             }
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 0d0787e..ecbf813 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -18,7 +18,7 @@
  * limitations under the License.
  */
 
-#define HWC_FB_UPDATE 0
+#define DEBUG_FBUPDATE 0
 #include <gralloc_priv.h>
 #include <fb_priv.h>
 #include "hwc_fbupdate.h"
@@ -28,30 +28,38 @@
 
 namespace ovutils = overlay::utils;
 
-//Static Members
-bool FBUpdate::sModeOn[] = {false};
-ovutils::eDest FBUpdate::sDest[] = {ovutils::OV_INVALID};
-
-void FBUpdate::reset() {
-    sModeOn[HWC_DISPLAY_PRIMARY] = false;
-    sModeOn[HWC_DISPLAY_EXTERNAL] = false;
-    sDest[HWC_DISPLAY_PRIMARY] = ovutils::OV_INVALID;
-    sDest[HWC_DISPLAY_EXTERNAL] = ovutils::OV_INVALID;
+IFBUpdate* IFBUpdate::getObject(const int& width, const int& dpy) {
+    if(width > MAX_DISPLAY_DIM) {
+        return new FBUpdateHighRes(dpy);
+    }
+    return new FBUpdateLowRes(dpy);
 }
 
-bool FBUpdate::prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer, int dpy) {
+inline void IFBUpdate::reset() {
+    mModeOn = false;
+}
+
+//================= Low res====================================
+FBUpdateLowRes::FBUpdateLowRes(const int& dpy): IFBUpdate(dpy) {}
+
+inline void FBUpdateLowRes::reset() {
+    IFBUpdate::reset();
+    mDest = ovutils::OV_INVALID;
+}
+
+bool FBUpdateLowRes::prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer) {
     if(!ctx->mMDP.hasOverlay) {
-        ALOGD_IF(HWC_FB_UPDATE, "%s, this hw doesnt support mirroring",
+        ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
                 __FUNCTION__);
        return false;
     }
-
-    return (sModeOn[dpy] = configure(ctx, fblayer, dpy));
-
+    mModeOn = configure(ctx, fblayer);
+    ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
+    return mModeOn;
 }
 
 // Configure
-bool FBUpdate::configure(hwc_context_t *ctx, hwc_layer_1_t *layer, int dpy)
+bool FBUpdateLowRes::configure(hwc_context_t *ctx, hwc_layer_1_t *layer)
 {
     bool ret = false;
     if (LIKELY(ctx->mOverlay)) {
@@ -64,12 +72,12 @@
         ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
 
         //Request an RGB pipe
-        ovutils::eDest dest = ov.nextPipe(ovutils::OV_MDP_PIPE_RGB, dpy);
+        ovutils::eDest dest = ov.nextPipe(ovutils::OV_MDP_PIPE_RGB, mDpy);
         if(dest == ovutils::OV_INVALID) { //None available
             return false;
         }
 
-        sDest[dpy] = dest;
+        mDest = dest;
 
         ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_FLAGS_NONE;
         if(ctx->mSecureMode) {
@@ -112,14 +120,14 @@
     return ret;
 }
 
-bool FBUpdate::draw(hwc_context_t *ctx, hwc_layer_1_t *layer, int dpy)
+bool FBUpdateLowRes::draw(hwc_context_t *ctx, hwc_layer_1_t *layer)
 {
-    if(!sModeOn[dpy]) {
+    if(!mModeOn) {
         return true;
     }
     bool ret = true;
     overlay::Overlay& ov = *(ctx->mOverlay);
-    ovutils::eDest dest = sDest[dpy];
+    ovutils::eDest dest = mDest;
     private_handle_t *hnd = (private_handle_t *)layer->handle;
     if (!ov.queueBuffer(hnd->fd, hnd->offset, dest)) {
         ALOGE("%s: queueBuffer failed for external", __FUNCTION__);
@@ -128,5 +136,138 @@
     return ret;
 }
 
+//================= High res====================================
+FBUpdateHighRes::FBUpdateHighRes(const int& dpy): IFBUpdate(dpy) {}
+
+inline void FBUpdateHighRes::reset() {
+    IFBUpdate::reset();
+    mDestLeft = ovutils::OV_INVALID;
+    mDestRight = ovutils::OV_INVALID;
+}
+
+bool FBUpdateHighRes::prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer) {
+    if(!ctx->mMDP.hasOverlay) {
+        ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
+                __FUNCTION__);
+       return false;
+    }
+    ALOGD_IF(DEBUG_FBUPDATE, "%s, mModeOn = %d", __FUNCTION__, mModeOn);
+    mModeOn = configure(ctx, fblayer);
+    return mModeOn;
+}
+
+// Configure
+bool FBUpdateHighRes::configure(hwc_context_t *ctx, hwc_layer_1_t *layer)
+{
+    bool ret = false;
+    if (LIKELY(ctx->mOverlay)) {
+        overlay::Overlay& ov = *(ctx->mOverlay);
+        private_handle_t *hnd = (private_handle_t *)layer->handle;
+        if (!hnd) {
+            ALOGE("%s:NULL private handle for layer!", __FUNCTION__);
+            return false;
+        }
+        ovutils::Whf info(hnd->width, hnd->height, hnd->format, hnd->size);
+
+        //Request left RGB pipe
+        ovutils::eDest destL = ov.nextPipe(ovutils::OV_MDP_PIPE_RGB, mDpy);
+        if(destL == ovutils::OV_INVALID) { //None available
+            return false;
+        }
+        //Request right RGB pipe
+        ovutils::eDest destR = ov.nextPipe(ovutils::OV_MDP_PIPE_RGB, mDpy);
+        if(destR == ovutils::OV_INVALID) { //None available
+            return false;
+        }
+
+        mDestLeft = destL;
+        mDestRight = destR;
+
+        ovutils::eMdpFlags mdpFlagsL = ovutils::OV_MDP_FLAGS_NONE;
+        if(ctx->mSecureMode) {
+            ovutils::setMdpFlags(mdpFlagsL,
+                    ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
+        }
+
+        ovutils::PipeArgs pargL(mdpFlagsL,
+                info,
+                ovutils::ZORDER_0,
+                ovutils::IS_FG_SET,
+                ovutils::ROT_FLAG_DISABLED);
+        ov.setSource(pargL, destL);
+
+        ovutils::eMdpFlags mdpFlagsR = mdpFlagsL;
+        ovutils::setMdpFlags(mdpFlagsR, ovutils::OV_MDSS_MDP_RIGHT_MIXER);
+        ovutils::PipeArgs pargR(mdpFlagsR,
+                info,
+                ovutils::ZORDER_0,
+                ovutils::IS_FG_SET,
+                ovutils::ROT_FLAG_DISABLED);
+        ov.setSource(pargR, destR);
+
+        hwc_rect_t sourceCrop = layer->sourceCrop;
+        ovutils::Dim dcropL(sourceCrop.left, sourceCrop.top,
+                (sourceCrop.right - sourceCrop.left) / 2,
+                sourceCrop.bottom - sourceCrop.top);
+        ovutils::Dim dcropR(
+                sourceCrop.left + (sourceCrop.right - sourceCrop.left) / 2,
+                sourceCrop.top,
+                (sourceCrop.right - sourceCrop.left) / 2,
+                sourceCrop.bottom - sourceCrop.top);
+        ov.setCrop(dcropL, destL);
+        ov.setCrop(dcropR, destR);
+
+        int transform = layer->transform;
+        ovutils::eTransform orient =
+                static_cast<ovutils::eTransform>(transform);
+        ov.setTransform(orient, destL);
+        ov.setTransform(orient, destR);
+
+        hwc_rect_t displayFrame = layer->displayFrame;
+        //For FB left, top will always be 0
+        //That should also be the case if using 2 mixers for single display
+        ovutils::Dim dpos(displayFrame.left,
+                displayFrame.top,
+                (displayFrame.right - displayFrame.left) / 2,
+                displayFrame.bottom - displayFrame.top);
+        ov.setPosition(dpos, destL);
+        ov.setPosition(dpos, destR);
+
+        ret = true;
+        if (!ov.commit(destL)) {
+            ALOGE("%s: commit fails for left", __FUNCTION__);
+            ret = false;
+        }
+        if (!ov.commit(destR)) {
+            ALOGE("%s: commit fails for right", __FUNCTION__);
+            ret = false;
+        }
+    }
+    return ret;
+}
+
+bool FBUpdateHighRes::draw(hwc_context_t *ctx, hwc_layer_1_t *layer)
+{
+    if(!mModeOn) {
+        return true;
+    }
+    bool ret = true;
+    overlay::Overlay& ov = *(ctx->mOverlay);
+    ovutils::eDest destL = mDestLeft;
+    ovutils::eDest destR = mDestRight;
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+    if (!ov.queueBuffer(hnd->fd, hnd->offset, destL)) {
+        ALOGE("%s: queue failed for left of dpy = %d",
+                __FUNCTION__, mDpy);
+        ret = false;
+    }
+    if (!ov.queueBuffer(hnd->fd, hnd->offset, destR)) {
+        ALOGE("%s: queue failed for right of dpy = %d",
+                __FUNCTION__, mDpy);
+        ret = false;
+    }
+    return ret;
+}
+
 //---------------------------------------------------------------------
 }; //namespace qhwc
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index 708eb6f..a30a3af 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -28,22 +28,50 @@
 namespace qhwc {
 namespace ovutils = overlay::utils;
 
-//Framebuffer update
-class FBUpdate {
-    public:
-        // Sets up members and prepares overlay if conditions are met
-        static bool prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer, int dpy);
-        // Draws layer if this feature is on
-        static bool draw(hwc_context_t *ctx, hwc_layer_1_t *fblayer, int dpy);
-        //Reset values
-        static void reset();
-    private:
-        //Configures overlay
-        static bool configure(hwc_context_t *ctx, hwc_layer_1_t *fblayer,
-            int dpy);
-        //Flags if this feature is on.
-        static bool sModeOn[HWC_NUM_DISPLAY_TYPES];
-        static ovutils::eDest sDest[HWC_NUM_DISPLAY_TYPES];
+//Framebuffer update Interface
+class IFBUpdate {
+public:
+    explicit IFBUpdate(const int& dpy) : mDpy(dpy) {}
+    virtual ~IFBUpdate() {};
+    // Sets up members and prepares overlay if conditions are met
+    virtual bool prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer) = 0;
+    // Draws layer
+    virtual bool draw(hwc_context_t *ctx, hwc_layer_1_t *fblayer) = 0;
+    //Reset values
+    virtual void reset();
+    //Factory method that returns a low-res or high-res version
+    static IFBUpdate *getObject(const int& width, const int& dpy);
+
+protected:
+    const int mDpy; // display to update
+    bool mModeOn; // if prepare happened
+};
+
+//Low resolution (<= 2048) panel handler.
+class FBUpdateLowRes : public IFBUpdate {
+public:
+    explicit FBUpdateLowRes(const int& dpy);
+    virtual ~FBUpdateLowRes() {};
+    bool prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
+    bool draw(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
+    void reset();
+private:
+    bool configure(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
+    ovutils::eDest mDest; //pipe to draw on
+};
+
+//High resolution (> 2048) panel handler.
+class FBUpdateHighRes : public IFBUpdate {
+public:
+    explicit FBUpdateHighRes(const int& dpy);
+    virtual ~FBUpdateHighRes() {};
+    bool prepare(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
+    bool draw(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
+    void reset();
+private:
+    bool configure(hwc_context_t *ctx, hwc_layer_1_t *fblayer);
+    ovutils::eDest mDestLeft; //left pipe to draw on
+    ovutils::eDest mDestRight; //right pipe to draw on
 };
 
 }; //namespace qhwc
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 398634a..3d121ef 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include "hwc_utils.h"
+#include "hwc_fbupdate.h"
 #include "external.h"
 
 namespace qhwc {
@@ -65,10 +66,18 @@
 
     if(connected != -1) { //either we got switch_state connected or disconnect
         ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = connected;
-        if(connected) {
+        if (connected) {
             ctx->mExtDisplay->processUEventOnline(udata);
-        }else {
+            ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL] =
+                IFBUpdate::getObject(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].xres,
+                HWC_DISPLAY_EXTERNAL);
+        } else {
             ctx->mExtDisplay->processUEventOffline(udata);
+            if(ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL]) {
+                Locker::Autolock _l(ctx->mExtSetLock);
+                delete ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL];
+                ctx->mFBUpdate[HWC_DISPLAY_EXTERNAL] = NULL;
+            }
         }
         ALOGD("%s sending hotplug: connected = %d", __FUNCTION__, connected);
         Locker::Autolock _l(ctx->mExtSetLock); //hwc comp could be on
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 2f35567..7ae4afd 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -23,6 +23,7 @@
 #include <overlay.h>
 #include "hwc_utils.h"
 #include "hwc_mdpcomp.h"
+#include "hwc_fbupdate.h"
 #include "mdp_version.h"
 #include "external.h"
 #include "QService.h"
@@ -59,6 +60,12 @@
     ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion();
     ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
     ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
+    //Is created and destroyed only once for primary
+    //For external it could get created and destroyed multiple times depending
+    //on what external we connect to.
+    ctx->mFBUpdate[HWC_DISPLAY_PRIMARY] =
+        IFBUpdate::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres,
+        HWC_DISPLAY_PRIMARY);
     ctx->mExtDisplay = new ExternalDisplay(ctx);
     for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++)
         ctx->mLayerCache[i] = new LayerCache();
@@ -91,6 +98,13 @@
         ctx->mExtDisplay = NULL;
     }
 
+    for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+        if(ctx->mFBUpdate[i]) {
+            delete ctx->mFBUpdate[i];
+            ctx->mFBUpdate[i] = NULL;
+        }
+    }
+
     pthread_mutex_destroy(&(ctx->vstate.lock));
     pthread_cond_destroy(&(ctx->vstate.cond));
 }
@@ -238,15 +252,25 @@
     int count = 0;
     int releaseFd = -1;
     int fbFd = -1;
+    bool swapzero = false;
     data.flags = MDP_BUF_SYNC_FLAG_WAIT;
     data.acq_fen_fd = acquireFd;
     data.rel_fen_fd = &releaseFd;
+    char property[PROPERTY_VALUE_MAX];
+    if(property_get("debug.egl.swapinterval", property, "1") > 0) {
+        if(atoi(property) == 0)
+            swapzero = true;
+    }
+
     //Accumulate acquireFenceFds
     for(uint32_t i = 0; i < list->numHwLayers; i++) {
         if((list->hwLayers[i].compositionType == HWC_OVERLAY ||
             list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) &&
             list->hwLayers[i].acquireFenceFd != -1 ){
-            acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
+            if(UNLIKELY(swapzero))
+                acquireFd[count++] = -1;
+            else
+                acquireFd[count++] = list->hwLayers[i].acquireFenceFd;
         }
     }
 
@@ -254,7 +278,8 @@
     fbFd = ctx->dpyAttr[dpy].fd;
 
     //Waits for acquire fences, returns a release fence
-    ret = ioctl(fbFd, MSMFB_BUFFER_SYNC, &data);
+    if(LIKELY(!swapzero))
+        ret = ioctl(fbFd, MSMFB_BUFFER_SYNC, &data);
     if(ret < 0) {
         ALOGE("ioctl MSMFB_BUFFER_SYNC failed, err=%s",
                 strerror(errno));
@@ -269,10 +294,18 @@
                 list->hwLayers[i].acquireFenceFd = -1;
             }
             //Populate releaseFenceFds.
-            list->hwLayers[i].releaseFenceFd = dup(releaseFd);
+            if(UNLIKELY(swapzero))
+                list->hwLayers[i].releaseFenceFd = -1;
+            else
+                list->hwLayers[i].releaseFenceFd = dup(releaseFd);
         }
     }
-    list->retireFenceFd = releaseFd;
+    if(UNLIKELY(swapzero)){
+        list->retireFenceFd = -1;
+        close(releaseFd);
+    } else {
+        list->retireFenceFd = releaseFd;
+    }
     return ret;
 }
 
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index d7200b0..f3a0fd6 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -31,6 +31,7 @@
 #define FINAL_TRANSFORM_MASK 0x000F
 #define MAX_NUM_DISPLAYS 4 //Yes, this is ambitious
 #define MAX_NUM_LAYERS 32
+#define MAX_DISPLAY_DIM 2048
 
 //Fwrd decls
 struct hwc_context_t;
@@ -48,6 +49,7 @@
 //fwrd decl
 class QueuedBufferStore;
 class ExternalDisplay;
+class IFBUpdate;
 
 struct MDPInfo {
     int version;
@@ -215,6 +217,9 @@
     overlay::Overlay *mOverlay;
     //QService object
     qService::QService *mQService;
+
+    //Primary and external FB updater
+    qhwc::IFBUpdate *mFBUpdate[HWC_NUM_DISPLAY_TYPES];
     // External display related information
     qhwc::ExternalDisplay *mExtDisplay;
     qhwc::MDPInfo mMDP;
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index ee6af28..7f7bb1f 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -112,9 +112,11 @@
         if(!fakevsync) {
             for(int i = 0; i < MAX_RETRY_COUNT; i++) {
                 len = pread(fd_timestamp, vdata, MAX_DATA, 0);
-                if(len < 0 && (errno == EAGAIN || errno == EINTR)) {
-                    ALOGW("%s: vsync read: EAGAIN, retry (%d/%d).",
-                          __FUNCTION__, i, MAX_RETRY_COUNT);
+                if(len < 0 && (errno == EAGAIN ||
+                               errno == EINTR  ||
+                               errno == EBUSY)) {
+                    ALOGW("%s: vsync read: %s, retry (%d/%d).",
+                          __FUNCTION__, strerror(errno), i, MAX_RETRY_COUNT);
                     continue;
                 } else {
                     break;
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index cb3c48f..60d63a2 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -119,6 +119,7 @@
 
 bool MdssRot::commit() {
     doTransform();
+    setBufSize(mRotInfo.src.format);
     mRotInfo.flags |= MDSS_MDP_ROT_ONLY;
     if(!overlay::mdp_wrapper::setOverlay(mFd.getFD(), mRotInfo)) {
         ALOGE("MdssRot commit failed!");
@@ -248,4 +249,10 @@
     ALOGE("== Dump MdssRot end ==");
 }
 
+void MdssRot::setBufSize(int format) {
+    if (format == MDP_Y_CBCR_H2V2_VENUS) {
+        mBufSize = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, mRotInfo.dst_rect.w,
+                                     mRotInfo.dst_rect.h);
+    }
+}
 } // namespace overlay
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index 4ef33f3..ca71402 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -199,6 +199,7 @@
     void doTransform();
     /* reset underlying data, basically memset 0 */
     void reset();
+    void setBufSize(int format);
 
     /* MdssRot info structure */
     mdp_overlay   mRotInfo;
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index d0f9457..49a1eaf 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -231,7 +231,8 @@
             return MDP_Y_CBCR_H1V1;
         case HAL_PIXEL_FORMAT_YCrCb_444_SP:
             return MDP_Y_CRCB_H1V1;
-
+        case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+            return MDP_Y_CBCR_H2V2_VENUS;
         default:
             //Unsupported by MDP
             //---graphics.h--------
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index f9fcca8..28d2b67 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -44,6 +44,10 @@
 #include <utils/Log.h>
 #include "gralloc_priv.h" //for interlace
 
+#ifndef MDP_Y_CBCR_H2V2_VENUS
+#define MDP_Y_CBCR_H2V2_VENUS (MDP_IMGTYPE_LIMIT2 + 1)
+#endif
+
 /*
 *
 * Collection of utilities functions/structs/enums etc...
@@ -63,6 +67,10 @@
 #define DEBUG_OVERLAY 0
 #define PROFILE_OVERLAY 0
 
+#ifndef MDSS_MDP_RIGHT_MIXER
+#define MDSS_MDP_RIGHT_MIXER 0x100
+#endif
+
 namespace overlay {
 
 // fwd
@@ -297,6 +305,7 @@
     OV_MDP_BLEND_FG_PREMULT = MDP_BLEND_FG_PREMULT,
     OV_MDP_FLIP_H = MDP_FLIP_LR,
     OV_MDP_FLIP_V = MDP_FLIP_UD,
+    OV_MDSS_MDP_RIGHT_MIXER = MDSS_MDP_RIGHT_MIXER,
 };
 
 enum eZorder {
@@ -487,6 +496,7 @@
         case MDP_Y_CBCR_H2V2_TILE:
         case MDP_Y_CR_CB_H2V2:
         case MDP_Y_CR_CB_GH2V2:
+        case MDP_Y_CBCR_H2V2_VENUS:
             return true;
         default:
             return false;
@@ -534,6 +544,8 @@
         "MDP_YCRCB_H1V1",
         "MDP_YCBCR_H1V1",
         "MDP_BGR_565",
+        "MDP_BGR_888",
+        "MDP_Y_CBCR_H2V2_VENUS",
         "MDP_IMGTYPE_LIMIT",
         "MDP_RGB_BORDERFILL",
         "MDP_FB_FORMAT",