Merge "h/q/d: Add support to update framebuffer partially"
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 1268b0f..0465521 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -113,7 +113,7 @@
  * Used to show QCOM 8974 instead of Input 1 for example
  */
 void ExternalDisplay::setSPDInfo(const char* node, const char* property) {
-    int err = -1;
+    ssize_t err = -1;
     char info[PROPERTY_VALUE_MAX];
     char sysFsSPDFilePath[MAX_SYSFS_FILE_PATH];
     memset(sysFsSPDFilePath, 0, sizeof(sysFsSPDFilePath));
@@ -172,7 +172,7 @@
 void ExternalDisplay::readCEUnderscanInfo()
 {
     int hdmiScanInfoFile = -1;
-    int len = -1;
+    ssize_t len = -1;
     char scanInfo[17];
     char *ce_info_str = NULL;
     char *save_ptr;
@@ -191,7 +191,7 @@
         return;
     } else {
         len = read(hdmiScanInfoFile, scanInfo, sizeof(scanInfo)-1);
-        ALOGD("%s: Scan Info string: %s length = %d",
+        ALOGD("%s: Scan Info string: %s length = %zu",
                  __FUNCTION__, scanInfo, len);
         if (len <= 0) {
             close(hdmiScanInfoFile);
@@ -200,8 +200,8 @@
             return;
         }
         scanInfo[len] = '\0';  /* null terminate the string */
+        close(hdmiScanInfoFile);
     }
-    close(hdmiScanInfoFile);
 
     /*
      * The scan_info contains the three fields
@@ -304,7 +304,7 @@
             "/sys/devices/virtual/graphics/fb%d/edid_modes", mFbNum);
 
     int hdmiEDIDFile = open(sysFsEDIDFilePath, O_RDONLY, 0);
-    int len = -1;
+    ssize_t len = -1;
     char edidStr[128] = {'\0'};
 
     if (hdmiEDIDFile < 0) {
@@ -313,7 +313,7 @@
         return false;
     } else {
         len = read(hdmiEDIDFile, edidStr, sizeof(edidStr)-1);
-        ALOGD_IF(DEBUG, "%s: EDID string: %s length = %d",
+        ALOGD_IF(DEBUG, "%s: EDID string: %s length = %zu",
                  __FUNCTION__, edidStr, len);
         if ( len <= 0) {
             ALOGE("%s: edid_modes file empty '%s'",
@@ -326,8 +326,8 @@
             }
             edidStr[len] = '\0';
         }
+        close(hdmiEDIDFile);
     }
-    close(hdmiEDIDFile);
     if(len > 0) {
         // Get EDID modes from the EDID strings
         mModeCount = parseResolution(edidStr, mEDIDModes);
@@ -558,7 +558,7 @@
                   __FUNCTION__, sysFsHPDFilePath, hdmiHPDFile, strerror(errno));
             ret = false;
         } else {
-            int err = -1;
+            ssize_t err = -1;
             ALOGD_IF(DEBUG, "%s: option = %d", __FUNCTION__, userOption);
             if(userOption)
                 err = write(hdmiHPDFile, "1", 2);
@@ -585,7 +585,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
@@ -607,7 +608,7 @@
             }
         }
         mHwcContext->dpyAttr[HWC_DISPLAY_EXTERNAL].vsync_period =
-                1000000000l / fps;
+                (int) 1000000000l / fps;
     }
 }
 
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/gpu.cpp b/libgralloc/gpu.cpp
index bb7060b..b6253cd 100644
--- a/libgralloc/gpu.cpp
+++ b/libgralloc/gpu.cpp
@@ -95,13 +95,6 @@
 
         if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY) {
             flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY;
-            //The EXTERNAL_BLOCK flag is always an add-on
-            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK) {
-                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK;
-            }
-            if (usage & GRALLOC_USAGE_PRIVATE_EXTERNAL_CC) {
-                flags |= private_handle_t::PRIV_FLAGS_EXTERNAL_CC;
-            }
         }
 
         if (bufferType == BUFFER_TYPE_VIDEO) {
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/libgralloc/gralloc_priv.h b/libgralloc/gralloc_priv.h
index c56eca9..89f1a88 100644
--- a/libgralloc/gralloc_priv.h
+++ b/libgralloc/gralloc_priv.h
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -60,13 +60,8 @@
     /* Buffer content should be displayed on an external display only */
     GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY   =       0x08000000,
 
-    /* Only this buffer content should be displayed on external, even if
-     * other EXTERNAL_ONLY buffers are available. Used during suspend.
-     */
-    GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK  =       0x00100000,
-
-    /* Close Caption displayed on an external display only */
-    GRALLOC_USAGE_PRIVATE_EXTERNAL_CC     =       0x00200000,
+    /* This flag is set for WFD usecase */
+    GRALLOC_USAGE_PRIVATE_WFD             =       0x00200000,
 
     /* CAMERA heap is a carveout heap for camera, is not secured*/
     GRALLOC_USAGE_PRIVATE_CAMERA_HEAP     =       0x00400000,
@@ -85,6 +80,7 @@
     GRALLOC_MODULE_PERFORM_GET_STRIDE,
     GRALLOC_MODULE_PERFORM_GET_CUSTOM_STRIDE_FROM_HANDLE,
     GRALLOC_MODULE_PERFORM_GET_ATTRIBUTES,
+    GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE,
 };
 
 #define GRALLOC_HEAP_MASK   (GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP |\
@@ -194,10 +190,6 @@
             PRIV_FLAGS_NOT_MAPPED         = 0x00001000,
             // Display on external only
             PRIV_FLAGS_EXTERNAL_ONLY      = 0x00002000,
-            // Display only this buffer on external
-            PRIV_FLAGS_EXTERNAL_BLOCK     = 0x00004000,
-            // Display this buffer on external as close caption
-            PRIV_FLAGS_EXTERNAL_CC        = 0x00008000,
             PRIV_FLAGS_VIDEO_ENCODER      = 0x00010000,
             PRIV_FLAGS_CAMERA_WRITE       = 0x00020000,
             PRIV_FLAGS_CAMERA_READ        = 0x00040000,
diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp
index 109c141..df9f7e4 100644
--- a/libgralloc/mapper.cpp
+++ b/libgralloc/mapper.cpp
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -368,6 +368,19 @@
                 res = 0;
             } break;
 
+        case GRALLOC_MODULE_PERFORM_GET_COLOR_SPACE_FROM_HANDLE:
+            {
+                private_handle_t* hnd =  va_arg(args, private_handle_t*);
+                int *color_space = va_arg(args, int *);
+                if (private_handle_t::validate(hnd)) {
+                    return res;
+                }
+                MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+                if(metadata && metadata->operation & UPDATE_COLOR_SPACE) {
+                    *color_space = metadata->colorSpace;
+                    res = 0;
+                }
+            } break;
         default:
             break;
     }
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index f1c54f2..15b9da4 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -437,8 +437,11 @@
     int ret = 0;
     hwc_context_t* ctx = (hwc_context_t*)(dev);
 
