Merge "hwc:Change the flip value in case of MDP3.0 based target."
diff --git a/Android.mk b/Android.mk
index b62e45b..afc4e4f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1,5 +1,6 @@
-display-hals := libgralloc libgenlock libcopybit liblight
+display-hals := libgralloc libgenlock libcopybit liblight libvirtual
 display-hals += libhwcomposer liboverlay libqdutils libexternal libqservice
+
 ifeq ($(call is-vendor-board-platform,QCOM),true)
     include $(call all-named-subdir-makefiles,$(display-hals))
 else
diff --git a/common.mk b/common.mk
index e8a50c1..13cd6ef 100644
--- a/common.mk
+++ b/common.mk
@@ -6,6 +6,7 @@
 common_includes += hardware/qcom/display/libhwcomposer
 common_includes += hardware/qcom/display/libexternal
 common_includes += hardware/qcom/display/libqservice
+common_includes += hardware/qcom/display/libvirtual
 
 ifeq ($(TARGET_USES_POST_PROCESSING),true)
     common_flags     += -DUSES_POST_PROCESSING
diff --git a/libcopybit/copybit.cpp b/libcopybit/copybit.cpp
index 2a4b1c5..65c78f7 100644
--- a/libcopybit/copybit.cpp
+++ b/libcopybit/copybit.cpp
@@ -341,6 +341,13 @@
                             __FUNCTION__, value);
                 }
                 break;
+            case COPYBIT_FG_LAYER:
+                if(value == COPYBIT_ENABLE) {
+                     ctx->mFlags |= MDP_IS_FG;
+                } else if (value == COPYBIT_DISABLE) {
+                    ctx->mFlags &= ~MDP_IS_FG;
+                }
+                break ;
             default:
                 status = -EINVAL;
                 break;
diff --git a/libcopybit/copybit.h b/libcopybit/copybit.h
index 0f4332f..878eca4 100644
--- a/libcopybit/copybit.h
+++ b/libcopybit/copybit.h
@@ -77,6 +77,7 @@
     COPYBIT_FRAMEBUFFER_WIDTH = 7,
     /* FB height */
     COPYBIT_FRAMEBUFFER_HEIGHT = 8,
+    COPYBIT_FG_LAYER = 9,
 };
 
 /* values for copybit_set_parameter(COPYBIT_TRANSFORM) */
diff --git a/libexternal/Android.mk b/libexternal/Android.mk
index f723113..3df6984 100644
--- a/libexternal/Android.mk
+++ b/libexternal/Android.mk
@@ -6,7 +6,7 @@
 LOCAL_MODULE_PATH             := $(TARGET_OUT_SHARED_LIBRARIES)
 LOCAL_MODULE_TAGS             := optional
 LOCAL_C_INCLUDES              := $(common_includes) $(kernel_includes)
-LOCAL_SHARED_LIBRARIES        := $(common_libs) liboverlay
+LOCAL_SHARED_LIBRARIES        := $(common_libs) liboverlay libqdutils
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdexternal\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
 LOCAL_SRC_FILES               := external.cpp
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 97f031d..89d63e9 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -21,8 +21,6 @@
 #define DEBUG 0
 #include <ctype.h>
 #include <fcntl.h>
-#include <media/IAudioPolicyService.h>
-#include <media/AudioSystem.h>
 #include <utils/threads.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
@@ -31,64 +29,25 @@
 #include <video/msm_hdmi_modes.h>
 #include <linux/fb.h>
 #include <sys/ioctl.h>
-#include <sys/poll.h>
-#include <sys/resource.h>
 #include <cutils/properties.h>
 #include "hwc_utils.h"
 #include "external.h"
 #include "overlayUtils.h"
 #include "overlay.h"
+#include "mdp_version.h"
 
 using namespace android;
 
 namespace qhwc {
-
-#define MAX_FRAME_BUFFER_NAME_SIZE      (80)
-#define MAX_DISPLAY_DEVICES             (3)
 #define MAX_SYSFS_FILE_PATH             255
 #define UNKNOWN_STRING                  "unknown"
 #define SPD_NAME_LENGTH                 16
 
-const char* msmFbDevicePath[] = {  "/dev/graphics/fb1",
-                                   "/dev/graphics/fb2"};
-
-/*
- * Updates extDeviceFbIndex Array with the correct frame buffer indices
- * of avaiable external devices
- *
- */
-void ExternalDisplay::updateExtDispDevFbIndex()
-{
-    FILE *displayDeviceFP = NULL;
-    char fbType[MAX_FRAME_BUFFER_NAME_SIZE];
-    char msmFbTypePath[MAX_FRAME_BUFFER_NAME_SIZE];
-
-    for(int j = 1; j < MAX_DISPLAY_DEVICES; j++) {
-        snprintf (msmFbTypePath, sizeof(msmFbTypePath),
-                  "/sys/class/graphics/fb%d/msm_fb_type", j);
-        displayDeviceFP = fopen(msmFbTypePath, "r");
-        if(displayDeviceFP){
-            fread(fbType, sizeof(char), MAX_FRAME_BUFFER_NAME_SIZE,
-                    displayDeviceFP);
-            if(strncmp(fbType, "dtv panel", strlen("dtv panel")) == 0){
-                ALOGD_IF(DEBUG,"hdmi framebuffer index is %d",j);
-                mHdmiFbNum = j;
-            } else if(strncmp(fbType, "writeback panel",
-                                    strlen("writeback panel")) == 0){
-                ALOGD_IF(DEBUG,"wfd framebuffer index is %d",j);
-                mWfdFbNum = j;
-            }
-            fclose(displayDeviceFP);
-        }
-    }
-    ALOGD_IF(DEBUG,"%s: mHdmiFbNum: %d mWfdFbNum: %d ",__FUNCTION__,
-                                                       mHdmiFbNum, mWfdFbNum);
-}
-
-int ExternalDisplay::configureHDMIDisplay() {
-    openFrameBuffer(mHdmiFbNum);
-    if(mFd == -1)
+int ExternalDisplay::configure() {
+    if(!openFrameBuffer()) {
+        ALOGE("%s: Failed to open FB: %d", __FUNCTION__, mFbNum);
         return -1;
+    }
     readCEUnderscanInfo();
     readResolution();
     // TODO: Move this to activate
@@ -101,82 +60,38 @@
         mode = getBestMode();
     }
     setResolution(mode);
-    setDpyHdmiAttr();
-    setExternalDisplay(true, mHdmiFbNum);
+    setAttributes();
     // set system property
     property_set("hw.hdmiON", "1");
     return 0;
 }
 
-int ExternalDisplay::configureWFDDisplay() {
-    int ret = 0;
-    if(mConnectedFbNum == mHdmiFbNum) {
-        ALOGE("%s: Cannot process WFD connection while HDMI is active",
-                     __FUNCTION__);
-        return -1;
-    }
-    openFrameBuffer(mWfdFbNum);
-    if(mFd == -1)
-        return -1;
-    ret = ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo);
-    if(ret < 0) {
-        ALOGD("In %s: FBIOGET_VSCREENINFO failed Err Str = %s", __FUNCTION__,
-                strerror(errno));
-    }
-    setDpyWfdAttr();
-    setExternalDisplay(true, mWfdFbNum);
+void ExternalDisplay::getAttributes(int& width, int& height) {
+    int fps = 0;
+    getAttrForMode(width, height, fps);
+}
+
+int ExternalDisplay::teardown() {
+    closeFrameBuffer();
+    resetInfo();
+    // unset system property
+    property_set("hw.hdmiON", "0");
     return 0;
 }
 
-int ExternalDisplay::teardownHDMIDisplay() {
-    if(mConnectedFbNum == mHdmiFbNum) {
-        // hdmi offline event..!
-        closeFrameBuffer();
-        resetInfo();
-        setExternalDisplay(false);
-        // unset system property
-        property_set("hw.hdmiON", "0");
-    }
-    return 0;
-}
-
-int ExternalDisplay::teardownWFDDisplay() {
-    if(mConnectedFbNum == mWfdFbNum) {
-        // wfd offline event..!
-        closeFrameBuffer();
-        memset(&mVInfo, 0, sizeof(mVInfo));
-        setExternalDisplay(false);
-    }
-    return 0;
-}
-
-int ExternalDisplay::ignoreRequest(const char *str) {
-    const char *s1 = str + strlen("change@/devices/virtual/switch/");
-    if(!strncmp(s1,"wfd",strlen(s1))) {
-        if(mConnectedFbNum == mHdmiFbNum) {
-            ALOGE("Ignore wfd event when HDMI is active");
-            return true;
-        }
-    }
-    return false;
-}
-
-
 ExternalDisplay::ExternalDisplay(hwc_context_t* ctx):mFd(-1),
-    mCurrentMode(-1), mConnected(0), mConnectedFbNum(0), mModeCount(0),
-    mUnderscanSupported(false), mHwcContext(ctx), mHdmiFbNum(-1),
-    mWfdFbNum(-1), mExtDpyNum(HWC_DISPLAY_EXTERNAL)
+    mCurrentMode(-1), mModeCount(0),
+    mUnderscanSupported(false), mHwcContext(ctx)
 {
     memset(&mVInfo, 0, sizeof(mVInfo));
-    //Determine the fb index for external display devices.
-    updateExtDispDevFbIndex();
+    mFbNum = overlay::Overlay::getInstance()->getFbForDpy(HWC_DISPLAY_EXTERNAL);
     // disable HPD at start, it will be enabled later
     // when the display powers on
     // This helps for framework reboot or adb shell stop/start
     writeHPDOption(0);
 
     // for HDMI - retreive all the modes supported by the driver
-    if(mHdmiFbNum != -1) {
+    if(mFbNum != -1) {
         supported_video_mode_lut =
                         new msm_hdmi_mode_timing_info[HDMI_VFRMT_MAX];
         // Populate the mode table for supported modes
@@ -201,7 +116,7 @@
     memset(sysFsSPDFilePath, 0, sizeof(sysFsSPDFilePath));
     snprintf(sysFsSPDFilePath , sizeof(sysFsSPDFilePath),
                  "/sys/devices/virtual/graphics/fb%d/%s",
-                 mHdmiFbNum, node);
+                 mFbNum, node);
     int spdFile = open(sysFsSPDFilePath, O_RDWR, 0);
     if (spdFile < 0) {
         ALOGE("%s: file '%s' not found : ret = %d"
@@ -225,17 +140,6 @@
     }
 }
 
-void ExternalDisplay::setEDIDMode(int resMode) {
-    ALOGD_IF(DEBUG,"resMode=%d ", resMode);
-    {
-        Mutex::Autolock lock(mExtDispLock);
-        setExternalDisplay(false);
-        openFrameBuffer(mHdmiFbNum);
-        setResolution(resMode);
-    }
-    setExternalDisplay(true, mHdmiFbNum);
-}
-
 void ExternalDisplay::setHPD(uint32_t startEnd) {
     ALOGD_IF(DEBUG,"HPD enabled=%d", startEnd);
     writeHPDOption(startEnd);
@@ -243,24 +147,20 @@
 
 void ExternalDisplay::setActionSafeDimension(int w, int h) {
     ALOGD_IF(DEBUG,"ActionSafe w=%d h=%d", w, h);
-    Mutex::Autolock lock(mExtDispLock);
     char actionsafeWidth[PROPERTY_VALUE_MAX];
     char actionsafeHeight[PROPERTY_VALUE_MAX];
     snprintf(actionsafeWidth, sizeof(actionsafeWidth), "%d", w);
     property_set("persist.sys.actionsafe.width", actionsafeWidth);
     snprintf(actionsafeHeight, sizeof(actionsafeHeight), "%d", h);
     property_set("persist.sys.actionsafe.height", actionsafeHeight);
-    setExternalDisplay(true, mHdmiFbNum);
 }
 
 int ExternalDisplay::getModeCount() const {
     ALOGD_IF(DEBUG,"HPD mModeCount=%d", mModeCount);
-    Mutex::Autolock lock(mExtDispLock);
     return mModeCount;
 }
 
 void ExternalDisplay::getEDIDModes(int *out) const {
-    Mutex::Autolock lock(mExtDispLock);
     for(int i = 0;i < mModeCount;i++) {
         out[i] = mEDIDModes[i];
     }
@@ -277,7 +177,7 @@
     char sysFsScanInfoFilePath[MAX_SYSFS_FILE_PATH];
     snprintf(sysFsScanInfoFilePath, sizeof(sysFsScanInfoFilePath),
             "/sys/devices/virtual/graphics/fb%d/"
-                                   "scan_info", mHdmiFbNum);
+                                   "scan_info", mFbNum);
 
     memset(scanInfo, 0, sizeof(scanInfo));
     hdmiScanInfoFile = open(sysFsScanInfoFilePath, O_RDONLY, 0);
@@ -397,7 +297,7 @@
 {
     char sysFsEDIDFilePath[MAX_SYSFS_FILE_PATH];
     snprintf(sysFsEDIDFilePath , sizeof(sysFsEDIDFilePath),
-            "/sys/devices/virtual/graphics/fb%d/edid_modes", mHdmiFbNum);
+            "/sys/devices/virtual/graphics/fb%d/edid_modes", mFbNum);
 
     int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0);
     int len = -1;
@@ -431,16 +331,15 @@
     return (strlen(mEDIDs) > 0);
 }
 
-bool ExternalDisplay::openFrameBuffer(int fbNum)
+bool ExternalDisplay::openFrameBuffer()
 {
     if (mFd == -1) {
-        mFd = open(msmFbDevicePath[fbNum-1], O_RDWR);
+        char strDevPath[MAX_SYSFS_FILE_PATH];
+        snprintf(strDevPath, MAX_SYSFS_FILE_PATH, "/dev/graphics/fb%d", mFbNum);
+        mFd = open(strDevPath, O_RDWR);
         if (mFd < 0)
-            ALOGE("%s: %s is not available", __FUNCTION__,
-                                            msmFbDevicePath[fbNum-1]);
-        if(mHwcContext) {
-            mHwcContext->dpyAttr[mExtDpyNum].fd = mFd;
-        }
+            ALOGE("%s: %s is not available", __FUNCTION__, strDevPath);
+        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
     }
     return (mFd > 0);
 }
@@ -452,9 +351,7 @@
         ret = close(mFd);
         mFd = -1;
     }
-    if(mHwcContext) {
-        mHwcContext->dpyAttr[mExtDpyNum].fd = mFd;
-    }
+    mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].fd = mFd;
     return (ret == 0);
 }
 
@@ -547,7 +444,6 @@
 int ExternalDisplay::getBestMode() {
     int bestOrder = 0;
     int bestMode = HDMI_VFRMT_640x480p60_4_3;
-    Mutex::Autolock lock(mExtDispLock);
     // for all the edid read, get the best mode
     for(int i = 0; i < mModeCount; i++) {
         int mode = mEDIDModes[i];
@@ -644,40 +540,17 @@
     }
 }
 
