Merge "gralloc: Move getAllocator in unlock"
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 b247dfb..89d63e9 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -34,6 +34,7 @@
 #include "external.h"
 #include "overlayUtils.h"
 #include "overlay.h"
+#include "mdp_version.h"
 
 using namespace android;
 
@@ -65,6 +66,11 @@
     return 0;
 }
 
+void ExternalDisplay::getAttributes(int& width, int& height) {
+    int fps = 0;
+    getAttrForMode(width, height, fps);
+}
+
 int ExternalDisplay::teardown() {
     closeFrameBuffer();
     resetInfo();
@@ -564,15 +570,38 @@
     return ret;
 }
 
+
 void ExternalDisplay::setAttributes() {
     int width = 0, height = 0, fps = 0;
     getAttrForMode(width, height, fps);
-
     ALOGD("ExtDisplay setting xres = %d, yres = %d", width, height);
-    mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = width;
-    mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = height;
-    mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
-        1000000000l / fps;
+    if(mHwcContext) {
+        // 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;
+    }
 }
 
 void ExternalDisplay::getAttrForMode(int& width, int& height, int& fps) {
diff --git a/libexternal/external.h b/libexternal/external.h
index 2fbb027..1a3602d 100644
--- a/libexternal/external.h
+++ b/libexternal/external.h
@@ -45,6 +45,7 @@
     void setActionSafeDimension(int w, int h);
     bool isCEUnderscanSupported() { return mUnderscanSupported; }
     int configure();
+    void getAttributes(int& width, int& height);
     int teardown();
     bool isConnected() {
         return  mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].connected;
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index ea6711b..5fd7564 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -123,6 +123,7 @@
     }
 
     ctx->mAD->reset();
+    MDPComp::reset();
 }
 
 //clear prev layer prop flags and realloc for current frame
@@ -576,7 +577,7 @@
 
     closeAcquireFds(list);
 
-    if (list && !ctx->mVirtualonExtActive) {
+    if (list && !ctx->mVirtualonExtActive && (list->retireFenceFd < 0) ) {
         // SF assumes HWC waits for the acquire fence and returns a new fence
         // that signals when we're done. Since we don't wait, and also don't
         // touch the buffer, we can just handle the acquire fence back to SF
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index 9ac8958..34c241d 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -118,7 +118,7 @@
         }
         close(adFd);
     } else {
-        ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s",
+        ALOGD("%s: /sys/class/graphics/fb%d/ad could not be opened : %s",
                 __func__, wbFbNum, strerror(errno));
     }
     return ret;
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index a395ee0..dbb4413 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -223,24 +223,18 @@
     if (!useCopybitForYUV && ctx->listStats[dpy].yuvCount)
         return true;
 
-    // numAppLayers-1, as we iterate till 0th layer index
-    for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
-        private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
-
-        if ((hnd->bufferType == BUFFER_TYPE_VIDEO && useCopybitForYUV) ||
-            (hnd->bufferType == BUFFER_TYPE_UI && useCopybitForRGB)) {
+    mCopyBitDraw = false;
+    if (useCopybitForRGB &&
+        (useCopybitForYUV || !ctx->listStats[dpy].yuvCount)) {
+        mCopyBitDraw =  true;
+        // numAppLayers-1, as we iterate till 0th layer index
+        // Mark all layers to be drawn by copybit
+        for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
             layerProp[i].mFlags |= HWC_COPYBIT;
             list->hwLayers[i].compositionType = HWC_OVERLAY;
-            mCopyBitDraw = true;
-        } else {
-            // We currently cannot mix copybit layers with layers marked to
-            // be drawn on the framebuffer or that are on the layer cache.
-            mCopyBitDraw = false;
-            //There is no need to reset layer properties here as we return in
-            //draw if mCopyBitDraw is false
-            break;
         }
     }
+
     return true;
 }
 
@@ -364,6 +358,27 @@
     // if needed in the future
     src.vert_padding = 0;
 