-    if (!ctx->mPanelResetStatus)
+    if (!ctx->dpyAttr[HWC_DISPLAY_PRIMARY].isActive) {
+        ALOGD ("%s : Display OFF - Skip BLANK & UNBLANK", __FUNCTION__);
+        ctx->mPanelResetStatus = false;
         return;
+    }
 
     ALOGD("%s: calling BLANK DISPLAY", __FUNCTION__);
     ret = hwc_blank(dev, HWC_DISPLAY_PRIMARY, 1);
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index d47853a..3a4bada 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -26,6 +26,7 @@
 #include "gr.h"
 #include "cb_utils.h"
 #include "cb_swap_rect.h"
+#include "math.h"
 using namespace qdutils;
 namespace qhwc {
 
@@ -488,12 +489,6 @@
               dsdx,dtdy,copybitsMaxScale,1/copybitsMinScale,screen_w,screen_h,
                                               src_crop_width,src_crop_height);
 
-       //Driver makes width and height as even
-       //that may cause wrong calculation of the ratio
-       //in display and crop.Hence we make
-       //crop width and height as even.
-       src_crop_width  = (src_crop_width/2)*2;
-       src_crop_height = (src_crop_height/2)*2;
 
        int tmp_w =  src_crop_width;
        int tmp_h =  src_crop_height;
@@ -502,10 +497,11 @@
          tmp_w = src_crop_width*copybitsMaxScale;
          tmp_h = src_crop_height*copybitsMaxScale;
        }else if (dsdx < 1/copybitsMinScale ||dtdy < 1/copybitsMinScale ){
-         tmp_w = src_crop_width/copybitsMinScale;
-         tmp_h = src_crop_height/copybitsMinScale;
-         tmp_w  = (tmp_w/2)*2;
-         tmp_h = (tmp_h/2)*2;
+         // ceil the tmp_w and tmp_h value to maintain proper ratio
+         // b/w src and dst (should not cross the desired scale limit
+         // due to float -> int )
+         tmp_w = ceil(src_crop_width/copybitsMinScale);
+         tmp_h = ceil(src_crop_height/copybitsMinScale);
        }
        ALOGD("%s:%d::tmp_w = %d,tmp_h = %d",__FUNCTION__,__LINE__,tmp_w,tmp_h);
 
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index b1b7159..678eecb 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -39,6 +39,9 @@
 
 IFBUpdate* IFBUpdate::getObject(hwc_context_t *ctx, const int& dpy) {
     if(isDisplaySplit(ctx, dpy)) {
+        if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
+            return new FBSrcSplit(ctx, dpy);
+        }
         return new FBUpdateSplit(ctx, dpy);
     }
     return new FBUpdateNonSplit(ctx, dpy);
@@ -408,5 +411,102 @@
     return ret;
 }
 
+//=================FBSrcSplit====================================
+FBSrcSplit::FBSrcSplit(hwc_context_t *ctx, const int& dpy):
+        FBUpdateSplit(ctx, dpy) {}
+
+bool FBSrcSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
+        hwc_rect_t fbUpdatingRect, int fbZorder) {
+    bool ret = false;
+    hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
+    int extOnlyLayerIndex = ctx->listStats[mDpy].extOnlyLayerIndex;
+    // ext only layer present..
+    if(extOnlyLayerIndex != -1) {
+        layer = &list->hwLayers[extOnlyLayerIndex];
+        layer->compositionType = HWC_OVERLAY;
+    }
+    overlay::Overlay& ov = *(ctx->mOverlay);
+
+    ovutils::Whf info(mAlignedFBWidth,
+            mAlignedFBHeight,
+            ovutils::getMdpFormat(HAL_PIXEL_FORMAT_RGBA_8888,
+                mTileEnabled));
+    //Request left pipe, VG first owing to higher prio
+    ovutils::eDest destL = ov.nextPipe(ovutils::OV_MDP_PIPE_VG, mDpy,
+            Overlay::MIXER_DEFAULT);
+    if(destL == ovutils::OV_INVALID) {
+        destL = ov.nextPipe(ovutils::OV_MDP_PIPE_ANY, mDpy,
+            Overlay::MIXER_DEFAULT);
+        if(destL == ovutils::OV_INVALID) {
+            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_DEFAULT);
+    if(destR == ovutils::OV_INVALID) {
+        ALOGE("%s: No pipes available to configure fb for dpy %d's right"
+                " mixer", __FUNCTION__, mDpy);
+        return false;
+    }
+
+    mDestLeft = destL;
+    mDestRight = destR;
+
+    ovutils::eMdpFlags mdpFlags = OV_MDP_BLEND_FG_PREMULT;
+    ovutils::eZorder zOrder = static_cast<ovutils::eZorder>(fbZorder);
+
+    ovutils::PipeArgs parg(mdpFlags,
+            info,
+            zOrder,
+            ovutils::IS_FG_OFF,
+            ovutils::ROT_FLAGS_NONE,
+            ovutils::DEFAULT_PLANE_ALPHA,
+            (ovutils::eBlending)
+            getBlending(layer->blending));
+    ov.setSource(parg, destL);
+    ov.setSource(parg, destR);
+
+    //Crop and Position are same for FB
+    ovutils::Dim cropPosL(
+            fbUpdatingRect.left,
+            fbUpdatingRect.top,
+            (fbUpdatingRect.right - fbUpdatingRect.left) / 2,
+            fbUpdatingRect.bottom - fbUpdatingRect.top);
+
+    ovutils::Dim cropPosR(
+            cropPosL.x + cropPosL.w,
+            cropPosL.y,
+            cropPosL.w,
+            cropPosL.h);
+
+    ov.setCrop(cropPosL, destL);
+    ov.setCrop(cropPosR, destR);
+    ov.setPosition(cropPosL, destL);
+    ov.setPosition(cropPosR, destR);
+
+    int transform = layer->transform;
+    ovutils::eTransform orient =
+            static_cast<ovutils::eTransform>(transform);
+    ov.setTransform(orient, destL);
+    ov.setTransform(orient, destR);
+
+    ret = true;
+    if (!ov.commit(destL)) {
+        ALOGE("%s: commit fails for left", __FUNCTION__);
+        ret = false;
+    }
+    if (!ov.commit(destR)) {
+        ALOGE("%s: commit fails for right", __FUNCTION__);
+        ret = false;
+    }
+    if(ret == false) {
+        ctx->mLayerRotMap[mDpy]->clear();
+    }
+    return ret;
+}
+
 //---------------------------------------------------------------------
 }; //namespace qhwc
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index c8347fa..545f5bd 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -88,13 +88,24 @@
             hwc_rect_t fbUpdatingRect, int fbZorder);
     bool draw(hwc_context_t *ctx, private_handle_t *hnd);
     void reset();