-void ExternalDisplay::setExternalDisplay(bool connected, int extFbNum)
-{
-    hwc_context_t* ctx = mHwcContext;
-    if(ctx) {
-        ALOGD_IF(DEBUG, "%s: connected = %d", __FUNCTION__, connected);
-        // Store the external display
-        mConnected = connected;
-        mConnectedFbNum = extFbNum;
-        mHwcContext->dpyAttr[mExtDpyNum].connected = connected;
-        // Update external fb number in Overlay context
-        overlay::Overlay::getInstance()->setExtFbNum(extFbNum);
-    }
-}
-
-int ExternalDisplay::getExtFbNum(int &fbNum) {
-    int ret = -1;
-    if(mConnected) {
-        fbNum = mConnectedFbNum;
-        ret = 0;
-    }
-    return ret;
-}
-
 bool ExternalDisplay::writeHPDOption(int userOption) const
 {
     bool ret = true;
-    if(mHdmiFbNum != -1) {
+    if(mFbNum != -1) {
         char sysFsHPDFilePath[MAX_SYSFS_FILE_PATH];
         snprintf(sysFsHPDFilePath ,sizeof(sysFsHPDFilePath),
-                 "/sys/devices/virtual/graphics/fb%d/hpd", mHdmiFbNum);
+                 "/sys/devices/virtual/graphics/fb%d/hpd", mFbNum);
         int hdmiHPDFile = open(sysFsHPDFilePath,O_RDWR, 0);
         if (hdmiHPDFile < 0) {
-            ALOGE("%s: state file '%s' not found : ret%d err str: %s", __FUNCTION__,
-                  sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
+            ALOGE("%s: state file '%s' not found : ret%d err str: %s",
+                  __FUNCTION__, sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
             ret = false;
         } else {
             int err = -1;
@@ -687,7 +560,8 @@
             else
                 err = write(hdmiHPDFile, "0" , 2);
             if (err <= 0) {
-                ALOGE("%s: file write failed '%s'", __FUNCTION__, sysFsHPDFilePath);
+                ALOGE("%s: file write failed '%s'", __FUNCTION__,
+                      sysFsHPDFilePath);
                 ret = false;
             }
             close(hdmiHPDFile);
@@ -696,25 +570,37 @@
     return ret;
 }
 
-void ExternalDisplay::setDpyWfdAttr() {
-    if(mHwcContext) {
-        mHwcContext->dpyAttr[mExtDpyNum].xres = mVInfo.xres;
-        mHwcContext->dpyAttr[mExtDpyNum].yres = mVInfo.yres;
-        mHwcContext->dpyAttr[mExtDpyNum].vsync_period =
-                1000000000l /60;
-        ALOGD_IF(DEBUG,"%s: wfd...connected..!",__FUNCTION__);
-    }
-}
 
-void ExternalDisplay::setDpyHdmiAttr() {
+void ExternalDisplay::setAttributes() {
     int width = 0, height = 0, fps = 0;
     getAttrForMode(width, height, fps);
+    ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
     if(mHwcContext) {
-        ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
+        // Always set dpyAttr res to mVInfo res
         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
+        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false;
+        if(!qdutils::MDPVersion::getInstance().is8x26()) {
+            int priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+            int priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+            // if primary resolution is more than the hdmi resolution
+            // configure dpy attr to primary resolution and set
+            // downscale mode
+            if((priW * priH) > (width * height)) {
+                mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priW;
+                mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priH;
+                // HDMI is always in landscape, so always assign the higher
+                // dimension to hdmi's xres
+                if(priH > priW) {
+                    mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priH;
+                    mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priW;
+                }
+                // Set External Display MDP Downscale mode indicator
+                mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true;
+            }
+        }
         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
-            1000000000l / fps;
+                1000000000l / fps;
     }
 }
 
diff --git a/libexternal/external.h b/libexternal/external.h
index 7ab7c3f..1a3602d 100644
--- a/libexternal/external.h
+++ b/libexternal/external.h
@@ -21,7 +21,6 @@
 #ifndef HWC_EXTERNAL_DISPLAY_H
 #define HWC_EXTERNAL_DISPLAY_H
 
-#include <utils/threads.h>
 #include <linux/fb.h>
 
 struct hwc_context_t;
@@ -42,61 +41,46 @@
 public:
     ExternalDisplay(hwc_context_t* ctx);
     ~ExternalDisplay();
-    int getModeCount() const;
-    void getEDIDModes(int *out) const;
-    bool isCEUnderscanSupported() { return mUnderscanSupported; }
-    void setExternalDisplay(bool connected, int extFbNum = 0);
-    bool isExternalConnected() { return mConnected;};
-    void  setExtDpyNum(int extDpyNum) { mExtDpyNum = extDpyNum;};
-    int  getExternalType() {return mConnectedFbNum;};
-    bool isWFDActive() {return (mConnectedFbNum == mWfdFbNum);};
     void setHPD(uint32_t startEnd);
-    void setEDIDMode(int resMode);
     void setActionSafeDimension(int w, int h);
-    int ignoreRequest(const char *str);
-    int  configureHDMIDisplay();
-    int  configureWFDDisplay();
-    int  teardownHDMIDisplay();
-    int  teardownWFDDisplay();
-    int getHDMIIndex() { return mHdmiFbNum; }
+    bool isCEUnderscanSupported() { return mUnderscanSupported; }
+    int configure();
+    void getAttributes(int& width, int& height);
+    int teardown();
+    bool isConnected() {
+        return  mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].connected;
+    }
 
 private:
+    int getModeCount() const;
+    void getEDIDModes(int *out) const;
+    void setEDIDMode(int resMode);
     void setSPDInfo(const char* node, const char* property);
     void readCEUnderscanInfo();
     bool readResolution();
     int  parseResolution(char* edidStr, int* edidModes);
     void setResolution(int ID);
-    bool openFrameBuffer(int fbNum);
+    bool openFrameBuffer();
     bool closeFrameBuffer();
     bool writeHPDOption(int userOption) const;
     bool isValidMode(int ID);
-    void handleUEvent(char* str, int len);
     int  getModeOrder(int mode);
     int  getUserMode();
     int  getBestMode();
     bool isInterlacedMode(int mode);
     void resetInfo();
-    void setDpyHdmiAttr();
-    void setDpyWfdAttr();
+    void setAttributes();
     void getAttrForMode(int& width, int& height, int& fps);
-    void updateExtDispDevFbIndex();
-    int  getExtFbNum(int &fbNum);
 
-    mutable android::Mutex mExtDispLock;
     int mFd;
+    int mFbNum;
     int mCurrentMode;
-    int mConnected;
-    int mConnectedFbNum;
-    int mResolutionMode;
     char mEDIDs[128];
     int mEDIDModes[64];
     int mModeCount;
     bool mUnderscanSupported;
     hwc_context_t *mHwcContext;
     fb_var_screeninfo mVInfo;
-    int mHdmiFbNum;
-    int mWfdFbNum;
-    int mExtDpyNum;
     // Holds all the HDMI modes and timing info supported by driver
     msm_hdmi_mode_timing_info* supported_video_mode_lut;
 };
diff --git a/libgenlock/Android.mk b/libgenlock/Android.mk
deleted file mode 100644
index 96e8b4e..0000000
--- a/libgenlock/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(LOCAL_PATH)/../common.mk
-include $(CLEAR_VARS)
-
-LOCAL_MODULE                  := libgenlock
-LOCAL_MODULE_TAGS             := optional
-LOCAL_C_INCLUDES              := $(common_includes)
-LOCAL_SHARED_LIBRARIES        := liblog libcutils
-LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdgenlock\"
-LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
-LOCAL_SRC_FILES               := genlock.cpp
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/libgenlock/genlock.cpp b/libgenlock/genlock.cpp
deleted file mode 100644
index c606ecc..0000000
--- a/libgenlock/genlock.cpp
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (c) 2011-2012, 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 <cutils/log.h>
-#include <cutils/native_handle.h>
-#include <gralloc_priv.h>
-#include <linux/genlock.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-
-#include "genlock.h"
-
-#define GENLOCK_DEVICE "/dev/genlock"
-
-namespace {
-/* Internal function to map the userspace locks to the kernel lock types */
-    int get_kernel_lock_type(genlock_lock_type lockType)
-    {
-        int kLockType = 0;
-#ifdef USE_GENLOCK
-        // If the user sets both a read and write lock, higher preference is
-        // given to the write lock.
-        if (lockType & GENLOCK_WRITE_LOCK) {
-            kLockType = GENLOCK_WRLOCK;
-        } else if (lockType & GENLOCK_READ_LOCK) {
-            kLockType = GENLOCK_RDLOCK;
-        } else {
-            ALOGE("%s: invalid lockType (lockType = %d)",
-                  __FUNCTION__, lockType);
-            return -1;
-        }
-#endif
-        return kLockType;
-    }
-
-    /* Internal function to perform the actual lock/unlock operations */
-    genlock_status_t perform_lock_unlock_operation(native_handle_t *buffer_handle,
-                                                   int lockType, int timeout,
-                                                   int flags)
-    {
-#ifdef USE_GENLOCK
-        if (private_handle_t::validate(buffer_handle)) {
-            ALOGE("%s: handle is invalid", __FUNCTION__);
-            return GENLOCK_FAILURE;
-        }
-
-        private_handle_t *hnd = reinterpret_cast<private_handle_t*>
-                                (buffer_handle);
-        if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
-            if (hnd->genlockPrivFd < 0) {
-                ALOGE("%s: the lock has not been created,"
-                      "or has not been attached", __FUNCTION__);
-                return GENLOCK_FAILURE;
-            }
-
-            genlock_lock lock;
-            lock.op = lockType;
-            lock.flags = flags;
-            lock.timeout = timeout;
-            lock.fd = hnd->genlockHandle;
-
-#ifdef GENLOCK_IOC_DREADLOCK
-            if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_DREADLOCK, &lock)) {
-                ALOGE("%s: GENLOCK_IOC_DREADLOCK failed (lockType0x%x,"
-                       "err=%s fd=%d)", __FUNCTION__,
-                      lockType, strerror(errno), hnd->fd);
-                if (ETIMEDOUT == errno)
-                    return GENLOCK_TIMEDOUT;
-
-                return GENLOCK_FAILURE;
-            }
-#else
-            // depreciated
-            if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_LOCK, &lock)) {
-                ALOGE("%s: GENLOCK_IOC_LOCK failed (lockType0x%x, err=%s fd=%d)"
-                      ,__FUNCTION__, lockType, strerror(errno), hnd->fd);
-                if (ETIMEDOUT == errno)
-                    return GENLOCK_TIMEDOUT;
-
-                return GENLOCK_FAILURE;
-            }
-#endif
-        }
-#endif
-        return GENLOCK_NO_ERROR;
-    }
-
-    /* Internal function to close the fd and release the handle */
-    void close_genlock_fd_and_handle(int& fd, int& handle)
-    {
-        if (fd >=0 ) {
-            close(fd);
-            fd = -1;
-        }
-
-        if (handle >= 0) {
-            close(handle);
-            handle = -1;
-        }
-    }
-}
-/*
- * Create a genlock lock. The genlock lock file descriptor and the lock
- * handle are stored in the buffer_handle.
- *
- * @param: handle of the buffer
- * @return error status.
- */
-genlock_status_t genlock_create_lock(native_handle_t *buffer_handle)
-{
-    genlock_status_t ret = GENLOCK_NO_ERROR;
-#ifdef USE_GENLOCK
-    if (private_handle_t::validate(buffer_handle)) {
-        ALOGE("%s: handle is invalid", __FUNCTION__);
-        return GENLOCK_FAILURE;
-    }
-
-    private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
-    if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
-        // Open the genlock device
-        int fd = open(GENLOCK_DEVICE, O_RDWR);
-        if (fd < 0) {
-            ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
-                  strerror(errno));
-            return GENLOCK_FAILURE;
-        }
-
-        // Create a new lock
-        genlock_lock lock;
-        if (ioctl(fd, GENLOCK_IOC_NEW, NULL)) {
-            ALOGE("%s: GENLOCK_IOC_NEW failed (error=%s)", __FUNCTION__,
-                  strerror(errno));
-            close_genlock_fd_and_handle(fd, lock.fd);
-            ret = GENLOCK_FAILURE;
-        }
-
-        // Export the lock for other processes to be able to use it.
-        if (GENLOCK_FAILURE != ret) {
-            if (ioctl(fd, GENLOCK_IOC_EXPORT, &lock)) {
-                ALOGE("%s: GENLOCK_IOC_EXPORT failed (error=%s)", __FUNCTION__,
-                      strerror(errno));
-                close_genlock_fd_and_handle(fd, lock.fd);
-                ret = GENLOCK_FAILURE;
-            }
-        }
-
-        // Store the lock params in the handle.
-        hnd->genlockPrivFd = fd;
-        hnd->genlockHandle = lock.fd;
-    } else {
-        hnd->genlockHandle = 0;
-    }
-#endif
-    return ret;
-}
-
-
-/*
- * Release a genlock lock associated with the handle.
- *
- * @param: handle of the buffer
- * @return error status.
- */
-genlock_status_t genlock_release_lock(native_handle_t *buffer_handle)
-{
-    genlock_status_t ret = GENLOCK_NO_ERROR;
-#ifdef USE_GENLOCK
-    if (private_handle_t::validate(buffer_handle)) {
-        ALOGE("%s: handle is invalid", __FUNCTION__);
-        return GENLOCK_FAILURE;
-    }
-
-    private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
-    if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
-        if (hnd->genlockPrivFd < 0) {
-            ALOGE("%s: the lock is invalid", __FUNCTION__);
-            return GENLOCK_FAILURE;
-        }
-
-        // Close the fd and reset the parameters.
-        close_genlock_fd_and_handle(hnd->genlockPrivFd, hnd->genlockHandle);
-    }
-#endif
-    return ret;
-}
-
-
-/*
- * Attach a lock to the buffer handle passed via an IPC.
- *
- * @param: handle of the buffer
- * @return error status.
- */
-genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle)
-{
-    genlock_status_t ret = GENLOCK_NO_ERROR;
-#ifdef USE_GENLOCK
-    if (private_handle_t::validate(buffer_handle)) {
-        ALOGE("%s: handle is invalid", __FUNCTION__);
-        return GENLOCK_FAILURE;
-    }
-
-    private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
-    if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
-        // Open the genlock device
-        int fd = open(GENLOCK_DEVICE, O_RDWR);
-        if (fd < 0) {
-            ALOGE("%s: open genlock device failed (err=%s)", __FUNCTION__,
-                  strerror(errno));
-            return GENLOCK_FAILURE;
-        }
-
-        // Attach the local handle to an existing lock
-        genlock_lock lock;
-        lock.fd = hnd->genlockHandle;
-        if (ioctl(fd, GENLOCK_IOC_ATTACH, &lock)) {
-            ALOGE("%s: GENLOCK_IOC_ATTACH failed (err=%s)", __FUNCTION__,
-                  strerror(errno));
-            close_genlock_fd_and_handle(fd, lock.fd);
-            ret = GENLOCK_FAILURE;
-        }
-
-        // Store the relavant information in the handle
-        hnd->genlockPrivFd = fd;
-    }
-#endif
-    return ret;
-}
-
-/*
- * Lock the buffer specified by the buffer handle. The lock held by the buffer
- * is specified by the lockType. This function will block if a write lock is
- * requested on the buffer which has previously been locked for a read or write
- * operation. A buffer can be locked by multiple clients for read. An optional
- * timeout value can be specified. By default, there is no timeout.
- *
- * @param: handle of the buffer
- * @param: type of lock to be acquired by the buffer.
- * @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout value.
- * @return error status.
- */
-genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
-                                     genlock_lock_type_t lockType,
-                                     int timeout)
-{
-    genlock_status_t ret = GENLOCK_NO_ERROR;
-#ifdef USE_GENLOCK
-    // Translate the locktype
-    int kLockType = get_kernel_lock_type(lockType);
-    if (-1 == kLockType) {
-        ALOGE("%s: invalid lockType", __FUNCTION__);
-        return GENLOCK_FAILURE;
-    }
-
-    if (0 == timeout) {
-        ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
-    }
-    // Call the private function to perform the lock operation specified.
-    ret = perform_lock_unlock_operation(buffer_handle, kLockType, timeout, 0);
-#endif
-    return ret;
-}
-
-
-/*
- * Unlocks a buffer that has previously been locked by the client.
- *
- * @param: handle of the buffer to be unlocked.
- * @return: error status.
- */
-genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle)
-{
-    genlock_status_t ret = GENLOCK_NO_ERROR;
-#ifdef USE_GENLOCK
-    // Do the unlock operation by setting the unlock flag. Timeout is always
-    // 0 in this case.
-    ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_UNLOCK, 0, 0);
-#endif
-    return ret;
-}
-
-/*
- * Blocks the calling process until the lock held on the handle is unlocked.
- *
- * @param: handle of the buffer
- * @param: timeout value for the wait.
- * return: error status.
- */
-genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout) {
-#ifdef USE_GENLOCK
-    if (private_handle_t::validate(buffer_handle)) {
-        ALOGE("%s: handle is invalid", __FUNCTION__);
-        return GENLOCK_FAILURE;
-    }
-
-    private_handle_t *hnd = reinterpret_cast<private_handle_t*>(buffer_handle);
-    if ((hnd->flags & private_handle_t::PRIV_FLAGS_UNSYNCHRONIZED) == 0) {
-        if (hnd->genlockPrivFd < 0) {
-            ALOGE("%s: the lock is invalid", __FUNCTION__);
-            return GENLOCK_FAILURE;
-        }
-
-        if (0 == timeout)
-            ALOGW("%s: timeout = 0", __FUNCTION__);
-
-        genlock_lock lock;
-        lock.fd = hnd->genlockHandle;
-        lock.timeout = timeout;
-        if (ioctl(hnd->genlockPrivFd, GENLOCK_IOC_WAIT, &lock)) {
-            ALOGE("%s: GENLOCK_IOC_WAIT failed (err=%s)",  __FUNCTION__,
-                  strerror(errno));
-            return GENLOCK_FAILURE;
-        }
-    }
-#endif
-    return GENLOCK_NO_ERROR;
-}
-
-/*
- * Convert a write lock that we own to a read lock
- *
- * @param: handle of the buffer
- * @param: timeout value for the wait.
- * return: error status.
- */
-genlock_status_t genlock_write_to_read(native_handle_t *buffer_handle,
-                                       int timeout) {
-    genlock_status_t ret = GENLOCK_NO_ERROR;
-#ifdef USE_GENLOCK
-    if (0 == timeout) {
-        ALOGW("%s: trying to lock a buffer with timeout = 0", __FUNCTION__);
-    }
-    // Call the private function to perform the lock operation specified.
-#ifdef GENLOCK_IOC_DREADLOCK
-    ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK, timeout,
-                                        GENLOCK_WRITE_TO_READ);
-#else
-    // depreciated
-    ret = perform_lock_unlock_operation(buffer_handle, GENLOCK_RDLOCK,
-                                        timeout, 0);
-#endif
-#endif
-    return ret;
-}
diff --git a/libgenlock/genlock.h b/libgenlock/genlock.h
deleted file mode 100644
index 222f2a7..0000000
--- a/libgenlock/genlock.h
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright (c) 2011-2012, 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 INCLUDE_LIBGENLOCK
-#define INCLUDE_LIBGENLOCK
-
-#include <cutils/native_handle.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-    /* Genlock lock types */
-    typedef enum genlock_lock_type{
-        GENLOCK_READ_LOCK  = 1<<0,  // Read lock
-        GENLOCK_WRITE_LOCK = 1<<1,  // Write lock
-    }genlock_lock_type_t;
-
-    /* Genlock return values */
-    typedef enum genlock_status{
-        GENLOCK_NO_ERROR = 0,
-        GENLOCK_TIMEDOUT,
-        GENLOCK_FAILURE,
-    } genlock_status_t;
-
-    /* Genlock defines */
-#define GENLOCK_MAX_TIMEOUT 1000 // Max 1s timeout
-
-    /*
-     * Create a genlock lock. The genlock lock file descriptor and the lock
-     * handle are stored in the buffer_handle.
-     *
-     * @param: handle of the buffer
-     * @return error status.
-     */
-    genlock_status_t genlock_create_lock(native_handle_t *buffer_handle);
-
-
-    /*
-     * Release a genlock lock associated with the handle.
-     *
-     * @param: handle of the buffer
-     * @return error status.
-     */
-    genlock_status_t genlock_release_lock(native_handle_t *buffer_handle);
-
-    /*
-     * Attach a lock to the buffer handle passed via an IPC.
-     *
-     * @param: handle of the buffer
-     * @return error status.
-     */
-    genlock_status_t genlock_attach_lock(native_handle_t *buffer_handle);
-
-    /*
-     * Lock the buffer specified by the buffer handle. The lock held by the
-     * buffer is specified by the lockType. This function will block if a write
-     * lock is requested on the buffer which has previously been locked for a
-     * read or write operation. A buffer can be locked by multiple clients for
-     * read. An optional timeout value can be specified.
-     * By default, there is no timeout.
-     *
-     * @param: handle of the buffer
-     * @param: type of lock to be acquired by the buffer.
-     * @param: timeout value in ms. GENLOCK_MAX_TIMEOUT is the maximum timeout
-     *         value.
-     * @return error status.
-     */
-    genlock_status_t genlock_lock_buffer(native_handle_t *buffer_handle,
-                                         genlock_lock_type_t lockType,
-                                         int timeout);
-
-    /*
-     * Unlocks a buffer that has previously been locked by the client.
-     *
-     * @param: handle of the buffer to be unlocked.
-     * @return: error status.
-     */
-    genlock_status_t genlock_unlock_buffer(native_handle_t *buffer_handle);
-
-    /*
-     * Blocks the calling process until the lock held on the handle is unlocked.
-     *
-     * @param: handle of the buffer
-     * @param: timeout value for the wait.
-     * return: error status.
-     */
-    genlock_status_t genlock_wait(native_handle_t *buffer_handle, int timeout);
-
-    /*
-     * Convert a write lock that we own to a read lock
-     *
-     * @param: handle of the buffer
-     * @param: timeout value for the wait.
-     * return: error status.
-     */
-    genlock_status_t genlock_write_to_read(native_handle_t *buffer_handle,
-                                           int timeout);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 0ae3eb4..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;
 }
