Merge "display: Add support for dynamic refresh rate"
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index b0dbf2e..42e469c 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -581,14 +581,14 @@
         // 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;
+        mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mMDPScalingMode = false;
         if(mHwcContext->mOverlay->isUIScalingOnExternalSupported()
                 && mHwcContext->mMDPDownscaleEnabled) {
             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
+            // configure dpy attr to primary resolution and set MDP
+            // scaling mode.
             // Restrict this upto 1080p resolution max, if target does not
             // support source split feature.
             if((priW * priH) > (width * height) &&
@@ -632,16 +632,17 @@
                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = alignedExtW;
                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = alignedExtH;
                 // Set External Display MDP Downscale mode indicator
-                mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true;
+                mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mMDPScalingMode
+                        = true;
             }
         }
         ALOGD_IF(DEBUG_MDPDOWNSCALE, "Selected external resolution [%d X %d] "
-                 "maxMDPDownScale %d MDPDownScaleMode %d srcSplitEnabled %d "
+                 "maxMDPDownScale %d mMDPScalingMode %d srcSplitEnabled %d "
                  "MDPDownscale feature %d",
                  mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres,
                  mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres,
                  qdutils::MDPVersion::getInstance().getMaxMDPDownscale(),
-                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode,
+                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mMDPScalingMode,
                  qdutils::MDPVersion::getInstance().isSrcSplit(),
                  mHwcContext->mMDPDownscaleEnabled);
         //Initialize the display viewFrame info
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 099a82e..ae1389d 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -44,7 +44,7 @@
 using namespace overlay;
 
 #define VSYNC_DEBUG 0
