Merge "hwc: Perform MDP downscaling for WFD/HDMI Scenario"
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 50528c7..89ac919 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -75,9 +75,10 @@
 
 static bool useUncached(int usage)
 {
-    if (usage & GRALLOC_USAGE_PRIVATE_UNCACHED ||
-        usage & GRALLOC_USAGE_SW_WRITE_RARELY  ||
-        usage & GRALLOC_USAGE_SW_READ_RARELY)
+    if (usage & GRALLOC_USAGE_PRIVATE_UNCACHED)
+        return true;
+    if(((usage & GRALLOC_USAGE_SW_WRITE_MASK) == GRALLOC_USAGE_SW_WRITE_RARELY)
+       ||((usage & GRALLOC_USAGE_SW_READ_MASK) == GRALLOC_USAGE_SW_READ_RARELY))
         return true;
     return false;
 }
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index f90420f..113e916 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -134,16 +134,11 @@
     ctx->layerProp[dpy] = new LayerProp[numAppLayers];
 }
 
-static int display_commit(hwc_context_t *ctx, int dpy) {
-    struct mdp_display_commit commit_info;
-    memset(&commit_info, 0, sizeof(struct mdp_display_commit));
-    commit_info.flags = MDP_DISPLAY_COMMIT_OVERLAY;
-    if(ioctl(ctx->dpyAttr[dpy].fd, MSMFB_DISPLAY_COMMIT, &commit_info) < 0){
-        ALOGE("%s: MSMFB_DISPLAY_COMMIT for dpy %d failed", __FUNCTION__,
-              dpy);
-        return -errno;
+static void handleGeomChange(hwc_context_t *ctx, int dpy,
+        hwc_display_contents_1_t *list) {
+    if(list->flags & HWC_GEOMETRY_CHANGED) {
+        ctx->mOverlay->forceSet(dpy);
     }
-    return 0;
 }
 
 static int hwc_prepare_primary(hwc_composer_device_1 *dev,
@@ -153,6 +148,7 @@
     if (LIKELY(list && list->numHwLayers > 1) &&
             ctx->dpyAttr[dpy].isActive) {
         reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
+        handleGeomChange(ctx, dpy, list);
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         if(fbLayer->handle) {
@@ -179,6 +175,7 @@
             ctx->dpyAttr[dpy].isActive &&
             ctx->dpyAttr[dpy].connected) {
         reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
+        handleGeomChange(ctx, dpy, list);
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         if(!ctx->dpyAttr[dpy].isPause) {
@@ -220,6 +217,7 @@
             ctx->dpyAttr[dpy].isActive &&
             ctx->dpyAttr[dpy].connected) {
         reset_layer_prop(ctx, dpy, list->numHwLayers - 1);
+        handleGeomChange(ctx, dpy, list);
         uint32_t last = list->numHwLayers - 1;
         hwc_layer_1_t *fbLayer = &list->hwLayers[last];
         if(!ctx->dpyAttr[dpy].isPause) {
@@ -257,10 +255,8 @@
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    ctx->mBlankLock.lock();
     //Will be unlocked at the end of set
-    ctx->mExtLock.lock();
-    ctx->mSecureLock.lock();
+    ctx->mDrawLock.lock();
     reset(ctx, numDisplays, displays);
 
     ctx->mOverlay->configBegin();
@@ -312,7 +308,7 @@
 #ifdef QCOM_BSP
         case  HWC_EVENT_ORIENTATION:
             if(dpy == HWC_DISPLAY_PRIMARY) {
-                Locker::Autolock _l(ctx->mBlankLock);
+                Locker::Autolock _l(ctx->mDrawLock);
                 // store the primary display orientation
                 // will be used in hwc_video::configure to disable
                 // rotation animation on external display
@@ -331,7 +327,7 @@
     ATRACE_CALL();
     hwc_context_t* ctx = (hwc_context_t*)(dev);
 
-    Locker::Autolock _l(ctx->mBlankLock);
+    Locker::Autolock _l(ctx->mDrawLock);
     int ret = 0, value = 0;
     ALOGD_IF(BLANK_DEBUG, "%s: %s display: %d", __FUNCTION__,
           blank==1 ? "Blanking":"Unblanking", dpy);
@@ -365,14 +361,22 @@
          * activate/deactive VIRTUAL DISPLAY */
 
         if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
-            if(blank)
-                display_commit(ctx, HWC_DISPLAY_VIRTUAL);
+            if(blank) {
+                int dpy = HWC_DISPLAY_VIRTUAL;
+                if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+                    ALOGE("%s: display commit fail for virtual!", __FUNCTION__);
+                    ret = -1;
+                }
+            }
             ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
         }
         break;
     case HWC_DISPLAY_EXTERNAL:
         if(blank) {
-            display_commit(ctx, HWC_DISPLAY_EXTERNAL);
+            if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+                ALOGE("%s: display commit fail for external!", __FUNCTION__);
+                ret = -1;
+            }
         }
         break;
     default:
@@ -383,7 +387,7 @@
 
     ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__,
           blank ? "blanking":"unblanking", dpy);
-    return 0;
+    return ret;
 }
 
 static int hwc_query(struct hwc_composer_device_1* dev,
@@ -447,8 +451,8 @@
             }
         }
 
-        if (display_commit(ctx, dpy) < 0) {
-            ALOGE("%s: display commit fail!", __FUNCTION__);
+        if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+            ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
             ret = -1;
         }
     }
@@ -467,49 +471,47 @@
 
 
     if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
-        ctx->dpyAttr[dpy].connected) {
+        ctx->dpyAttr[dpy].connected &&
+        !ctx->dpyAttr[dpy].isPause) {
+        uint32_t last = list->numHwLayers - 1;
+        hwc_layer_1_t *fbLayer = &list->hwLayers[last];
+        int fd = -1; //FenceFD from the Copybit(valid in async mode)
+        bool copybitDone = false;
+        if(ctx->mCopyBit[dpy])
+            copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
 
-        if(!ctx->dpyAttr[dpy].isPause) {
-            uint32_t last = list->numHwLayers - 1;
-            hwc_layer_1_t *fbLayer = &list->hwLayers[last];
-            int fd = -1; //FenceFD from the Copybit(valid in async mode)
-            bool copybitDone = false;
-            if(ctx->mCopyBit[dpy])
-                copybitDone = ctx->mCopyBit[dpy]->draw(ctx, list, dpy, &fd);
+        if(list->numHwLayers > 1)
+            hwc_sync(ctx, list, dpy, fd);
 
-            if(list->numHwLayers > 1)
-                hwc_sync(ctx, list, dpy, fd);
+        // Dump the layers for external
+        if(ctx->mHwcDebug[dpy])
+            ctx->mHwcDebug[dpy]->dumpLayers(list);
 
-            // Dump the layers for external
-            if(ctx->mHwcDebug[dpy])
-                ctx->mHwcDebug[dpy]->dumpLayers(list);
+        if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
+            ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+            ret = -1;
+        }
 
-            if (!ctx->mMDPComp[dpy]->draw(ctx, list)) {
-                ALOGE("%s: MDPComp draw failed", __FUNCTION__);
+        int extOnlyLayerIndex =
+                ctx->listStats[dpy].extOnlyLayerIndex;
+
+        private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
+        if(extOnlyLayerIndex!= -1) {
+            hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
+            hnd = (private_handle_t *)extLayer->handle;
+        } else if(copybitDone) {
+            hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
+        }
+
+        if(hnd && !isYuvBuffer(hnd)) {
+            if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
+                ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
                 ret = -1;
             }
-
-            int extOnlyLayerIndex =
-                    ctx->listStats[dpy].extOnlyLayerIndex;
-
-            private_handle_t *hnd = (private_handle_t *)fbLayer->handle;
-            if(extOnlyLayerIndex!= -1) {
-                hwc_layer_1_t *extLayer = &list->hwLayers[extOnlyLayerIndex];
-                hnd = (private_handle_t *)extLayer->handle;
-            } else if(copybitDone) {
-                hnd = ctx->mCopyBit[dpy]->getCurrentRenderBuffer();
-            }
-
-            if(hnd && !isYuvBuffer(hnd)) {
-                if (!ctx->mFBUpdate[dpy]->draw(ctx, hnd)) {
-                    ALOGE("%s: FBUpdate::draw fail!", __FUNCTION__);
-                    ret = -1;
-                }
-            }
         }
 
-        if (display_commit(ctx, dpy) < 0) {
-            ALOGE("%s: display commit fail!", __FUNCTION__);
+        if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+            ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
             ret = -1;
         }
     }