@@ -146,7 +147,6 @@
             case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
                 stride = ALIGN(width, 128);
                 break;
-            case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
             case HAL_PIXEL_FORMAT_YCbCr_420_SP:
             case HAL_PIXEL_FORMAT_YCrCb_420_SP:
             case HAL_PIXEL_FORMAT_YV12:
@@ -155,6 +155,7 @@
                 stride = ALIGN(width, 16);
                 break;
             case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+            case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
                 stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, width);
                 break;
             case HAL_PIXEL_FORMAT_BLOB:
@@ -306,21 +307,14 @@
             size  = ALIGN( alignedw * alignedh, 8192);
             size += ALIGN( alignedw * ALIGN(height/2, 32), 8192);
             break;
-        case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
         case HAL_PIXEL_FORMAT_YV12:
             if ((format == HAL_PIXEL_FORMAT_YV12) && ((width&1) || (height&1))) {
                 ALOGE("w or h is odd for the YV12 format");
                 return -EINVAL;
             }
             alignedh = height;
-            if (HAL_PIXEL_FORMAT_NV12_ENCODEABLE == format) {
-                // The encoder requires a 2K aligned chroma offset.
-                size = ALIGN(alignedw*alignedh, 2048) +
+            size = alignedw*alignedh +
                     (ALIGN(alignedw/2, 16) * (alignedh/2))*2;
-            } else {
-                size = alignedw*alignedh +
-                    (ALIGN(alignedw/2, 16) * (alignedh/2))*2;
-            }
             size = ALIGN(size, 4096);
             break;
         case HAL_PIXEL_FORMAT_YCbCr_420_SP:
@@ -338,6 +332,7 @@
             size = ALIGN(alignedw * alignedh * 2, 4096);
             break;
         case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+        case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
             alignedh = VENUS_Y_SCANLINES(COLOR_FMT_NV12, height);
             size = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, width, height);
             break;
diff --git a/libgralloc/gpu.cpp b/libgralloc/gpu.cpp
index 1f757bc..1b3e934 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -109,11 +109,17 @@
 #ifndef MDSS_TARGET
                 flags |= private_handle_t::PRIV_FLAGS_ITU_R_601_FR;
 #else
-                    if (usage & (GRALLOC_USAGE_HW_TEXTURE |
-                                 GRALLOC_USAGE_HW_VIDEO_ENCODER))
+                // Per the camera spec ITU 709 format should be set only for
+                // video encoding.
+                // It should be set to ITU 601 full range format for any other
+                // camera buffer
+                //
+                if (usage & GRALLOC_USAGE_HW_CAMERA_MASK) {
+                    if (usage & GRALLOC_USAGE_HW_VIDEO_ENCODER)
                         flags |= private_handle_t::PRIV_FLAGS_ITU_R_709;
-                    else if (usage & GRALLOC_USAGE_HW_CAMERA_ZSL)
+                    else
                         flags |= private_handle_t::PRIV_FLAGS_ITU_R_601_FR;
+                }
 #endif
             } else {
                 flags |= private_handle_t::PRIV_FLAGS_ITU_R_601;
diff --git a/libhwcomposer/Android.mk b/libhwcomposer/Android.mk
index 4b9d04b..d47e4b0 100644
--- a/libhwcomposer/Android.mk
+++ b/libhwcomposer/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_SHARED_LIBRARIES        := $(common_libs) libEGL liboverlay \
                                  libexternal libqdutils libhardware_legacy \
                                  libdl libmemalloc libqservice libsync \
-                                 libbinder libmedia libskia
+                                 libbinder libmedia libskia libvirtual
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdhwcomposer\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
 LOCAL_SRC_FILES               := hwc.cpp          \
@@ -22,6 +22,7 @@
                                  hwc_mdpcomp.cpp  \
                                  hwc_copybit.cpp  \
                                  hwc_qclient.cpp  \
-                                 hwc_dump_layers.cpp
+                                 hwc_dump_layers.cpp \
+                                 hwc_ad.cpp
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 6dd77b1..113e916 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -36,6 +36,7 @@
 #include "hwc_dump_layers.h"
 #include "external.h"
 #include "hwc_copybit.h"
+#include "hwc_ad.h"
 #include "profiler.h"
 
 using namespace qhwc;
@@ -66,6 +67,17 @@
     }
 };
 
+/* In case of proprietary WFD session, we are fooling SF by piggybacking on
+ * HDMI display ID for virtual. This helper is needed to differentiate their
+ * paths in HAL.
+ * TODO: Not needed once we have WFD client working on top of Google API's */
+
+static int getHWCDpy(hwc_context_t *ctx, int dpy) {
+    if(dpy == HWC_DISPLAY_EXTERNAL && ctx->mVirtualonExtActive)
+        return HWC_DISPLAY_VIRTUAL;
+    return dpy;
+}
+
 /*
  * Save callback functions registered to HWC
  */
@@ -106,7 +118,11 @@
             ctx->mFBUpdate[i]->reset();
         if(ctx->mCopyBit[i])
             ctx->mCopyBit[i]->reset();
+        if(ctx->mLayerRotMap[i])
+            ctx->mLayerRotMap[i]->reset();
     }
+
+    ctx->mAD->reset();
 }
 
 //clear prev layer prop flags and realloc for current frame
@@ -118,15 +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) == -1) {
-       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,
@@ -136,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) {
@@ -154,31 +167,26 @@
 }
 
 static int hwc_prepare_external(hwc_composer_device_1 *dev,
-        hwc_display_contents_1_t *list, int dpy) {
-
+        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[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) {
             if(fbLayer->handle) {
-                ctx->mExtDispConfiguring = false;
+                ctx->dpyAttr[dpy].isConfiguring = false;
                 setListStats(ctx, list, dpy);
                 if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
                     const int fbZ = 0;
                     ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
                 }
 
-                /* Temporarily commenting out C2D until we support partial
-                   copybit composition for mixed mode MDP
-
-                if((fbZOrder >= 0) && ctx->mCopyBit[dpy])
-                    ctx->mCopyBit[dpy]->prepare(ctx, list, dpy);
-                */
                 if(ctx->listStats[dpy].isDisplayAnimating) {
                     // Mark all app layers as HWC_OVERLAY for external during
                     // animation, so that SF doesnt draw it on FB
@@ -199,14 +207,56 @@
     return 0;
 }
 
+static int hwc_prepare_virtual(hwc_composer_device_1 *dev,
+        hwc_display_contents_1_t *list) {
+
+    hwc_context_t* ctx = (hwc_context_t*)(dev);
+    const int dpy = HWC_DISPLAY_VIRTUAL;
+
+    if (LIKELY(list && list->numHwLayers > 1) &&
+            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) {
+            if(fbLayer->handle) {
+                ctx->dpyAttr[dpy].isConfiguring = false;
+                setListStats(ctx, list, dpy);
+                if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
+                    const int fbZ = 0;
+                    ctx->mFBUpdate[dpy]->prepare(ctx, list, fbZ);
+                }
+
+                if(ctx->listStats[dpy].isDisplayAnimating) {
+                    // Mark all app layers as HWC_OVERLAY for virtual during
+                    // animation, so that SF doesnt draw it on FB
+                    for(int i = 0 ;i < ctx->listStats[dpy].numAppLayers; i++) {
+                        hwc_layer_1_t *layer = &list->hwLayers[i];
+                        layer->compositionType = HWC_OVERLAY;
+                    }
+                }
+            }
+        } else {
+            // Virtual Display is in Pause state.
+            // ToDo:
+            // Mark all application layers as OVERLAY so that
+            // GPU will not compose. This is done for power
+            // optimization
+        }
+    }
+    return 0;
+}
+
+
 static int hwc_prepare(hwc_composer_device_1 *dev, size_t numDisplays,
                        hwc_display_contents_1_t** displays)
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    Locker::Autolock _bl(ctx->mBlankLock);
     //Will be unlocked at the end of set
-    ctx->mExtLock.lock();
+    ctx->mDrawLock.lock();
     reset(ctx, numDisplays, displays);
 
     ctx->mOverlay->configBegin();
@@ -217,13 +267,16 @@
 
     for (int32_t i = numDisplays; i >= 0; i--) {
         hwc_display_contents_1_t *list = displays[i];
-        switch(i) {
+        int dpy = getHWCDpy(ctx, i);
+        switch(dpy) {
             case HWC_DISPLAY_PRIMARY:
                 ret = hwc_prepare_primary(dev, list);
                 break;
             case HWC_DISPLAY_EXTERNAL:
+                ret = hwc_prepare_external(dev, list);
+                break;
             case HWC_DISPLAY_VIRTUAL:
-                ret = hwc_prepare_external(dev, list, i);
+                ret = hwc_prepare_virtual(dev, list);
                 break;
             default:
                 ret = -EINVAL;
@@ -255,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
@@ -274,8 +327,8 @@
     ATRACE_CALL();
     hwc_context_t* ctx = (hwc_context_t*)(dev);
 
-    Locker::Autolock _l(ctx->mBlankLock);
-    int ret = 0;
+    Locker::Autolock _l(ctx->mDrawLock);
+    int ret = 0, value = 0;
     ALOGD_IF(BLANK_DEBUG, "%s: %s display: %d", __FUNCTION__,
           blank==1 ? "Blanking":"Unblanking", dpy);
     if(blank) {
@@ -288,58 +341,53 @@
         overlay::Writeback::clear();
     }
     switch(dpy) {
-        case HWC_DISPLAY_PRIMARY:
-            if(blank) {
-                ret = ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK,FB_BLANK_POWERDOWN);
+    case HWC_DISPLAY_PRIMARY:
+        value = blank ? FB_BLANK_POWERDOWN : FB_BLANK_UNBLANK;
+        if(ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, value) < 0 ) {
+            ALOGE("%s: Failed to handle blank event(%d) for Primary!!",
+                  __FUNCTION__, blank );
+            return -1;
+        }
 
-                if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected == true) {
-                    // Surfaceflinger does not send Blank/unblank event to hwc
-                    // for virtual display, handle it explicitly when blank for
-                    // primary is invoked, so that any pipes unset get committed
-                    if (display_commit(ctx, HWC_DISPLAY_VIRTUAL) < 0) {
-                        ret = -1;
-                        ALOGE("%s:post failed for virtual display !!",
-                                                            __FUNCTION__);
-                    } else {
-                        ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
-                    }
-                }
-            } else {
-                ret = ioctl(ctx->dpyAttr[dpy].fd, FBIOBLANK, FB_BLANK_UNBLANK);
-                if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected == true) {
-                    ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
-                }
-            }
-            break;
-        case HWC_DISPLAY_EXTERNAL:
+        if(!blank) {
+            // Enable HPD here, as during bootup unblank is called
+            // when SF is completely initialized
+            ctx->mExtDisplay->setHPD(1);
+        }
+
+        /* Since SF is not aware of VIRTUAL DISPLAY being handle by HWC,
+         * it wont send blank / unblank events for it. We piggyback on
+         * PRIMARY DISPLAY events to release mdp pips and
+         * activate/deactive VIRTUAL DISPLAY */
+
+        if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
             if(blank) {
-                // call external framebuffer commit on blank,
-                // so that any pipe unsets gets committed
-                if (display_commit(ctx, dpy) < 0) {
+                int dpy = HWC_DISPLAY_VIRTUAL;
+                if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+                    ALOGE("%s: display commit fail for virtual!", __FUNCTION__);
                     ret = -1;
-                    ALOGE("%s:post failed for external display !! ",
-                          __FUNCTION__);
                 }
-            } else {
             }
-            break;
-        default:
-            return -EINVAL;
+            ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
+        }
+        break;
+    case HWC_DISPLAY_EXTERNAL:
+        if(blank) {
+            if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+                ALOGE("%s: display commit fail for external!", __FUNCTION__);
+                ret = -1;
+            }
+        }
+        break;
+    default:
+        return -EINVAL;
     }
-    // Enable HPD here, as during bootup unblank is called
-    // when SF is completely initialized
-    ctx->mExtDisplay->setHPD(1);
-    if(ret == 0){
-        ctx->dpyAttr[dpy].isActive = !blank;
-    } else {
-        ALOGE("%s: Failed in %s display: %d error:%s", __FUNCTION__,
-              blank==1 ? "blanking":"unblanking", dpy, strerror(errno));
-        return ret;
-    }
+
+    ctx->dpyAttr[dpy].isActive = !blank;
 
     ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__,
-          blank==1 ? "blanking":"unblanking", dpy);
-    return 0;
+          blank ? "blanking":"unblanking", dpy);
+    return ret;
 }
 
 static int hwc_query(struct hwc_composer_device_1* dev,
@@ -403,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;
         }
     }
@@ -414,14 +462,73 @@
 }
 
 static int hwc_set_external(hwc_context_t *ctx,
-                            hwc_display_contents_1_t* list, int dpy)
+                            hwc_display_contents_1_t* list)
 {
     ATRACE_CALL();
     int ret = 0;
 
-    if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
-        ctx->dpyAttr[dpy].connected) {
+    const int dpy = HWC_DISPLAY_EXTERNAL;
 
+
+    if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
+        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(list->numHwLayers > 1)
+            hwc_sync(ctx, list, dpy, fd);
+
+        // 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;
+        }
+
+        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(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
+            ALOGE("%s: display commit fail for %d dpy!", __FUNCTION__, dpy);
+            ret = -1;
+        }
+    }
+
+    closeAcquireFds(list);
+    return ret;
+}
+
+static int hwc_set_virtual(hwc_context_t *ctx,
+                            hwc_display_contents_1_t* list)
+{
+    ATRACE_CALL();
+    int ret = 0;
+    const int dpy = HWC_DISPLAY_VIRTUAL;
+
+    if (LIKELY(list) && ctx->dpyAttr[dpy].isActive &&
+                           ctx->dpyAttr[dpy].connected) {
         if(!ctx->dpyAttr[dpy].isPause) {
             uint32_t last = list->numHwLayers - 1;
             hwc_layer_1_t *fbLayer = &list->hwLayers[last];
@@ -433,7 +540,7 @@
             if(list->numHwLayers > 1)
                 hwc_sync(ctx, list, dpy, fd);
 
-            // Dump the layers for external
+            // Dump the layers for virtual
             if(ctx->mHwcDebug[dpy])
                 ctx->mHwcDebug[dpy]->dumpLayers(list);
 
@@ -461,36 +568,44 @@
             }
         }
 
-        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 && (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
+        // as the retire fence.
+        list->retireFenceFd = list->outbufAcquireFenceFd;
+    }
+
     return ret;
 }
 