+    int layerTransform = layer->transform ;
+    // When flip and rotation(90) are present alter the flip,
+    // as GPU is doing the flip and rotation in opposite order
+    // to that of MDP3.0
+    // For 270 degrees, we get 90 + (H+V) which is same as doing
+    // flip first and then rotation (H+V) + 90
+    if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) {
+                if (((layer->transform& HAL_TRANSFORM_FLIP_H) ||
+                (layer->transform & HAL_TRANSFORM_FLIP_V)) &&
+                (layer->transform &  HAL_TRANSFORM_ROT_90) &&
+                !(layer->transform ==  HAL_TRANSFORM_ROT_270)){
+                      if(layer->transform & HAL_TRANSFORM_FLIP_H){
+                                 layerTransform ^= HAL_TRANSFORM_FLIP_H;
+                                 layerTransform |= HAL_TRANSFORM_FLIP_V;
+                      }
+                      if(layer->transform & HAL_TRANSFORM_FLIP_V){
+                                 layerTransform ^= HAL_TRANSFORM_FLIP_V;
+                                 layerTransform |= HAL_TRANSFORM_FLIP_H;
+                      }
+               }
+    }
     // Copybit source rect
     hwc_rect_t sourceCrop = layer->sourceCrop;
     copybit_rect_t srcRect = {sourceCrop.left, sourceCrop.top,
@@ -519,7 +534,7 @@
     copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT,
                                           renderBuffer->height);
     copybit->set_parameter(copybit, COPYBIT_TRANSFORM,
-                                              layer->transform);
+                                              layerTransform);
     //TODO: once, we are able to read layer alpha, update this
     copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
     copybit->set_parameter(copybit, COPYBIT_BLEND_MODE,
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index ac2650c..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) {
@@ -114,45 +140,33 @@
 
         ovutils::eTransform orient =
                     static_cast<ovutils::eTransform>(transform);
+        // 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;
             }
         }
-
-        if(mDpy && !qdutils::MDPVersion::getInstance().is8x26()) {
-            if(ctx->mExtOrientation) {
-                calcExtDisplayPosition(ctx, mDpy, displayFrame);
-                // If there is a external orientation set, use that
-                transform = ctx->mExtOrientation;
-                orient = static_cast<ovutils::eTransform >(ctx->mExtOrientation);
-            }
-            // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
-            getActionSafePosition(ctx, mDpy, displayFrame);
-       }
+        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;
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 f2217b9..8956be5 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -42,6 +42,8 @@
 bool MDPComp::sEnabled = false;
 bool MDPComp::sEnableMixedMode = true;
 int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
+float MDPComp::sMaxBw = 2.3f;
+uint32_t MDPComp::sCompBytesClaimed = 0;
 
 MDPComp* MDPComp::getObject(const int& width, const int& rightSplit,
         const int& dpy) {
@@ -125,6 +127,13 @@
             sMaxPipesPerMixer = min(val, MAX_PIPES_PER_MIXER);
     }
 
+    if(property_get("debug.mdpcomp.bw", property, "0") > 0) {
+        float val = atof(property);
+        if(val > 0.0f) {
+            sMaxBw = val;
+        }
+    }
+
     if(ctx->mMDP.panel != MIPI_CMD_PANEL) {
         // Idle invalidation is not necessary on command mode panels
         long idle_timeout = DEFAULT_IDLE_TIME;
@@ -497,6 +506,12 @@
         return false;
     }
 
+    uint32_t size = calcMDPBytesRead(ctx, list);
+    if(!bandwidthCheck(ctx, size)) {
+        ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
+        return false;
+    }
+
     return true;
 }
 
@@ -525,6 +540,12 @@
         return false;
     }
 
+    uint32_t size = calcMDPBytesRead(ctx, list);
+    if(!bandwidthCheck(ctx, size)) {
+        ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
+        return false;
+    }
+
     return true;
 }
 
@@ -552,6 +573,12 @@
         return false;
     }
 
+    uint32_t size = calcMDPBytesRead(ctx, list);
+    if(!bandwidthCheck(ctx, size)) {
+        ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
+        return false;
+    }
+
     return true;
 }
 
@@ -753,7 +780,46 @@
     return true;
 }
 
+uint32_t MDPComp::calcMDPBytesRead(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
+    uint32_t size = 0;
+
+    for (uint32_t i = 0; i < list->numHwLayers - 1; i++) {
+        if(!mCurrentFrame.isFBComposed[i]) {
+            hwc_layer_1_t* layer = &list->hwLayers[i];
+            private_handle_t *hnd = (private_handle_t *)layer->handle;
+            hwc_rect_t crop = layer->sourceCrop;
+            float bpp = ((float)hnd->size) / (hnd->width * hnd->height);
+            size += bpp * ((crop.right - crop.left) *
+                    (crop.bottom - crop.top));
+        }
+    }
+
+    if(mCurrentFrame.fbCount) {
+        hwc_layer_1_t* layer = &list->hwLayers[list->numHwLayers - 1];
+        private_handle_t *hnd = (private_handle_t *)layer->handle;
+        size += hnd->size;
+    }
+
+    return size;
+}
+
+bool MDPComp::bandwidthCheck(hwc_context_t *ctx, const uint32_t& size) {
+    //Will be added for other targets if we run into bandwidth issues and when
+    //we have profiling data to set an upper limit.
+    if(qdutils::MDPVersion::getInstance().is8x74v2()) {
+        const uint32_t ONE_GIG = 1024 * 1024 * 1024;
+        double panelRefRate =
+                1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
+        if((size + sCompBytesClaimed) > ((sMaxBw / panelRefRate) * ONE_GIG)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    int ret = 0;
     const int numLayers = ctx->listStats[mDpy].numAppLayers;
 
     //reset old data
@@ -765,7 +831,8 @@
         mCachedFrame.updateCounts(mCurrentFrame);
         ALOGD_IF(isDebug(), "%s: Number of App layers exceeded the limit ",
                 __FUNCTION__);
-        return -1;
+        ret = -1;
+        goto exit;
     }
 
     //Hard conditions, if not met, cannot do MDP comp
@@ -773,7 +840,8 @@
         ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
                 __FUNCTION__);
         reset(numLayers, list);
-        return -1;
+        ret = -1;
+        goto exit;
     }
 
     //Check whether layers marked for MDP Composition is actually doable.