-#define BLANK_DEBUG 1
+#define POWER_MODE_DEBUG 1
 
 static int hwc_device_open(const struct hw_module_t* module,
                            const char* name,
@@ -138,7 +138,8 @@
                     if (canUseRotator(ctx, dpy) &&
                         (has90Transform(layer) || getRotDownscale(ctx, layer))
                         && isRotationDoable(ctx, hnd)) {
-                        if(not ctx->mOverlay->isDMAMultiplexingSupported()) {
+                        if(not (ctx->mOverlay->isDMAMultiplexingSupported() &&
+                                          dpy)) {
                             if(ctx->mOverlay->isPipeTypeAttached(
                                              overlay::utils::OV_MDP_PIPE_DMA))
                                 ctx->isPaddingRound = true;
@@ -395,80 +396,86 @@
     return ret;
 }
 
-static int hwc_blank(struct hwc_composer_device_1* dev, int dpy, int blank)
+static int hwc_setPowerMode(struct hwc_composer_device_1* dev, int dpy,
+        int mode)
 {
     ATRACE_CALL();
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-
-    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) {
-        // free up all the overlay pipes in use
-        // when we get a blank for either display
-        // makes sure that all pipes are freed
-        ctx->mOverlay->configBegin();
-        ctx->mOverlay->configDone();
-        ctx->mRotMgr->clear();
-        // If VDS is connected, do not clear WB object as it
-        // will end up detaching IOMMU. This is required
-        // to send black frame to WFD sink on power suspend.
-        // Note: With this change, we keep the WriteBack object
-        // alive on power suspend for AD use case.
+    Locker::Autolock _l(ctx->mDrawLock);
+    ALOGD_IF(POWER_MODE_DEBUG, "%s: Setting mode %d on display: %d",
+            __FUNCTION__, mode, dpy);
+
+    switch(mode) {
+        case HWC_POWER_MODE_OFF:
+            // free up all the overlay pipes in use
+            // when we get a blank for either display
+            // makes sure that all pipes are freed
+            ctx->mOverlay->configBegin();
+            ctx->mOverlay->configDone();
+            ctx->mRotMgr->clear();
+            // If VDS is connected, do not clear WB object as it
+            // will end up detaching IOMMU. This is required
+            // to send black frame to WFD sink on power suspend.
+            // Note: With this change, we keep the WriteBack object
+            // alive on power suspend for AD use case.
+            value = FB_BLANK_POWERDOWN;
+            break;
+        case HWC_POWER_MODE_DOZE:
+        case HWC_POWER_MODE_DOZE_SUSPEND:
+            value = FB_BLANK_VSYNC_SUSPEND;
+            break;
+        case HWC_POWER_MODE_NORMAL:
+            value = FB_BLANK_UNBLANK;
+            break;
     }
+
     switch(dpy) {
     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;
+            ALOGE("%s: ioctl FBIOBLANK failed for Primary with error %s"
+                    " value %d", __FUNCTION__, strerror(errno), value);
+            return -errno;
         }
 
-        if(!blank) {
-            // Enable HPD here, as during bootup unblank is called
+        if(mode == HWC_POWER_MODE_NORMAL) {
+            // Enable HPD here, as during bootup POWER_MODE_NORMAL is set
             // when SF is completely initialized
             ctx->mExtDisplay->setHPD(1);
         }
 
-        ctx->dpyAttr[dpy].isActive = !blank;
-
+        ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
+        //Deliberate fall through since there is no explicit power mode for
+        //virtual displays.
     case HWC_DISPLAY_VIRTUAL:
-        /* Display hal has received unblank call on HWC_DISPLAY_PRIMARY
-         and 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 pipes and
-         activate/deactivate VIRTUAL DISPLAY.
-         */
-
         if(ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].connected) {
-            if(blank and (!ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isPause)) {
-                int dpy = HWC_DISPLAY_VIRTUAL;
+            const int dpy = HWC_DISPLAY_VIRTUAL;
+            if(mode == HWC_POWER_MODE_OFF and
+                    (not ctx->dpyAttr[dpy].isPause)) {
                 if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
-                    ALOGE("%s: display commit fail for virtual!", __FUNCTION__);
+                    ALOGE("%s: displayCommit failed for virtual", __FUNCTION__);
                     ret = -1;
                 }
             }
-            ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].isActive = !blank;
+            ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
         }
         break;
     case HWC_DISPLAY_EXTERNAL:
-        if(blank) {
+        if(mode == HWC_POWER_MODE_OFF) {
             if(!Overlay::displayCommit(ctx->dpyAttr[dpy].fd)) {
-                ALOGE("%s: display commit fail for external!", __FUNCTION__);
+                ALOGE("%s: displayCommit failed for external", __FUNCTION__);
                 ret = -1;
             }
         }
-        ctx->dpyAttr[dpy].isActive = !blank;
+        ctx->dpyAttr[dpy].isActive = not(mode == HWC_POWER_MODE_OFF);
         break;
     default:
         return -EINVAL;
     }
 
-    ALOGD_IF(BLANK_DEBUG, "%s: Done %s display: %d", __FUNCTION__,
-          blank ? "blanking":"unblanking", dpy);
+    ALOGD_IF(POWER_MODE_DEBUG, "%s: Done setting mode %d on display %d",
+            __FUNCTION__, mode, dpy);
     return ret;
 }
 
@@ -483,18 +490,18 @@
         return;
     }
 
-    ALOGD("%s: calling BLANK DISPLAY", __FUNCTION__);
-    ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 1);
+    ALOGD("%s: setting power mode off", __FUNCTION__);
+    ret = hwc_setPowerMode(dev, HWC_DISPLAY_PRIMARY, HWC_POWER_MODE_OFF);
     if (ret < 0) {
         ALOGE("%s: FBIOBLANK failed to BLANK:  %s", __FUNCTION__,
-                                                            strerror(errno));
+                strerror(errno));
     }
 