+
 static int hwc_set(hwc_composer_device_1 *dev,
                    size_t numDisplays,
                    hwc_display_contents_1_t** displays)
 {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    Locker::Autolock _bl(ctx->mBlankLock);
     for (uint32_t i = 0; i <= numDisplays; i++) {
         hwc_display_contents_1_t* list = displays[i];
-        switch(i) {
+        int dpy = getHWCDpy(ctx, i);
+        switch(dpy) {
             case HWC_DISPLAY_PRIMARY:
                 ret = hwc_set_primary(ctx, list);
                 break;
             case HWC_DISPLAY_EXTERNAL:
+                ret = hwc_set_external(ctx, list);
+                break;
             case HWC_DISPLAY_VIRTUAL:
-            /* ToDo: We are using hwc_set_external path for both External and
-                     Virtual displays on HWC1.1. Eventually, we will have
-                     separate functions when we move to HWC1.2
-            */
-                ret = hwc_set_external(ctx, list, i);
+                ret = hwc_set_virtual(ctx, list);
                 break;
             default:
                 ret = -EINVAL;
@@ -502,7 +617,7 @@
     MDPComp::resetIdleFallBack();
     ctx->mVideoTransFlag = false;
     //Was locked at the beginning of prepare
-    ctx->mExtLock.unlock();
+    ctx->mDrawLock.unlock();
     return ret;
 }
 
@@ -510,6 +625,7 @@
         uint32_t* configs, size_t* numConfigs) {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+    disp = getHWCDpy(ctx, disp);
     //in 1.1 there is no way to choose a config, report as config id # 0
     //This config is passed to getDisplayAttributes. Ignore for now.
     switch(disp) {
@@ -539,8 +655,9 @@
         uint32_t config, const uint32_t* attributes, int32_t* values) {
 
     hwc_context_t* ctx = (hwc_context_t*)(dev);
+    disp = getHWCDpy(ctx, disp);
     //If hotpluggable displays(i.e, HDMI, WFD) are inactive return error
-    if( (disp >= HWC_DISPLAY_EXTERNAL) && !ctx->dpyAttr[disp].connected) {
+    if( (disp != HWC_DISPLAY_PRIMARY) && !ctx->dpyAttr[disp].connected) {
         return -1;
     }
 
@@ -590,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);
@@ -634,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_ad.cpp b/libhwcomposer/hwc_ad.cpp
new file mode 100644
index 0000000..9ac8958
--- /dev/null
+++ b/libhwcomposer/hwc_ad.cpp
@@ -0,0 +1,261 @@
+/*
+* 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 <unistd.h>
+#include <overlay.h>
+#include <overlayUtils.h>
+#include <overlayWriteback.h>
+#include <mdp_version.h>
+#include "hwc_ad.h"
+#include "hwc_utils.h"
+#include "external.h"
+
+#define DEBUG 0
+using namespace overlay;
+using namespace overlay::utils;
+namespace qhwc {
+
+//Opens writeback framebuffer and returns fd.
+static int openWbFb() {
+    int wbFd = -1;
+    //Check opening which FB would connect LM to WB
+    const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+    if(wbFbNum >= 0) {
+        char wbFbPath[256];
+        snprintf (wbFbPath, sizeof(wbFbPath),
+                "/sys/class/graphics/fb%d", wbFbNum);
+        //Opening writeback fb first time would create ad node if the device
+        //supports adaptive display
+        wbFd = open(wbFbPath, O_RDONLY);
+        if(wbFd < 0) {
+            ALOGE("%s: Failed to open /sys/class/graphics/fb%d with error %s",
+                    __func__, wbFbNum, strerror(errno));
+        }
+    } else {
+        ALOGD_IF(DEBUG, "%s: No writeback available", __func__);
+    }
+    return wbFd;
+}
+
+static inline void closeWbFb(int& fd) {
+    if(fd >= 0) {
+        close(fd);
+        fd = -1;
+    } else {
+        ALOGE("%s: Invalid fd %d", __func__, fd);
+    }
+}
+
+//Helper to write data to ad node
+static void adWrite(const int& value) {
+    const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+    char wbFbPath[256];
+    snprintf (wbFbPath, sizeof(wbFbPath),
+            "/sys/class/graphics/fb%d/ad", wbFbNum);
+    int adFd = open(wbFbPath, O_WRONLY);
+    if(adFd >= 0) {
+        char opStr[4] = "";
+        snprintf(opStr, sizeof(opStr), "%d", value);
+        int ret = write(adFd, opStr, strlen(opStr));
+        if(ret < 0) {
+            ALOGE("%s: Failed to write %d with error %s",
+                    __func__, value, strerror(errno));
+        } else if (ret == 0){
+            ALOGE("%s Nothing written to ad", __func__);
+        } else {
+            ALOGD_IF(DEBUG, "%s: Wrote %d to ad", __func__, value);
+        }
+        close(adFd);
+    } else {
+        ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s",
+                __func__, wbFbNum, strerror(errno));
+    }
+}
+
+//Helper to read data from ad node
+static int adRead() {
+    const int wbFbNum = Overlay::getFbForDpy(Overlay::DPY_WRITEBACK);
+    int ret = -1;
+    char wbFbPath[256];
+    snprintf (wbFbPath, sizeof(wbFbPath),
+            "/sys/class/graphics/fb%d/ad", wbFbNum);
+    int adFd = open(wbFbPath, O_RDONLY);
+    if(adFd >= 0) {
+        char opStr[4] = {'\0'};
+        if(read(adFd, opStr, strlen(opStr)) >= 0) {
+            //Should return -1, 0 or 1
+            ret = atoi(opStr);
+            ALOGD_IF(DEBUG, "%s: Read %d from ad", __func__, ret);
+        } else {
+            ALOGE("%s: Read from ad node failed with error %s", __func__,
+                    strerror(errno));
+        }
+        close(adFd);
+    } else {
+        ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s",
+                __func__, wbFbNum, strerror(errno));
+    }
+    return ret;
+}
+
+AssertiveDisplay::AssertiveDisplay() :mWbFd(-1), mDoable(false),
+        mFeatureEnabled(false), mDest(overlay::utils::OV_INVALID) {
+    int fd = openWbFb();
+    if(fd >= 0) {
+        //-1 means feature is disabled on device
+        // 0 means feature exists but turned off, will be turned on by hwc
+        // 1 means feature is turned on by hwc
+        if(adRead() >= 0) {
+            ALOGD_IF(DEBUG, "Assertive display feature supported");
+            mFeatureEnabled = true;
+        }
+        closeWbFb(fd);
+    }
+}
+
+void AssertiveDisplay::markDoable(hwc_context_t *ctx,
+        const hwc_display_contents_1_t* list) {
+    mDoable = false;
+    if(mFeatureEnabled &&
+        !ctx->mExtDisplay->isConnected() &&
+        ctx->listStats[HWC_DISPLAY_PRIMARY].yuvCount == 1) {
+        int nYuvIndex = ctx->listStats[HWC_DISPLAY_PRIMARY].yuvIndices[0];
+        const hwc_layer_1_t* layer = &list->hwLayers[nYuvIndex];
+        private_handle_t *hnd = (private_handle_t *)layer->handle;
+        if(hnd && hnd->width <= qdutils::MAX_DISPLAY_DIM) {
+            mDoable = true;
+        }
+    }
+}
+
+bool AssertiveDisplay::prepare(hwc_context_t *ctx,
+        const hwc_rect_t& crop,
+        const Whf& whf,
+        const private_handle_t *hnd) {
+    if(!isDoable()) {
+        if(isModeOn()) {
+            //Cleanup one time during this switch
+            const int off = 0;
+            adWrite(off);
+            closeWbFb(mWbFd);
+        }
+        return false;
+    }
+
+    ovutils::eDest dest = ctx->mOverlay->nextPipe(ovutils::OV_MDP_PIPE_VG,
+            overlay::Overlay::DPY_WRITEBACK, Overlay::MIXER_DEFAULT);
+    if(dest == OV_INVALID) {
+        ALOGE("%s failed: No VG pipe available", __func__);
+        mDoable = false;
+        return false;
+    }
+
+    overlay::Writeback *wb = overlay::Writeback::getInstance();
+
+    if(!wb->configureDpyInfo(hnd->width, hnd->height)) {
+        ALOGE("%s: config display failed", __func__);
+        mDoable = false;
+        return false;
+    }
+
+    int tmpW, tmpH, size;
+    int format = ovutils::getHALFormat(wb->getOutputFormat());
+    if(format < 0) {
+        ALOGE("%s invalid format %d", __func__, format);
+        mDoable = false;
+        return false;
+    }
+
+    size = getBufferSizeAndDimensions(hnd->width, hnd->height,
+                format, tmpW, tmpH);
+
+    if(!wb->configureMemory(size, isSecureBuffer(hnd))) {
+        ALOGE("%s: config memory failed", __func__);
+        mDoable = false;
+        return false;
+    }
+
+    eMdpFlags mdpFlags = OV_MDP_FLAGS_NONE;
+    if(isSecureBuffer(hnd)) {
+        ovutils::setMdpFlags(mdpFlags,
+                ovutils::OV_MDP_SECURE_OVERLAY_SESSION);
+    }
+
+    PipeArgs parg(mdpFlags, whf, ZORDER_0, IS_FG_OFF,
+            ROT_FLAGS_NONE);
+    hwc_rect_t dst = crop; //input same as output
+
+    if(configMdp(ctx->mOverlay, parg, OVERLAY_TRANSFORM_0, crop, dst, NULL,
+                dest) < 0) {
+        ALOGE("%s: configMdp failed", __func__);
+        mDoable = false;
+        return false;
+    }
+
+    mDest = dest;
+    if(!isModeOn()) {
+        mWbFd = openWbFb();
+        if(mWbFd >= 0) {
+            //write to sysfs, one time during this switch
+            const int on = 1;
+            adWrite(on);
+        }
+    }
+    return true;
+}
+
+bool AssertiveDisplay::draw(hwc_context_t *ctx, int fd, uint32_t offset) {
+    if(!isDoable() || !isModeOn()) {
+        return false;
+    }
+
+    if (!ctx->mOverlay->queueBuffer(fd, offset, mDest)) {
+        ALOGE("%s: queueBuffer failed", __func__);
+        return false;
+    }
+
+    overlay::Writeback *wb = overlay::Writeback::getInstance();
+    if(!wb->writeSync()) {
+        return false;
+    }
+
+    return true;
+}
+
+int AssertiveDisplay::getDstFd(hwc_context_t *ctx) const {
+    overlay::Writeback *wb = overlay::Writeback::getInstance();
+    return wb->getDstFd();
+}
+
+uint32_t AssertiveDisplay::getDstOffset(hwc_context_t *ctx) const {
+    overlay::Writeback *wb = overlay::Writeback::getInstance();
+    return wb->getOffset();
+}
+
+}
diff --git a/libhwcomposer/hwc_ad.h b/libhwcomposer/hwc_ad.h
new file mode 100644
index 0000000..38b724d
--- /dev/null
+++ b/libhwcomposer/hwc_ad.h
@@ -0,0 +1,67 @@
+/*
+* 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 HWC_AD_H
+#define HWC_AD_H
+
+#include <overlayUtils.h>
+#include <hwc_utils.h>
+
+struct hwc_context_t;
+
+namespace qhwc {
+
+class AssertiveDisplay {
+public:
+    AssertiveDisplay();
+    void markDoable(hwc_context_t *ctx, const hwc_display_contents_1_t* list);
+    bool prepare(hwc_context_t *ctx, const hwc_rect_t& crop,
+            const overlay::utils::Whf& whf,
+            const private_handle_t *hnd);
+    bool draw(hwc_context_t *ctx, int fd, uint32_t offset);
+    //Resets a few members on each draw round
+    void reset() { mDoable = false;
+            mDest = overlay::utils::OV_INVALID;
+    }
+    bool isDoable() const { return mDoable; }
+    bool isModeOn() const { return (mWbFd >= 0); }
+    int getDstFd(hwc_context_t *ctx) const;
+    uint32_t getDstOffset(hwc_context_t *ctx) const;
+
+private:
+    //State of feature turned on and off
+    int mWbFd;
+    bool mDoable;
+    //State of feature existence on certain devices and configs.
+    bool mFeatureEnabled;
+    overlay::utils::eDest mDest;
+};
+
+}
+#endif
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index 8aa0181..e155e54 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) {
 
@@ -166,7 +180,10 @@
     private_handle_t *fbHnd = (private_handle_t *)fbLayer->handle;
 
 
-    // Avoid issue with mdp3 and rotation by using gpu composition
+    // Following are MDP3 limitations for which we
+    // need to fallback to GPU composition:
+    // 1. HW issues with mdp3 and rotation.
+    // 2. Plane alpha is not supported by MDP3.
     if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) {
         for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
             hwc_layer_1_t *layer = (hwc_layer_1_t *) &list->hwLayers[i];
@@ -175,7 +192,18 @@
                    ((layer->displayFrame.bottom - layer->displayFrame.top) % 16 ||
                    (layer->displayFrame.right - layer->displayFrame.left) % 16))
                 return true;
+            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
@@ -286,7 +314,7 @@
             list->hwLayers[i].acquireFenceFd = -1;
         }
         retVal = drawLayerUsingCopybit(ctx, &(list->hwLayers[i]),
-                                                    renderBuffer, dpy);
+                                                    renderBuffer, dpy, !i);
         copybitLayerCount++;
         if(retVal < 0) {
             ALOGE("%s : drawLayerUsingCopybit failed", __FUNCTION__);
@@ -302,7 +330,7 @@
 }
 
 int  CopyBit::drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
-                                     private_handle_t *renderBuffer, int dpy)
+                          private_handle_t *renderBuffer, int dpy, bool isFG)
 {
     hwc_context_t* ctx = (hwc_context_t*)(dev);
     int err = 0, acquireFd;
@@ -427,7 +455,7 @@
         dtdy < 1/copybitsMinScale){
         // The requested scale is out of the range the hardware
         // can support.
-       ALOGE("%s:%d::Need to scale twice dsdx=%f, dtdy=%f,copybitsMaxScale=%f,\
+       ALOGD("%s:%d::Need to scale twice dsdx=%f, dtdy=%f,copybitsMaxScale=%f,\
                                  copybitsMinScale=%f,screen_w=%d,screen_h=%d \
                   src_crop_width=%d src_crop_height=%d",__FUNCTION__,__LINE__,
               dsdx,dtdy,copybitsMaxScale,1/copybitsMinScale,screen_w,screen_h,
@@ -452,7 +480,7 @@
          tmp_w  = (tmp_w/2)*2;
          tmp_h = (tmp_h/2)*2;
        }
-       ALOGE("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h);
+       ALOGD("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h);
 
        int usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP;
        int format = fbHandle->format;
@@ -520,6 +548,9 @@
     copybit->set_parameter(copybit, COPYBIT_DITHER,
                              (dst.format == HAL_PIXEL_FORMAT_RGB_565)?
                                              COPYBIT_ENABLE : COPYBIT_DISABLE);
+    copybit->set_parameter(copybit, COPYBIT_FG_LAYER, isFG ?
+                                             COPYBIT_ENABLE : COPYBIT_DISABLE);
+
     copybit->set_parameter(copybit, COPYBIT_BLIT_TO_FRAMEBUFFER,
                                                 COPYBIT_ENABLE);
     copybit->set_sync(copybit, acquireFd);
diff --git a/libhwcomposer/hwc_copybit.h b/libhwcomposer/hwc_copybit.h
index 31de9ee..03fe950 100644
--- a/libhwcomposer/hwc_copybit.h
+++ b/libhwcomposer/hwc_copybit.h
@@ -49,7 +49,7 @@
     struct copybit_device_t *mEngine;
     // Helper functions for copybit composition
     int  drawLayerUsingCopybit(hwc_context_t *dev, hwc_layer_1_t *layer,
-                                       private_handle_t *renderBuffer, int dpy);
+                          private_handle_t *renderBuffer, int dpy, bool isFG);
     bool canUseCopybitForYUV (hwc_context_t *ctx);
     bool canUseCopybitForRGB (hwc_context_t *ctx,
                                      hwc_display_contents_1_t *list, int dpy);
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 7ba2ddc..2337b2a 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -26,10 +26,12 @@
 #include "hwc_fbupdate.h"
 #include "mdp_version.h"
 #include "external.h"
+#include "virtual.h"
 
 using namespace qdutils;
 using namespace overlay;
 using overlay::Rotator;
+using namespace overlay::utils;
 
 namespace qhwc {
 
@@ -56,6 +58,30 @@
     mDest = ovutils::OV_INVALID;
 }
 
+bool FBUpdateLowRes::preRotateExtDisplay(hwc_context_t *ctx,
+                                            ovutils::Whf &info,
+                                            hwc_rect_t& sourceCrop,
+                                            ovutils::eMdpFlags& mdpFlags,
+                                            int& rotFlags)
+{
+    int extOrient = getExtOrientation(ctx);
+    ovutils::eTransform orient = static_cast<ovutils::eTransform >(extOrient);
+    if(mDpy && (extOrient & HWC_TRANSFORM_ROT_90)) {
+        mRot = ctx->mRotMgr->getNext();
+        if(mRot == NULL) return false;
+        //Configure rotator for pre-rotation
+        if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0) < 0) {
+            ALOGE("%s: configRotator Failed!", __FUNCTION__);
+            mRot = NULL;
+            return false;
+        }
+        info.format = (mRot)->getDstFormat();
+        updateSource(orient, info, sourceCrop);
+        rotFlags |= ovutils::ROT_PREROTATED;
+    }
+    return true;
+}
+
 bool FBUpdateLowRes::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
                              int fbZorder) {
     if(!ctx->mMDP.hasOverlay) {
@@ -110,68 +136,46 @@
         hwc_rect_t sourceCrop = layer->sourceCrop;
         hwc_rect_t displayFrame = layer->displayFrame;
         int transform = layer->transform;
-        int fbWidth  = ctx->dpyAttr[mDpy].xres;
-        int fbHeight = ctx->dpyAttr[mDpy].yres;
         int rotFlags = ovutils::ROT_FLAGS_NONE;
 
         ovutils::eTransform orient =
                     static_cast<ovutils::eTransform>(transform);
-        if(mDpy && ctx->mExtOrientation) {
-            // If there is a external orientation set, use that
-            transform = ctx->mExtOrientation;
-            orient = static_cast<ovutils::eTransform >(ctx->mExtOrientation);
-        }
+        // use ext orientation if any
+        int extOrient = getExtOrientation(ctx);
 
         // Do not use getNonWormholeRegion() function to calculate the
         // sourceCrop during animation on external display and
         // Dont do wormhole calculation when extorientation is set on External
+        // Dont do wormhole calculation when extDownscale is enabled on External
         if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
             sourceCrop = layer->displayFrame;
             displayFrame = sourceCrop;
-        } else if((!mDpy || (mDpy && !ctx->mExtOrientation))
-                               && extOnlyLayerIndex == -1) {
+        } else if((!mDpy ||
+                   (mDpy && !extOrient
+                   && !ctx->dpyAttr[mDpy].mDownScaleMode))
+                   && (extOnlyLayerIndex == -1)) {
             if(!qdutils::MDPVersion::getInstance().is8x26()) {
                 getNonWormholeRegion(list, sourceCrop);
                 displayFrame = sourceCrop;
             }
         }
-        ovutils::Dim dpos(displayFrame.left,
-                          displayFrame.top,
-                          displayFrame.right - displayFrame.left,
-                          displayFrame.bottom - displayFrame.top);
-
-        if(mDpy && !qdutils::MDPVersion::getInstance().is8x26()) {
-            // Get Aspect Ratio for external
-            getAspectRatioPosition(ctx, mDpy, ctx->mExtOrientation, dpos.x,
-                                    dpos.y, dpos.w, dpos.h);
-            // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
-            getActionSafePosition(ctx, mDpy, dpos.x, dpos.y, dpos.w, dpos.h);
-            // Convert dim to hwc_rect_t
-            displayFrame.left = dpos.x;
-            displayFrame.top = dpos.y;
-            displayFrame.right = dpos.w + displayFrame.left;
-            displayFrame.bottom = dpos.h + displayFrame.top;
-        }
+        calcExtDisplayPosition(ctx, hnd, mDpy, sourceCrop, displayFrame,
+                                   transform, orient);
         setMdpFlags(layer, mdpFlags, 0, transform);
         // For External use rotator if there is a rotation value set
-        if(mDpy && (ctx->mExtOrientation & HWC_TRANSFORM_ROT_90)) {
-            mRot = ctx->mRotMgr->getNext();
-            if(mRot == NULL) return -1;
-            //Configure rotator for pre-rotation
-            if(configRotator(mRot, info, sourceCrop, mdpFlags, orient, 0) < 0) {
-                ALOGE("%s: configRotator Failed!", __FUNCTION__);
-                mRot = NULL;
-                return -1;
-            }
-            info.format = (mRot)->getDstFormat();
-            updateSource(orient, info, sourceCrop);
-            rotFlags |= ovutils::ROT_PREROTATED;
+        ret = preRotateExtDisplay(ctx, info, sourceCrop, mdpFlags, rotFlags);
+        if(!ret) {
+            ALOGE("%s: preRotate for external Failed!", __FUNCTION__);
+            return false;
         }
         //For the mdp, since either we are pre-rotating or MDP does flips
         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) {
@@ -268,11 +272,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;
@@ -281,23 +290,18 @@
                                 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;
         hwc_rect_t displayFrame = layer->displayFrame;
 
         const float xres = ctx->dpyAttr[mDpy].xres;
-        //Default even split for all displays with high res
-        float lSplit = xres / 2;
-        if(mDpy == HWC_DISPLAY_PRIMARY &&
-                qdutils::MDPVersion::getInstance().getLeftSplit()) {
-            //Override if split published by driver for primary
-            lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
-        }
-
+        const int lSplit = getLeftSplit(ctx, mDpy);
         const float lSplitRatio = lSplit / xres;
-
         const float lCropWidth =
                 (sourceCrop.right - sourceCrop.left) * lSplitRatio;
 
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index 55cd655..3c76efe 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -66,6 +66,11 @@
 private:
     bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
             int fbZorder);
+    bool preRotateExtDisplay(hwc_context_t *ctx,
+                                 ovutils::Whf &info,
+                                 hwc_rect_t& sourceCrop,
+                                 ovutils::eMdpFlags& mdpFlags,
+                                 int& rotFlags);
     ovutils::eDest mDest; //pipe to draw on
 };
 
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 462cc6d..f2217b9 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -20,9 +20,11 @@
 #include "hwc_mdpcomp.h"
 #include <sys/ioctl.h>
 #include "external.h"
+#include "virtual.h"
 #include "qdMetaData.h"
 #include "mdp_version.h"
 #include "hwc_fbupdate.h"
+#include "hwc_ad.h"
 #include <overlayRotator.h>
 
 using namespace overlay;
@@ -53,9 +55,12 @@
 
 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 ? "\"EXTERNAL\"" : "\"PRIMARY\"");
+                (mDpy == 0) ? "\"PRIMARY\"" :
+                (mDpy == 1) ? "\"EXTERNAL\"" : "\"VIRTUAL\"");
     dumpsys_log(buf,"PREV_FRAME: layerCount:%2d    mdpCount:%2d \
                 cacheCount:%2d \n", mCachedFrame.layerCount,
                 mCachedFrame.mdpCount, mCachedFrame.cacheCount);
@@ -120,20 +125,24 @@
             sMaxPipesPerMixer = min(val, MAX_PIPES_PER_MIXER);
     }
 
-    long idle_timeout = DEFAULT_IDLE_TIME;
-    if(property_get("debug.mdpcomp.idletime", property, NULL) > 0) {
-        if(atoi(property) != 0)
-            idle_timeout = atoi(property);
-    }
+    if(ctx->mMDP.panel != MIPI_CMD_PANEL) {
+        // Idle invalidation is not necessary on command mode panels
+        long idle_timeout = DEFAULT_IDLE_TIME;
+        if(property_get("debug.mdpcomp.idletime", property, NULL) > 0) {
+            if(atoi(property) != 0)
+                idle_timeout = atoi(property);
+        }
 
-    //create Idle Invalidator only when not disabled through property
-    if(idle_timeout != -1)
-        idleInvalidator = IdleInvalidator::getInstance();
+        //create Idle Invalidator only when not disabled through property
+        if(idle_timeout != -1)
+            idleInvalidator = IdleInvalidator::getInstance();
 
-    if(idleInvalidator == NULL) {
-        ALOGE("%s: failed to instantiate idleInvalidator object", __FUNCTION__);
-    } else {
-        idleInvalidator->init(timeout_handler, ctx, idle_timeout);
+        if(idleInvalidator == NULL) {
+            ALOGE("%s: failed to instantiate idleInvalidator object",
+                  __FUNCTION__);
+        } else {
+            idleInvalidator->init(timeout_handler, ctx, idle_timeout);
+        }
     }
     return true;
 }
@@ -377,13 +386,13 @@
         ALOGD_IF(isDebug(),"%s: MDP Comp. not enabled.", __FUNCTION__);
         ret = false;
     } else if(qdutils::MDPVersion::getInstance().is8x26() &&
-            ctx->mVideoTransFlag &&
-            ctx->mExtDisplay->isExternalConnected()) {
+            ctx->mVideoTransFlag && ctx->mVirtualDisplay->isConnected()) {
         //1 Padding round to shift pipes across mixers
         ALOGD_IF(isDebug(),"%s: MDP Comp. video transition padding round",
                 __FUNCTION__);
         ret = false;
-    } else if(ctx->mExtDispConfiguring) {
+    } else if(ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isConfiguring ||
+              ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isConfiguring) {
         ALOGD_IF( isDebug(),"%s: External Display connection is pending",
                   __FUNCTION__);
         ret = false;
@@ -433,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__);
@@ -453,6 +466,10 @@
                    return false;
     }
 
+    if(ctx->mAD->isDoable()) {
+        return false;
+    }
+
     //If all above hard conditions are met we can do full or partial MDP comp.
     bool ret = false;
     if(fullMDPComp(ctx, list)) {
@@ -547,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;
@@ -558,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;
 }
 
@@ -727,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));
@@ -914,8 +939,6 @@
         return true;
     }
 
-    Locker::Autolock _l(mMdpCompLock);
-
     /* reset Invalidator */
     if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
         idleInvalidator->markForSleep();
@@ -955,6 +978,14 @@
 
         int fd = hnd->fd;
         uint32_t offset = hnd->offset;
+
+        if(ctx->mAD->isModeOn()) {
+            if(ctx->mAD->draw(ctx, fd, offset)) {
+                fd = ctx->mAD->getDstFd(ctx);
+                offset = ctx->mAD->getDstOffset(ctx);
+            }
+        }
+
         Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
         if(rot) {
             if(!rot->queueBuffer(fd, offset))
@@ -980,13 +1011,8 @@
         int mixer) {
     int pipesNeeded = 0;
     const int xres = ctx->dpyAttr[mDpy].xres;
-    //Default even split for all displays with high res
-    int lSplit = xres / 2;
-    if(mDpy == HWC_DISPLAY_PRIMARY &&
-            qdutils::MDPVersion::getInstance().getLeftSplit()) {
-        //Override if split published by driver for primary
-        lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
-    }
+
+    const int lSplit = getLeftSplit(ctx, mDpy);
 
     for(int i = 0; i < mCurrentFrame.layerCount; ++i) {
         if(!mCurrentFrame.isFBComposed[i]) {
@@ -1028,13 +1054,7 @@
         MdpPipeInfoHighRes& pipe_info,
         ePipeType type) {
     const int xres = ctx->dpyAttr[mDpy].xres;
-    //Default even split for all displays with high res
-    int lSplit = xres / 2;
-    if(mDpy == HWC_DISPLAY_PRIMARY &&
-            qdutils::MDPVersion::getInstance().getLeftSplit()) {
-        //Override if split published by driver for primary
-        lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
-    }
+    const int lSplit = getLeftSplit(ctx, mDpy);
 
     hwc_rect_t dst = layer->displayFrame;
     pipe_info.lIndex = ovutils::OV_INVALID;
@@ -1124,8 +1144,6 @@
         return true;
     }
 
-    Locker::Autolock _l(mMdpCompLock);
-
     /* reset Invalidator */
     if(idleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount)
         idleInvalidator->markForSleep();
@@ -1161,6 +1179,13 @@
         int fd = hnd->fd;
         int offset = hnd->offset;
 
+        if(ctx->mAD->isModeOn()) {
+            if(ctx->mAD->draw(ctx, fd, offset)) {
+                fd = ctx->mAD->getDstFd(ctx);
+                offset = ctx->mAD->getDstOffset(ctx);
+            }
+        }
+
         if(rot) {
             rot->queueBuffer(fd, offset);
             fd = rot->getDstMemId();
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 b27a88c..12a9f32 100644
--- a/libhwcomposer/hwc_qclient.cpp
+++ b/libhwcomposer/hwc_qclient.cpp
@@ -64,6 +64,9 @@
         case IQService::EXTERNAL_ORIENTATION:
             setExtOrientation(value);
             break;
+        case IQService::BUFFER_MIRRORMODE:
+            setBufferMirrorMode(value);
+            break;
         default:
             return NO_ERROR;
     }
@@ -71,6 +74,7 @@
 }
 
 void QClient::securing(uint32_t startEnd) {
+    Locker::Autolock _sl(mHwcContext->mDrawLock);
     //The only way to make this class in this process subscribe to media
     //player's death.
     IMediaDeathNotifier::getMediaPlayerService();
@@ -84,6 +88,7 @@
 }
 
 void QClient::unsecuring(uint32_t startEnd) {
+    Locker::Autolock _sl(mHwcContext->mDrawLock);
     mHwcContext->mSecuring = startEnd;
     //We're done unsecuring
     if(startEnd == IQService::END)
@@ -93,6 +98,7 @@
 }
 
 void QClient::MPDeathNotifier::died() {
+    Locker::Autolock _sl(mHwcContext->mDrawLock);
     ALOGD_IF(QCLIENT_DEBUG, "Media Player died");
     mHwcContext->mSecuring = false;
     mHwcContext->mSecureMode = false;
@@ -115,4 +121,8 @@
     mHwcContext->mExtOrientation = orientation;
 }
 
+void QClient::setBufferMirrorMode(uint32_t enable) {
+    mHwcContext->mBufferMirrorMode = enable;
+}
+
 }
diff --git a/libhwcomposer/hwc_qclient.h b/libhwcomposer/hwc_qclient.h
index 4cbabef..848d8d2 100644
--- a/libhwcomposer/hwc_qclient.h
+++ b/libhwcomposer/hwc_qclient.h
@@ -61,6 +61,7 @@
     void unsecuring(uint32_t startEnd);
     android::status_t screenRefresh();
     void setExtOrientation(uint32_t orientation);
+    void setBufferMirrorMode(uint32_t enable);
 
     hwc_context_t *mHwcContext;
     const android::sp<android::IMediaDeathNotifier> mMPDeathNotifier;
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index c658224..5590798 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -31,8 +31,9 @@
 #include "hwc_copybit.h"
 #include "comptype.h"
 #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"
@@ -45,22 +46,20 @@
     EXTERNAL_RESUME
 };
 
-static bool isHDMI(const char* str)
-{
-    if(strcasestr("change@/devices/virtual/switch/hdmi", str))
-        return true;
-    return false;
-}
-
-static void setup(hwc_context_t* ctx, int dpy, bool usecopybit)
+static void setup(hwc_context_t* ctx, int dpy)
 {
     const int rSplit = 0; //Even split for external if at all
     ctx->mFBUpdate[dpy] = IFBUpdate::getObject(ctx->dpyAttr[dpy].xres,
             rSplit, dpy);
     ctx->mMDPComp[dpy] =  MDPComp::getObject(ctx->dpyAttr[dpy].xres,
             rSplit, dpy);
-    if(usecopybit)
+    int compositionType =
+                qdutils::QCCompositionType::getInstance().getCompositionType();
+    if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
+                           qdutils::COMPOSITION_TYPE_MDP |
+                           qdutils::COMPOSITION_TYPE_C2D)) {
         ctx->mCopyBit[dpy] = new CopyBit();
+    }
 }
 
 static void clear(hwc_context_t* ctx, int dpy)
@@ -79,155 +78,192 @@
     }
 }
 
