Merge "HWC: Use proper typecast to avoid scaling issues"
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 370a7b2..b08c0c1 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -35,6 +35,7 @@
 #include "overlayUtils.h"
 #include "overlay.h"
 #include "mdp_version.h"
+#include "qd_utils.h"
 
 using namespace android;
 
@@ -585,7 +586,8 @@
         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()) {
+        if(!qdutils::MDPVersion::getInstance().is8x26()
+                && 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
@@ -594,14 +596,27 @@
             // Restrict this upto 1080p resolution max
             if(((priW * priH) > (width * height)) &&
                ((priW * priH) <= SUPPORTED_DOWNSCALE_EXT_AREA)) {
-                mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres = priW;
-                mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres = priH;
+                // tmpW and tmpH will hold the primary dimensions before we
+                // update the aspect ratio if necessary.
+                int tmpW = priW;
+                int tmpH = 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;
+                    tmpW = priH;
+                    tmpH = priW;
                 }
+                // The aspect ratios of the external and primary displays
+                // can be different. As a result, directly assigning primary
+                // resolution could lead to an incorrect final image.
+                // We get around this by calculating a new resolution by
+                // keeping aspect ratio intact.
+                hwc_rect r = {0, 0, 0, 0};
+                getAspectRatioPosition(tmpW, tmpH, width, height, r);
+                mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].xres =
+                                                              r.right - r.left;
+                mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].yres =
+                                                              r.bottom - r.top;
                 // Set External Display MDP Downscale mode indicator
                 mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].mDownScaleMode =true;
             }
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 88b9b00..878f17c 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -47,7 +47,6 @@
 #endif
 
 #define ASTC_BLOCK_SIZE 16
-#define ASTC_IN_UNITS(n, unit_size)  (((n) + (unit_size) -1) / (unit_size))
 
 using namespace gralloc;
 using namespace qdutils;
@@ -93,6 +92,7 @@
     LINK_adreno_compute_aligned_width_and_height = NULL;
     LINK_adreno_compute_padding = NULL;
     LINK_adreno_isMacroTilingSupportedByGpu = NULL;
+    LINK_adreno_compute_compressedfmt_aligned_width_and_height = NULL;
 
     libadreno_utils = ::dlopen("libadreno_utils.so", RTLD_NOW);
     if (libadreno_utils) {
@@ -102,6 +102,9 @@
                 ::dlsym(libadreno_utils, "compute_surface_padding");
         *(void **)&LINK_adreno_isMacroTilingSupportedByGpu =
                 ::dlsym(libadreno_utils, "isMacroTilingSupportedByGpu");
+        *(void **)&LINK_adreno_compute_compressedfmt_aligned_width_and_height =
+                ::dlsym(libadreno_utils,
+                        "compute_compressedfmt_aligned_width_and_height");
     }
 }
 
@@ -207,73 +210,47 @@
                 break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_4x4_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 4);
-                aligned_h = ASTC_IN_UNITS(height, 4);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x4_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 5);
-                aligned_h = ASTC_IN_UNITS(height, 4);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_5x5_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 5);
-                aligned_h = ASTC_IN_UNITS(height, 5);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x5_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 6);
-                aligned_h = ASTC_IN_UNITS(height, 5);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_6x6_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 6);
-                aligned_h = ASTC_IN_UNITS(height, 6);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x5_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 8);
-                aligned_h = ASTC_IN_UNITS(height, 5);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x6_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 8);
-                aligned_h = ASTC_IN_UNITS(height, 6);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_8x8_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 8);
-                aligned_h = ASTC_IN_UNITS(height, 8);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x5_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 10);
-                aligned_h = ASTC_IN_UNITS(height, 5);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x6_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 10);
-                aligned_h = ASTC_IN_UNITS(height, 6);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x8_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 10);
-                aligned_h = ASTC_IN_UNITS(height, 8);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_10x10_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 10);
-                aligned_h = ASTC_IN_UNITS(height, 10);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x10_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 12);
-                aligned_h = ASTC_IN_UNITS(height, 10);
-                break;
             case HAL_PIXEL_FORMAT_COMPRESSED_RGBA_ASTC_12x12_KHR:
             case HAL_PIXEL_FORMAT_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