-    ALOGD("%s: calling UNBLANK DISPLAY and enabling vsync", __FUNCTION__);
-    ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 0);
+    ALOGD("%s: setting power mode normal and enabling vsync", __FUNCTION__);
+    ret = hwc_setPowerMode(dev, HWC_DISPLAY_PRIMARY, HWC_POWER_MODE_NORMAL);
     if (ret < 0) {
         ALOGE("%s: FBIOBLANK failed to UNBLANK : %s", __FUNCTION__,
-                                                            strerror(errno));
+                strerror(errno));
     }
     hwc_vsync_control(ctx, HWC_DISPLAY_PRIMARY, 1);
 
@@ -700,8 +707,8 @@
         uint32_t* configs, size_t* numConfigs) {
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    //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.
+    //Currently we allow only 1 config, reported as config id # 0
+    //This config is passed in to getDisplayAttributes. Ignored for now.
     switch(disp) {
         case HWC_DISPLAY_PRIMARY:
             if(*numConfigs > 0) {
@@ -812,6 +819,17 @@
     strlcpy(buff, aBuf.string(), buff_len);
 }
 
+int hwc_getActiveConfig(struct hwc_composer_device_1* /*dev*/, int /*disp*/) {
+    //Supports only the default config (0th index) for now
+    return 0;
+}
+
+int hwc_setActiveConfig(struct hwc_composer_device_1* /*dev*/, int /*disp*/,
+        int index) {
+    //Supports only the default config (0th index) for now
+    return (index == 0) ? index : -EINVAL;
+}
+
 static int hwc_device_close(struct hw_device_t *dev)
 {
     if(!dev) {
@@ -841,18 +859,20 @@
 
         //Setup HWC methods
         dev->device.common.tag          = HARDWARE_DEVICE_TAG;
-        dev->device.common.version      = HWC_DEVICE_API_VERSION_1_3;
+        dev->device.common.version      = HWC_DEVICE_API_VERSION_1_4;
         dev->device.common.module       = const_cast<hw_module_t*>(module);
         dev->device.common.close        = hwc_device_close;
         dev->device.prepare             = hwc_prepare;
         dev->device.set                 = hwc_set;
         dev->device.eventControl        = hwc_eventControl;
-        dev->device.blank               = hwc_blank;
+        dev->device.setPowerMode        = hwc_setPowerMode;
         dev->device.query               = hwc_query;
         dev->device.registerProcs       = hwc_registerProcs;
         dev->device.dump                = hwc_dump;
         dev->device.getDisplayConfigs   = hwc_getDisplayConfigs;
         dev->device.getDisplayAttributes = hwc_getDisplayAttributes;
+        dev->device.getActiveConfig     = hwc_getActiveConfig;
+        dev->device.setActiveConfig     = hwc_setActiveConfig;
         *device = &dev->device.common;
         status = 0;
     }
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index d5139f4..7839139 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -182,11 +182,11 @@
         // 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
+        // Dont do wormhole calculation when scaling mode is set on External
         if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
             sourceCrop = layer->displayFrame;
         } else if((mDpy && !extOrient
-                  && !ctx->dpyAttr[mDpy].mDownScaleMode)) {
+                  && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
             if(ctx->mOverlay->isUIScalingOnExternalSupported() &&
                 !ctx->dpyAttr[mDpy].customFBSize) {
                 getNonWormholeRegion(list, sourceCrop);
@@ -307,11 +307,11 @@
         // 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
+        // Dont do wormhole calculation when scaling mode is set on External
         if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
             sourceCrop = layer->displayFrame;
         } else if((mDpy && !extOrient
-                  && !ctx->dpyAttr[mDpy].mDownScaleMode)) {
+                  && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
             if(!qdutils::MDPVersion::getInstance().is8x26() &&
                 !ctx->dpyAttr[mDpy].customFBSize) {
                 getNonWormholeRegion(list, sourceCrop);
@@ -473,11 +473,11 @@
     // 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
+    // Dont do wormhole calculation when scaling mode is set on External
     if(ctx->listStats[mDpy].isDisplayAnimating && mDpy) {
         sourceCrop = layer->displayFrame;
     } else if((mDpy && !extOrient
-              && !ctx->dpyAttr[mDpy].mDownScaleMode)) {
+              && !ctx->dpyAttr[mDpy].mMDPScalingMode)) {
         if(!qdutils::MDPVersion::getInstance().is8x26() &&
             !ctx->dpyAttr[mDpy].customFBSize) {
             getNonWormholeRegion(list, sourceCrop);
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 552beae..08cfbde 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -723,9 +723,9 @@
         return false;
     }
 
-    // check for action safe flag and downscale mode which requires scaling.
+    // check for action safe flag and MDP scaling mode which requires scaling.
     if(ctx->dpyAttr[mDpy].mActionSafePresent
-            || ctx->dpyAttr[mDpy].mDownScaleMode) {
+            || ctx->dpyAttr[mDpy].mMDPScalingMode) {
         ALOGD_IF(isDebug(), "%s: Scaling needed for this frame",__FUNCTION__);
         return false;
     }
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 7061991..c535c5e 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -129,6 +129,8 @@
             clear(ctx, dpy);
             ctx->dpyAttr[dpy].connected = false;
             ctx->dpyAttr[dpy].isActive = false;
+            /* If disconnect comes before any composition cycle */
+            ctx->dpyAttr[dpy].isConfiguring = false;
 
             ctx->mExtDisplay->teardown();
 
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index d0b3567..a11baa9 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -228,9 +228,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->dpyAttr[HWC_DISPLAY_PRIMARY].mMDPScalingMode= false;
+    ctx->dpyAttr[HWC_DISPLAY_EXTERNAL].mMDPScalingMode = false;
+    ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].mMDPScalingMode = false;
 
     ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
          MDPComp::getObject(ctx, HWC_DISPLAY_PRIMARY);
@@ -447,8 +447,8 @@
 
     int fbWidth = ctx->dpyAttr[dpy].xres;
     int fbHeight = ctx->dpyAttr[dpy].yres;
-    if(ctx->dpyAttr[dpy].mDownScaleMode) {
-        // if downscale Mode is enabled for external, need to query
+    if(ctx->dpyAttr[dpy].mMDPScalingMode) {
+        // if MDP scaling mode is enabled for external, need to query
         // the actual width and height, as that is the physical w & h
          ctx->mExtDisplay->getAttributes(fbWidth, fbHeight);
     }
@@ -579,9 +579,17 @@
                  outPos.x, outPos.y,
                  outPos.w, outPos.h);
     }
-    if(ctx->dpyAttr[dpy].mDownScaleMode) {
-        int extW, extH;
-        ctx->mExtDisplay->getAttributes(extW, extH);
+    if(ctx->dpyAttr[dpy].mMDPScalingMode) {
+        int extW = 0, extH = 0;
+        if(dpy == HWC_DISPLAY_EXTERNAL) {
+            ctx->mExtDisplay->getAttributes(extW, extH);
+        } else if(dpy == HWC_DISPLAY_VIRTUAL) {
+            extW = ctx->mHWCVirtual->getScalingWidth();
+            extH = ctx->mHWCVirtual->getScalingHeight();
+        }
+        ALOGD_IF(HWC_UTILS_DEBUG, "%s: Scaling mode extW=%d extH=%d",
+                __FUNCTION__, extW, extH);
+
         fbWidth  = (float)ctx->dpyAttr[dpy].xres;
         fbHeight = (float)ctx->dpyAttr[dpy].yres;
         //Calculate the position...
@@ -652,14 +660,22 @@
                     displayFrame.bottom = dstHeight;
                 }
             }
-            if(ctx->dpyAttr[dpy].mDownScaleMode) {
-                int extW, extH;
-                // if downscale is enabled, map the co-ordinates to new
+            if(ctx->dpyAttr[dpy].mMDPScalingMode) {
+                int extW = 0, extH = 0;
+                // if MDP scaling mode is enabled, map the co-ordinates to new
                 // domain(downscaled)
                 float fbWidth  = (float)ctx->dpyAttr[dpy].xres;
                 float fbHeight = (float)ctx->dpyAttr[dpy].yres;
                 // query MDP configured attributes
-                ctx->mExtDisplay->getAttributes(extW, extH);
+                if(dpy == HWC_DISPLAY_EXTERNAL) {
+                    ctx->mExtDisplay->getAttributes(extW, extH);
+                } else if(dpy == HWC_DISPLAY_VIRTUAL) {
+                    extW = ctx->mHWCVirtual->getScalingWidth();
+                    extH = ctx->mHWCVirtual->getScalingHeight();
+                }
+                ALOGD_IF(HWC_UTILS_DEBUG, "%s: Scaling mode extW=%d extH=%d",
+                        __FUNCTION__, extW, extH);
+
                 //Calculate the ratio...
                 float wRatio = ((float)extW)/fbWidth;
                 float hRatio = ((float)extH)/fbHeight;
@@ -675,7 +691,7 @@
                          displayFrame.right, displayFrame.bottom);
             }
         }else {
-            if(extOrient || ctx->dpyAttr[dpy].mDownScaleMode) {
+            if(extOrient || ctx->dpyAttr[dpy].mMDPScalingMode) {
                 getAspectRatioPosition(ctx, dpy, extOrient,
                                        displayFrame, displayFrame);
             }
@@ -1867,7 +1883,7 @@
             whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
     }
 
-    /* Calculate the external display position based on MDP downscale,
+    /* Calculate the external display position based on MDP scaling mode,
        ActionSafe, and extorientation features. */
     calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
     int downscale = getRotDownscale(ctx, layer);
@@ -2161,13 +2177,19 @@
     if (ohnd != NULL && ohnd->base) {
         char dumpFilename[PATH_MAX];
         bool bResult = false;
+        int width = getWidth(ohnd);
+        int height = getHeight(ohnd);
+        int format = ohnd->format;
+        //dummy aligned w & h.
+        int alW = 0, alH = 0;
+        int size = getBufferSizeAndDimensions(width, height, format, alW, alH);
         snprintf(dumpFilename, sizeof(dumpFilename), "/data/%s.%s.%dx%d.raw",
             bufferName,
-            overlay::utils::getFormatString(utils::getMdpFormat(ohnd->format)),
-            getWidth(ohnd), getHeight(ohnd));
+            overlay::utils::getFormatString(utils::getMdpFormat(format)),
+            width, height);
         FILE* fp = fopen(dumpFilename, "w+");
         if (NULL != fp) {
-            bResult = (bool) fwrite((void*)ohnd->base, ohnd->size, 1, fp);
+            bResult = (bool) fwrite((void*)ohnd->base, size, 1, fp);
             fclose(fp);
         }
         ALOGD("Buffer[%s] Dump to %s: %s",
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 9d1e7c0..f7885b8 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -99,8 +99,8 @@
     // To trigger padding round to clean up mdp
     // pipes
     bool isConfiguring;
-    // External Display is in MDP Downscale mode indicator
-    bool mDownScaleMode;
+    // Indicates whether external/virtual display is in MDP scaling mode
+    bool mMDPScalingMode;
     // Ext dst Rect
     hwc_rect_t mDstRect;
     //Action safe attributes
@@ -451,21 +451,17 @@
 }
 
 static inline int getWidth(const private_handle_t* hnd) {
-    if(isYuvBuffer(hnd)) {
-        MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
-        if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
-            return metadata->bufferDim.sliceWidth;
-        }
+    MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
+    if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
+        return metadata->bufferDim.sliceWidth;
     }
     return hnd->width;
 }
 
 static inline int getHeight(const private_handle_t* hnd) {
-    if(isYuvBuffer(hnd)) {
-        MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
-        if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
-            return metadata->bufferDim.sliceHeight;
-        }
+    MetaData_t *metadata = reinterpret_cast<MetaData_t*>(hnd->base_metadata);
+    if(metadata && metadata->operation & UPDATE_BUFFER_GEOMETRY) {
+        return metadata->bufferDim.sliceHeight;
     }
     return hnd->height;
 }
diff --git a/libhwcomposer/hwc_virtual.cpp b/libhwcomposer/hwc_virtual.cpp
index b1dde9d..146d671 100644
--- a/libhwcomposer/hwc_virtual.cpp
+++ b/libhwcomposer/hwc_virtual.cpp
@@ -40,6 +40,7 @@
 
 void HWCVirtualVDS::init(hwc_context_t *ctx) {
     const int dpy = HWC_DISPLAY_VIRTUAL;
+    mScalingWidth = 0, mScalingHeight = 0;
     ctx->mFBUpdate[dpy] =
             IFBUpdate::getObject(ctx, dpy);
     ctx->mMDPComp[dpy] =  MDPComp::getObject(ctx, dpy);
@@ -106,8 +107,14 @@
             ctx->dpyAttr[dpy].isConfiguring = false;
             ctx->dpyAttr[dpy].fd = Writeback::getInstance()->getFbFd();
             private_handle_t *ohnd = (private_handle_t *)list->outbuf;
-            Writeback::getInstance()->configureDpyInfo(ohnd->width,
-                                                          ohnd->height);
+
+            setMDPScalingMode(ctx, ohnd, dpy);
+
+            mScalingWidth = getWidth(ohnd);
+            mScalingHeight = getHeight(ohnd);
+
+            Writeback::getInstance()->configureDpyInfo(mScalingWidth,
+                                                        mScalingHeight);
             setListStats(ctx, list, dpy);
 
             if(ctx->mMDPComp[dpy]->prepare(ctx, list) < 0) {
@@ -258,3 +265,20 @@
     }
     return;
 }
+
+/* We set scaling mode on the VD if the output handle width and height
+   differs from the virtual frame buffer width and height. */
+void HWCVirtualVDS::setMDPScalingMode(hwc_context_t* ctx,
+        private_handle_t* ohnd, int dpy) {
+    bool scalingMode = false;
+    int fbWidth = ctx->dpyAttr[dpy].xres;
+    int fbHeight =  ctx->dpyAttr[dpy].yres;
+    if((getWidth(ohnd) != fbWidth) || (getHeight(ohnd) != fbHeight)) {
+        scalingMode = true;
+    }
+    ctx->dpyAttr[dpy].mMDPScalingMode = scalingMode;
+
+    ALOGD_IF(HWCVIRTUAL_LOG, "%s fb(%dx%d) outputBuffer(%dx%d) scalingMode=%d",
+            __FUNCTION__, fbWidth, fbHeight,
+            getWidth(ohnd), getHeight(ohnd), scalingMode);
+}
diff --git a/libhwcomposer/hwc_virtual.h b/libhwcomposer/hwc_virtual.h
index 5ca99f7..525ae2a 100644
--- a/libhwcomposer/hwc_virtual.h
+++ b/libhwcomposer/hwc_virtual.h
@@ -45,12 +45,21 @@
                        hwc_display_contents_1_t** displays);
     void pause(hwc_context_t* ctx, int dpy);
     void resume(hwc_context_t* ctx, int dpy);
+    int getScalingHeight() const { return mScalingHeight; };
+    int getScalingWidth() const { return mScalingWidth; };
     // We can dump the frame buffer and WB
     // output buffer by dynamically enabling
     // dumping via a binder call:
     // adb shell service call display.qservice 15 i32 3 i32 1
     static bool sVDDumpEnabled;
     static void dynamicDebug(bool enable) {sVDDumpEnabled = enable;};
+
+private:
+    // These variables store the resolution that WB is being configured to
+    // in the current draw cycle.
+    int mScalingWidth, mScalingHeight;
+    void setMDPScalingMode(hwc_context_t* ctx,
+            private_handle_t* ohnd, int dpy);
 };
 
 }; //namespace