@@ -566,15 +568,15 @@
             }
         }
 
-        if (display_commit(ctx, dpy) < 0) {
-            ALOGE("%s: display commit fail!", __FUNCTION__);
+        if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+            ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
             ret = -1;
         }
     }
 
     closeAcquireFds(list);
 
-    if (list && !ctx->mVirtualonExtActive) {
+    if (list && !ctx->mVirtualonExtActive && (list->retireFenceFd < 0) ) {
         // SF assumes HWC waits for the acquire fence and returns a new fence
         // that signals when we're done. Since we don't wait, and also don't
         // touch the buffer, we can just handle the acquire fence back to SF
@@ -615,9 +617,7 @@
     MDPComp::resetIdleFallBack();
     ctx->mVideoTransFlag = false;
     //Was locked at the beginning of prepare
-    ctx->mSecureLock.unlock();
-    ctx->mExtLock.unlock();
-    ctx->mBlankLock.unlock();
+    ctx->mDrawLock.unlock();
     return ret;
 }
 
@@ -707,6 +707,7 @@
 void hwc_dump(struct hwc_composer_device_1* dev, char *buff, int buff_len)
 {
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+    Locker::Autolock _l(ctx->mDrawLock);
     android::String8 aBuf("");
     dumpsys_log(aBuf, "Qualcomm HWC state:\n");
     dumpsys_log(aBuf, "  MDPVersion=%d\n", ctx->mMDP.version);
@@ -751,7 +752,7 @@
 
         //Setup HWC methods
         dev->device.common.tag          = HARDWARE_DEVICE_TAG;
-        dev->device.common.version      = HWC_DEVICE_API_VERSION_1_1;
+        dev->device.common.version      = HWC_DEVICE_API_VERSION_1_2;
         dev->device.common.module       = const_cast<hw_module_t*>(module);
         dev->device.common.close        = hwc_device_close;
         dev->device.prepare             = hwc_prepare;
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 068e28a..a395ee0 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -127,6 +127,20 @@
     return renderArea;
 }
 
+bool checkNonWormholeRegion(private_handle_t* hnd, hwc_rect_t& rect)
+{
+    unsigned int height = rect.bottom - rect.top;
+    unsigned int width = rect.right - rect.left;
+    copybit_image_t buf;
+    buf.w = ALIGN(hnd->width, 32);
+    buf.h = hnd->height;
+
+    if (buf.h != height || buf.w != width)
+        return false;
+
+    return true;
+}
+
 bool CopyBit::prepare(hwc_context_t *ctx, hwc_display_contents_1_t *list,
                                                             int dpy) {
 
@@ -181,6 +195,15 @@
             if (layer->planeAlpha != 0xFF)
                 return true;
         }
+        /*
+         * Fallback to GPU in MDP3 when NonWormholeRegion is not of frame buffer
+         * size as artifact is seen in WormholeRegion of previous frame.
+         */
+        hwc_rect_t nonWormHoleRegion;
+        getNonWormholeRegion(list, nonWormHoleRegion);
+        if(!checkNonWormholeRegion(fbHnd, nonWormHoleRegion))
+           return true;
+
     }
 
     //Allocate render buffers if they're not allocated
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 7c2e643..fafe03b 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -165,7 +165,10 @@
         orient = ovutils::OVERLAY_TRANSFORM_0;
         transform = 0;
         ovutils::PipeArgs parg(mdpFlags, info, zOrder, isFg,
-                                static_cast<ovutils::eRotFlags>(rotFlags));
+                               static_cast<ovutils::eRotFlags>(rotFlags),
+                               ovutils::DEFAULT_PLANE_ALPHA,
+                               (ovutils::eBlending)
+                               getBlending(layer->blending));
         ret = true;
         if(configMdp(ctx->mOverlay, parg, orient, sourceCrop, displayFrame,
                     NULL, mDest) < 0) {
@@ -262,11 +265,16 @@
 
         ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
 
+        //XXX: FB layer plane alpha is currently sent as zero from
+        //surfaceflinger
         ovutils::PipeArgs pargL(mdpFlagsL,
                                 info,
                                 zOrder,
                                 ovutils::IS_FG_OFF,
-                                ovutils::ROT_FLAGS_NONE);
+                                ovutils::ROT_FLAGS_NONE,
+                                ovutils::DEFAULT_PLANE_ALPHA,
+                                (ovutils::eBlending)
+                                getBlending(layer->blending));
         ov.setSource(pargL, destL);
 
         ovutils::eMdpFlags mdpFlagsR = mdpFlagsL;