-private:
-    bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
+
+protected:
+    virtual bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
             hwc_rect_t fbUpdatingRect, int fbZorder);
     ovutils::eDest mDestLeft; //left pipe to draw on
     ovutils::eDest mDestRight; //right pipe to draw on
 };
 
+//Source Split Handler
+class FBSrcSplit : public FBUpdateSplit {
+public:
+    explicit FBSrcSplit(hwc_context_t *ctx, const int& dpy);
+    virtual ~FBSrcSplit() {};
+private:
+    bool configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
+            hwc_rect_t fbUpdatingRect, int fbZorder);
+};
+
 }; //namespace qhwc
 
 #endif //HWC_FBUPDATE_H
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 469ffba..028af47 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -44,12 +44,13 @@
 bool MDPComp::sEnableMixedMode = true;
 bool MDPComp::sEnablePartialFrameUpdate = false;
 int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
-double MDPComp::sMaxBw = 0.0;
-double MDPComp::sBwClaimed = 0.0;
 bool MDPComp::sEnable4k2kYUVSplit = false;
 
 MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
     if(isDisplaySplit(ctx, dpy)) {
+        if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
+            return new MDPCompSrcSplit(dpy);
+        }
         return new MDPCompSplit(dpy);
     }
     return new MDPCompNonSplit(dpy);
@@ -663,13 +664,11 @@
 
     bool ret = false;
     if(list->flags & HWC_GEOMETRY_CHANGED) { //Try load based first
-        ret =   loadBasedCompPreferGPU(ctx, list) or
-                loadBasedCompPreferMDP(ctx, list) or
+        ret =   loadBasedComp(ctx, list) or
                 cacheBasedComp(ctx, list);
     } else {
         ret =   cacheBasedComp(ctx, list) or
-                loadBasedCompPreferGPU(ctx, list) or
-                loadBasedCompPreferMDP(ctx, list);
+                loadBasedComp(ctx, list);
     }
 
     return ret;
@@ -725,196 +724,89 @@
     return true;
 }
 