diff --git a/libmemtrack/kgsl.c b/libmemtrack/kgsl.c
index b644d73..208b22f 100644
--- a/libmemtrack/kgsl.c
+++ b/libmemtrack/kgsl.c
@@ -49,6 +49,7 @@
     FILE *fp;
     char line[1024];
     char tmp[128];
+    bool is_surfaceflinger = false;
     size_t accounted_size = 0;
     size_t unaccounted_size = 0;
     unsigned long smaps_addr = 0;
@@ -60,6 +61,16 @@
         return 0;
     }
 
+    snprintf(tmp, sizeof(tmp), "/proc/%d/cmdline", pid);
+    fp = fopen(tmp, "r");
+    if (fp != NULL) {
+        if (fgets(line, sizeof(line), fp)) {
+            if (strcmp(line, "/system/bin/surfaceflinger") == 0)
+                is_surfaceflinger = true;
+        }
+        fclose(fp);
+    }
+
     memcpy(records, record_templates,
            sizeof(struct memtrack_record) * allocated_records);
 
@@ -77,6 +88,7 @@
         unsigned long size;
         char line_type[7];
         char flags[7];
+        char line_usage[19];
         int ret;
 
         if (fgets(line, sizeof(line), fp) == NULL) {
@@ -87,9 +99,9 @@
          *  gpuaddr useraddr     size    id flags       type            usage sglen
          * 545ba000 545ba000     4096     1 ----pY     gpumem      arraybuffer     1
          */
-        ret = sscanf(line, "%*x %*x %lu %*d %6s %6s %*s %*d\n",
-                     &size, flags, line_type);
-        if (ret != 3) {
+        ret = sscanf(line, "%*x %*lx %lu %*d %6s %6s %18s %*d\n",
+                     &size, flags, line_type, line_usage);
+        if (ret != 4) {
             continue;
         }
 
@@ -101,7 +113,9 @@
                 unaccounted_size += size;
 
         } else if (type == MEMTRACK_TYPE_GRAPHICS && strcmp(line_type, "ion") == 0) {
-            unaccounted_size += size;
+            if (!is_surfaceflinger || strcmp(line_usage, "egl_image") != 0) {
+                unaccounted_size += size;
+            }
         }
     }
 