@@ -275,7 +283,10 @@
                                 info,
                                 zOrder,
                                 ovutils::IS_FG_OFF,
-                                ovutils::ROT_FLAGS_NONE);
+                                ovutils::ROT_FLAGS_NONE,
+                                ovutils::DEFAULT_PLANE_ALPHA,
+                                (ovutils::eBlending)
+                                getBlending(layer->blending));
         ov.setSource(pargR, destR);
 
         hwc_rect_t sourceCrop = layer->sourceCrop;
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index e97d769..f2217b9 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -55,7 +55,9 @@
 
 void MDPComp::dump(android::String8& buf)
 {
-    Locker::Autolock _l(mMdpCompLock);
+    if(mCurrentFrame.layerCount > MAX_NUM_APP_LAYERS)
+        return;
+
     dumpsys_log(buf,"HWC Map for Dpy: %s \n",
                 (mDpy == 0) ? "\"PRIMARY\"" :
                 (mDpy == 1) ? "\"EXTERNAL\"" : "\"VIRTUAL\"");
@@ -440,11 +442,15 @@
         hwc_layer_1_t* layer = &list->hwLayers[i];
         private_handle_t *hnd = (private_handle_t *)layer->handle;
 
-        if((layer->transform & HWC_TRANSFORM_ROT_90) && !isYuvBuffer(hnd)) {
-            ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__);
-            return false;
+        if(layer->transform & HWC_TRANSFORM_ROT_90) {
+            if(!isYuvBuffer(hnd) ) {
+                ALOGD_IF(isDebug(), "%s: orientation involved",__FUNCTION__);
+                return false;
+            }else if(!canUseRotator(ctx, mDpy)) {
+                ALOGD_IF(isDebug(), "%s: no free DMA pipe",__FUNCTION__);
+                return false;
+            }
         }
-
         if(!isValidDimension(ctx,layer)) {
             ALOGD_IF(isDebug(), "%s: Buffer is of invalid width",
                 __FUNCTION__);
@@ -558,6 +564,11 @@
         return false;
     }
 
+    if(layer->transform & HWC_TRANSFORM_ROT_90 && !canUseRotator(ctx,mDpy)) {
+        ALOGD_IF(isDebug(), "%s: no free DMA pipe",__FUNCTION__);
+        return false;
+    }
+
     if(isSecuring(ctx, layer)) {
         ALOGD_IF(isDebug(), "%s: MDP securing is active", __FUNCTION__);
         return false;
@@ -569,6 +580,13 @@
         return false;
     }
 
+    if(layer->planeAlpha < 0xFF) {
+        ALOGD_IF(isDebug(), "%s: Cannot handle YUV layer with plane alpha\
+                 in video only mode",
+                 __FUNCTION__);
+        return false;
+    }
+
     return true;
 }
 
@@ -738,92 +756,88 @@
 int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     const int numLayers = ctx->listStats[mDpy].numAppLayers;
 