-                aligned_w = ASTC_IN_UNITS(width, 12);
-                aligned_h = ASTC_IN_UNITS(height, 12);
+                if(LINK_adreno_compute_compressedfmt_aligned_width_and_height) {
+                    int bytesPerPixel = 0;
+                    int raster_mode         = 0;   //Adreno unknown raster mode.
+                    int padding_threshold   = 512; //Threshold for padding
+                    //surfaces.
+
+                    LINK_adreno_compute_compressedfmt_aligned_width_and_height(
+                        width, height, format, 0,raster_mode, padding_threshold,
+                        &aligned_w, &aligned_h, &bytesPerPixel);
+
+                } else {
+                    ALOGW("%s: Warning!! Symbols" \
+                          " compute_compressedfmt_aligned_width_and_height" \
+                          " not found", __FUNCTION__);
+                }
                 break;
             default: break;
         }
diff --git a/libgralloc/gr.h b/libgralloc/gr.h
index 8c68e16..20b2994 100644
--- a/libgralloc/gr.h
+++ b/libgralloc/gr.h
@@ -120,12 +120,12 @@
         // Pointer to the padding library.
         void *libadreno_utils;
 
-        // link to the surface padding library.
+        // link(s)to adreno surface padding library.
         int (*LINK_adreno_compute_padding) (int width, int bpp,
                                                 int surface_tile_height,
                                                 int screen_tile_height,
                                                 int padding_threshold);
-        // link to the surface padding library.
+
         void (*LINK_adreno_compute_aligned_width_and_height) (int width,
                                                 int height,
                                                 int bpp,
@@ -134,8 +134,18 @@
                                                 int padding_threshold,
                                                 int *aligned_w,
                                                 int *aligned_h);
-        // link to the surface padding library.
+
         int (*LINK_adreno_isMacroTilingSupportedByGpu) (void);
 
+        void(*LINK_adreno_compute_compressedfmt_aligned_width_and_height)(
+                                                int width,
+                                                int height,
+                                                int format,
+                                                int tile_mode,
+                                                int raster_mode,
+                                                int padding_threshold,
+                                                int *aligned_w,
+                                                int *aligned_h,
+                                                int *bpp);
 };
 #endif /* GR_H_ */
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 27abf6a..678eecb 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -281,121 +281,105 @@
     bool ret = false;
     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
     if (LIKELY(ctx->mOverlay)) {
+        /*  External only layer present */
         int extOnlyLayerIndex = ctx->listStats[mDpy].extOnlyLayerIndex;
-        // ext only layer present..
         if(extOnlyLayerIndex != -1) {
             layer = &list->hwLayers[extOnlyLayerIndex];
             layer->compositionType = HWC_OVERLAY;
         }
+        ovutils::Whf info(mAlignedFBWidth, mAlignedFBHeight,
+                          ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888,
+                                                mTileEnabled));
+
         overlay::Overlay& ov = *(ctx->mOverlay);
-
-        ovutils::Whf info(mAlignedFBWidth,
-                mAlignedFBHeight,
-                ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888,
-                    mTileEnabled));
-        //Request left pipe
-        ovutils::eDest destL = ov.nextPipe(ovutils::OV_MDP_PIPE_ANY, mDpy,
-                Overlay::MIXER_LEFT);
-        if(destL == ovutils::OV_INVALID) { //None available
-            ALOGE("%s: No pipes available to configure fb for dpy %d's left"
-                    " mixer", __FUNCTION__, mDpy);
-            return false;
-        }
-        //Request right pipe
-        ovutils::eDest destR = ov.nextPipe(ovutils::OV_MDP_PIPE_ANY, mDpy,
-                Overlay::MIXER_RIGHT);
-        if(destR == ovutils::OV_INVALID) { //None available
-            ALOGE("%s: No pipes available to configure fb for dpy %d's right"
-                    " mixer", __FUNCTION__, mDpy);
-            return false;
-        }
-
-        mDestLeft = destL;
-        mDestRight = destR;
-
-        ovutils::eMdpFlags mdpFlagsL = ovutils::OV_MDP_BLEND_FG_PREMULT;
-
+        ovutils::eMdpFlags mdpFlags = ovutils::OV_MDP_BLEND_FG_PREMULT;
         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::DEFAULT_PLANE_ALPHA,