+/* Parse uevent data for devices which we are interested */
+static int getConnectedDisplay(const char* strUdata)
+{
+    if(strcasestr("change@/devices/virtual/switch/hdmi", strUdata))
+        return HWC_DISPLAY_EXTERNAL;
+    if(strcasestr("change@/devices/virtual/switch/wfd", strUdata))
+        return HWC_DISPLAY_VIRTUAL;
+    return -1;
+}
+
+/* Parse uevent data for action requested for the display */
+static int getConnectedState(const char* strUdata, int len)
+{
+    const char* iter_str = strUdata;
+    while(((iter_str - strUdata) <= len) && (*iter_str)) {
+        char* pstr = strstr(iter_str, "SWITCH_STATE=");
+        if (pstr != NULL) {
+            return (atoi(pstr + strlen("SWITCH_STATE=")));
+        }
+        iter_str += strlen(iter_str)+1;
+    }
+    return -1;
+}
+
 static void handle_uevent(hwc_context_t* ctx, const char* udata, int len)
 {
-    int vsync = 0;
-    int64_t timestamp = 0;
-    const char *str = udata;
-    bool usecopybit = false;
-    int compositionType =
-        qdutils::QCCompositionType::getInstance().getCompositionType();
-
-    if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
-                           qdutils::COMPOSITION_TYPE_MDP |
-                           qdutils::COMPOSITION_TYPE_C2D)) {
-        usecopybit = true;
-    }
-    if(!strcasestr("change@/devices/virtual/switch/hdmi", str) &&
-       !strcasestr("change@/devices/virtual/switch/wfd", str)) {
-        ALOGD_IF(UEVENT_DEBUG, "%s: Not Ext Disp Event ", __FUNCTION__);
+    int dpy = getConnectedDisplay(udata);
+    if(dpy < 0) {
+        ALOGD_IF(UEVENT_DEBUG, "%s: Not disp Event ", __FUNCTION__);
         return;
     }
-    int connected = -1; // initial value - will be set to  1/0 based on hotplug
-    int extDpyNum = HWC_DISPLAY_EXTERNAL;
-    char property[PROPERTY_VALUE_MAX];
-    if((property_get("persist.sys.wfd.virtual", property, NULL) > 0) &&
-            (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
-             (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
-        // This means we are using Google API to trigger WFD Display
-        extDpyNum = HWC_DISPLAY_VIRTUAL;
 
-    }
+    int switch_state = getConnectedState(udata, len);
 
-    int dpy = isHDMI(str) ? HWC_DISPLAY_EXTERNAL : extDpyNum;
+    ALOGE_IF(UEVENT_DEBUG,"%s: uevent recieved: %s switch state: %d",
+             __FUNCTION__,udata, switch_state);
 
-    // parse HDMI/WFD switch state for connect/disconnect
-    // for HDMI:
-    // The event will be of the form:
-    // change@/devices/virtual/switch/hdmi ACTION=change
-    // SWITCH_STATE=1 or SWITCH_STATE=0
-    while(*str) {
-        if (!strncmp(str, "SWITCH_STATE=", strlen("SWITCH_STATE="))) {
-            connected = atoi(str + strlen("SWITCH_STATE="));
-            //Disabled until SF calls unblank
-            ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
-            //Ignored for Virtual Displays
-            //ToDo: we can do this in a much better way
-            ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = true;
-            break;
-        }
-        str += strlen(str) + 1;
-        if (str - udata >= len)
-            break;
-    }
-    ALOGD_IF(UEVENT_DEBUG, "Received str:%s",udata);
-
-    if(connected != EXTERNAL_ONLINE) {
-        if(ctx->mExtDisplay->ignoreRequest(udata)) {
-            ALOGD_IF(UEVENT_DEBUG,"No need to process this connection request"
-                                  "str:%s",udata);
-           ctx->dpyAttr[dpy].isActive = true;
-           return;
-        }
-    }
-
-    // update extDpyNum
-    ctx->mExtDisplay->setExtDpyNum(dpy);
-    switch(connected) {
-        case EXTERNAL_OFFLINE:
-            {   // disconnect event
-                const char *s1 = udata + strlen(HWC_UEVENT_SWITCH_STR);
-                if(!strncmp(s1,"hdmi",strlen(s1))) {
-                    ctx->mExtDisplay->teardownHDMIDisplay();
-                }else if(!strncmp(s1,"wfd",strlen(s1))) {
-                    ctx->mExtDisplay->teardownWFDDisplay();
-                }
-                Locker::Autolock _l(ctx->mExtLock);
-                clear(ctx, dpy);
-                ALOGD("%s sending hotplug: connected = %d and dpy:%d",
-                      __FUNCTION__, connected, dpy);
-                ctx->dpyAttr[dpy].connected = false;
-                //hwc comp could be on
-                ctx->proc->hotplug(ctx->proc, dpy, connected);
+    switch(switch_state) {
+    case EXTERNAL_OFFLINE:
+        {
+            /* Display not connected */
+            if(!ctx->dpyAttr[dpy].connected){
+                ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_OFFLINE event"
+                         "for display: %d", __FUNCTION__, dpy);
                 break;
             }
-        case EXTERNAL_ONLINE:
-            {   // connect case
-                {
-                    //Force composition to give up resources like pipes and
-                    //close fb. For example if assertive display is going on,
-                    //fb2 could be open, thus connecting Layer Mixer#0 to
-                    //WriteBack module. If HDMI attempts to open fb1, the driver
-                    //will try to attach Layer Mixer#0 to HDMI INT, which will
-                    //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);
-                    ctx->mExtDispConfiguring = true;
-                    ctx->dpyAttr[dpy].connected = false;
-                    ctx->proc->invalidate(ctx->proc);
-                }
-                //2 cycles for slower content
-                usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
-                        * 2 / 1000);
-                const char *s1 = udata + strlen(HWC_UEVENT_SWITCH_STR);
-                if(!strncmp(s1,"hdmi",strlen(s1))) {
-                    // hdmi online event..!
-                    // check if WFD is configured
-                    if(ctx->mExtDisplay->isWFDActive()) {
-                        ALOGD_IF(UEVENT_DEBUG,"Received HDMI connection request"
-                                "when WFD is active");
-                        // teardown Active WFD Display
-                        ctx->mExtDisplay->teardownWFDDisplay();
-                        {
-                            Locker::Autolock _l(ctx->mExtLock);
-                            clear(ctx, dpy);
-                            //send hotplug disconnect event
-                            ALOGD_IF(UEVENT_DEBUG, "sending hotplug: disconnect"
-                                    "for WFD");
-                            // hwc comp could be on
-                            ctx->proc->hotplug(ctx->proc, dpy, EXTERNAL_OFFLINE);
-                        }
-                        //Invalidate
-                        ctx->proc->invalidate(ctx->proc);
-                        //wait for 1 second
-                        ALOGE_IF(UEVENT_DEBUG, "wait for 1 second -- padding"
-                                "round");
-                        sleep(1);
+
+            Locker::Autolock _l(ctx->mDrawLock);
+            clear(ctx, dpy);
+            ctx->dpyAttr[dpy].connected = false;
+            ctx->dpyAttr[dpy].isActive = false;
+
+            if(dpy == HWC_DISPLAY_EXTERNAL) {
+                ctx->mExtDisplay->teardown();
+            } else {
+                ctx->mVirtualDisplay->teardown();
+            }
+
+            /* We need to send hotplug to SF only when we are disconnecting
+             * (1) HDMI OR (2) proprietary WFD session */
+            if(dpy == HWC_DISPLAY_EXTERNAL ||
+               ctx->mVirtualonExtActive) {
+                ALOGE_IF(UEVENT_DEBUG,"%s:Sending EXTERNAL OFFLINE hotplug"
+                         "event", __FUNCTION__);
+                ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL,
+                                   EXTERNAL_OFFLINE);
+            }
+            break;
+        }
+    case EXTERNAL_ONLINE:
+        {
+            /* Display already connected */
+            if(ctx->dpyAttr[dpy].connected) {
+                ALOGE_IF(UEVENT_DEBUG,"%s: Ignoring EXTERNAL_ONLINE event"
+                         "for display: %d", __FUNCTION__, dpy);
+                break;
+            }
+            {
+                //Force composition to give up resources like pipes and
+                //close fb. For example if assertive display is going on,
+                //fb2 could be open, thus connecting Layer Mixer#0 to
+                //WriteBack module. If HDMI attempts to open fb1, the driver
+                //will try to attach Layer Mixer#0 to HDMI INT, which will
+                //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->mDrawLock);
+                ctx->dpyAttr[dpy].isConfiguring = true;
+                ctx->proc->invalidate(ctx->proc);
+            }
+            //2 cycles for slower content
+            usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+                   * 2 / 1000);
+
+            if(dpy == HWC_DISPLAY_EXTERNAL) {
+                if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
+                    ALOGD_IF(UEVENT_DEBUG,"Received HDMI connection request"
+                             "when WFD is active");
+                    {
+                        Locker::Autolock _l(ctx->mDrawLock);
+                        clear(ctx, HWC_DISPLAY_VIRTUAL);
+                        ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false;
+                        ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = false;
                     }
-                    ctx->mExtDisplay->configureHDMIDisplay();
-                } else if(!strncmp(s1,"wfd",strlen(s1))) {
-                    // wfd online event..!
-                    ctx->mExtDisplay->configureWFDDisplay();
+
+                    ctx->mVirtualDisplay->teardown();
+
+                    /* Need to send hotplug only when connected WFD in
+                     * proprietary path */
+                    if(ctx->mVirtualonExtActive) {
+                        ALOGE_IF(UEVENT_DEBUG,"%s: Sending EXTERNAL OFFLINE"
+                                 "hotplug event", __FUNCTION__);
+                        ctx->proc->hotplug(ctx->proc, HWC_DISPLAY_EXTERNAL,
+                                           EXTERNAL_OFFLINE);
+                        {
+                            Locker::Autolock _l(ctx->mDrawLock);
+                            ctx->mVirtualonExtActive = false;
+                        }
+                    }
+                    /* Wait for few frames for SF to tear down
+                     * the WFD session. */
+                    usleep(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].vsync_period
+                           * 2 / 1000);
                 }
+                ctx->mExtDisplay->configure();
+            } else {
                 {
-                    Locker::Autolock _l(ctx->mExtLock);
-                    ctx->dpyAttr[dpy].isPause = false;
-                    setup(ctx, dpy, usecopybit);
-                    ALOGD("%s sending hotplug: connected = %d", __FUNCTION__,
-                            connected);
-                    ctx->dpyAttr[dpy].connected = true;
-                    ctx->proc->hotplug(ctx->proc, dpy, connected);
+                    Locker::Autolock _l(ctx->mDrawLock);
+                    /* TRUE only when we are on proprietary WFD session */
+                    ctx->mVirtualonExtActive = true;
+                    char property[PROPERTY_VALUE_MAX];
+                    if((property_get("persist.sys.wfd.virtual",
+                                                  property, NULL) > 0) &&
+                       (!strncmp(property, "1", PROPERTY_VALUE_MAX ) ||
+                       (!strncasecmp(property,"true", PROPERTY_VALUE_MAX )))) {
+                        // This means we are on Google's WFD session
+                        ctx->mVirtualonExtActive = false;
+                    }
                 }
-                break;
+                ctx->mVirtualDisplay->configure();
             }
+
+            Locker::Autolock _l(ctx->mDrawLock);
+            setup(ctx, dpy);
+            ctx->dpyAttr[dpy].isPause = false;
+            ctx->dpyAttr[dpy].connected = true;
+            ctx->dpyAttr[dpy].isConfiguring = true;
+
+            if(dpy == HWC_DISPLAY_VIRTUAL) {
+                /* We wont be getting unblank for VIRTUAL DISPLAY and its
+                 * always guaranteed from WFD stack that CONNECT uevent for
+                 * VIRTUAL DISPLAY will be triggered before creating
+                 * 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"
+                         "hotplug event", __FUNCTION__);
+                ctx->proc->hotplug(ctx->proc,HWC_DISPLAY_EXTERNAL,
+                                   EXTERNAL_ONLINE);
+            }
+            break;
+        }
         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;
+                 {
+                     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;
             }
         case EXTERNAL_RESUME:
             {  // resume case
@@ -236,8 +272,8 @@
                 //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->mExtDispConfiguring = true;
+                    Locker::Autolock _l(ctx->mDrawLock);
+                    ctx->dpyAttr[dpy].isConfiguring = true;
                     ctx->dpyAttr[dpy].isActive = true;
                     ctx->proc->invalidate(ctx->proc);
                 }
@@ -245,17 +281,17 @@
                         * 2 / 1000);
                 //At this point external has all the pipes it would need.
                 {
-                    Locker::Autolock _l(ctx->mExtLock);
+                    Locker::Autolock _l(ctx->mDrawLock);
                     ctx->dpyAttr[dpy].isPause = false;
                     ctx->proc->invalidate(ctx->proc);
                 }
                 break;
             }
-        default:
-            {
-                ALOGE("ignore event and connected:%d",connected);
-                break;
-            }
+    default:
+        {
+            ALOGE("%s: Invalid state to swtich:%d", __FUNCTION__, switch_state);
+            break;
+        }
     }
 }
 
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 93017c5..ffaa9cb 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -27,13 +27,16 @@
 #include <gralloc_priv.h>
 #include <overlay.h>
 #include <overlayRotator.h>
+#include <overlayWriteback.h>
 #include "hwc_utils.h"
 #include "hwc_mdpcomp.h"
 #include "hwc_fbupdate.h"
+#include "hwc_ad.h"
 #include "mdp_version.h"
 #include "hwc_copybit.h"
 #include "hwc_dump_layers.h"
 #include "external.h"
+#include "virtual.h"
 #include "hwc_qclient.h"
 #include "QService.h"
 #include "comptype.h"
@@ -150,10 +153,20 @@
     }
 
     ctx->mExtDisplay = new ExternalDisplay(ctx);
+    ctx->mVirtualDisplay = new VirtualDisplay(ctx);
+    ctx->mVirtualonExtActive = false;
+    ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].isActive = false;
+    ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].connected = false;
+    ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = false;
+    ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected = false;
+    ctx->dpyAttr[HWC_DISPLAY_PRIMARY].mDownScaleMode= false;
+    ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode = false;
+    ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = false;
 
     ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
          MDPComp::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres,
                 rightSplit, HWC_DISPLAY_PRIMARY);
+    ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
 
     for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
         ctx->mHwcDebug[i] = new HwcDebug(i);
@@ -161,10 +174,10 @@
     }
 
     MDPComp::init(ctx);
+    ctx->mAD = new AssertiveDisplay();
 
     ctx->vstate.enable = false;
     ctx->vstate.fakevsync = false;
-    ctx->mExtDispConfiguring = false;
     ctx->mExtOrientation = 0;
 
     //Right now hwc starts the service but anybody could do it, or it could be
@@ -183,6 +196,8 @@
         ctx->mPrevDestVideo.right = ctx->mPrevDestVideo.bottom = 0;
     ctx->mPrevTransformVideo = 0;
 
+    ctx->mBufferMirrorMode = false;
+
     ALOGI("Initializing Qualcomm Hardware Composer");
     ALOGI("MDP version: %d", ctx->mMDP.version);
 }
@@ -234,6 +249,10 @@
             ctx->mLayerRotMap[i] = NULL;
         }
     }
+    if(ctx->mAD) {
+        delete ctx->mAD;
+        ctx->mAD = NULL;
+    }
 
 
 }
@@ -247,9 +266,19 @@
     va_end(varargs);
 }
 
+int getExtOrientation(hwc_context_t* ctx) {
+    int extOrient = ctx->mExtOrientation;
+    if(ctx->mBufferMirrorMode)
+        extOrient = getMirrorModeOrientation(ctx);
+    return extOrient;
+}
+
 /* Calculates the destination position based on the action safe rectangle */
-void getActionSafePosition(hwc_context_t *ctx, int dpy, uint32_t& x,
-                           uint32_t& y, uint32_t& w, uint32_t& h) {
+void getActionSafePosition(hwc_context_t *ctx, int dpy, hwc_rect_t& rect) {
+    // Position
+    int x = rect.left, y = rect.top;
+    int w = rect.right - rect.left;
+    int h = rect.bottom - rect.top;
 
     // if external supports underscan, do nothing
     // it will be taken care in the driver
@@ -277,7 +306,9 @@
     float fbHeight = ctx->dpyAttr[dpy].yres;
 
     // Since external is rotated 90, need to swap width/height
-    if(ctx->mExtOrientation & HWC_TRANSFORM_ROT_90)
+    int extOrient = getExtOrientation(ctx);
+
+    if(extOrient & HWC_TRANSFORM_ROT_90)
         swap(fbWidth, fbHeight);
 
     float asX = 0;
@@ -303,40 +334,263 @@
     w = (wRatio * asW);
     h = (hRatio * asH);
 
+    // Convert it back to hwc_rect_t
+    rect.left = x;
+    rect.top = y;
+    rect.right = w + rect.left;
+    rect.bottom = h + rect.top;
+
     return;
 }
 
-/* Calculates the aspect ratio for external based on the primary */
-void getAspectRatioPosition(hwc_context_t *ctx, int dpy, int orientation,
-                        uint32_t& x, uint32_t& y, uint32_t& w, uint32_t& h) {
-    int fbWidth  = ctx->dpyAttr[dpy].xres;
-    int fbHeight = ctx->dpyAttr[dpy].yres;
+/* Calculates the aspect ratio for based on src & dest */
+void getAspectRatioPosition(int destWidth, int destHeight, int srcWidth,
+                                int srcHeight, hwc_rect_t& rect) {
+   int x =0, y =0;
 
-    switch(orientation) {
-        case HAL_TRANSFORM_ROT_90:
-        case HAL_TRANSFORM_ROT_270:
-            y = 0;
-            h = fbHeight;
-            if (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres <
-                ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres) {
-                // Portrait primary panel
-                w = (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres *
-                     fbHeight/ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres);
-            } else {
-                //Landscape primary panel
-                w = (ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres *
-                     fbHeight/ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres);
-            }
-            x = (fbWidth - w)/2;
-            break;
-        default:
-            //Do nothing
-            break;
-     }
-    ALOGD_IF(HWC_UTILS_DEBUG, "%s: Position: x = %d, y = %d w = %d h = %d",
-                    __FUNCTION__, x, y, w ,h);
+   if (srcWidth * destHeight > destWidth * srcHeight) {
+        srcHeight = destWidth * srcHeight / srcWidth;
+        srcWidth = destWidth;
+    } else if (srcWidth * destHeight < destWidth * srcHeight) {
+        srcWidth = destHeight * srcWidth / srcHeight;
+        srcHeight = destHeight;
+    } else {
+        srcWidth = destWidth;
+        srcHeight = destHeight;
+    }
+    if (srcWidth > destWidth) srcWidth = destWidth;
+    if (srcHeight > destHeight) srcHeight = destHeight;
+    x = (destWidth - srcWidth) / 2;
+    y = (destHeight - srcHeight) / 2;
+    ALOGD_IF(HWC_UTILS_DEBUG, "%s: AS Position: x = %d, y = %d w = %d h = %d",
+             __FUNCTION__, x, y, srcWidth , srcHeight);
+    // Convert it back to hwc_rect_t
+    rect.left = x;
+    rect.top = y;
+    rect.right = srcWidth + rect.left;
+    rect.bottom = srcHeight + rect.top;
 }
 
+// This function gets the destination position for Seconday display
+// based on the position and aspect ratio with orientation
+void getAspectRatioPosition(hwc_context_t* ctx, int dpy, int extOrientation,
+                            hwc_rect_t& inRect, hwc_rect_t& outRect) {
+    // Physical display resolution
+    float fbWidth  = ctx->dpyAttr[dpy].xres;
+    float fbHeight = ctx->dpyAttr[dpy].yres;
+    //display position(x,y,w,h) in correct aspectratio after rotation
+    int xPos = 0;
+    int yPos = 0;
+    float width = fbWidth;
+    float height = fbHeight;
+    // Width/Height used for calculation, after rotation
+    float actualWidth = fbWidth;
+    float actualHeight = fbHeight;
+
+    float wRatio = 1.0;
+    float hRatio = 1.0;
+    float xRatio = 1.0;
+    float yRatio = 1.0;
+    hwc_rect_t rect = {0, 0, (int)fbWidth, (int)fbHeight};
+
+    Dim inPos(inRect.left, inRect.top, inRect.right - inRect.left,
+                inRect.bottom - inRect.top);
+    Dim outPos(outRect.left, outRect.top, outRect.right - outRect.left,
+                outRect.bottom - outRect.top);
+
+    Whf whf(fbWidth, fbHeight, 0);
+    eTransform extorient = static_cast<eTransform>(extOrientation);
+    // To calculate the destination co-ordinates in the new orientation
+    preRotateSource(extorient, whf, inPos);
+
+    if(extOrientation & HAL_TRANSFORM_ROT_90) {
+        // Swap width/height for input position
+        swapWidthHeight(actualWidth, actualHeight);
+        getAspectRatioPosition(fbWidth, fbHeight, (int)actualWidth,
+                               (int)actualHeight, rect);
+        xPos = rect.left;
+        yPos = rect.top;
+        width = rect.right - rect.left;
+        height = rect.bottom - rect.top;
+    }
+
+    //Calculate the position...
+    xRatio = inPos.x/actualWidth;
+    yRatio = inPos.y/actualHeight;
+    wRatio = inPos.w/actualWidth;
+    hRatio = inPos.h/actualHeight;
+
+    outPos.x = (xRatio * width) + xPos;
+    outPos.y = (yRatio * height) + yPos;
+    outPos.w = wRatio * width;
+    outPos.h = hRatio * height;
+    ALOGD_IF(HWC_UTILS_DEBUG, "%s: Calculated AspectRatio Position: x = %d,"
+                 "y = %d w = %d h = %d", __FUNCTION__, outPos.x, outPos.y,
+                 outPos.w, outPos.h);
+
+    // For sidesync, the dest fb will be in portrait orientation, and the crop
+    // will be updated to avoid the black side bands, and it will be upscaled
+    // to fit the dest RB, so recalculate
+    // the position based on the new width and height
+    if ((extOrientation & HWC_TRANSFORM_ROT_90) &&
+                        isOrientationPortrait(ctx)) {
+        hwc_rect_t r;
+        //Calculate the position
+        xRatio = (outPos.x - xPos)/width;
+        // GetaspectRatio -- tricky to get the correct aspect ratio
+        // But we need to do this.
+        getAspectRatioPosition(width, height, width, height, r);
+        xPos = r.left;
+        yPos = r.top;
+        float tempWidth = r.right - r.left;
+        float tempHeight = r.bottom - r.top;
+        yRatio = yPos/height;
+        wRatio = outPos.w/width;
+        hRatio = tempHeight/height;
+
+        //Map the coordinates back to Framebuffer domain
+        outPos.x = (xRatio * fbWidth);
+        outPos.y = (yRatio * fbHeight);
+        outPos.w = wRatio * fbWidth;
+        outPos.h = hRatio * fbHeight;
+
+        ALOGD_IF(HWC_UTILS_DEBUG, "%s: Calculated AspectRatio for device in"
+                 "portrait: x = %d,y = %d w = %d h = %d", __FUNCTION__,
+                 outPos.x, outPos.y,
+                 outPos.w, outPos.h);
+    }
+    if(ctx->dpyAttr[dpy].mDownScaleMode) {
+        int extW, extH;
+        if(dpy == HWC_DISPLAY_EXTERNAL)
+            ctx->mExtDisplay->getAttributes(extW, extH);
+        else
+            ctx->mVirtualDisplay->getAttributes(extW, extH);
+        fbWidth  = ctx->dpyAttr[dpy].xres;
+        fbHeight = ctx->dpyAttr[dpy].yres;
+        //Calculate the position...
+        xRatio = outPos.x/fbWidth;
+        yRatio = outPos.y/fbHeight;
+        wRatio = outPos.w/fbWidth;
+        hRatio = outPos.h/fbHeight;
+
+        outPos.x = xRatio * extW;
+        outPos.y = yRatio * extH;
+        outPos.w = wRatio * extW;
+        outPos.h = hRatio * extH;
+    }
+    // Convert Dim to hwc_rect_t
+    outRect.left = outPos.x;
+    outRect.top = outPos.y;
+    outRect.right = outPos.x + outPos.w;
+    outRect.bottom = outPos.y + outPos.h;
+
+    return;
+}
+
+bool isPrimaryPortrait(hwc_context_t *ctx) {
+    int fbWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+    int fbHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+    if(fbWidth < fbHeight) {
+        return true;
+    }
+    return false;
+}
+
+bool isOrientationPortrait(hwc_context_t *ctx) {
+    if(isPrimaryPortrait(ctx)) {
+        return !(ctx->deviceOrientation & 0x1);
+    }
+    return (ctx->deviceOrientation & 0x1);
+}
+
+void calcExtDisplayPosition(hwc_context_t *ctx,
+                               private_handle_t *hnd,
+                               int dpy,
+                               hwc_rect_t& sourceCrop,
+                               hwc_rect_t& displayFrame,
+                               int& transform,
+                               ovutils::eTransform& orient) {
+    // Swap width and height when there is a 90deg transform
+    int extOrient = getExtOrientation(ctx);
+    if(dpy && !qdutils::MDPVersion::getInstance().is8x26()) {
+        if(!isYuvBuffer(hnd)) {
+            if(extOrient & HWC_TRANSFORM_ROT_90) {
+                int dstWidth = ctx->dpyAttr[dpy].xres;
+                int dstHeight = ctx->dpyAttr[dpy].yres;;
+                int srcWidth = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+                int srcHeight = ctx->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+                if(!isPrimaryPortrait(ctx)) {
+                    swap(srcWidth, srcHeight);
+                }                    // Get Aspect Ratio for external
+                getAspectRatioPosition(dstWidth, dstHeight, srcWidth,
+                                    srcHeight, displayFrame);
+                // Crop - this is needed, because for sidesync, the dest fb will
+                // be in portrait orientation, so update the crop to not show the
+                // black side bands.
+                if (isOrientationPortrait(ctx)) {
+                    sourceCrop = displayFrame;
+                    displayFrame.left = 0;
+                    displayFrame.top = 0;
+                    displayFrame.right = dstWidth;
+                    displayFrame.bottom = dstHeight;
+                }
+            }
+            if(ctx->dpyAttr[dpy].mDownScaleMode) {
+                int extW, extH;
+                // if downscale is enabled, map the co-ordinates to new
+                // domain(downscaled)
+                float fbWidth  = ctx->dpyAttr[dpy].xres;
+                float fbHeight = ctx->dpyAttr[dpy].yres;
+                // query MDP configured attributes
+                if(dpy == HWC_DISPLAY_EXTERNAL)
+                    ctx->mExtDisplay->getAttributes(extW, extH);
+                else
+                    ctx->mVirtualDisplay->getAttributes(extW, extH);
+                //Calculate the ratio...
+                float wRatio = ((float)extW)/fbWidth;
+                float hRatio = ((float)extH)/fbHeight;
+
+                //convert Dim to hwc_rect_t
+                displayFrame.left *= wRatio;
+                displayFrame.top *= hRatio;
+                displayFrame.right *= wRatio;
+                displayFrame.bottom *= hRatio;
+            }
+        }else {
+            if(extOrient || ctx->dpyAttr[dpy].mDownScaleMode) {
+                getAspectRatioPosition(ctx, dpy, extOrient,
+                                       displayFrame, displayFrame);
+            }
+        }
+        // If there is a external orientation set, use that
+        if(extOrient) {
+            transform = extOrient;
+            orient = static_cast<ovutils::eTransform >(extOrient);
+        }
+        // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
+        getActionSafePosition(ctx, dpy, displayFrame);
+    }
+}
+
+/* Returns the orientation which needs to be set on External for
+ *  SideSync/Buffer Mirrormode
+ */
+int getMirrorModeOrientation(hwc_context_t *ctx) {
+    int extOrientation = 0;
+    int deviceOrientation = ctx->deviceOrientation;
+    if(!isPrimaryPortrait(ctx))
+        deviceOrientation = (deviceOrientation + 1) % 4;
+     if (deviceOrientation == 0)
+         extOrientation = HWC_TRANSFORM_ROT_270;
+     else if (deviceOrientation == 1)//90
+         extOrientation = 0;
+     else if (deviceOrientation == 2)//180
+         extOrientation = HWC_TRANSFORM_ROT_90;
+     else if (deviceOrientation == 3)//270
+         extOrientation = HWC_TRANSFORM_FLIP_V | HWC_TRANSFORM_FLIP_H;
+
+    return extOrientation;
+}
 
 bool needsScaling(hwc_context_t* ctx, hwc_layer_1_t const* layer,
         const int& dpy) {
@@ -420,8 +674,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);
@@ -460,9 +715,10 @@
         ctx->mExtOrientation = atoi(value); */
         // Assuming the orientation value is in terms of HAL_TRANSFORM,
         // This needs mapping to HAL, if its in different convention
-        if(ctx->mExtOrientation) {
-            ALOGD_IF(HWC_UTILS_DEBUG, "%s: ext orientation = %d",
-                     __FUNCTION__, ctx->mExtOrientation);
+        if(ctx->mExtOrientation || ctx->mBufferMirrorMode) {
+            ALOGD_IF(HWC_UTILS_DEBUG, "%s: ext orientation = %d"
+                     "BufferMirrorMode = %d", __FUNCTION__,
+                     ctx->mExtOrientation, ctx->mBufferMirrorMode);
             if(ctx->mOverlay->isPipeTypeAttached(OV_MDP_PIPE_DMA)) {
                 ctx->isPaddingRound = true;
             }
@@ -475,6 +731,9 @@
     if(prevYuvCount != ctx->listStats[dpy].yuvCount) {
         ctx->mVideoTransFlag = true;
     }
+    if(dpy == HWC_DISPLAY_PRIMARY) {
+        ctx->mAD->markDoable(ctx, list);
+    }
 }
 
 
@@ -528,6 +787,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) {
@@ -835,10 +1106,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() >=
@@ -957,23 +1234,8 @@
                 z = ZORDER_1;
             }
         }
-    }
-
-    uint32_t x = dst.left, y  = dst.top;
-    uint32_t w = dst.right - dst.left;
-    uint32_t h = dst.bottom - dst.top;
-
-    if(dpy) {
-        // Just need to set the position to portrait as the transformation
-        // will already be set to required orientation on TV
-        getAspectRatioPosition(ctx, dpy, ctx->mExtOrientation, x, y, w, h);
-        // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
-        getActionSafePosition(ctx, dpy, x, y, w, h);
-        // Convert position to hwc_rect_t
-        dst.left = x;
-        dst.top = y;
-        dst.right = w + dst.left;
-        dst.bottom = h + dst.top;
+        calcExtDisplayPosition(ctx, hnd, dpy, crop, dst,
+                                           transform, orient);
     }
 
     if(isYuvBuffer(hnd) && ctx->mMDP.version >= qdutils::MDP_V4_2 &&
@@ -991,6 +1253,13 @@
     setMdpFlags(layer, mdpFlags, downscale, transform);
     trimLayer(ctx, dpy, transform, crop, dst);
 
+    //Will do something only if feature enabled and conditions suitable
+    //hollow call otherwise
+    if(ctx->mAD->prepare(ctx, crop, whf, hnd)) {
+        overlay::Writeback *wb = overlay::Writeback::getInstance();
+        whf.format = wb->getOutputFormat();
+    }
+
     if(isYuvBuffer(hnd) && //if 90 component or downscale, use rot
             ((transform & HWC_TRANSFORM_ROT_90) || downscale)) {
         *rot = ctx->mRotMgr->getNext();
@@ -1011,7 +1280,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;
@@ -1069,6 +1341,13 @@
     setMdpFlags(layer, mdpFlagsL, 0, transform);
     trimLayer(ctx, dpy, transform, crop, dst);
 
+    //Will do something only if feature enabled and conditions suitable
+    //hollow call otherwise
+    if(ctx->mAD->prepare(ctx, crop, whf, hnd)) {
+        overlay::Writeback *wb = overlay::Writeback::getInstance();
+        whf.format = wb->getOutputFormat();
+    }
+
     if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
         (*rot) = ctx->mRotMgr->getNext();
         if((*rot) == NULL) return -1;
@@ -1090,7 +1369,8 @@
     hwc_rect_t tmp_cropL, tmp_dstL;
     hwc_rect_t tmp_cropR, tmp_dstR;
 
-    const int lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
+    const int lSplit = getLeftSplit(ctx, dpy);
+
     if(lDest != OV_INVALID) {
         tmp_cropL = crop;
         tmp_dstL = dst;
@@ -1132,7 +1412,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__);
@@ -1143,7 +1425,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,
@@ -1156,16 +1440,31 @@
     return 0;
 }
 
-bool canUseRotator(hwc_context_t *ctx) {
+bool canUseRotator(hwc_context_t *ctx, int dpy) {
     if(qdutils::MDPVersion::getInstance().is8x26() &&
-            ctx->mExtDisplay->isExternalConnected()) {
-        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;
     return true;
 }
 
+int getLeftSplit(hwc_context_t *ctx, const int& dpy) {
+    //Default even split for all displays with high res
+    int lSplit = ctx->dpyAttr[dpy].xres / 2;
+    if(dpy == HWC_DISPLAY_PRIMARY &&
+            qdutils::MDPVersion::getInstance().getLeftSplit()) {
+        //Override if split published by driver for primary
+        lSplit = qdutils::MDPVersion::getInstance().getLeftSplit();
+    }
+    return lSplit;
+}
 
 void BwcPM::setBwc(hwc_context_t *ctx, const hwc_rect_t& crop,
             const hwc_rect_t& dst, const int& transform,
@@ -1179,7 +1478,7 @@
         return;
     }
     //External connected
-    if(ctx->mExtDisplay->isExternalConnected()) {
+    if(ctx->mExtDisplay->isConnected()|| ctx->mVirtualDisplay->isConnected()) {
         return;
     }
     //Decimation necessary, cannot use BWC. H/W requirement.
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index cf359ee..5695f28 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -50,11 +50,13 @@
 //fwrd decl
 class QueuedBufferStore;
 class ExternalDisplay;
+class VirtualDisplay;
 class IFBUpdate;
 class IVideoOverlay;
 class MDPComp;
 class CopyBit;
 class HwcDebug;
+class AssertiveDisplay;
 
 
 struct MDPInfo {
@@ -78,6 +80,11 @@
     // In pause state, composition is bypassed
     // used for WFD displays only
     bool isPause;
+    // To trigger padding round to clean up mdp
+    // pipes
+    bool isConfiguring;
+    // External Display is in MDP Downscale mode indicator
+    bool mDownScaleMode;
 };
 
 struct ListStats {
@@ -165,17 +172,37 @@
 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, ...);
 
+int getExtOrientation(hwc_context_t* ctx);
+
 /* Calculates the destination position based on the action safe rectangle */
-void getActionSafePosition(hwc_context_t *ctx, int dpy, uint32_t& x,
-                                        uint32_t& y, uint32_t& w, uint32_t& h);
+void getActionSafePosition(hwc_context_t *ctx, int dpy, hwc_rect_t& dst);
 
+void getAspectRatioPosition(int destWidth, int destHeight, int srcWidth,
+                                int srcHeight, hwc_rect_t& rect);
 
-void getAspectRatioPosition(hwc_context_t *ctx, int dpy, int orientation,
-                        uint32_t& x, uint32_t& y, uint32_t& w, uint32_t& h);
+void getAspectRatioPosition(hwc_context_t* ctx, int dpy, int extOrientation,
+                                hwc_rect_t& inRect, hwc_rect_t& outRect);
+
+bool isPrimaryPortrait(hwc_context_t *ctx);
+
+bool isOrientationPortrait(hwc_context_t *ctx);
+
+void calcExtDisplayPosition(hwc_context_t *ctx,
+                               private_handle_t *hnd,
+                               int dpy,
+                               hwc_rect_t& sourceCrop,
+                               hwc_rect_t& displayFrame,
+                               int& transform,
+                               ovutils::eTransform& orient);
+
+// Returns the orientation that needs to be set on external for
+// BufferMirrirMode(Sidesync)
+int getMirrorModeOrientation(hwc_context_t *ctx);
 
 //Close acquireFenceFds of all layers of incoming list
 void closeAcquireFds(hwc_display_contents_1_t* list);
@@ -193,7 +220,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);
 
@@ -223,7 +250,9 @@
 //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);
 
 // Inline utility functions
 static inline bool isSkipLayer(const hwc_layer_1_t* l) {
@@ -268,8 +297,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;
@@ -312,6 +340,7 @@
     qhwc::IFBUpdate *mFBUpdate[HWC_NUM_DISPLAY_TYPES];
     // External display related information
     qhwc::ExternalDisplay *mExtDisplay;
+    qhwc::VirtualDisplay *mVirtualDisplay;
     qhwc::MDPInfo mMDP;
     qhwc::VsyncState vstate;
     qhwc::DisplayAttributes dpyAttr[HWC_NUM_DISPLAY_TYPES];
@@ -319,6 +348,7 @@
     qhwc::LayerProp *layerProp[HWC_NUM_DISPLAY_TYPES];
     qhwc::MDPComp *mMDPComp[HWC_NUM_DISPLAY_TYPES];
     qhwc::HwcDebug *mHwcDebug[HWC_NUM_DISPLAY_TYPES];
+    qhwc::AssertiveDisplay *mAD;
 
     // No animation on External display feature
     // Notifies hwcomposer about the device orientation before animation.
@@ -329,20 +359,23 @@
     int mPrevTransformVideo;
     //Securing in progress indicator
     bool mSecuring;
-    //External Display configuring progress indicator
-    bool mExtDispConfiguring;
+    //WFD on proprietary stack
+    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 protect drawing data structures
+    mutable Locker mDrawLock;
     //Drawing round when we use GPU
     bool isPaddingRound;
     // External Orientation
     int mExtOrientation;
     //Flags the transition of a video session
     bool mVideoTransFlag;
+
+    //Used for SideSync feature
+    //which overrides the mExtOrientation
+    bool mBufferMirrorMode;
+
     qhwc::LayerRotMap *mLayerRotMap[HWC_NUM_DISPLAY_TYPES];
 };
 
diff --git a/libhwcomposer/hwc_vsync.cpp b/libhwcomposer/hwc_vsync.cpp
index e4da4f7..595b7f2 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -29,6 +29,7 @@
 #include "hwc_utils.h"
 #include "string.h"
 #include "external.h"
+#include "overlay.h"
 
 namespace qhwc {
 
@@ -63,7 +64,7 @@
 
     struct pollfd pfd[2];
     int fb_fd[2];
-    uint64_t timestamp[2];
+    uint64_t timestamp[2] = {0,0};
     int num_displays;
 
     char property[PROPERTY_VALUE_MAX];
@@ -77,7 +78,7 @@
             logvsync = true;
     }
 
-    if (ctx->mExtDisplay->getHDMIIndex() > 0)
+    if (ctx->mExtDisplay->isConnected())
         num_displays = 2;
     else
         num_displays = 1;
@@ -87,7 +88,8 @@
         snprintf(vsync_node_path, sizeof(vsync_node_path),
                 "/sys/class/graphics/fb%d/vsync_event",
                 dpy == HWC_DISPLAY_PRIMARY ? 0 :
-                ctx->mExtDisplay->getHDMIIndex());
+                overlay::Overlay::getInstance()->
+                                getFbForDpy(HWC_DISPLAY_EXTERNAL));
         ALOGI("%s: Reading vsync for dpy=%d from %s", __FUNCTION__, dpy,
                 vsync_node_path);
         fb_fd[dpy] = open(vsync_node_path, O_RDONLY);
@@ -102,6 +104,8 @@
                 break;
             }
         }
+        // Read once from the fds to clear the first notify
+        pread(fb_fd[dpy], vdata , MAX_DATA, 0);
 
         pfd[dpy].fd = fb_fd[dpy];
         if (pfd[dpy].fd >= 0)
@@ -118,7 +122,7 @@
                         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",
+                            ALOGE ("%s: Unable to read vsync for dpy=%d : %s",
                                     __FUNCTION__, dpy, strerror(errno));
                             continue;
                         }
diff --git a/liblight/lights.c b/liblight/lights.c
index 14a6646..ccfbe10 100644
--- a/liblight/lights.c
+++ b/liblight/lights.c
@@ -51,9 +51,18 @@
 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";
 
+char const*const GREEN_BLINK_FILE
+        = "/sys/class/leds/green/blink";
+
+char const*const BLUE_BLINK_FILE
+        = "/sys/class/leds/blue/blink";
+
 /**
  * device methods
  */
@@ -152,7 +161,12 @@
     }
 
     if (blink) {
-        write_int(RED_BLINK_FILE, blink);
+        if (red)
+            write_int(RED_BLINK_FILE, blink);
+        if (green)
+            write_int(GREEN_BLINK_FILE, blink);
+        if (blue)
+            write_int(BLUE_BLINK_FILE, blink);
     } else {
         write_int(RED_LED_FILE, red);
         write_int(GREEN_LED_FILE, green);
@@ -198,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
@@ -227,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 fac0c49..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++)
@@ -385,9 +387,9 @@
 }
 
 Overlay* Overlay::sInstance = 0;
-int Overlay::sExtFbIndex = 1;
 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 63f5bf1..280223c 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -82,27 +82,25 @@
     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
      * displays
      */
     bool isPipeTypeAttached(utils::eMdpPipeType type);
-    /* 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.
      */
     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 */
@@ -171,10 +169,9 @@
 
     /* Singleton Instance*/
     static Overlay *sInstance;
-    //TODO Deprecate
-    static int sExtFbIndex;
     static int sDpyFbMap[DPY_MAX];
     static int sDMAMode;
+    static int sForceSetBitmap;
 };
 
 inline void Overlay::validate(int index) {
@@ -201,14 +198,6 @@
     return avail;
 }
 
-inline void Overlay::setExtFbNum(int fbNum) {
-    sExtFbIndex = fbNum;
-}
-
-inline int Overlay::getExtFbNum() {
-    return sExtFbIndex;
-}
-
 inline void Overlay::setDMAMode(const int& mode) {
     if(mode == DMA_LINE_MODE || mode == DMA_BLOCK_MODE)
         sDMAMode = mode;
@@ -223,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
diff --git a/liboverlay/overlayWriteback.cpp b/liboverlay/overlayWriteback.cpp
index b6ed53c..f711ca6 100644
--- a/liboverlay/overlayWriteback.cpp
+++ b/liboverlay/overlayWriteback.cpp
@@ -73,12 +73,13 @@
 }
 
 //=========== class Writeback =================================================
-Writeback::Writeback() : mXres(0), mYres(0) {
+Writeback::Writeback() : mXres(0), mYres(0), mOpFmt(-1) {
     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;
     }
+    queryOutputFormat();
     startSession();
 }
 
@@ -184,6 +185,17 @@
     return writeSync(mWbMem.getDstFd(), mWbMem.getOffset());
 }
 