-    { //LOCK SCOPE BEGIN
-        Locker::Autolock _l(mMdpCompLock);
+    //reset old data
+    mCurrentFrame.reset(numLayers);
 
-        //reset old data
-        mCurrentFrame.reset(numLayers);
-
-        //number of app layers exceeds MAX_NUM_APP_LAYERS fall back to GPU
-        //do not cache the information for next draw cycle.
-        if(numLayers > MAX_NUM_APP_LAYERS) {
-            mCachedFrame.updateCounts(mCurrentFrame);
-            ALOGD_IF(isDebug(), "%s: Number of App layers exceeded the limit ",
-                                    __FUNCTION__);
-            return -1;
-        }
-
-        //Hard conditions, if not met, cannot do MDP comp
-        if(!isFrameDoable(ctx)) {
-            ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
-                                    __FUNCTION__);
-            reset(numLayers, list);
-            return -1;
-        }
-
-        //Check whether layers marked for MDP Composition is actually doable.
-        if(isFullFrameDoable(ctx, list)){
-            mCurrentFrame.map();
-            //Configure framebuffer first if applicable
-            if(mCurrentFrame.fbZ >= 0) {
-                if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list,
-                        mCurrentFrame.fbZ)) {
-                    ALOGE("%s configure framebuffer failed", __func__);
-                    reset(numLayers, list);
-                    return -1;
-                }
-            }
-            //Acquire and Program MDP pipes
-            if(!programMDP(ctx, list)) {
-                reset(numLayers, list);
-                return -1;
-            } else { //Success
-                //Any change in composition types needs an FB refresh
-                mCurrentFrame.needsRedraw = false;
-                if(mCurrentFrame.fbCount &&
-                        ((mCurrentFrame.mdpCount != mCachedFrame.mdpCount) ||
-                        (mCurrentFrame.fbCount != mCachedFrame.cacheCount) ||
-                        (mCurrentFrame.fbZ != mCachedFrame.fbZ) ||
-                        (!mCurrentFrame.mdpCount) ||
-                        (list->flags & HWC_GEOMETRY_CHANGED) ||
-                        isSkipPresent(ctx, mDpy) ||
-                        (mDpy > HWC_DISPLAY_PRIMARY))) {
-                    mCurrentFrame.needsRedraw = true;
-                }
-            }
-        } else if(isOnlyVideoDoable(ctx, list)) {
-            //All layers marked for MDP comp cannot be bypassed.
-            //Try to compose atleast YUV layers through MDP comp and let
-            //all the RGB layers compose in FB
-            //Destination over
-            mCurrentFrame.fbZ = -1;
-            if(mCurrentFrame.fbCount)
-                mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
-
-            mCurrentFrame.map();
-
-            //Configure framebuffer first if applicable
-            if(mCurrentFrame.fbZ >= 0) {
-                if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list, mCurrentFrame.fbZ)) {
-                    ALOGE("%s configure framebuffer failed", __func__);
-                    reset(numLayers, list);
-                    return -1;
-                }
-            }
-            if(!programYUV(ctx, list)) {
-                reset(numLayers, list);
-                return -1;
-            }
-        } else {
-            reset(numLayers, list);
-            return -1;
-        }
-
-        //UpdateLayerFlags
-        setMDPCompLayerFlags(ctx, list);
+    //number of app layers exceeds MAX_NUM_APP_LAYERS fall back to GPU
+    //do not cache the information for next draw cycle.
+    if(numLayers > MAX_NUM_APP_LAYERS) {
         mCachedFrame.updateCounts(mCurrentFrame);
+        ALOGD_IF(isDebug(), "%s: Number of App layers exceeded the limit ",
+                __FUNCTION__);
+        return -1;
+    }
 
-    } //LOCK SCOPE END. dump also need this lock.
+    //Hard conditions, if not met, cannot do MDP comp
+    if(!isFrameDoable(ctx)) {
+        ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
+                __FUNCTION__);
+        reset(numLayers, list);
+        return -1;
+    }
+
+    //Check whether layers marked for MDP Composition is actually doable.
+    if(isFullFrameDoable(ctx, list)) {
+        mCurrentFrame.map();
+        //Configure framebuffer first if applicable
+        if(mCurrentFrame.fbZ >= 0) {
+            if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list,
+                        mCurrentFrame.fbZ)) {
+                ALOGE("%s configure framebuffer failed", __func__);
+                reset(numLayers, list);
+                return -1;
+            }
+        }
+        //Acquire and Program MDP pipes
+        if(!programMDP(ctx, list)) {
+            reset(numLayers, list);
+            return -1;
+        } else { //Success
+            //Any change in composition types needs an FB refresh
+            mCurrentFrame.needsRedraw = false;
+            if(mCurrentFrame.fbCount &&
+                    ((mCurrentFrame.mdpCount != mCachedFrame.mdpCount) ||
+                     (mCurrentFrame.fbCount != mCachedFrame.cacheCount) ||
+                     (mCurrentFrame.fbZ != mCachedFrame.fbZ) ||
+                     (!mCurrentFrame.mdpCount) ||
+                     (list->flags & HWC_GEOMETRY_CHANGED) ||
+                     isSkipPresent(ctx, mDpy) ||
+                     (mDpy > HWC_DISPLAY_PRIMARY))) {
+                mCurrentFrame.needsRedraw = true;
+            }
+        }
+    } else if(isOnlyVideoDoable(ctx, list)) {
+        //All layers marked for MDP comp cannot be bypassed.
+        //Try to compose atleast YUV layers through MDP comp and let
+        //all the RGB layers compose in FB
+        //Destination over
+        mCurrentFrame.fbZ = -1;
+        if(mCurrentFrame.fbCount)
+            mCurrentFrame.fbZ = mCurrentFrame.mdpCount;
+
+        mCurrentFrame.map();
+
+        //Configure framebuffer first if applicable
+        if(mCurrentFrame.fbZ >= 0) {
+            if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list, mCurrentFrame.fbZ)) {
+                ALOGE("%s configure framebuffer failed", __func__);
+                reset(numLayers, list);
+                return -1;
+            }
+        }
+        if(!programYUV(ctx, list)) {
+            reset(numLayers, list);
+            return -1;
+        }
+    } else {
+        reset(numLayers, list);
+        return -1;
+    }
+
+    //UpdateLayerFlags
+    setMDPCompLayerFlags(ctx, list);
+    mCachedFrame.updateCounts(mCurrentFrame);
+
     // unlock it before calling dump function to avoid deadlock
     if(isDebug()) {
         ALOGD("GEOMETRY change: %d", (list->flags & HWC_GEOMETRY_CHANGED));
@@ -925,8 +939,6 @@
         return true;
     }
 
-    Locker::Autolock _l(mMdpCompLock);
-
     /* reset Invalidator */
     if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
         idleInvalidator->markForSleep();
@@ -1132,8 +1144,6 @@
         return true;
     }
 
-    Locker::Autolock _l(mMdpCompLock);
-
     /* reset Invalidator */
     if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
         idleInvalidator->markForSleep();
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 1385fbb..2f1670b 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -170,7 +170,6 @@
     static IdleInvalidator *idleInvalidator;
     struct FrameInfo mCurrentFrame;
     struct LayerCache mCachedFrame;