-                                (ovutils::eBlending)
-                                getBlending(layer->blending));
-        ov.setSource(pargL, destL);
-
-        ovutils::eMdpFlags mdpFlagsR = mdpFlagsL;
-        ovutils::setMdpFlags(mdpFlagsR, ovutils::OV_MDSS_MDP_RIGHT_MIXER);
-        ovutils::PipeArgs pargR(mdpFlagsR,
-                                info,
-                                zOrder,
-                                ovutils::IS_FG_OFF,
-                                ovutils::ROT_FLAGS_NONE,
-                                ovutils::DEFAULT_PLANE_ALPHA,
-                                (ovutils::eBlending)
-                                getBlending(layer->blending));
-        ov.setSource(pargR, destR);
+        ovutils::eTransform orient =
+            static_cast<ovutils::eTransform>(layer->transform);
+        const int hw_w = ctx->dpyAttr[mDpy].xres;
+        const int hw_h = ctx->dpyAttr[mDpy].yres;
+        const int lSplit = getLeftSplit(ctx, mDpy);
+        mDestLeft = ovutils::OV_INVALID;
+        mDestRight = ovutils::OV_INVALID;
 
         hwc_rect_t sourceCrop = fbUpdatingRect;
         hwc_rect_t displayFrame = fbUpdatingRect;
 
-        const float xres = ctx->dpyAttr[mDpy].xres;
-        const int lSplit = getLeftSplit(ctx, mDpy);
-        const float lSplitRatio = lSplit / xres;
-        const float lCropWidth =
-                (sourceCrop.right - sourceCrop.left) * lSplitRatio;
-
-        ovutils::Dim dcropL(
-                sourceCrop.left,
-                sourceCrop.top,
-                lCropWidth,
-                sourceCrop.bottom - sourceCrop.top);
-
-        ovutils::Dim dcropR(
-                sourceCrop.left + lCropWidth,
-                sourceCrop.top,
-                (sourceCrop.right - sourceCrop.left) - lCropWidth,
-                sourceCrop.bottom - sourceCrop.top);
-
-        ov.setCrop(dcropL, destL);
-        ov.setCrop(dcropR, destR);
-
-        int transform = layer->transform;
-        ovutils::eTransform orient =
-            static_cast<ovutils::eTransform>(transform);
-        ov.setTransform(orient, destL);
-        ov.setTransform(orient, destR);
-
-        const int lWidth = (lSplit - displayFrame.left);
-        const int rWidth = (displayFrame.right - lSplit);
-        const int height = displayFrame.bottom - displayFrame.top;
-
-        ovutils::Dim dposL(displayFrame.left,
-                           displayFrame.top,
-                           lWidth,
-                           height);
-        ov.setPosition(dposL, destL);
-
-        ovutils::Dim dposR(0,
-                           displayFrame.top,
-                           rWidth,
-                           height);
-        ov.setPosition(dposR, destR);
-
         ret = true;