@@ -785,13 +853,17 @@
                         mCurrentFrame.fbZ)) {
                 ALOGE("%s configure framebuffer failed", __func__);
                 reset(numLayers, list);
-                return -1;
+                ctx->mOverlay->clear(mDpy);
+                ret = -1;
+                goto exit;
             }
         }
         //Acquire and Program MDP pipes
         if(!programMDP(ctx, list)) {
             reset(numLayers, list);
-            return -1;
+            ctx->mOverlay->clear(mDpy);
+            ret = -1;
+            goto exit;
         } else { //Success
             //Any change in composition types needs an FB refresh
             mCurrentFrame.needsRedraw = false;
@@ -822,16 +894,21 @@
             if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list, mCurrentFrame.fbZ)) {
                 ALOGE("%s configure framebuffer failed", __func__);
                 reset(numLayers, list);
-                return -1;
+                ctx->mOverlay->clear(mDpy);
+                ret = -1;
+                goto exit;
             }
         }
         if(!programYUV(ctx, list)) {
             reset(numLayers, list);
-            return -1;
+            ctx->mOverlay->clear(mDpy);
+            ret = -1;
+            goto exit;
         }
     } else {
         reset(numLayers, list);
-        return -1;
+        ret = -1;
+        goto exit;
     }
 
     //UpdateLayerFlags
@@ -846,7 +923,9 @@
         ALOGE("%s",sDump.string());
     }
 
-    return 0;
+exit:
+    sCompBytesClaimed += calcMDPBytesRead(ctx, list);
+    return ret;
 }
 
 //=============MDPCompLowRes===================================================
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 2f1670b..1e374aa 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -53,6 +53,7 @@
     /* Initialize MDP comp*/
     static bool init(hwc_context_t *ctx);
     static void resetIdleFallBack() { sIdleFallBack = false; }
+    static void reset() { sCompBytesClaimed = 0; };
 
 protected:
     enum ePipeType {
@@ -142,6 +143,11 @@
     bool isOnlyVideoDoable(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     /* checks for conditions where YUV layers cannot be bypassed */
     bool isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
+    /* calcs bytes read by MDP for a given frame */
+    uint32_t calcMDPBytesRead(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
+    /* checks if the required bandwidth exceeds a certain max */
+    bool bandwidthCheck(hwc_context_t *ctx, const uint32_t& size);
 
     /* set up Border fill as Base pipe */
     static bool setupBasePipe(hwc_context_t*);
@@ -167,6 +173,11 @@
     static bool sDebugLogs;
     static bool sIdleFallBack;
     static int sMaxPipesPerMixer;
+    //Max bandwidth. Value is in GBPS. For ex: 2.3 means 2.3GBPS
+    static float sMaxBw;
+    //Tracks composition bytes claimed. Represented as the total w*h*bpp
+    //going to MDP mixers
+    static uint32_t sCompBytesClaimed;
     static IdleInvalidator *idleInvalidator;
     struct FrameInfo mCurrentFrame;
     struct LayerCache mCachedFrame;
diff --git a/libhwcomposer/hwc_qclient.cpp b/libhwcomposer/hwc_qclient.cpp
index 45c82fd..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;
     }
@@ -118,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_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 35e724d..ffaa9cb 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -159,6 +159,9 @@
     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,
@@ -193,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);
 }
@@ -261,6 +266,13 @@
     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, hwc_rect_t& rect) {
     // Position
@@ -294,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;
@@ -414,6 +428,56 @@
                  "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;
@@ -432,20 +496,100 @@
     return false;
 }
 
-void calcExtDisplayPosition(hwc_context_t *ctx,
-                               int dpy, hwc_rect_t& displayFrame) {
-    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;
-    // Swap width and height when there is a 90deg transform
-    if(ctx->mExtOrientation & HWC_TRANSFORM_ROT_90) {
-        if(!isPrimaryPortrait(ctx)) {
-            swap(srcWidth, srcHeight);
-        }                    // Get Aspect Ratio for external
-        getAspectRatioPosition(dstWidth, dstHeight, srcWidth,
-                            srcHeight, displayFrame);
+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,
@@ -571,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;
             }
@@ -961,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() >=
@@ -1083,15 +1234,8 @@
                 z = ZORDER_1;
             }
         }