-    mutable Locker mMdpCompLock;
 };
 
 class MDPCompLowRes : public MDPComp {
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index c20f5c1..45c82fd 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -71,7 +71,7 @@
 }
 
 void QClient::securing(uint32_t startEnd) {
-    Locker::Autolock _sl(mHwcContext->mSecureLock);
+    Locker::Autolock _sl(mHwcContext->mDrawLock);
     //The only way to make this class in this process subscribe to media
     //player's death.
     IMediaDeathNotifier::getMediaPlayerService();
@@ -85,7 +85,7 @@
 }
 
 void QClient::unsecuring(uint32_t startEnd) {
-    Locker::Autolock _sl(mHwcContext->mSecureLock);
+    Locker::Autolock _sl(mHwcContext->mDrawLock);
     mHwcContext->mSecuring = startEnd;
     //We're done unsecuring
     if(startEnd == IQService::END)
@@ -95,7 +95,7 @@
 }
 
 void QClient::MPDeathNotifier::died() {
-    Locker::Autolock _sl(mHwcContext->mSecureLock);
+    Locker::Autolock _sl(mHwcContext->mDrawLock);
     ALOGD_IF(QCLIENT_DEBUG, "Media Player died");
     mHwcContext->mSecuring = false;
     mHwcContext->mSecureMode = false;
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 1d127f0..5590798 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -33,7 +33,7 @@
 #include "external.h"
 #include "virtual.h"
 #include "mdp_version.h"
-
+using namespace overlay;
 namespace qhwc {
 #define HWC_UEVENT_SWITCH_STR  "change@/devices/virtual/switch/"
 #define HWC_UEVENT_THREAD_NAME "hwcUeventThread"
@@ -125,7 +125,7 @@
                 break;
             }
 
-            Locker::Autolock _l(ctx->mExtLock);
+            Locker::Autolock _l(ctx->mDrawLock);
             clear(ctx, dpy);
             ctx->dpyAttr[dpy].connected = false;
             ctx->dpyAttr[dpy].isActive = false;
@@ -164,7 +164,7 @@
                 //fail, since Layer Mixer#0 is still connected to WriteBack.
                 //This block will force composition to close fb2 in above
                 //example.
-                Locker::Autolock _l(ctx->mExtLock);
+                Locker::Autolock _l(ctx->mDrawLock);
                 ctx->dpyAttr[dpy].isConfiguring = true;
                 ctx->proc->invalidate(ctx->proc);
             }
@@ -177,7 +177,7 @@
                     ALOGD_IF(UEVENT_DEBUG,"Received HDMI connection request"
                              "when WFD is active");
                     {
-                        Locker::Autolock _l(ctx->mExtLock);
+                        Locker::Autolock _l(ctx->mDrawLock);
                         clear(ctx, HWC_DISPLAY_VIRTUAL);
                         ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false;
                         ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = false;
@@ -193,7 +193,7 @@
                         ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL,
                                            EXTERNAL_OFFLINE);
                         {
-                            Locker::Autolock _l(ctx->mExtLock);
+                            Locker::Autolock _l(ctx->mDrawLock);
                             ctx->mVirtualonExtActive = false;
                         }
                     }
@@ -205,7 +205,7 @@
                 ctx->mExtDisplay->configure();
             } else {
                 {
-                    Locker::Autolock _l(ctx->mExtLock);
+                    Locker::Autolock _l(ctx->mDrawLock);
                     /* TRUE only when we are on proprietary WFD session */
                     ctx->mVirtualonExtActive = true;
                     char property[PROPERTY_VALUE_MAX];
@@ -220,7 +220,7 @@
                 ctx->mVirtualDisplay->configure();
             }
 
-            Locker::Autolock _l(ctx->mExtLock);
+            Locker::Autolock _l(ctx->mDrawLock);
             setup(ctx, dpy);
             ctx->dpyAttr[dpy].isPause = false;
             ctx->dpyAttr[dpy].connected = true;
@@ -233,7 +233,6 @@
                  * surface for the same. */
                 ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = true;
             }
-
             if(dpy == HWC_DISPLAY_EXTERNAL ||
                ctx->mVirtualonExtActive) {
                 ALOGE_IF(UEVENT_DEBUG, "%s: Sending EXTERNAL_OFFLINE ONLINE"
@@ -243,33 +242,51 @@
             }
             break;
         }
-    case EXTERNAL_PAUSE:
-        {
-            ctx->dpyAttr[dpy].isActive = true;
-            ctx->dpyAttr[dpy].isPause = true;
-            break;
-        }
-    case EXTERNAL_RESUME:
-        {
-            //Treat Resume as Online event
-            //Since external didnt have any pipes, force primary to give up
-            //its pipes; we don't allow inter-mixer pipe transfers.
-            {
-                Locker::Autolock _l(ctx->mExtLock);
-                ctx->dpyAttr[dpy].isConfiguring = true;
-                ctx->dpyAttr[dpy].isActive = true;
-                ctx->proc->invalidate(ctx->proc);
+        case EXTERNAL_PAUSE:
+            {   // pause case
+                ALOGD("%s Received Pause event",__FUNCTION__);
+                 {
+                     Locker::Autolock _l(ctx->mDrawLock);
+                     ctx->dpyAttr[dpy].isActive = true;
+                     ctx->dpyAttr[dpy].isPause = true;
+                     ctx->proc->invalidate(ctx->proc);
+                 }
+                 usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+                         * 2 / 1000);
+                 // At this point all the pipes used by External have been
+                 // marked as UNSET.
+                 {
+                     Locker::Autolock _l(ctx->mDrawLock);
+                     // Perform commit to unstage the pipes.
+                     if (!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+                         ALOGE("%s: display commit fail! for %d dpy",
+                                 __FUNCTION__, dpy);
+                     }
+                 }
+                 break;
             }
-            usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
-                   * 2 / 1000);
-            {
-                //At this point external has all the pipes it  would need.
-                Locker::Autolock _l(ctx->mExtLock);
-                ctx->dpyAttr[dpy].isPause = false;
-                ctx->proc->invalidate(ctx->proc);
+        case EXTERNAL_RESUME:
+            {  // resume case
+                ALOGD("%s Received resume event",__FUNCTION__);
+                //Treat Resume as Online event
+                //Since external didnt have any pipes, force primary to give up
+                //its pipes; we don't allow inter-mixer pipe transfers.
+                {
+                    Locker::Autolock _l(ctx->mDrawLock);
+                    ctx->dpyAttr[dpy].isConfiguring = true;
+                    ctx->dpyAttr[dpy].isActive = true;
+                    ctx->proc->invalidate(ctx->proc);
+                }
+                usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+                        * 2 / 1000);
+                //At this point external has all the pipes it would need.
+                {
+                    Locker::Autolock _l(ctx->mDrawLock);
+                    ctx->dpyAttr[dpy].isPause = false;
+                    ctx->proc->invalidate(ctx->proc);
+                }
+                break;
             }