-bool MDPComp::loadBasedCompPreferGPU(hwc_context_t *ctx,
-        hwc_display_contents_1_t* list) {
-    if(not isLoadBasedCompDoable(ctx)) {
-        return false;
-    }
-
-    int numAppLayers = ctx->listStats[mDpy].numAppLayers;
-    mCurrentFrame.reset(numAppLayers);
-
-    int stagesForMDP = min(sMaxPipesPerMixer, ctx->mOverlay->availablePipes(
-            mDpy, Overlay::MIXER_DEFAULT));
-    //If MDP has X possible stages, it can take X layers.
-    const int batchSize = (numAppLayers - mCurrentFrame.dropCount) -
-                                               (stagesForMDP - 1); //1 for FB
-
-    if(batchSize <= 0) {
-        ALOGD_IF(isDebug(), "%s: Not attempting", __FUNCTION__);
-        return false;
-    }
-
-    int minBatchStart = -1;
-    int minBatchEnd = -1;
-    size_t minBatchPixelCount = SIZE_MAX;
-
-    /* Iterate through the layer list to find out a contigous batch of batchSize
-     * non-dropped layers with loweest pixel count */
-    for(int i = 0; i <= (numAppLayers - batchSize); i++) {
-        if(mCurrentFrame.drop[i])
-            continue;
-
-        int batchCount = batchSize;
-        uint32_t batchPixelCount = 0;
-        int j = i;
-        for(; j < numAppLayers && batchCount; j++){
-            if(!mCurrentFrame.drop[j]) {
-                hwc_layer_1_t* layer = &list->hwLayers[j];
-                hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
-                hwc_rect_t dst = layer->displayFrame;
-
-                /* If we have a valid ROI, count pixels only for the MDP fetched
-                 * region of the buffer */
-                if((ctx->listStats[mDpy].roi.w != ctx->dpyAttr[mDpy].xres) ||
-                   (ctx->listStats[mDpy].roi.h != ctx->dpyAttr[mDpy].yres)) {
-                    hwc_rect_t roi;
-                    roi.left = ctx->listStats[mDpy].roi.x;
-                    roi.top = ctx->listStats[mDpy].roi.y;
-                    roi.right = roi.left + ctx->listStats[mDpy].roi.w;
-                    roi.bottom = roi.top + ctx->listStats[mDpy].roi.h;
-
-                    /* valid ROI means no scaling layer is composed. So check
-                     * only intersection to find actual fetched pixels */
-                    crop  = getIntersection(roi, dst);
-                }
-
-                batchPixelCount += (crop.right - crop.left) *
-                    (crop.bottom - crop.top);
-                batchCount--;
-            }
-        }
-
-        /* we dont want to program any batch of size lesser than batchSize */
-        if(!batchCount && (batchPixelCount < minBatchPixelCount)) {
-            minBatchPixelCount = batchPixelCount;
-            minBatchStart = i;
-            minBatchEnd = j-1;
-        }
-    }
-
-    if(minBatchStart < 0) {
-        ALOGD_IF(isDebug(), "%s: No batch found batchSize %d numAppLayers %d",
-                __FUNCTION__, batchSize, numAppLayers);
-        return false;
-    }
-
-    /* non-dropped layers falling ouside the selected batch will be marked for
-     * MDP */
-    for(int i = 0; i < numAppLayers; i++) {
-        if((i < minBatchStart || i > minBatchEnd) && !mCurrentFrame.drop[i] ) {
-            hwc_layer_1_t* layer = &list->hwLayers[i];
-            if(not isSupportedForMDPComp(ctx, layer)) {
-                ALOGD_IF(isDebug(), "%s: MDP unsupported layer found at %d",
-                        __FUNCTION__, i);
-                reset(ctx);
-                return false;
-            }
-            mCurrentFrame.isFBComposed[i] = false;
-        }
-    }
-
-    mCurrentFrame.fbZ = minBatchStart;
-    mCurrentFrame.fbCount = batchSize;
-    mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount -
-             mCurrentFrame.dropCount;
-
-    ALOGD_IF(isDebug(), "%s: fbZ %d batchSize %d fbStart: %d fbEnd: %d",
-             __FUNCTION__, mCurrentFrame.fbZ, batchSize, minBatchStart,
-             minBatchEnd);
-
-    if(sEnable4k2kYUVSplit){
-        adjustForSourceSplit(ctx, list);
-    }
-
-    if(!postHeuristicsHandling(ctx, list)) {
-        ALOGD_IF(isDebug(), "post heuristic handling failed");
-        reset(ctx);
-        return false;
-    }
-
-    return true;
-}
-
-bool MDPComp::loadBasedCompPreferMDP(hwc_context_t *ctx,
+bool MDPComp::loadBasedComp(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
     if(not isLoadBasedCompDoable(ctx)) {
         return false;
     }
 
     const int numAppLayers = ctx->listStats[mDpy].numAppLayers;
-    mCurrentFrame.reset(numAppLayers);
+    const int numNonDroppedLayers = numAppLayers - mCurrentFrame.dropCount;
+    const int stagesForMDP = min(sMaxPipesPerMixer,
+            ctx->mOverlay->availablePipes(mDpy, Overlay::MIXER_DEFAULT));
 
-    //Full screen is from ib perspective, not actual full screen
-    const int bpp = 4;
-    double panelRefRate =
-                1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
+    int mdpBatchSize = stagesForMDP - 1; //1 stage for FB
+    int fbBatchSize = numNonDroppedLayers - mdpBatchSize;
+    int lastMDPSupportedIndex = numAppLayers;
+    int dropCount = 0;
 
-    double bwLeft = sMaxBw - sBwClaimed;
-
-    const int fullScreenLayers = bwLeft * 1000000000 / (ctx->dpyAttr[mDpy].xres
-            * ctx->dpyAttr[mDpy].yres * bpp * panelRefRate);
-
-    const int fbBatchSize = (numAppLayers - mCurrentFrame.dropCount)
-            - (fullScreenLayers - 1);
-
-    //If batch size is not at least 2, we aren't really preferring MDP, since
-    //only 1 layer going to GPU could actually translate into an entire FB
-    //needed to be fetched by MDP, thus needing more b/w rather than less.
-    if(fbBatchSize < 2 || fbBatchSize > numAppLayers) {
-        ALOGD_IF(isDebug(), "%s: Not attempting", __FUNCTION__);
-        return false;
-    }
-
-    //Find top fbBatchSize non-dropped layers to get your batch
-    int fbStart = -1, fbEnd = -1, batchCount = fbBatchSize;
-    for(int i = numAppLayers - 1; i >= 0; i--) {
-        if(mCurrentFrame.drop[i])
+    //Find the minimum MDP batch size
+    for(int i = 0; i < numAppLayers;i++) {
+        if(mCurrentFrame.drop[i]) {
+            dropCount++;
             continue;
-
-        if(fbEnd < 0)
-            fbEnd = i;
-
-        if(!(--batchCount)) {
-            fbStart = i;
+        }
+        hwc_layer_1_t* layer = &list->hwLayers[i];
+        if(not isSupportedForMDPComp(ctx, layer)) {
+            lastMDPSupportedIndex = i;
+            mdpBatchSize = min(i - dropCount, stagesForMDP - 1);
+            fbBatchSize = numNonDroppedLayers - mdpBatchSize;
             break;
         }
     }
 
-    //Bottom layers constitute MDP batch
-    for(int i = 0; i < fbStart; i++) {
-        if((i < fbStart || i > fbEnd) && !mCurrentFrame.drop[i] ) {
-            hwc_layer_1_t* layer = &list->hwLayers[i];
-            if(not isSupportedForMDPComp(ctx, layer)) {
-                ALOGD_IF(isDebug(), "%s: MDP unsupported layer found at %d",
-                         __FUNCTION__, i);
-                reset(ctx);
-                return false;
-            }
-            mCurrentFrame.isFBComposed[i] = false;
-        }
+    ALOGD_IF(isDebug(), "%s:Before optimizing fbBatch, mdpbatch %d, fbbatch %d "
+            "dropped %d", __FUNCTION__, mdpBatchSize, fbBatchSize,
+            mCurrentFrame.dropCount);
+
+    //Start at a point where the fb batch should at least have 2 layers, for
+    //this mode to be justified.
+    while(fbBatchSize < 2) {
+        ++fbBatchSize;
+        --mdpBatchSize;
     }
 
-    mCurrentFrame.fbZ = fbStart;
-    mCurrentFrame.fbCount = fbBatchSize;
-    mCurrentFrame.mdpCount = mCurrentFrame.layerCount - mCurrentFrame.fbCount
-                                                      - mCurrentFrame.dropCount;
-
-    ALOGD_IF(isDebug(), "%s: FB Z %d, app layers %d, non-dropped layers: %d, "
-             "MDP Batch Size %d",__FUNCTION__, mCurrentFrame.fbZ, numAppLayers,
-             numAppLayers - mCurrentFrame.dropCount, mCurrentFrame.mdpCount);
-
-    if(sEnable4k2kYUVSplit){
-        adjustForSourceSplit(ctx, list);
-    }
-
-    if(!postHeuristicsHandling(ctx, list)) {
-        ALOGD_IF(isDebug(), "post heuristic handling failed");
-        reset(ctx);
+    //If there are no layers for MDP, this mode doesnt make sense.
+    if(mdpBatchSize < 1) {
+        ALOGD_IF(isDebug(), "%s: No MDP layers after optimizing for fbBatch",
+                __FUNCTION__);
         return false;
     }
 
-    return true;
+    mCurrentFrame.reset(numAppLayers);
+
+    //Try with successively smaller mdp batch sizes until we succeed or reach 1
+    while(mdpBatchSize > 0) {
+        //Mark layers for MDP comp
+        int mdpBatchLeft = mdpBatchSize;
+        for(int i = 0; i < lastMDPSupportedIndex and mdpBatchLeft; i++) {
+            if(mCurrentFrame.drop[i]) {
+                continue;
+            }
+            mCurrentFrame.isFBComposed[i] = false;
+            --mdpBatchLeft;
+        }
+
+        mCurrentFrame.fbZ = mdpBatchSize;
+        mCurrentFrame.fbCount = fbBatchSize;
+        mCurrentFrame.mdpCount = mdpBatchSize;
+
+        ALOGD_IF(isDebug(), "%s:Trying with: mdpbatch %d fbbatch %d dropped %d",
+                __FUNCTION__, mdpBatchSize, fbBatchSize,
+                mCurrentFrame.dropCount);
+
+        if(postHeuristicsHandling(ctx, list)) {
+            ALOGD_IF(isDebug(), "%s: Postheuristics handling succeeded",
+                    __FUNCTION__);
+            return true;
+        }
+
+        reset(ctx);
+        --mdpBatchSize;
+        ++fbBatchSize;
+    }
+
+    return false;
 }
 
 bool MDPComp::isLoadBasedCompDoable(hwc_context_t *ctx) {
@@ -1322,45 +1214,6 @@
     return true;
 }
 
-double MDPComp::calcMDPBytesRead(hwc_context_t *ctx,
-        hwc_display_contents_1_t* list) {
-    double size = 0;
-    const double GIG = 1000000000.0;
-
-    //Skip for targets where no device tree value for bw is supplied
-    if(sMaxBw <= 0.0) {
-        return 0.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;
-            if (hnd) {
-                hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
-                hwc_rect_t dst = layer->displayFrame;
-                float bpp = ((float)hnd->size) / (hnd->width * hnd->height);
-                size += (bpp * (crop.right - crop.left) *
-                        (crop.bottom - crop.top) *
-                        ctx->dpyAttr[mDpy].yres / (dst.bottom - dst.top)) /
-                        GIG;
-            }
-        }
-    }
-
-    if(mCurrentFrame.fbCount) {
-        hwc_layer_1_t* layer = &list->hwLayers[list->numHwLayers - 1];
-        int tempw, temph;
-        size += (getBufferSizeAndDimensions(
-                    layer->displayFrame.right - layer->displayFrame.left,
-                    layer->displayFrame.bottom - layer->displayFrame.top,
-                    HAL_PIXEL_FORMAT_RGBA_8888,
-                    tempw, temph)) / GIG;
-    }
-
-    return size;
-}
-
 bool MDPComp::hwLimitationsCheck(hwc_context_t* ctx,
         hwc_display_contents_1_t* list) {
 
@@ -1441,13 +1294,6 @@
     if(isFrameDoable(ctx)) {
         generateROI(ctx, list);
 
-        //Convert from kbps to gbps
-        sMaxBw = mdpVersion.getHighBw() / 1000000.0;
-        if (ctx->mExtDisplay->isConnected() ||
-                    ctx->mMDP.panel != MIPI_CMD_PANEL) {
-            sMaxBw = mdpVersion.getLowBw() / 1000000.0;
-        }
-
         if(tryFullFrame(ctx, list) || tryVideoOnly(ctx, list)) {
             setMDPCompLayerFlags(ctx, list);
         } else {
@@ -1472,9 +1318,6 @@
 
     mCachedFrame.cacheAll(list);
     mCachedFrame.updateCounts(mCurrentFrame);
-    double panelRefRate =
-            1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
-    sBwClaimed += calcMDPBytesRead(ctx, list) * panelRefRate;
     return ret;
 }
 
@@ -1985,5 +1828,183 @@
 
     return true;
 }
+
+//================MDPCompSrcSplit==============================================
+bool MDPCompSrcSplit::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
+        MdpPipeInfoSplit& pipe_info, ePipeType /*type*/) {
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+    hwc_rect_t dst = layer->displayFrame;
+    hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+    pipe_info.lIndex = ovutils::OV_INVALID;
+    pipe_info.rIndex = ovutils::OV_INVALID;
+
+    //If 2 pipes are staged on a single stage of a mixer, then the left pipe
+    //should have a higher priority than the right one. Pipe priorities are
+    //starting with VG0, VG1 ... , RGB0 ..., DMA1
+    //TODO Currently we acquire VG pipes for left side and RGB/DMA for right to
+    //make sure pipe priorities are satisfied. A better way is to have priority
+    //as part of overlay object and acquire any 2 pipes. Assign the higher
+    //priority one to left side and lower to right side.
+
+    //1 pipe by default for a layer
+    pipe_info.lIndex = getMdpPipe(ctx, MDPCOMP_OV_VG, Overlay::MIXER_DEFAULT);
+    if(pipe_info.lIndex == ovutils::OV_INVALID) {
+        if(isYuvBuffer(hnd)) {
+            return false;
+        }
+        pipe_info.lIndex = getMdpPipe(ctx, MDPCOMP_OV_ANY,
+                Overlay::MIXER_DEFAULT);
+        if(pipe_info.lIndex == ovutils::OV_INVALID) {
+            return false;
+        }
+    }
+
+    //If layer's crop width or dest width > 2048, use 2 pipes
+    if((dst.right - dst.left) > qdutils::MAX_DISPLAY_DIM or
+            (crop.right - crop.left) > qdutils::MAX_DISPLAY_DIM) {
+        ePipeType rightType = isYuvBuffer(hnd) ?
+                MDPCOMP_OV_VG : MDPCOMP_OV_ANY;
+        pipe_info.rIndex = getMdpPipe(ctx, rightType, Overlay::MIXER_DEFAULT);
+        if(pipe_info.rIndex == ovutils::OV_INVALID) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool MDPCompSrcSplit::allocLayerPipes(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
+    for(int index = 0 ; index < mCurrentFrame.layerCount; index++) {
+        if(mCurrentFrame.isFBComposed[index]) continue;
+        hwc_layer_1_t* layer = &list->hwLayers[index];
+        int mdpIndex = mCurrentFrame.layerToMDP[index];
+        PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
+        info.pipeInfo = new MdpPipeInfoSplit;
+        info.rot = NULL;
+        MdpPipeInfoSplit& pipe_info = *(MdpPipeInfoSplit*)info.pipeInfo;
+
+        ePipeType type = MDPCOMP_OV_ANY;
+        if(!acquireMDPPipes(ctx, layer, pipe_info, type)) {
+            ALOGD_IF(isDebug(), "%s: Unable to get pipe for type = %d",
+                    __FUNCTION__, (int) type);
+            return false;
+        }
+    }
+    return true;
+}
+
+int MDPCompSrcSplit::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+        PipeLayerPair& PipeLayerPair) {
+    private_handle_t *hnd = (private_handle_t *)layer->handle;
+    if(!hnd) {
+        ALOGE("%s: layer handle is NULL", __FUNCTION__);
+        return -1;
+    }
+    MetaData_t *metadata = (MetaData_t *)hnd->base_metadata;
+    MdpPipeInfoSplit& mdp_info =
+        *(static_cast<MdpPipeInfoSplit*>(PipeLayerPair.pipeInfo));
+    Rotator **rot = &PipeLayerPair.rot;
+    eZorder z = static_cast<eZorder>(mdp_info.zOrder);
+    eIsFg isFg = IS_FG_OFF;
+    eDest lDest = mdp_info.lIndex;
+    eDest rDest = mdp_info.rIndex;
+    hwc_rect_t crop = integerizeSourceCrop(layer->sourceCropf);
+    hwc_rect_t dst = layer->displayFrame;
+    int transform = layer->transform;
+    eTransform orient = static_cast<eTransform>(transform);
+    const int downscale = 0;
+    int rotFlags = ROT_FLAGS_NONE;
+    uint32_t format = ovutils::getMdpFormat(hnd->format, isTileRendered(hnd));
+    Whf whf(getWidth(hnd), getHeight(hnd), format, hnd->size);
+
+    ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
+             "dest_pipeR: %d",__FUNCTION__, layer, z, lDest, rDest);
+
+    // Handle R/B swap
+    if (layer->flags & HWC_FORMAT_RB_SWAP) {
+        if (hnd->format == HAL_PIXEL_FORMAT_RGBA_8888)
+            whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRA_8888);
+        else if (hnd->format == HAL_PIXEL_FORMAT_RGBX_8888)
+            whf.format = getMdpFormat(HAL_PIXEL_FORMAT_BGRX_8888);
+    }
+
+    eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
+    setMdpFlags(layer, mdpFlagsL, 0, transform);
+    eMdpFlags mdpFlagsR = mdpFlagsL;
+
+    if(lDest != OV_INVALID && rDest != OV_INVALID) {
+        //Enable overfetch
+        setMdpFlags(mdpFlagsL, OV_MDSS_MDP_DUAL_PIPE);
+    }
+
+    if(isYuvBuffer(hnd) && (transform & HWC_TRANSFORM_ROT_90)) {
+        (*rot) = ctx->mRotMgr->getNext();
+        if((*rot) == NULL) return -1;
+        //Configure rotator for pre-rotation
+        if(configRotator(*rot, whf, crop, mdpFlagsL, orient, downscale) < 0) {
+            ALOGE("%s: configRotator failed!", __FUNCTION__);
+            return -1;
+        }
+        ctx->mLayerRotMap[mDpy]->add(layer, *rot);
+        whf.format = (*rot)->getDstFormat();
+        updateSource(orient, whf, crop);
+        rotFlags |= ROT_PREROTATED;
+    }
+
+    //If 2 pipes being used, divide layer into half, crop and dst
+    hwc_rect_t cropL = crop;
+    hwc_rect_t cropR = crop;
+    hwc_rect_t dstL = dst;
+    hwc_rect_t dstR = dst;
+    if(lDest != OV_INVALID && rDest != OV_INVALID) {
+        cropL.right = (crop.right + crop.left) / 2;
+        cropR.left = cropL.right;
+        sanitizeSourceCrop(cropL, cropR, hnd);
+
+        //Swap crops on H flip since 2 pipes are being used
+        if((orient & OVERLAY_TRANSFORM_FLIP_H) && (*rot) == NULL) {
+            hwc_rect_t tmp = cropL;
+            cropL = cropR;
+            cropR = tmp;
+        }
+
+        dstL.right = (dst.right + dst.left) / 2;
+        dstR.left = dstL.right;
+    }
+
+    //For the mdp, since either we are pre-rotating or MDP does flips
+    orient = OVERLAY_TRANSFORM_0;
+    transform = 0;
+
+    //configure left pipe
+    if(lDest != OV_INVALID) {
+        PipeArgs pargL(mdpFlagsL, whf, z, isFg,
+                static_cast<eRotFlags>(rotFlags), layer->planeAlpha,
+                (ovutils::eBlending) getBlending(layer->blending));
+
+        if(configMdp(ctx->mOverlay, pargL, orient,
+                    cropL, dstL, metadata, lDest) < 0) {
+            ALOGE("%s: commit failed for left mixer config", __FUNCTION__);
+            return -1;
+        }
+    }
+
+    //configure right pipe
+    if(rDest != OV_INVALID) {
+        PipeArgs pargR(mdpFlagsR, whf, z, isFg,
+                static_cast<eRotFlags>(rotFlags),
+                layer->planeAlpha,
+                (ovutils::eBlending) getBlending(layer->blending));
+        if(configMdp(ctx->mOverlay, pargR, orient,
+                    cropR, dstR, metadata, rDest) < 0) {
+            ALOGE("%s: commit failed for right mixer config", __FUNCTION__);
+            return -1;
+        }
+    }
+
+    return 0;
+}
+
 }; //namespace
 
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 4215881..94199e3 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -52,7 +52,7 @@
     /* Initialize MDP comp*/
     static bool init(hwc_context_t *ctx);
     static void resetIdleFallBack() { sIdleFallBack = false; }
-    static void reset() { sBwClaimed = 0.0; sHandleTimeout = false; };
+    static void reset() { sHandleTimeout = false; };
 
 protected:
     enum { MAX_SEC_LAYERS = 1 }; //TODO add property support
@@ -158,16 +158,11 @@
     bool partialMDPComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     /* Partial MDP comp that uses caching to save power as primary goal */
     bool cacheBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
-    /* Partial MDP comp that prefers GPU perf-wise. Since the GPU's
-     * perf is proportional to the pixels it processes, we use the number of
-     * pixels as a heuristic */
-    bool loadBasedCompPreferGPU(hwc_context_t *ctx,
-            hwc_display_contents_1_t* list);
-    /* Partial MDP comp that prefers MDP perf-wise. Since the MDP's perf is
-     * proportional to the bandwidth, overlaps it sees, we use that as a
-     * heuristic */
-    bool loadBasedCompPreferMDP(hwc_context_t *ctx,
-            hwc_display_contents_1_t* list);
+    /* Partial MDP comp that balances the load between MDP and GPU such that
+     * MDP is loaded to the max of its capacity. The lower z order layers are
+     * fed to MDP, whereas the upper ones to GPU, because the upper ones have
+     * lower number of pixels and can reduce GPU processing time */
+    bool loadBasedComp(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     /* Checks if its worth doing load based partial comp */
     bool isLoadBasedCompDoable(hwc_context_t *ctx);
     /* checks for conditions where only video can be bypassed */
@@ -176,9 +171,6 @@
             bool secureOnly);
     /* 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 in gigs for a given frame */
-    double calcMDPBytesRead(hwc_context_t *ctx,
-            hwc_display_contents_1_t* list);
     /* checks if MDP/MDSS can process current list w.r.to HW limitations
      * All peculiar HW limitations should go here */
     bool hwLimitationsCheck(hwc_context_t* ctx, hwc_display_contents_1_t* list);
@@ -234,11 +226,6 @@
     /* Handles the timeout event from kernel, if the value is set to true */
     static bool sHandleTimeout;
     static int sMaxPipesPerMixer;
-    //Max bandwidth. Value is in GBPS. For ex: 2.3 means 2.3GBPS
-    static double sMaxBw;
-    //Tracks composition bandwidth claimed. Represented as the total
-    //w*h*bpp*fps (gigabytes-per-second) going to MDP mixers.
-    static double sBwClaimed;
     static IdleInvalidator *idleInvalidator;
     struct FrameInfo mCurrentFrame;
     struct LayerCache mCachedFrame;
@@ -282,14 +269,15 @@
     explicit MDPCompSplit(int dpy):MDPComp(dpy){};
     virtual ~MDPCompSplit(){};
     virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list);
-private:
+
+protected:
     struct MdpPipeInfoSplit : public MdpPipeInfo {
         ovutils::eDest lIndex;
         ovutils::eDest rIndex;
         virtual ~MdpPipeInfoSplit() {};
     };
 
-    bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
+    virtual bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
                          MdpPipeInfoSplit& pipe_info, ePipeType type);
 
     /* configure's overlay pipes for the frame */