+void Writeback::queryOutputFormat() {
+    struct msmfb_metadata metadata;
+    memset(&metadata, 0 , sizeof(metadata));
+    metadata.op = metadata_op_wb_format;
+    if (ioctl(mFd.getFD(), MSMFB_METADATA_GET, &metadata) < 0) {
+        ALOGE("Error retrieving MDP Writeback format");
+        return;
+    }
+    mOpFmt = metadata.data.mixer_cfg.writeback_format;
+}
+
 //static
 
 Writeback *Writeback::getInstance() {
diff --git a/liboverlay/overlayWriteback.h b/liboverlay/overlayWriteback.h
index fbfd889..6280391 100644
--- a/liboverlay/overlayWriteback.h
+++ b/liboverlay/overlayWriteback.h
@@ -81,6 +81,7 @@
     bool queueBuffer(int opFd, uint32_t opOffset);
     uint32_t getOffset() const { return mWbMem.getOffset(); }
     int getDstFd() const { return mWbMem.getDstFd(); }
+    int getOutputFormat() const { return mOpFmt; }
 
     static Writeback* getInstance();
     static void configBegin() { sUsed = false; }
@@ -93,11 +94,13 @@
     bool stopSession();
     //Actually block_until_write_done for the usage here.
     bool dequeueBuffer();
+    void queryOutputFormat();
     OvFD mFd;
     WritebackMem mWbMem;
     struct msmfb_data mFbData;
     int mXres;
     int mYres;
+    int mOpFmt;
 
     static bool sUsed;
     static Writeback *sWb;
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 0de7129..35f686c 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -47,13 +47,10 @@
     ALOGE_IF(DEBUG_OVERLAY, "GenericPipe init");
     mRotDownscaleOpt = false;
 
-    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);
+    int fbNum = Overlay::getFbForDpy(mDpy);
+    if( fbNum < 0 ) {
+        ALOGE("%s: Invalid FB for the display: %d",__FUNCTION__, mDpy);
+        return false;
     }
 
     ALOGD_IF(DEBUG_OVERLAY,"%s: mFbNum:%d",__FUNCTION__, fbNum);
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index a3ff150..e45f42e 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -78,6 +78,13 @@
         data.writeInt32(orientation);
         remote()->transact(EXTERNAL_ORIENTATION, data, &reply);
     }