-            break;
-        }
     default:
         {
             ALOGE("%s: Invalid state to swtich:%d", __FUNCTION__, switch_state);
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index e013876..ea123d0 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -623,8 +623,9 @@
             yuvCount++;
 
             if((layer->transform & HWC_TRANSFORM_ROT_90) &&
-                    canUseRotator(ctx)) {
-                if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
+                    canUseRotator(ctx, dpy)) {
+                if( (dpy == HWC_DISPLAY_PRIMARY) &&
+                        ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
                     ctx->isPaddingRound = true;
                 }
                 Overlay::setDMAMode(Overlay::DMA_BLOCK_MODE);
@@ -734,6 +735,18 @@
         return false;
 }
 
+int getBlending(int blending) {
+    switch(blending) {
+    case HWC_BLENDING_NONE:
+        return overlay::utils::OVERLAY_BLENDING_OPAQUE;
+    case HWC_BLENDING_PREMULT:
+        return overlay::utils::OVERLAY_BLENDING_PREMULT;
+    case HWC_BLENDING_COVERAGE :
+    default:
+        return overlay::utils::OVERLAY_BLENDING_COVERAGE;
+    }
+}
+
 //Crops source buffer against destination and FB boundaries
 void calculate_crop_rects(hwc_rect_t& crop, hwc_rect_t& dst,
                           const hwc_rect_t& scissor, int orient) {
@@ -1041,10 +1054,16 @@
     }
 }
 