@@ -300,6 +288,7 @@
     virtual bool allocLayerPipes(hwc_context_t *ctx,
                                  hwc_display_contents_1_t* list);
 
+private:
     /* Increments mdpCount if 4k2k yuv layer split is enabled.
      * updates framebuffer z order if fb lies above source-split layer */
     virtual void adjustForSourceSplit(hwc_context_t *ctx,
@@ -310,5 +299,20 @@
             PipeLayerPair& PipeLayerPair);
 };
 
+class MDPCompSrcSplit : public MDPCompSplit {
+public:
+    explicit MDPCompSrcSplit(int dpy) : MDPCompSplit(dpy){};
+    virtual ~MDPCompSrcSplit(){};
+private:
+    virtual bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
+            MdpPipeInfoSplit& pipe_info, ePipeType type);
+
+    virtual bool allocLayerPipes(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
+
+    virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+            PipeLayerPair& pipeLayerPair);
+};
+
 }; //namespace
 #endif
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index d2104ed..ff0e839 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -238,6 +238,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);
@@ -985,8 +993,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 +1738,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) {
@@ -1859,6 +1877,10 @@
     Whf whf(getWidth(hnd), getHeight(hnd),
             getMdpFormat(hnd->format), hnd->size);
 
+    /* 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);
     trimLayer(ctx, dpy, transform, crop, dst);
 
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 8293505..d451964 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -382,16 +382,6 @@
     return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_ONLY));
 }
 
-//Return true if buffer is for external display only with a BLOCK flag.
-static inline bool isExtBlock(const private_handle_t* hnd) {
-    return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_BLOCK));
-}
-
-//Return true if buffer is for external display only with a Close Caption flag.
-static inline bool isExtCC(const private_handle_t* hnd) {
-    return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_EXTERNAL_CC));
-}
-
 //Return true if the buffer is intended for Secure Display
 static inline bool isSecureDisplayBuffer(const private_handle_t* hnd) {
     return (hnd && (hnd->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY));
@@ -516,6 +506,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/liblight/lights.c b/liblight/lights.c
index 229777a..1aa0b58 100644
--- a/liblight/lights.c
+++ b/liblight/lights.c
@@ -84,7 +84,7 @@
     if (fd >= 0) {
         char buffer[20];
         int bytes = sprintf(buffer, "%d\n", value);
-        int amt = write(fd, buffer, bytes);
+        ssize_t amt = write(fd, buffer, (size_t)bytes);
         close(fd);
         return amt == -1 ? -errno : 0;
     } else {
diff --git a/libqdutils/cb_utils.cpp b/libqdutils/cb_utils.cpp
index 3d07c4f..a2b706c 100644
--- a/libqdutils/cb_utils.cpp
+++ b/libqdutils/cb_utils.cpp
@@ -43,14 +43,14 @@
 int CBUtils::getuiClearRegion(hwc_display_contents_1_t* list,
           hwc_rect_t &clearWormholeRect, LayerProp *layerProp) {
 
-    uint32_t last = list->numHwLayers - 1;
+    size_t last = list->numHwLayers - 1;
     hwc_rect_t fbFrame = list->hwLayers[last].displayFrame;
     Rect fbFrameRect(fbFrame.left,fbFrame.top,fbFrame.right,fbFrame.bottom);
     Region wormholeRegion(fbFrameRect);
 
     if(cb_swap_rect::getInstance().checkSwapRectFeature_on() == true){
       wormholeRegion.set(0,0);
-      for(uint32_t i = 0 ; i < last; i++) {
+      for(size_t i = 0 ; i < last; i++) {
          if((list->hwLayers[i].blending == HWC_BLENDING_NONE) ||
            !(layerProp[i].mFlags & HWC_COPYBIT) ||
            (list->hwLayers[i].flags  & HWC_SKIP_HWC_COMPOSITION))
@@ -61,7 +61,7 @@
          wormholeRegion.set(tmpRect);
       }
    }else{
-     for (uint32_t i = 0 ; i < last; i++) {
+     for (size_t i = 0 ; i < last; i++) {
         // need to take care only in per pixel blending.
         // Restrict calculation only for copybit layers.
         if((list->hwLayers[i].blending != HWC_BLENDING_NONE) ||
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index c341dfa..ed21b2c 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -70,6 +70,7 @@
     mPanelType = NO_PANEL;
     mLowBw = 0;
     mHighBw = 0;
+    mSourceSplit = false;
 
     if(!updatePanelInfo()) {
         ALOGE("Unable to read Primary Panel Information");
@@ -184,13 +185,13 @@
                     mMdpRev = atoi(tokens[1]);
                 }
                 else if(!strncmp(tokens[0], "rgb_pipes", strlen("rgb_pipes"))) {
-                    mRGBPipes = atoi(tokens[1]);
+                    mRGBPipes = (uint8_t)atoi(tokens[1]);
                 }
                 else if(!strncmp(tokens[0], "vig_pipes", strlen("vig_pipes"))) {
-                    mVGPipes = atoi(tokens[1]);
+                    mVGPipes = (uint8_t)atoi(tokens[1]);
                 }
                 else if(!strncmp(tokens[0], "dma_pipes", strlen("dma_pipes"))) {
-                    mDMAPipes = atoi(tokens[1]);
+                    mDMAPipes = (uint8_t)atoi(tokens[1]);
                 }
                 else if(!strncmp(tokens[0], "max_downscale_ratio",
                                 strlen("max_downscale_ratio"))) {
@@ -218,6 +219,9 @@
                                     strlen("tile_format"))) {
                            if(enableMacroTile)
                                mMacroTileEnabled = true;
+                        } else if(!strncmp(tokens[i], "src_split",
+                                    strlen("src_split"))) {
+                            mSourceSplit = true;
                         }
                     }
                 }
@@ -287,6 +291,10 @@
     return mMacroTileEnabled;
 }
 
+bool MDPVersion::isSrcSplit() const {
+    return mSourceSplit;
+}
+
 bool MDPVersion::is8x26() {
     return (mMdpRev >= MDSS_MDP_HW_REV_101 and
             mMdpRev < MDSS_MDP_HW_REV_102);
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 853b9f5..5e36291 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -100,7 +100,9 @@
     int getMDPVersion() {return mMDPVersion;}
     char getPanelType() {return mPanelType;}
     bool hasOverlay() {return mHasOverlay;}
-    uint8_t getTotalPipes() { return (mRGBPipes + mVGPipes + mDMAPipes);}
+    uint8_t getTotalPipes() {
+        return (uint8_t)(mRGBPipes + mVGPipes + mDMAPipes);
+    }
     uint8_t getRGBPipes() { return mRGBPipes; }
     uint8_t getVGPipes() { return mVGPipes; }
     uint8_t getDMAPipes() { return mDMAPipes; }
@@ -113,6 +115,7 @@
     int getRightSplit() { return mSplit.right(); }
     unsigned long getLowBw() { return mLowBw; }
     unsigned long getHighBw() { return mHighBw; }
+    bool isSrcSplit() const;
     bool is8x26();
     bool is8x74v2();
     bool is8084();
@@ -139,6 +142,7 @@
     Split mSplit;
     unsigned long mLowBw; //kbps
     unsigned long mHighBw; //kbps
+    bool mSourceSplit;
 };
 }; //namespace qdutils
 #endif //INCLUDE_LIBQCOMUTILS_MDPVER
diff --git a/libqdutils/profiler.cpp b/libqdutils/profiler.cpp
index 997c839..56bb2c6 100644
--- a/libqdutils/profiler.cpp
+++ b/libqdutils/profiler.cpp
@@ -90,7 +90,7 @@
     debug_fps_metadata.ignorethresh_us = atoi(prop);
 
     debug_fps_metadata.framearrival_steps =
-        (debug_fps_metadata.ignorethresh_us / 16666);
+        (unsigned int)(debug_fps_metadata.ignorethresh_us / 16666);
 
     if (debug_fps_metadata.framearrival_steps > MAX_FRAMEARRIVAL_STEPS) {
         debug_fps_metadata.framearrival_steps = MAX_FRAMEARRIVAL_STEPS;
@@ -106,7 +106,7 @@
 
     debug_fps_metadata.curr_frame = 0;
 
-    ALOGD("period: %d", debug_fps_metadata.period);
+    ALOGD("period: %u", debug_fps_metadata.period);
     ALOGD("ignorethresh_us: %"PRId64, debug_fps_metadata.ignorethresh_us);
 }
 
@@ -165,7 +165,8 @@
     debug_fps_metadata.curr_frame++;
 
     if (debug_fps_level > 1) {
-        unsigned int currstep = (diff + debug_fps_metadata.margin_us) / 16666;
+        unsigned int currstep =
+            (unsigned int)(diff + debug_fps_metadata.margin_us) / 16666;
 
         if (currstep < debug_fps_metadata.framearrival_steps) {
             debug_fps_metadata.accum_framearrivals[currstep-1]++;
@@ -178,14 +179,15 @@
             nsecs_t sum = 0;
             for (unsigned int i = 0; i < debug_fps_metadata.period; i++)
                 sum += debug_fps_metadata.framearrivals[i];
-            print_fps((debug_fps_metadata.period * float(1000000))/float(sum));
+            print_fps(float(float(debug_fps_metadata.period * 1000000) /
+                                                              (float)sum));
         }
     }
     else if (debug_fps_metadata_t::DFM_TIME == debug_fps_metadata.type) {
-        debug_fps_metadata.time_elapsed += ((float)diff/1000.0);
+        debug_fps_metadata.time_elapsed += (float)((float)diff/1000.0);
         if (debug_fps_metadata.time_elapsed >= debug_fps_metadata.time_period) {
-            float fps = (1000.0 * debug_fps_metadata.curr_frame)/
-                (float)debug_fps_metadata.time_elapsed;
+            float fps = float(1000.0 * debug_fps_metadata.curr_frame/
+                                            debug_fps_metadata.time_elapsed);
             print_fps(fps);
         }
     }
diff --git a/libqdutils/qdMetaData.cpp b/libqdutils/qdMetaData.cpp
index ecbf873..b736478 100644
--- a/libqdutils/qdMetaData.cpp
+++ b/libqdutils/qdMetaData.cpp
@@ -103,12 +103,15 @@
             }
         }
         break;
+        case UPDATE_COLOR_SPACE:
+            data->colorSpace = *((ColorSpace_t *)param);
+            break;
         default:
             ALOGE("Unknown paramType %d", paramType);
             break;
     }
     if(munmap(base, size))
-        ALOGE("%s: failed to unmap ptr 0x%"PRIdPTR", err %d", __func__, (intptr_t)base,
+        ALOGE("%s: failed to unmap ptr %p, err %d", __func__, (void*)base,
                                                                         errno);
     return 0;
 }
diff --git a/libqdutils/qdMetaData.h b/libqdutils/qdMetaData.h
index 4b6e678..3a0e615 100644
--- a/libqdutils/qdMetaData.h
+++ b/libqdutils/qdMetaData.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -30,6 +30,10 @@
 #ifndef _QDMETADATA_H
 #define _QDMETADATA_H
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #define MAX_IGC_LUT_ENTRIES 256
 #define MAX_VFM_DATA_SIZE   64 //bytes per data buffer
 #define MAX_VFM_DATA_COUNT  16 //number of data buffers
@@ -45,6 +49,12 @@
     return indx;
 }
 
+enum ColorSpace_t{
+    ITU_R_601,
+    ITU_R_601_FR,
+    ITU_R_709,
+};
+
 struct HSICData_t {
     int32_t hue;
     float   saturation;
@@ -78,18 +88,19 @@
 struct MetaData_t {
     int32_t operation;
     int32_t interlaced;
-    BufferDim_t bufferDim;
-    HSICData_t hsicData;
+    struct BufferDim_t bufferDim;
+    struct HSICData_t hsicData;
     int32_t sharpness;
     int32_t video_interface;
-    IGCData_t igcData;
-    Sharp2Data_t Sharp2Data;
+    struct IGCData_t igcData;
+    struct Sharp2Data_t Sharp2Data;
     int64_t timestamp;
     int32_t vfmDataBitMap;
-    VfmData_t vfmData[MAX_VFM_DATA_COUNT];
+    struct VfmData_t vfmData[MAX_VFM_DATA_COUNT];
+    enum ColorSpace_t colorSpace;
 };
 
-typedef enum {
+enum DispParamType {
     PP_PARAM_HSIC       = 0x0001,
     PP_PARAM_SHARPNESS  = 0x0002,
     PP_PARAM_INTERLACED = 0x0004,
@@ -99,9 +110,16 @@
     PP_PARAM_TIMESTAMP  = 0x0040,
     UPDATE_BUFFER_GEOMETRY = 0x0080,
     PP_PARAM_VFM_DATA   = 0x0100,
-} DispParamType;
+    UPDATE_COLOR_SPACE = 0x0200,
+};
 
-int setMetaData(private_handle_t *handle, DispParamType paramType, void *param);
+struct private_handle_t;
+int setMetaData(struct private_handle_t *handle, enum DispParamType paramType,
+        void *param);
+
+#ifdef __cplusplus
+}
+#endif
 
 #endif /* _QDMETADATA_H */
 
diff --git a/libqdutils/qd_utils.cpp b/libqdutils/qd_utils.cpp
index 0698b33..c27167f 100644
--- a/libqdutils/qd_utils.cpp
+++ b/libqdutils/qd_utils.cpp
@@ -87,7 +87,7 @@
         return 0;
     }
 
-    size = read(edidFile, (char*)buffer, EDID_RAW_DATA_SIZE);
+    size = (int)read(edidFile, (char*)buffer, EDID_RAW_DATA_SIZE);
     close(edidFile);
     return size;
 }
diff --git a/libqservice/IQService.cpp b/libqservice/IQService.cpp
index f0d7576..eee22f0 100644
--- a/libqservice/IQService.cpp
+++ b/libqservice/IQService.cpp
@@ -125,8 +125,10 @@
     if (fd < 0) {
         strlcpy(buf, "Unknown", size);
     } else {
-        int len = read(fd, buf, size - 1);
-        buf[len] = 0;
+        ssize_t len = read(fd, buf, size - 1);
+        if (len >= 0)
+           buf[len] = 0;
+
         close(fd);
     }
 }
diff --git a/libvirtual/virtual.cpp b/libvirtual/virtual.cpp
index 795d8a1..7d8b942 100644
--- a/libvirtual/virtual.cpp
+++ b/libvirtual/virtual.cpp
@@ -167,7 +167,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.