+
+    virtual void setBufferMirrorMode(uint32_t enable) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IQService::getInterfaceDescriptor());
+        data.writeInt32(enable);
+        remote()->transact(BUFFER_MIRRORMODE, data, &reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(QService, "android.display.IQService");
@@ -160,6 +167,18 @@
             setExtOrientation(orientation);
             return NO_ERROR;
         } break;
+        case BUFFER_MIRRORMODE: {
+            CHECK_INTERFACE(IQService, data, reply);
+            if(callerUid != AID_SYSTEM) {
+                ALOGE("display.qservice BUFFER_MIRRORMODE access denied: \
+                      pid=%d uid=%d process=%s",callerPid,
+                      callerUid, callingProcName);
+                return PERMISSION_DENIED;
+            }
+            uint32_t enable = data.readInt32();
+            setBufferMirrorMode(enable);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libqservice/IQService.h b/libqservice/IQService.h
index ff034be..149cd8b 100644
--- a/libqservice/IQService.h
+++ b/libqservice/IQService.h
@@ -42,6 +42,7 @@
         CONNECT,
         SCREEN_REFRESH,
         EXTERNAL_ORIENTATION,
+        BUFFER_MIRRORMODE,
     };
     enum {
         END = 0,
@@ -52,6 +53,7 @@
     virtual void connect(const android::sp<qClient::IQClient>& client) = 0;
     virtual android::status_t screenRefresh() = 0;
     virtual void setExtOrientation(uint32_t orientation) = 0;
+    virtual void setBufferMirrorMode(uint32_t enable) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libqservice/QService.cpp b/libqservice/QService.cpp
index f780a75..a8c5dca 100644
--- a/libqservice/QService.cpp
+++ b/libqservice/QService.cpp
@@ -77,6 +77,12 @@
     }
 }
 