-int configRotator(Rotator *rot, const Whf& whf,
+int configRotator(Rotator *rot, Whf& whf,
         hwc_rect_t& crop, const eMdpFlags& mdpFlags,
         const eTransform& orient, const int& downscale) {
 
+    // Fix alignments for TILED format
+    if(whf.format == MDP_Y_CRCB_H2V2_TILE ||
+                            whf.format == MDP_Y_CBCR_H2V2_TILE) {
+        whf.w =  utils::alignup(whf.w, 64);
+        whf.h = utils::alignup(whf.h, 32);
+    }
     rot->setSource(whf);
 
     if (qdutils::MDPVersion::getInstance().getMDPVersion() >=
@@ -1220,7 +1239,10 @@
     //For the mdp, since either we are pre-rotating or MDP does flips
     orient = OVERLAY_TRANSFORM_0;
     transform = 0;
-    PipeArgs parg(mdpFlags, whf, z, isFg, static_cast<eRotFlags>(rotFlags));
+    PipeArgs parg(mdpFlags, whf, z, isFg,
+                  static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+                  (ovutils::eBlending) getBlending(layer->blending));
+
     if(configMdp(ctx->mOverlay, parg, orient, crop, dst, metadata, dest) < 0) {
         ALOGE("%s: commit failed for low res panel", __FUNCTION__);
         return -1;
@@ -1349,7 +1371,9 @@
     //configure left mixer
     if(lDest != OV_INVALID) {
         PipeArgs pargL(mdpFlagsL, whf, z, isFg,
-                static_cast<eRotFlags>(rotFlags));
+                       static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+                       (ovutils::eBlending) getBlending(layer->blending));
+
         if(configMdp(ctx->mOverlay, pargL, orient,
                 tmp_cropL, tmp_dstL, metadata, lDest) < 0) {
             ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
@@ -1360,7 +1384,9 @@
     //configure right mixer
     if(rDest != OV_INVALID) {
         PipeArgs pargR(mdpFlagsR, whf, z, isFg,
-                static_cast<eRotFlags>(rotFlags));
+                       static_cast<eRotFlags>(rotFlags),
+                       layer->planeAlpha,
+                       (ovutils::eBlending) getBlending(layer->blending));
         tmp_dstR.right = tmp_dstR.right - lSplit;
         tmp_dstR.left = tmp_dstR.left - lSplit;
         if(configMdp(ctx->mOverlay, pargR, orient,
@@ -1373,10 +1399,15 @@
     return 0;
 }
 
-bool canUseRotator(hwc_context_t *ctx) {
+bool canUseRotator(hwc_context_t *ctx, int dpy) {
     if(qdutils::MDPVersion::getInstance().is8x26() &&
-                       ctx->mVirtualDisplay->isConnected()) {
-        return false;
+            ctx->mVirtualDisplay->isConnected() &&
+            !ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause) {
+        // Allow if YUV needs rotation and DMA is configured to BLOCK mode for
+        // primary. For portrait videos usecase on WFD, Driver supports
+        // multiplexing of DMA pipe in LINE and BLOCK mode.
+        if(dpy == HWC_DISPLAY_PRIMARY)
+            return false;
     }
     if(ctx->mMDP.version == qdutils::MDP_V3_0_4)
         return false;
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 8809493..98749c1 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -172,6 +172,7 @@
 bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer, const int& dpy);
 bool isAlphaPresent(hwc_layer_1_t const* layer);
 int hwc_vsync_control(hwc_context_t* ctx, int dpy, int enable);
+int getBlending(int blending);
 
 //Helper function to dump logs
 void dumpsys_log(android::String8& buf, const char* fmt, ...);
@@ -210,7 +211,7 @@
         ovutils::eMdpFlags &mdpFlags,
         int rotDownscale, int transform);
 
-int configRotator(overlay::Rotator *rot, const ovutils::Whf& whf,
+int configRotator(overlay::Rotator *rot, ovutils::Whf& whf,
         hwc_rect_t& crop, const ovutils::eMdpFlags& mdpFlags,
         const ovutils::eTransform& orient, const int& downscale);
 
@@ -240,7 +241,7 @@
 //extreme unavailability of pipes. This can also be done via hybrid calculations
 //also involving many more variables like number of write-back interfaces etc,
 //but the variety of scenarios is too high to warrant that.
-bool canUseRotator(hwc_context_t *ctx);
+bool canUseRotator(hwc_context_t *ctx, int dpy);
 
 int getLeftSplit(hwc_context_t *ctx, const int& dpy);
 
@@ -287,8 +288,7 @@
 void init_vsync_thread(hwc_context_t* ctx);
 
 inline void getLayerResolution(const hwc_layer_1_t* layer,
-                               int& width, int& height)
-{
+                               int& width, int& height) {
     hwc_rect_t displayFrame  = layer->displayFrame;
     width = displayFrame.right - displayFrame.left;
     height = displayFrame.bottom - displayFrame.top;
@@ -354,17 +354,8 @@
     bool mVirtualonExtActive;
     //Display in secure mode indicator
     bool mSecureMode;
-    //Lock to prevent set from being called while blanking
-    mutable Locker mBlankLock;
-    //Lock to protect prepare & set when detaching external disp
-    mutable Locker mExtLock;
-    /*Lock to set both mSecureMode and mSecuring as part
-      of binder thread without context switch to composition
-      thread. This lock is needed only for A-family targets
-      since the state of mSecureMode and mSecuring variables
-      are not checked in B-family targets.
-    */
-    mutable Locker mSecureLock;
+    //Lock to protect drawing data structures
+    mutable Locker mDrawLock;
     //Drawing round when we use GPU
     bool isPaddingRound;
     // External Orientation
diff --git a/liblight/lights.c b/liblight/lights.c
index eb71b74..ccfbe10 100644
--- a/liblight/lights.c
+++ b/liblight/lights.c
@@ -51,6 +51,9 @@
 char const*const LCD_FILE
         = "/sys/class/leds/lcd-backlight/brightness";
 
+char const*const BUTTON_FILE
+        = "/sys/class/leds/button-backlight/brightness";
+
 char const*const RED_BLINK_FILE
         = "/sys/class/leds/red/blink";
 
@@ -209,6 +212,16 @@
     return 0;
 }
 
+static int
+set_light_buttons(struct light_device_t* dev,
+        struct light_state_t const* state)
+{
+    int err = 0;
+    pthread_mutex_lock(&g_lock);
+    err = write_int(BUTTON_FILE, state->color & 0xFF);
+    pthread_mutex_unlock(&g_lock);
+    return err;
+}
 
 /** Close the lights device */
 static int
@@ -238,6 +251,8 @@
         set_light = set_light_backlight;
     else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
         set_light = set_light_notifications;
+    else if (0 == strcmp(LIGHT_ID_BUTTONS, name))
+        set_light = set_light_buttons;
     else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
         set_light = set_light_attention;
     else
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index ecd66a6..afe62e2 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -58,12 +58,11 @@
         PipeBook::resetUse(i);
         PipeBook::resetAllocation(i);
     }
+    sForceSetBitmap = 0;
     mDumpStr[0] = '\0';
 }
 
 void Overlay::configDone() {
-    if(PipeBook::pipeUsageUnchanged()) return;
-
     for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
         if(PipeBook::isNotUsed(i)) {
             //Forces UNSET on pipes, flushes rotator memory and session, closes
@@ -142,6 +141,9 @@
     if(mPipeBook[index].mPipe->commit()) {
         ret = true;
         PipeBook::setUse((int)dest);
+        if(sForceSetBitmap & (1 << mPipeBook[index].mDisplay)) {
+            mPipeBook[index].mPipe->forceSet();
+        }
     } else {
         int dpy = mPipeBook[index].mDisplay;
         for(int i = 0; i < PipeBook::NUM_PIPES; i++)
@@ -387,6 +389,7 @@
 Overlay* Overlay::sInstance = 0;
 int Overlay::sDpyFbMap[DPY_MAX] = {0, -1, -1};
 int Overlay::sDMAMode = DMA_LINE_MODE;
+int Overlay::sForceSetBitmap = 0;
 int Overlay::PipeBook::NUM_PIPES = 0;
 int Overlay::PipeBook::sPipeUsageBitmap = 0;
 int Overlay::PipeBook::sLastUsageBitmap = 0;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index fea50b3..280223c 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -82,10 +82,6 @@
     bool commit(utils::eDest dest);
     bool queueBuffer(int fd, uint32_t offset, utils::eDest dest);
 
-    /* Closes open pipes, called during startup */
-    static int initOverlay();
-    /* Returns the singleton instance of overlay */
-    static Overlay* getInstance();
     /* Returns available ("unallocated") pipes for a display's mixer */
     int availablePipes(int dpy, int mixer);
     /* Returns if any of the requested pipe type is attached to any of the
@@ -98,6 +94,13 @@
     void getDump(char *buf, size_t len);
     /* Reset usage and allocation bits on all pipes for given display */
     void clear(int dpy);
+    /* Marks the display, whose pipes need to be forcibaly configured */
+    void forceSet(const int& dpy);
+
+    /* Closes open pipes, called during startup */
+    static int initOverlay();
+    /* Returns the singleton instance of overlay */
+    static Overlay* getInstance();
     static void setDMAMode(const int& mode);
     static int getDMAMode();
     /* Returns the framebuffer node backing up the display */
@@ -168,6 +171,7 @@
     static Overlay *sInstance;
     static int sDpyFbMap[DPY_MAX];
     static int sDMAMode;
+    static int sForceSetBitmap;
 };
 
 inline void Overlay::validate(int index) {
@@ -208,6 +212,10 @@
     return sDpyFbMap[dpy];
 }
 
+inline void Overlay::forceSet(const int& dpy) {
+    sForceSetBitmap |= (1 << dpy);
+}
+
 inline bool Overlay::PipeBook::valid() {
     return (mPipe != NULL);
 }
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 2d88376..674e62d 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -94,13 +94,14 @@
     setSrcWhf(args.whf);
 
     //TODO These are hardcoded. Can be moved out of setSource.
-    mOVInfo.alpha = 0xff;
     mOVInfo.transp_mask = 0xffffffff;
 
     //TODO These calls should ideally be a part of setPipeParams API
     setFlags(args.mdpFlags);
     setZ(args.zorder);
     setIsFg(args.isFg);
+    setPlaneAlpha(args.planeAlpha);
+    setBlending(args.blending);
 }
 
 void MdpCtrl::setCrop(const utils::Dim& d) {
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index 056d982..5bfec6b 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -99,8 +99,13 @@
     void setZ(utils::eZorder z);
     /* set isFg flag */
     void setIsFg(utils::eIsFg isFg);
-        /* return a copy of src whf*/
+    /* return a copy of src whf*/
     utils::Whf getSrcWhf() const;
+    /* set plane alpha */
+    void setPlaneAlpha(int planeAlpha);
+    /* set blending method */
+    void setBlending(overlay::utils::eBlending blending);
+
     /* set src whf */
     void setSrcWhf(const utils::Whf& whf);
     /* set src/dst rect dim */
@@ -241,6 +246,24 @@
     mDownscale = dscale;
 }
 
+inline void MdpCtrl::setPlaneAlpha(int planeAlpha) {
+    mOVInfo.alpha = planeAlpha;
+}
+
+inline void MdpCtrl::setBlending(overlay::utils::eBlending blending) {
+    switch((int) blending) {
+    case utils::OVERLAY_BLENDING_OPAQUE:
+        mOVInfo.blend_op = BLEND_OP_OPAQUE;
+        break;
+    case utils::OVERLAY_BLENDING_PREMULT:
+        mOVInfo.blend_op = BLEND_OP_PREMULTIPLIED;
+        break;
+    case utils::OVERLAY_BLENDING_COVERAGE:
+    default:
+        mOVInfo.blend_op = BLEND_OP_COVERAGE;
+    }
+}
+
 inline bool MdpCtrl::ovChanged() const {
 #ifdef USES_POST_PROCESSING
     // Some pp params are stored as pointer address,
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index c3d00f1..927e7e9 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -119,6 +119,9 @@
         case HAL_PIXEL_FORMAT_YCrCb_444_SP:
             return MDP_Y_CRCB_H1V1;
         case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+        case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+            //NV12 encodeable format maps to the venus format on
+            //B-Family targets
             return MDP_Y_CBCR_H2V2_VENUS;
         default:
             //Unsupported by MDP
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index b543018..e49a50c 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -212,6 +212,8 @@
 
 enum { MAX_PATH_LEN = 256 };
 
+enum { DEFAULT_PLANE_ALPHA = 0xFF };
+
 /**
  * Rotator flags: not to be confused with orientation flags.
  * Usually, you want to open the rotator to make sure it is
@@ -329,21 +331,36 @@
     OVERLAY_TRANSFORM_INV = 0x80
 };
 
+enum eBlending {
+    OVERLAY_BLENDING_UNDEFINED = 0x0,
+    /* No blending */
+    OVERLAY_BLENDING_OPAQUE,
+    /* src.rgb + dst.rgb*(1-src_alpha) */
+    OVERLAY_BLENDING_PREMULT,
+    /* src.rgb * src_alpha + dst.rgb (1 - src_alpha) */
+    OVERLAY_BLENDING_COVERAGE,
+};
+
 // Used to consolidate pipe params
 struct PipeArgs {
     PipeArgs() : mdpFlags(OV_MDP_FLAGS_NONE),
         zorder(Z_SYSTEM_ALLOC),
         isFg(IS_FG_OFF),
-        rotFlags(ROT_FLAGS_NONE){
+        rotFlags(ROT_FLAGS_NONE),
+        planeAlpha(DEFAULT_PLANE_ALPHA),
+        blending(OVERLAY_BLENDING_COVERAGE){
     }
 
     PipeArgs(eMdpFlags f, Whf _whf,
-            eZorder z, eIsFg fg, eRotFlags r) :
+            eZorder z, eIsFg fg, eRotFlags r,
+            int pA = DEFAULT_PLANE_ALPHA, eBlending b = OVERLAY_BLENDING_COVERAGE) :
         mdpFlags(f),
         whf(_whf),
         zorder(z),
         isFg(fg),
-        rotFlags(r) {
+        rotFlags(r),
+        planeAlpha(pA),
+        blending(b){
     }
 
     eMdpFlags mdpFlags; // for mdp_overlay flags
@@ -351,6 +368,8 @@
     eZorder zorder; // stage number
     eIsFg isFg; // control alpha & transp
     eRotFlags rotFlags;
+    int planeAlpha;
+    eBlending blending;
 };
 
 // Cannot use HW_OVERLAY_MAGNIFICATION_LIMIT, since at the time