-        if (!ov.commit(destL)) {
-            ALOGE("%s: commit fails for left", __FUNCTION__);
-            ret = false;
+        /* Configure left pipe */
+        if(displayFrame.left < lSplit) {
+            ovutils::eDest destL = ov.nextPipe(ovutils::OV_MDP_PIPE_ANY, mDpy,
+                                               Overlay::MIXER_LEFT);
+            if(destL == ovutils::OV_INVALID) { //None available
+                ALOGE("%s: No pipes available to configure fb for dpy %d's left"
+                      " mixer", __FUNCTION__, mDpy);
+                return false;
+            }
+
+            mDestLeft = destL;
+
+            //XXX: FB layer plane alpha is currently sent as zero from
+            //surfaceflinger
+            ovutils::PipeArgs pargL(mdpFlags,
+                                    info,
+                                    zOrder,
+                                    ovutils::IS_FG_OFF,
+                                    ovutils::ROT_FLAGS_NONE,
+                                    ovutils::DEFAULT_PLANE_ALPHA,
+                                    (ovutils::eBlending)
+                                    getBlending(layer->blending));
+            hwc_rect_t cropL = sourceCrop;
+            hwc_rect_t dstL = displayFrame;
+            hwc_rect_t scissorL = {0, 0, lSplit, hw_h };
+            qhwc::calculate_crop_rects(cropL, dstL, scissorL, 0);
+
+            if (configMdp(ctx->mOverlay, pargL, orient, cropL,
+                           dstL, NULL, destL)< 0) {
+                ALOGE("%s: configMdp fails for left FB", __FUNCTION__);
+                ret = false;
+            }
         }
-        if (!ov.commit(destR)) {
-            ALOGE("%s: commit fails for right", __FUNCTION__);
-            ret = false;
+
+        /* Configure right pipe */
+        if(displayFrame.right > lSplit) {
+            ovutils::eDest destR = ov.nextPipe(ovutils::OV_MDP_PIPE_ANY, mDpy,
+                                               Overlay::MIXER_RIGHT);
+            if(destR == ovutils::OV_INVALID) { //None available
+                ALOGE("%s: No pipes available to configure fb for dpy %d's"
+                      " right mixer", __FUNCTION__, mDpy);
+                return false;
+            }
+
+            mDestRight = destR;
+            ovutils::eMdpFlags mdpFlagsR = mdpFlags;
+            ovutils::setMdpFlags(mdpFlagsR, ovutils::OV_MDSS_MDP_RIGHT_MIXER);
+
+            //XXX: FB layer plane alpha is currently sent as zero from
+            //surfaceflinger
+            ovutils::PipeArgs pargR(mdpFlagsR,
+                                    info,
+                                    zOrder,
+                                    ovutils::IS_FG_OFF,
+                                    ovutils::ROT_FLAGS_NONE,
+                                    ovutils::DEFAULT_PLANE_ALPHA,
+                                    (ovutils::eBlending)
+                                    getBlending(layer->blending));
+
+            hwc_rect_t cropR = sourceCrop;
+            hwc_rect_t dstR = displayFrame;
+            hwc_rect_t scissorR = {lSplit, 0, hw_w, hw_h };
+            qhwc::calculate_crop_rects(cropR, dstR, scissorR, 0);
+
+            dstR.left -= lSplit;
+            dstR.right -= lSplit;
+
+            if (configMdp(ctx->mOverlay, pargR, orient, cropR,
+                           dstR, NULL, destR) < 0) {
+                ALOGE("%s: configMdp fails for right FB", __FUNCTION__);
+                ret = false;
+            }
         }
+
         if(ret == false) {
             ctx->mLayerRotMap[mDpy]->clear();
         }
@@ -410,17 +394,19 @@
     }
     bool ret = true;
     overlay::Overlay& ov = *(ctx->mOverlay);
-    ovutils::eDest destL = mDestLeft;
-    ovutils::eDest destR = mDestRight;
-    if (!ov.queueBuffer(hnd->fd, hnd->offset, destL)) {
-        ALOGE("%s: queue failed for left of dpy = %d",
-              __FUNCTION__, mDpy);
-        ret = false;
+    if(mDestLeft != ovutils::OV_INVALID) {
+        if (!ov.queueBuffer(hnd->fd, hnd->offset, mDestLeft)) {
+            ALOGE("%s: queue failed for left of dpy = %d",
+                  __FUNCTION__, mDpy);
+            ret = false;
+        }
     }
-    if (!ov.queueBuffer(hnd->fd, hnd->offset, destR)) {
-        ALOGE("%s: queue failed for right of dpy = %d",
-              __FUNCTION__, mDpy);
-        ret = false;
+    if(mDestRight != ovutils::OV_INVALID) {
+        if (!ov.queueBuffer(hnd->fd, hnd->offset, mDestRight)) {
+            ALOGE("%s: queue failed for right of dpy = %d",
+                  __FUNCTION__, mDpy);
+            ret = false;
+        }
     }
     return ret;
 }
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 146730a..5c36304 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -44,6 +44,7 @@
 #include "QService.h"
 #include "comptype.h"
 #include "hwc_virtual.h"
+#include "qd_utils.h"
 
 using namespace qClient;
 using namespace qService;
@@ -238,6 +239,14 @@
     ctx->mBufferMirrorMode = false;
     ctx->mVPUClient = NULL;
 
+    // Read the system property to determine if downscale feature is enabled.
+    ctx->mMDPDownscaleEnabled = false;
+    char value[PROPERTY_VALUE_MAX];
+    if(property_get("sys.hwc.mdp_downscale_enabled", value, "false")
+            && !strcmp(value, "true")) {
+        ctx->mMDPDownscaleEnabled = true;
+    }
+
 #ifdef VPU_TARGET
     if(qdutils::MDPVersion::getInstance().is8092())
         ctx->mVPUClient = new VPUClient(ctx);
@@ -392,34 +401,6 @@
     return;
 }
 
-/* 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;
-
-   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,
@@ -985,8 +966,14 @@
 bool isActionSafePresent(hwc_context_t *ctx, int dpy) {
     // if external supports underscan, do nothing
     // it will be taken care in the driver
-    if(!dpy || ctx->mExtDisplay->isCEUnderscanSupported())
+    // Disable Action safe for 8974 due to HW limitation for downscaling
+    // layers with overlapped region
+    // Disable Actionsafe for non HDMI displays.
+    if(!(dpy == HWC_DISPLAY_EXTERNAL) ||
+        qdutils::MDPVersion::getInstance().is8x74v2() ||
+        ctx->mExtDisplay->isCEUnderscanSupported()) {
         return false;
+    }
 
     char value[PROPERTY_VALUE_MAX];
     // Read action safe properties
@@ -1724,6 +1711,10 @@
             whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
     }
 
+    /* Calculate the external display position based on MDP downscale,
+       ActionSafe, and extorientation features. */
+    calcExtDisplayPosition(ctx, hnd, dpy, crop, dst, transform, orient);
+
     setMdpFlags(layer, mdpFlagsL, 0, transform);
 
     if(lDest != OV_INVALID && rDest != OV_INVALID) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 8a45029..4aa6410 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -262,9 +262,6 @@
 /* Calculates the destination position based on the action safe rectangle */
 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 extOrientation,
                                 hwc_rect_t& inRect, hwc_rect_t& outRect);
 