+void QService::setBufferMirrorMode(uint32_t enable) {
+    if(mClient.get()) {
+        mClient->notifyCallback(BUFFER_MIRRORMODE, enable);
+    }
+}
+
 void QService::init()
 {
     if(!sQService) {
diff --git a/libqservice/QService.h b/libqservice/QService.h
index 8eefa21..a241d44 100644
--- a/libqservice/QService.h
+++ b/libqservice/QService.h
@@ -50,6 +50,7 @@
     virtual void connect(const android::sp<qClient::IQClient>& client);
     virtual android::status_t screenRefresh();
     virtual void setExtOrientation(uint32_t orientation);
+    virtual void setBufferMirrorMode(uint32_t enable);
     static void init();
 private:
     QService();
diff --git a/libtilerenderer/Android.mk b/libtilerenderer/Android.mk
deleted file mode 100644
index ca17fbc..0000000
--- a/libtilerenderer/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-include $(LOCAL_PATH)/../common.mk
-include $(CLEAR_VARS)
-
-ifeq ($(USE_OPENGL_RENDERER),true)
-LOCAL_MODULE           := libtilerenderer
-LOCAL_MODULE_TAGS      := optional
-LOCAL_CFLAGS           := -DLOG_TAG=\"qdtilerenderer\"
-LOCAL_C_INCLUDES := \
-        frameworks/base/include/utils \
-        frameworks/base/libs/hwui \
-        external/skia/include/core \
-        external/skia/include/effects \
-        external/skia/include/images \
-        external/skia/src/ports \
-        external/skia/include/utils \
-        hardware/libhardware/include/hardware \
-        frameworks/base/opengl/include/GLES2
-LOCAL_SHARED_LIBRARIES := $(common_libs) libGLESv2 libhwui
-LOCAL_SRC_FILES        := tilerenderer.cpp
-
-include $(BUILD_SHARED_LIBRARY)
-endif
diff --git a/libtilerenderer/tilerenderer.cpp b/libtilerenderer/tilerenderer.cpp
deleted file mode 100644
index 03a0aea..0000000
--- a/libtilerenderer/tilerenderer.cpp
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <GLES2/gl2.h>
-#include <EGL/egl.h>
-#include <gl2ext.h>
-#include <OpenGLRenderer.h>
-#include "tilerenderer.h"
-
-namespace android {
-ANDROID_SINGLETON_STATIC_INSTANCE(uirenderer::TileRenderer) ;
-namespace uirenderer {
-
-TileRenderer::TileRenderer() {
-    mIsTiled = false;
-}
-
-TileRenderer::~TileRenderer() {
-}
-
-void TileRenderer::startTileRendering(OpenGLRenderer* renderer,
-                                      int left, int top,
-                                      int right, int bottom) {
-    int width = 0;
-    int height = 0;
-    GLenum status = GL_NO_ERROR;
-
-    if (renderer != NULL) {
-        renderer->getViewport(width, height);
-    }
-
-    if (!left && !right && !top && !bottom) {
-        left = 0;
-        top = 0;
-        right = width;
-        bottom = height;
-    }
-
-    if (!left && !right && !top && !bottom) {
-        //can't do tile rendering
-        ALOGE("can't tile render; drity region, width, height not available");
-        return;
-    }
-
-    int l = left, t = (height - bottom), w = (right - left), h = (bottom - top), preserve = 0;
-
-    if (l < 0 || t < 0) {
-        l = (l < 0) ? 0 : l;
-        t = (t < 0) ? 0 : t;
-        preserve = 1;
-    }
-
-    if (w > width || h > height) {
-        w = (w > width) ? width : w;
-        h = (h > height) ? height : h;
-        preserve = 1;
-    }
-
-    //clear off all errors before tiling, if any
-    while ((status = glGetError()) != GL_NO_ERROR);
-
-    if (preserve)
-        glStartTilingQCOM(l, t, w, h, GL_COLOR_BUFFER_BIT0_QCOM);
-    else
-        glStartTilingQCOM(l, t, w, h, GL_NONE);
-
-    status = glGetError();
-    if (status == GL_NO_ERROR)
-        mIsTiled = true;
-}
-
-void TileRenderer::endTileRendering(OpenGLRenderer*) {
-    if (!mIsTiled) {
-        return;
-    }
-    glEndTilingQCOM(GL_COLOR_BUFFER_BIT0_QCOM);
-    mIsTiled = false;
-    GLenum status = GL_NO_ERROR;
-    while ((status = glGetError()) != GL_NO_ERROR);
-}
-
-}; // namespace uirenderer
-}; // namespace android
diff --git a/libtilerenderer/tilerenderer.h b/libtilerenderer/tilerenderer.h
deleted file mode 100644
index d894d33..0000000
--- a/libtilerenderer/tilerenderer.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- * Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef ANDROID_TILE_RENDERER_H
-#define ANDROID_TILE_RENDERER_H
-
-#include <utils/Singleton.h>
-
-namespace android {
-namespace uirenderer {
-
-class OpenGLRenderer;
-
-class TileRenderer: public Singleton<TileRenderer> {
-    public:
-    TileRenderer();
-    ~TileRenderer();
-
-    void startTileRendering(OpenGLRenderer* renderer, int left, int top, int right, int bottom);
-    void endTileRendering(OpenGLRenderer*);
-
-    private:
-    bool mIsTiled;
-};
-
-}; // namespace uirenderer
-}; // namespace android
-
-#endif
diff --git a/libvirtual/Android.mk b/libvirtual/Android.mk
new file mode 100644
index 0000000..beeef25
--- /dev/null
+++ b/libvirtual/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_MODULE                  := libvirtual
+LOCAL_MODULE_PATH             := $(TARGET_OUT_SHARED_LIBRARIES)
+LOCAL_MODULE_TAGS             := optional
+LOCAL_C_INCLUDES              := $(common_includes) $(kernel_includes)
+LOCAL_SHARED_LIBRARIES        := $(common_libs) liboverlay libqdutils
+LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdvirtual\"
+LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
+LOCAL_SRC_FILES               := virtual.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
new file mode 100644
index 0000000..8e96a56
--- /dev/null
+++ b/libvirtual/virtual.cpp
@@ -0,0 +1,157 @@
+/*
+* 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.
+*/
+
+
+#define DEBUG 0
+#include <ctype.h>
+#include <fcntl.h>
+#include <media/IAudioPolicyService.h>
+#include <media/AudioSystem.h>
+#include <utils/threads.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <linux/msm_mdp.h>
+#include <linux/fb.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <sys/resource.h>
+#include <cutils/properties.h>
+#include "hwc_utils.h"
+#include "virtual.h"
+#include "overlayUtils.h"
+#include "overlay.h"
+#include "mdp_version.h"
+
+using namespace android;
+
+namespace qhwc {
+
+#define MAX_SYSFS_FILE_PATH             255
+
+int VirtualDisplay::configure() {
+    if(!openFrameBuffer())
+        return -1;
+
+    if(ioctl(mFd, FBIOGET_VSCREENINFO, &mVInfo) < 0) {
+        ALOGD("%s: FBIOGET_VSCREENINFO failed with %s", __FUNCTION__,
+                strerror(errno));
+        return -1;
+    }
+    setAttributes();
+    return 0;
+}
+
+void VirtualDisplay::getAttributes(int& width, int& height) {
+    width = mVInfo.xres;
+    height = mVInfo.yres;
+}
+
+int VirtualDisplay::teardown() {
+    closeFrameBuffer();
+    memset(&mVInfo, 0, sizeof(mVInfo));
+    return 0;
+}
+
+VirtualDisplay::VirtualDisplay(hwc_context_t* ctx):mFd(-1),
+     mHwcContext(ctx)
+{
+    memset(&mVInfo, 0, sizeof(mVInfo));
+}
+
+VirtualDisplay::~VirtualDisplay()
+{
+    closeFrameBuffer();
+}
+
+void VirtualDisplay::setAttributes() {
+    if(mHwcContext) {
+        // Always set dpyAttr res to mVInfo res
+        mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = mVInfo.xres;
+        mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = mVInfo.yres;
+        mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = false;
+        if(!qdutils::MDPVersion::getInstance().is8x26()) {
+            uint32_t priW = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].xres;
+            uint32_t priH = mHwcContext->dpyAttr[HWC_DISPLAY_PRIMARY].yres;
+            // if primary resolution is more than the wfd resolution
+            // configure dpy attr to primary resolution and set
+            // downscale mode
+            if((priW * priH) > (mVInfo.xres * mVInfo.yres)) {
+                mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = priW;
+                mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = priH;
+                // WFD is always in landscape, so always assign the higher
+                // dimension to wfd's xres
+                if(priH > priW) {
+                    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = priH;
+                    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = priW;
+                }
+                // Set External Display MDP Downscale mode indicator
+                mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = true;
+            }
+        }
+        mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].vsync_period =
+                1000000000l /60;
+        ALOGD_IF(DEBUG,"%s: Setting Virtual Attr: res(%d x %d)",__FUNCTION__,
+                 mVInfo.xres, mVInfo.yres);
+    }
+}
+
+bool VirtualDisplay::openFrameBuffer()
+{
+    if (mFd == -1) {
+        int fbNum = overlay::Overlay::getInstance()->
+                                   getFbForDpy(HWC_DISPLAY_VIRTUAL);
+
+        char strDevPath[MAX_SYSFS_FILE_PATH];
+        sprintf(strDevPath,"/dev/graphics/fb%d", fbNum);
+
+        mFd = open(strDevPath, O_RDWR);
+        if(mFd < 0) {
+            ALOGE("%s: Unable to open %s ", __FUNCTION__,strDevPath);
+            return -1;
+        }
+
+        mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].fd = mFd;
+    }
+    return 1;
+}
+
+bool VirtualDisplay::closeFrameBuffer()
+{
+    if(mFd >= 0) {
+        if(close(mFd) < 0 ) {
+            ALOGE("%s: Unable to close FD(%d)", __FUNCTION__, mFd);
+            return -1;
+        }
+        mFd = -1;
+        mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].fd = mFd;
+    }
+    return 1;
+}
+};
diff --git a/libvirtual/virtual.h b/libvirtual/virtual.h
new file mode 100644
index 0000000..8003e23
--- /dev/null
+++ b/libvirtual/virtual.h
@@ -0,0 +1,62 @@
+/*
+* 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 HWC_VIRTUAL_DISPLAY_H
+#define HWC_VIRTUAL_DISPLAY_H
+
+#include <linux/fb.h>
+
+struct hwc_context_t;
+
+namespace qhwc {
+
+class VirtualDisplay
+{
+public:
+    VirtualDisplay(hwc_context_t* ctx);
+    ~VirtualDisplay();
+    int  configure();
+    void getAttributes(int& width, int& height);
+    int  teardown();
+    bool isConnected() {
+        return  mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].connected;
+    }
+private:
+    bool openFrameBuffer();
+    bool closeFrameBuffer();
+    void setAttributes();
+
+    int mFd;
+    hwc_context_t *mHwcContext;
+    fb_var_screeninfo mVInfo;
+};
+}; //qhwc
+// ---------------------------------------------------------------------------
+#endif //HWC_VIRTUAL_DISPLAY_H