diff --git a/liboverlay/overlayWriteback.cpp b/liboverlay/overlayWriteback.cpp
index de18e55..ed42a9f 100644
--- a/liboverlay/overlayWriteback.cpp
+++ b/liboverlay/overlayWriteback.cpp
@@ -263,9 +263,12 @@
 bool Writeback::getDump(char *buf, size_t len) {
     if(sWb) {
         utils::getDump(buf, len, "WBData", sWb->mFbData);
-        char str[4] = {'\0'};
-        snprintf(str, 4, "\n");
-        strlcat(buf, str, len);
+        char outputBufferInfo[256];
+        snprintf(outputBufferInfo, sizeof(outputBufferInfo),
+                "OutputBuffer xres=%d yres=%d format=%s\n\n",
+                sWb->getWidth(), sWb->getHeight(),
+                utils::getFormatString(sWb->getOutputFormat()));
+        strlcat(buf, outputBufferInfo, len);
         return true;
     }
     return false;
diff --git a/liboverlay/overlayWriteback.h b/liboverlay/overlayWriteback.h
index ebd319f..21186e6 100644
--- a/liboverlay/overlayWriteback.h
+++ b/liboverlay/overlayWriteback.h
@@ -81,6 +81,8 @@
     bool queueBuffer(int opFd, uint32_t opOffset);
     uint32_t getOffset() const { return mWbMem.getOffset(); }
     int getDstFd() const { return mWbMem.getDstFd(); }
+    int getWidth() const { return mXres; }
+    int getHeight() const { return mYres; }
     /* Subject to GC if writeback isnt used for a drawing round.
      * Get always if caching the value.
      */