@@ -506,6 +503,9 @@
     bool mPanelResetStatus;
     // number of active Displays
     int numActiveDisplays;
+    // Downscale feature switch, set via system the property
+    // sys.hwc.mdp_downscale_enabled
+    bool mMDPDownscaleEnabled;
 };
 
 namespace qhwc {
diff --git a/libqdutils/qd_utils.cpp b/libqdutils/qd_utils.cpp
index c27167f..f67de52 100644
--- a/libqdutils/qd_utils.cpp
+++ b/libqdutils/qd_utils.cpp
@@ -31,6 +31,7 @@
 
 
 #define MAX_FRAME_BUFFER_NAME_SIZE      (80)
+#define QD_UTILS_DEBUG 0
 
 int getHDMINode(void)
 {
@@ -92,3 +93,31 @@
     return size;
 }
 
+/* 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;
+
+   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(QD_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;
+}
+
diff --git a/libqdutils/qd_utils.h b/libqdutils/qd_utils.h
index db6d367..a35f255 100644
--- a/libqdutils/qd_utils.h
+++ b/libqdutils/qd_utils.h
@@ -48,4 +48,7 @@
 
 int getEdidRawData(char *buffer);
 
+void getAspectRatioPosition(int destWidth, int destHeight, int srcWidth,
+                                int srcHeight, hwc_rect_t& rect);
+
 #endif
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
index 795d8a1..5453e3a 100644
--- a/libvirtual/virtual.cpp
+++ b/libvirtual/virtual.cpp
@@ -48,6 +48,7 @@
 #include "overlayUtils.h"
 #include "overlay.h"
 #include "mdp_version.h"
+#include "qd_utils.h"
 
 using namespace android;
 
@@ -127,14 +128,25 @@
     // by SUPPORTED_VIRTUAL_AREA).
     if((maxArea == (priW * priH))
         && (maxArea <= SUPPORTED_VIRTUAL_AREA)) {
-        extW = priW;
-        extH = priH;
+        // tmpW and tmpH will hold the primary dimensions before we
+        // update the aspect ratio if necessary.
+        uint32_t tmpW = priW;
+        uint32_t tmpH = priH;
         // If WFD is in landscape, assign the higher dimension
         // to WFD's xres.
         if(priH > priW) {
-            extW = priH;
-            extH = priW;
+            tmpW = priH;
+            tmpH = priW;
         }
+        // The aspect ratios of the external and primary displays
+        // can be different. As a result, directly assigning primary
+        // resolution could lead to an incorrect final image.
+        // We get around this by calculating a new resolution by
+        // keeping aspect ratio intact.
+        hwc_rect r = {0, 0, 0, 0};
+        getAspectRatioPosition(tmpW, tmpH, extW, extH, r);
+        extW = r.right - r.left;
+        extH = r.bottom - r.top;
     }
 }
 
@@ -167,7 +179,13 @@
 
         initResolution(extW, extH);
 
-        if(!qdutils::MDPVersion::getInstance().is8x26()) {
+        // Dynamic Resolution Change depends on MDP downscaling.
+        // MDP downscale property will be ignored to exercise DRC use case.
+        // If DRC is in progress, ext WxH will have non-zero values.
+        bool isDRC = (extW > 0) && (extH > 0);
+
+        if(!qdutils::MDPVersion::getInstance().is8x26()
+                && (mHwcContext->mMDPDownscaleEnabled || isDRC)) {
 
             // maxArea represents the maximum resolution between
             // primary and virtual display.