-    }
-    if(dpy) {
-        // Just need to set the position to portrait as the transformation
-        // will already be set to required orientation on TV
-        if(ctx->mExtOrientation) {
-            getAspectRatioPosition(ctx, dpy, ctx->mExtOrientation, dst, dst);
-        }
-        // Calculate the actionsafe dimensions for External(dpy = 1 or 2)
-        getActionSafePosition(ctx, dpy, dst);
+        calcExtDisplayPosition(ctx, hnd, dpy, crop, dst,
+                                           transform, orient);
     }
 
     if(isYuvBuffer(hnd) && ctx->mMDP.version >= qdutils::MDP_V4_2 &&
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 8e70a91..5695f28 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -83,6 +83,8 @@
     // To trigger padding round to clean up mdp
     // pipes
     bool isConfiguring;
+    // External Display is in MDP Downscale mode indicator
+    bool mDownScaleMode;
 };
 
 struct ListStats {
@@ -175,6 +177,8 @@
 //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, hwc_rect_t& dst);
 
@@ -186,8 +190,19 @@
 
 bool isPrimaryPortrait(hwc_context_t *ctx);
 
+bool isOrientationPortrait(hwc_context_t *ctx);
+
 void calcExtDisplayPosition(hwc_context_t *ctx,
-                               int dpy, hwc_rect_t& displayFrame);
+                               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);
@@ -205,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);
 
@@ -356,6 +371,11 @@
     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 7189a01..595b7f2 100644
--- a/libhwcomposer/hwc_vsync.cpp
+++ b/libhwcomposer/hwc_vsync.cpp
@@ -104,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)
@@ -120,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/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 1dd317f..4a695d3 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -166,5 +166,12 @@
     return false;
 }
 
+bool MDPVersion::is8x74v2() {
+    if( mMdpRev >= MDSS_MDP_HW_REV_102 && mMdpRev < MDSS_MDP_HW_REV_103) {
+        return true;
+    }
+    return false;
+}
+
 }; //namespace qdutils
 
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 316899f..8d23b2d 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -54,9 +54,10 @@
 };
 
 enum mdp_rev {
-    MDSS_MDP_HW_REV_100 = 0x10000000,
+    MDSS_MDP_HW_REV_100 = 0x10000000, //8974 v1
     MDSS_MDP_HW_REV_101 = 0x10010000, //8x26
-    MDSS_MDP_HW_REV_102 = 0x10020000,
+    MDSS_MDP_HW_REV_102 = 0x10020000, //8974 v2
+    MDSS_MDP_HW_REV_103 = 0x10030000, //Future
 };
 
 enum {
@@ -101,6 +102,7 @@
     uint32_t getMaxMDPDownscale();
     bool supportsBWC();
     bool is8x26();
+    bool is8x74v2();
     int getLeftSplit() { return mSplit.left(); }
     int getRightSplit() { return mSplit.right(); }
 private:
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/libvirtual/Android.mk b/libvirtual/Android.mk
index 1231f8d..beeef25 100644
--- a/libvirtual/Android.mk
+++ b/libvirtual/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=\"qdvirtual\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps)
 LOCAL_SRC_FILES               := virtual.cpp
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
index e2f239a..8e96a56 100644
--- a/libvirtual/virtual.cpp
+++ b/libvirtual/virtual.cpp
@@ -47,6 +47,7 @@
 #include "virtual.h"
 #include "overlayUtils.h"
 #include "overlay.h"
+#include "mdp_version.h"
 
 using namespace android;
 
@@ -67,6 +68,11 @@
     return 0;
 }
 
+void VirtualDisplay::getAttributes(int& width, int& height) {
+    width = mVInfo.xres;
+    height = mVInfo.yres;
+}
+
 int VirtualDisplay::teardown() {
     closeFrameBuffer();
     memset(&mVInfo, 0, sizeof(mVInfo));
@@ -85,12 +91,35 @@
 }
 
 void VirtualDisplay::setAttributes() {
-    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].xres = mVInfo.xres;
-    mHwcContext->dpyAttr[HWC_DISPLAY_VIRTUAL].yres = mVInfo.yres;
-    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);
+    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()
diff --git a/libvirtual/virtual.h b/libvirtual/virtual.h
index cd0e7da..8003e23 100644
--- a/libvirtual/virtual.h
+++ b/libvirtual/virtual.h
@@ -43,6 +43,7 @@
     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;