Merge "qdutils: initialize debug_fps_metadata.curr_frame before counting fps"
diff --git a/libgralloc/mapper.cpp b/libgralloc/mapper.cpp
index 10d372a..30754dd 100644
--- a/libgralloc/mapper.cpp
+++ b/libgralloc/mapper.cpp
@@ -247,9 +247,9 @@
         return -EINVAL;
     int err = 0;
     private_handle_t* hnd = (private_handle_t*)handle;
-    IMemAlloc* memalloc = getAllocator(hnd->flags);
 
     if (hnd->flags & private_handle_t::PRIV_FLAGS_USES_ION) {
+        IMemAlloc* memalloc = getAllocator(hnd->flags);
         if (hnd->flags & private_handle_t::PRIV_FLAGS_NEEDS_FLUSH) {
             err = memalloc->clean_buffer((void*)hnd->base,
                                          hnd->size, hnd->offset, hnd->fd,
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 113e916..5fd7564 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -123,6 +123,7 @@
     }
 
     ctx->mAD->reset();
+    MDPComp::reset();
 }
 
 //clear prev layer prop flags and realloc for current frame
diff --git a/libhwcomposer/hwc_ad.cpp b/libhwcomposer/hwc_ad.cpp
index 9ac8958..c2ea4ee 100644
--- a/libhwcomposer/hwc_ad.cpp
+++ b/libhwcomposer/hwc_ad.cpp
@@ -118,20 +118,34 @@
         }
         close(adFd);
     } else {
-        ALOGE("%s: Failed to open /sys/class/graphics/fb%d/ad with error %s",
+        ALOGD("%s: /sys/class/graphics/fb%d/ad could not be opened : %s",
                 __func__, wbFbNum, strerror(errno));
     }
     return ret;
 }
 
-AssertiveDisplay::AssertiveDisplay() :mWbFd(-1), mDoable(false),
-        mFeatureEnabled(false), mDest(overlay::utils::OV_INVALID) {
+AssertiveDisplay::AssertiveDisplay(hwc_context_t *ctx) : mWbFd(-1),
+        mDoable(false), mFeatureEnabled(false),
+        mDest(overlay::utils::OV_INVALID) {
     int fd = openWbFb();
     if(fd >= 0) {
+        //Values in ad node:
         //-1 means feature is disabled on device
         // 0 means feature exists but turned off, will be turned on by hwc
         // 1 means feature is turned on by hwc
-        if(adRead() >= 0) {
+        // Plus, we do this feature only on split primary displays.
+        // Plus, we do this feature only if ro.qcom.ad=2
+
+        char property[PROPERTY_VALUE_MAX];
+        const int ENABLED = 2;
+        int val = 0;
+
+        if(property_get("ro.qcom.ad", property, "0") > 0) {
+            val = atoi(property);
+        }
+
+        if(adRead() >= 0 && isDisplaySplit(ctx, HWC_DISPLAY_PRIMARY) &&
+                val == ENABLED) {
             ALOGD_IF(DEBUG, "Assertive display feature supported");
             mFeatureEnabled = true;
         }
diff --git a/libhwcomposer/hwc_ad.h b/libhwcomposer/hwc_ad.h
index 38b724d..c745b15 100644
--- a/libhwcomposer/hwc_ad.h
+++ b/libhwcomposer/hwc_ad.h
@@ -39,7 +39,7 @@
 
 class AssertiveDisplay {
 public:
-    AssertiveDisplay();
+    AssertiveDisplay(hwc_context_t *ctx);
     void markDoable(hwc_context_t *ctx, const hwc_display_contents_1_t* list);
     bool prepare(hwc_context_t *ctx, const hwc_rect_t& crop,
             const overlay::utils::Whf& whf,
diff --git a/libhwcomposer/hwc_copybit.cpp b/libhwcomposer/hwc_copybit.cpp
index a395ee0..dbb4413 100644
--- a/libhwcomposer/hwc_copybit.cpp
+++ b/libhwcomposer/hwc_copybit.cpp
@@ -223,24 +223,18 @@
     if (!useCopybitForYUV && ctx->listStats[dpy].yuvCount)
         return true;
 
-    // numAppLayers-1, as we iterate till 0th layer index
-    for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
-        private_handle_t *hnd = (private_handle_t *)list->hwLayers[i].handle;
-
-        if ((hnd->bufferType == BUFFER_TYPE_VIDEO && useCopybitForYUV) ||
-            (hnd->bufferType == BUFFER_TYPE_UI && useCopybitForRGB)) {
+    mCopyBitDraw = false;
+    if (useCopybitForRGB &&
+        (useCopybitForYUV || !ctx->listStats[dpy].yuvCount)) {
+        mCopyBitDraw =  true;
+        // numAppLayers-1, as we iterate till 0th layer index
+        // Mark all layers to be drawn by copybit
+        for (int i = ctx->listStats[dpy].numAppLayers-1; i >= 0 ; i--) {
             layerProp[i].mFlags |= HWC_COPYBIT;
             list->hwLayers[i].compositionType = HWC_OVERLAY;
-            mCopyBitDraw = true;
-        } else {
-            // We currently cannot mix copybit layers with layers marked to
-            // be drawn on the framebuffer or that are on the layer cache.
-            mCopyBitDraw = false;
-            //There is no need to reset layer properties here as we return in
-            //draw if mCopyBitDraw is false
-            break;
         }
     }
+
     return true;
 }
 
@@ -364,6 +358,27 @@
     // if needed in the future
     src.vert_padding = 0;
 
+    int layerTransform = layer->transform ;
+    // When flip and rotation(90) are present alter the flip,
+    // as GPU is doing the flip and rotation in opposite order
+    // to that of MDP3.0
+    // For 270 degrees, we get 90 + (H+V) which is same as doing
+    // flip first and then rotation (H+V) + 90
+    if (qdutils::MDPVersion::getInstance().getMDPVersion() < 400) {
+                if (((layer->transform& HAL_TRANSFORM_FLIP_H) ||
+                (layer->transform & HAL_TRANSFORM_FLIP_V)) &&
+                (layer->transform &  HAL_TRANSFORM_ROT_90) &&
+                !(layer->transform ==  HAL_TRANSFORM_ROT_270)){
+                      if(layer->transform & HAL_TRANSFORM_FLIP_H){
+                                 layerTransform ^= HAL_TRANSFORM_FLIP_H;
+                                 layerTransform |= HAL_TRANSFORM_FLIP_V;
+                      }
+                      if(layer->transform & HAL_TRANSFORM_FLIP_V){
+                                 layerTransform ^= HAL_TRANSFORM_FLIP_V;
+                                 layerTransform |= HAL_TRANSFORM_FLIP_H;
+                      }
+               }
+    }
     // Copybit source rect
     hwc_rect_t sourceCrop = layer->sourceCrop;
     copybit_rect_t srcRect = {sourceCrop.left, sourceCrop.top,
@@ -519,7 +534,7 @@
     copybit->set_parameter(copybit, COPYBIT_FRAMEBUFFER_HEIGHT,
                                           renderBuffer->height);
     copybit->set_parameter(copybit, COPYBIT_TRANSFORM,
-                                              layer->transform);
+                                              layerTransform);
     //TODO: once, we are able to read layer alpha, update this
     copybit->set_parameter(copybit, COPYBIT_PLANE_ALPHA, 255);
     copybit->set_parameter(copybit, COPYBIT_BLEND_MODE,
diff --git a/libhwcomposer/hwc_fbupdate.cpp b/libhwcomposer/hwc_fbupdate.cpp
index 2337b2a..53b3d18 100644
--- a/libhwcomposer/hwc_fbupdate.cpp
+++ b/libhwcomposer/hwc_fbupdate.cpp
@@ -37,12 +37,11 @@
 
 namespace ovutils = overlay::utils;
 
-IFBUpdate* IFBUpdate::getObject(const int& width, const int& rightSplit,
-        const int& dpy) {
-    if(width > MAX_DISPLAY_DIM || rightSplit) {
-        return new FBUpdateHighRes(dpy);
+IFBUpdate* IFBUpdate::getObject(hwc_context_t *ctx, const int& dpy) {
+    if(isDisplaySplit(ctx, dpy)) {
+        return new FBUpdateSplit(dpy);
     }
-    return new FBUpdateLowRes(dpy);
+    return new FBUpdateNonSplit(dpy);
 }
 
 inline void IFBUpdate::reset() {
@@ -51,14 +50,14 @@
 }
 
 //================= Low res====================================
-FBUpdateLowRes::FBUpdateLowRes(const int& dpy): IFBUpdate(dpy) {}
+FBUpdateNonSplit::FBUpdateNonSplit(const int& dpy): IFBUpdate(dpy) {}
 
-inline void FBUpdateLowRes::reset() {
+inline void FBUpdateNonSplit::reset() {
     IFBUpdate::reset();
     mDest = ovutils::OV_INVALID;
 }
 
-bool FBUpdateLowRes::preRotateExtDisplay(hwc_context_t *ctx,
+bool FBUpdateNonSplit::preRotateExtDisplay(hwc_context_t *ctx,
                                             ovutils::Whf &info,
                                             hwc_rect_t& sourceCrop,
                                             ovutils::eMdpFlags& mdpFlags,
@@ -82,7 +81,7 @@
     return true;
 }
 
-bool FBUpdateLowRes::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
+bool FBUpdateNonSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
                              int fbZorder) {
     if(!ctx->mMDP.hasOverlay) {
         ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
@@ -94,7 +93,7 @@
 }
 
 // Configure
-bool FBUpdateLowRes::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
+bool FBUpdateNonSplit::configure(hwc_context_t *ctx, hwc_display_contents_1 *list,
                                int fbZorder) {
     bool ret = false;
     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
@@ -186,7 +185,7 @@
     return ret;
 }
 
-bool FBUpdateLowRes::draw(hwc_context_t *ctx, private_handle_t *hnd)
+bool FBUpdateNonSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
 {
     if(!mModeOn) {
         return true;
@@ -210,16 +209,16 @@
 }
 
 //================= High res====================================
-FBUpdateHighRes::FBUpdateHighRes(const int& dpy): IFBUpdate(dpy) {}
+FBUpdateSplit::FBUpdateSplit(const int& dpy): IFBUpdate(dpy) {}
 
-inline void FBUpdateHighRes::reset() {
+inline void FBUpdateSplit::reset() {
     IFBUpdate::reset();
     mDestLeft = ovutils::OV_INVALID;
     mDestRight = ovutils::OV_INVALID;
     mRot = NULL;
 }
 
-bool FBUpdateHighRes::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
+bool FBUpdateSplit::prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
                               int fbZorder) {
     if(!ctx->mMDP.hasOverlay) {
         ALOGD_IF(DEBUG_FBUPDATE, "%s, this hw doesnt support overlays",
@@ -232,7 +231,7 @@
 }
 
 // Configure
-bool FBUpdateHighRes::configure(hwc_context_t *ctx,
+bool FBUpdateSplit::configure(hwc_context_t *ctx,
         hwc_display_contents_1 *list, int fbZorder) {
     bool ret = false;
     hwc_layer_1_t *layer = &list->hwLayers[list->numHwLayers - 1];
@@ -355,7 +354,7 @@
     return ret;
 }
 
-bool FBUpdateHighRes::draw(hwc_context_t *ctx, private_handle_t *hnd)
+bool FBUpdateSplit::draw(hwc_context_t *ctx, private_handle_t *hnd)
 {
     if(!mModeOn) {
         return true;
diff --git a/libhwcomposer/hwc_fbupdate.h b/libhwcomposer/hwc_fbupdate.h
index 3c76efe..0e3f29e 100644
--- a/libhwcomposer/hwc_fbupdate.h
+++ b/libhwcomposer/hwc_fbupdate.h
@@ -45,8 +45,7 @@
     //Reset values
     virtual void reset();
     //Factory method that returns a low-res or high-res version
-    static IFBUpdate *getObject(const int& width, const int& rightSplit,
-            const int& dpy);
+    static IFBUpdate *getObject(hwc_context_t *ctx, const int& dpy);
 
 protected:
     const int mDpy; // display to update
@@ -54,11 +53,11 @@
     overlay::Rotator *mRot;
 };
 
-//Low resolution (<= 2048) panel handler.
-class FBUpdateLowRes : public IFBUpdate {
+//Non-Split panel handler.
+class FBUpdateNonSplit : public IFBUpdate {
 public:
-    explicit FBUpdateLowRes(const int& dpy);
-    virtual ~FBUpdateLowRes() {};
+    explicit FBUpdateNonSplit(const int& dpy);
+    virtual ~FBUpdateNonSplit() {};
     bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
             int fbZorder);
     bool draw(hwc_context_t *ctx, private_handle_t *hnd);
@@ -74,11 +73,11 @@
     ovutils::eDest mDest; //pipe to draw on
 };
 
-//High resolution (> 2048) panel handler.
-class FBUpdateHighRes : public IFBUpdate {
+//Split panel handler.
+class FBUpdateSplit : public IFBUpdate {
 public:
-    explicit FBUpdateHighRes(const int& dpy);
-    virtual ~FBUpdateHighRes() {};
+    explicit FBUpdateSplit(const int& dpy);
+    virtual ~FBUpdateSplit() {};
     bool prepare(hwc_context_t *ctx, hwc_display_contents_1 *list,
             int fbZorder);
     bool draw(hwc_context_t *ctx, private_handle_t *hnd);
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index f2217b9..7ec99c1 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -42,13 +42,14 @@
 bool MDPComp::sEnabled = false;
 bool MDPComp::sEnableMixedMode = true;
 int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
+float MDPComp::sMaxBw = 2.3f;
+uint32_t MDPComp::sCompBytesClaimed = 0;
 
-MDPComp* MDPComp::getObject(const int& width, const int& rightSplit,
-        const int& dpy) {
-    if(width > MAX_DISPLAY_DIM || rightSplit) {
-        return new MDPCompHighRes(dpy);
+MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
+    if(isDisplaySplit(ctx, dpy)) {
+        return new MDPCompSplit(dpy);
     }
-    return new MDPCompLowRes(dpy);
+    return new MDPCompNonSplit(dpy);
 }
 
 MDPComp::MDPComp(int dpy):mDpy(dpy){};
@@ -125,6 +126,13 @@
             sMaxPipesPerMixer = min(val, MAX_PIPES_PER_MIXER);
     }
 
+    if(property_get("debug.mdpcomp.bw", property, "0") > 0) {
+        float val = atof(property);
+        if(val > 0.0f) {
+            sMaxBw = val;
+        }
+    }
+
     if(ctx->mMDP.panel != MIPI_CMD_PANEL) {
         // Idle invalidation is not necessary on command mode panels
         long idle_timeout = DEFAULT_IDLE_TIME;
@@ -497,6 +505,12 @@
         return false;
     }
 
+    uint32_t size = calcMDPBytesRead(ctx, list);
+    if(!bandwidthCheck(ctx, size)) {
+        ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
+        return false;
+    }
+
     return true;
 }
 
@@ -525,6 +539,12 @@
         return false;
     }
 
+    uint32_t size = calcMDPBytesRead(ctx, list);
+    if(!bandwidthCheck(ctx, size)) {
+        ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
+        return false;
+    }
+
     return true;
 }
 
@@ -552,6 +572,12 @@
         return false;
     }
 
+    uint32_t size = calcMDPBytesRead(ctx, list);
+    if(!bandwidthCheck(ctx, size)) {
+        ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
+        return false;
+    }
+
     return true;
 }
 
@@ -753,7 +779,46 @@
     return true;
 }
 
+uint32_t MDPComp::calcMDPBytesRead(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
+    uint32_t size = 0;
+
+    for (uint32_t i = 0; i < list->numHwLayers - 1; i++) {
+        if(!mCurrentFrame.isFBComposed[i]) {
+            hwc_layer_1_t* layer = &list->hwLayers[i];
+            private_handle_t *hnd = (private_handle_t *)layer->handle;
+            hwc_rect_t crop = layer->sourceCrop;
+            float bpp = ((float)hnd->size) / (hnd->width * hnd->height);
+            size += bpp * ((crop.right - crop.left) *
+                    (crop.bottom - crop.top));
+        }
+    }
+
+    if(mCurrentFrame.fbCount) {
+        hwc_layer_1_t* layer = &list->hwLayers[list->numHwLayers - 1];
+        private_handle_t *hnd = (private_handle_t *)layer->handle;
+        size += hnd->size;
+    }
+
+    return size;
+}
+
+bool MDPComp::bandwidthCheck(hwc_context_t *ctx, const uint32_t& size) {
+    //Will be added for other targets if we run into bandwidth issues and when
+    //we have profiling data to set an upper limit.
+    if(qdutils::MDPVersion::getInstance().is8x74v2()) {
+        const uint32_t ONE_GIG = 1024 * 1024 * 1024;
+        double panelRefRate =
+                1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
+        if((size + sCompBytesClaimed) > ((sMaxBw / panelRefRate) * ONE_GIG)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    int ret = 0;
     const int numLayers = ctx->listStats[mDpy].numAppLayers;
 
     //reset old data
@@ -765,7 +830,8 @@
         mCachedFrame.updateCounts(mCurrentFrame);
         ALOGD_IF(isDebug(), "%s: Number of App layers exceeded the limit ",
                 __FUNCTION__);
-        return -1;
+        ret = -1;
+        goto exit;
     }
 
     //Hard conditions, if not met, cannot do MDP comp
@@ -773,7 +839,8 @@
         ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
                 __FUNCTION__);
         reset(numLayers, list);
-        return -1;
+        ret = -1;
+        goto exit;
     }
 
     //Check whether layers marked for MDP Composition is actually doable.
@@ -785,13 +852,17 @@
                         mCurrentFrame.fbZ)) {
                 ALOGE("%s configure framebuffer failed", __func__);
                 reset(numLayers, list);
-                return -1;
+                ctx->mOverlay->clear(mDpy);
+                ret = -1;
+                goto exit;
             }
         }
         //Acquire and Program MDP pipes
         if(!programMDP(ctx, list)) {
             reset(numLayers, list);
-            return -1;
+            ctx->mOverlay->clear(mDpy);
+            ret = -1;
+            goto exit;
         } else { //Success
             //Any change in composition types needs an FB refresh
             mCurrentFrame.needsRedraw = false;
@@ -822,16 +893,21 @@
             if(!ctx->mFBUpdate[mDpy]->prepare(ctx, list, mCurrentFrame.fbZ)) {
                 ALOGE("%s configure framebuffer failed", __func__);
                 reset(numLayers, list);
-                return -1;
+                ctx->mOverlay->clear(mDpy);
+                ret = -1;
+                goto exit;
             }
         }
         if(!programYUV(ctx, list)) {
             reset(numLayers, list);
-            return -1;
+            ctx->mOverlay->clear(mDpy);
+            ret = -1;
+            goto exit;
         }
     } else {
         reset(numLayers, list);
-        return -1;
+        ret = -1;
+        goto exit;
     }
 
     //UpdateLayerFlags
@@ -846,18 +922,20 @@
         ALOGE("%s",sDump.string());
     }
 
-    return 0;
+exit:
+    sCompBytesClaimed += calcMDPBytesRead(ctx, list);
+    return ret;
 }
 
-//=============MDPCompLowRes===================================================
+//=============MDPCompNonSplit===================================================
 
 /*
  * Configures pipe(s) for MDP composition
  */
-int MDPCompLowRes::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+int MDPCompNonSplit::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
                              PipeLayerPair& PipeLayerPair) {
-    MdpPipeInfoLowRes& mdp_info =
-        *(static_cast<MdpPipeInfoLowRes*>(PipeLayerPair.pipeInfo));
+    MdpPipeInfoNonSplit& mdp_info =
+        *(static_cast<MdpPipeInfoNonSplit*>(PipeLayerPair.pipeInfo));
     eMdpFlags mdpFlags = OV_MDP_BACKEND_COMPOSITION;
     eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
     eIsFg isFg = IS_FG_OFF;
@@ -866,11 +944,11 @@
     ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipe: %d",
              __FUNCTION__, layer, zOrder, dest);
 
-    return configureLowRes(ctx, layer, mDpy, mdpFlags, zOrder, isFg, dest,
+    return configureNonSplit(ctx, layer, mDpy, mdpFlags, zOrder, isFg, dest,
                            &PipeLayerPair.rot);
 }
 
-bool MDPCompLowRes::arePipesAvailable(hwc_context_t *ctx,
+bool MDPCompNonSplit::arePipesAvailable(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
     overlay::Overlay& ov = *ctx->mOverlay;
     int numPipesNeeded = mCurrentFrame.mdpCount;
@@ -889,7 +967,7 @@
     return true;
 }
 
-bool MDPCompLowRes::allocLayerPipes(hwc_context_t *ctx,
+bool MDPCompNonSplit::allocLayerPipes(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
     for(int index = 0; index < mCurrentFrame.layerCount; index++) {
 
@@ -899,9 +977,9 @@
         private_handle_t *hnd = (private_handle_t *)layer->handle;
         int mdpIndex = mCurrentFrame.layerToMDP[index];
         PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
-        info.pipeInfo = new MdpPipeInfoLowRes;
+        info.pipeInfo = new MdpPipeInfoNonSplit;
         info.rot = NULL;
-        MdpPipeInfoLowRes& pipe_info = *(MdpPipeInfoLowRes*)info.pipeInfo;
+        MdpPipeInfoNonSplit& pipe_info = *(MdpPipeInfoNonSplit*)info.pipeInfo;
         ePipeType type = MDPCOMP_OV_ANY;
 
         if(isYuvBuffer(hnd)) {
@@ -922,7 +1000,7 @@
     return true;
 }
 
-bool MDPCompLowRes::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+bool MDPCompNonSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
 
     if(!isEnabled()) {
         ALOGD_IF(isDebug(),"%s: MDP Comp not configured", __FUNCTION__);
@@ -960,8 +1038,8 @@
 
         int mdpIndex = mCurrentFrame.layerToMDP[i];
 
-        MdpPipeInfoLowRes& pipe_info =
-            *(MdpPipeInfoLowRes*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+        MdpPipeInfoNonSplit& pipe_info =
+            *(MdpPipeInfoNonSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
         ovutils::eDest dest = pipe_info.index;
         if(dest == ovutils::OV_INVALID) {
             ALOGE("%s: Invalid pipe index (%d)", __FUNCTION__, dest);
@@ -979,13 +1057,6 @@
         int fd = hnd->fd;
         uint32_t offset = hnd->offset;
 
-        if(ctx->mAD->isModeOn()) {
-            if(ctx->mAD->draw(ctx, fd, offset)) {
-                fd = ctx->mAD->getDstFd(ctx);
-                offset = ctx->mAD->getDstOffset(ctx);
-            }
-        }
-
         Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
         if(rot) {
             if(!rot->queueBuffer(fd, offset))
@@ -1004,9 +1075,9 @@
     return true;
 }
 
-//=============MDPCompHighRes===================================================
+//=============MDPCompSplit===================================================
 
-int MDPCompHighRes::pipesNeeded(hwc_context_t *ctx,
+int MDPCompSplit::pipesNeeded(hwc_context_t *ctx,
         hwc_display_contents_1_t* list,
         int mixer) {
     int pipesNeeded = 0;
@@ -1028,7 +1099,7 @@
     return pipesNeeded;
 }
 
-bool MDPCompHighRes::arePipesAvailable(hwc_context_t *ctx,
+bool MDPCompSplit::arePipesAvailable(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
     overlay::Overlay& ov = *ctx->mOverlay;
 
@@ -1050,8 +1121,8 @@
     return true;
 }
 
-bool MDPCompHighRes::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
-        MdpPipeInfoHighRes& pipe_info,
+bool MDPCompSplit::acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
+        MdpPipeInfoSplit& pipe_info,
         ePipeType type) {
     const int xres = ctx->dpyAttr[mDpy].xres;
     const int lSplit = getLeftSplit(ctx, mDpy);
@@ -1075,7 +1146,7 @@
     return true;
 }
 
-bool MDPCompHighRes::allocLayerPipes(hwc_context_t *ctx,
+bool MDPCompSplit::allocLayerPipes(hwc_context_t *ctx,
         hwc_display_contents_1_t* list) {
     for(int index = 0 ; index < mCurrentFrame.layerCount; index++) {
 
@@ -1085,9 +1156,9 @@
         private_handle_t *hnd = (private_handle_t *)layer->handle;
         int mdpIndex = mCurrentFrame.layerToMDP[index];
         PipeLayerPair& info = mCurrentFrame.mdpToLayer[mdpIndex];
-        info.pipeInfo = new MdpPipeInfoHighRes;
+        info.pipeInfo = new MdpPipeInfoSplit;
         info.rot = NULL;
-        MdpPipeInfoHighRes& pipe_info = *(MdpPipeInfoHighRes*)info.pipeInfo;
+        MdpPipeInfoSplit& pipe_info = *(MdpPipeInfoSplit*)info.pipeInfo;
         ePipeType type = MDPCOMP_OV_ANY;
 
         if(isYuvBuffer(hnd)) {
@@ -1110,10 +1181,10 @@
 /*
  * Configures pipe(s) for MDP composition
  */
-int MDPCompHighRes::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
+int MDPCompSplit::configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
         PipeLayerPair& PipeLayerPair) {
-    MdpPipeInfoHighRes& mdp_info =
-        *(static_cast<MdpPipeInfoHighRes*>(PipeLayerPair.pipeInfo));
+    MdpPipeInfoSplit& mdp_info =
+        *(static_cast<MdpPipeInfoSplit*>(PipeLayerPair.pipeInfo));
     eZorder zOrder = static_cast<eZorder>(mdp_info.zOrder);
     eIsFg isFg = IS_FG_OFF;
     eMdpFlags mdpFlagsL = OV_MDP_BACKEND_COMPOSITION;
@@ -1123,11 +1194,11 @@
     ALOGD_IF(isDebug(),"%s: configuring: layer: %p z_order: %d dest_pipeL: %d"
              "dest_pipeR: %d",__FUNCTION__, layer, zOrder, lDest, rDest);
 
-    return configureHighRes(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg, lDest,
+    return configureSplit(ctx, layer, mDpy, mdpFlagsL, zOrder, isFg, lDest,
                             rDest, &PipeLayerPair.rot);
 }
 
-bool MDPCompHighRes::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+bool MDPCompSplit::draw(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
 
     if(!isEnabled()) {
         ALOGD_IF(isDebug(),"%s: MDP Comp not configured", __FUNCTION__);
@@ -1169,8 +1240,8 @@
 
         int mdpIndex = mCurrentFrame.layerToMDP[i];
 
-        MdpPipeInfoHighRes& pipe_info =
-            *(MdpPipeInfoHighRes*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
+        MdpPipeInfoSplit& pipe_info =
+            *(MdpPipeInfoSplit*)mCurrentFrame.mdpToLayer[mdpIndex].pipeInfo;
         Rotator *rot = mCurrentFrame.mdpToLayer[mdpIndex].rot;
 
         ovutils::eDest indexL = pipe_info.lIndex;
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 2f1670b..869eee7 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -46,13 +46,13 @@
     /* dumpsys */
     void dump(android::String8& buf);
 
-    static MDPComp* getObject(const int& width, const int& rightSplit,
-            const int& dpy);
+    static MDPComp* getObject(hwc_context_t *ctx, const int& dpy);
     /* Handler to invoke frame redraw on Idle Timer expiry */
     static void timeout_handler(void *udata);
     /* Initialize MDP comp*/
     static bool init(hwc_context_t *ctx);
     static void resetIdleFallBack() { sIdleFallBack = false; }
+    static void reset() { sCompBytesClaimed = 0; };
 
 protected:
     enum ePipeType {
@@ -142,6 +142,11 @@
     bool isOnlyVideoDoable(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     /* checks for conditions where YUV layers cannot be bypassed */
     bool isYUVDoable(hwc_context_t* ctx, hwc_layer_1_t* layer);
+    /* calcs bytes read by MDP for a given frame */
+    uint32_t calcMDPBytesRead(hwc_context_t *ctx,
+            hwc_display_contents_1_t* list);
+    /* checks if the required bandwidth exceeds a certain max */
+    bool bandwidthCheck(hwc_context_t *ctx, const uint32_t& size);
 
     /* set up Border fill as Base pipe */
     static bool setupBasePipe(hwc_context_t*);
@@ -167,21 +172,26 @@
     static bool sDebugLogs;
     static bool sIdleFallBack;
     static int sMaxPipesPerMixer;
+    //Max bandwidth. Value is in GBPS. For ex: 2.3 means 2.3GBPS
+    static float sMaxBw;
+    //Tracks composition bytes claimed. Represented as the total w*h*bpp
+    //going to MDP mixers
+    static uint32_t sCompBytesClaimed;
     static IdleInvalidator *idleInvalidator;
     struct FrameInfo mCurrentFrame;
     struct LayerCache mCachedFrame;
 };
 
-class MDPCompLowRes : public MDPComp {
+class MDPCompNonSplit : public MDPComp {
 public:
-    explicit MDPCompLowRes(int dpy):MDPComp(dpy){};
-    virtual ~MDPCompLowRes(){};
+    explicit MDPCompNonSplit(int dpy):MDPComp(dpy){};
+    virtual ~MDPCompNonSplit(){};
     virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list);
 
 private:
-    struct MdpPipeInfoLowRes : public MdpPipeInfo {
+    struct MdpPipeInfoNonSplit : public MdpPipeInfo {
         ovutils::eDest index;
-        virtual ~MdpPipeInfoLowRes() {};
+        virtual ~MdpPipeInfoNonSplit() {};
     };
 
     /* configure's overlay pipes for the frame */
@@ -197,20 +207,20 @@
             hwc_display_contents_1_t* list);
 };
 
-class MDPCompHighRes : public MDPComp {
+class MDPCompSplit : public MDPComp {
 public:
-    explicit MDPCompHighRes(int dpy):MDPComp(dpy){};
-    virtual ~MDPCompHighRes(){};
+    explicit MDPCompSplit(int dpy):MDPComp(dpy){};
+    virtual ~MDPCompSplit(){};
     virtual bool draw(hwc_context_t *ctx, hwc_display_contents_1_t *list);
 private:
-    struct MdpPipeInfoHighRes : public MdpPipeInfo {
+    struct MdpPipeInfoSplit : public MdpPipeInfo {
         ovutils::eDest lIndex;
         ovutils::eDest rIndex;
-        virtual ~MdpPipeInfoHighRes() {};
+        virtual ~MdpPipeInfoSplit() {};
     };
 
     bool acquireMDPPipes(hwc_context_t *ctx, hwc_layer_1_t* layer,
-                         MdpPipeInfoHighRes& pipe_info, ePipeType type);
+                         MdpPipeInfoSplit& pipe_info, ePipeType type);
 
     /* configure's overlay pipes for the frame */
     virtual int configure(hwc_context_t *ctx, hwc_layer_1_t *layer,
diff --git a/libhwcomposer/hwc_uevents.cpp b/libhwcomposer/hwc_uevents.cpp
index 5590798..a44924b 100644
--- a/libhwcomposer/hwc_uevents.cpp
+++ b/libhwcomposer/hwc_uevents.cpp
@@ -48,11 +48,8 @@
 
 static void setup(hwc_context_t* ctx, int dpy)
 {
-    const int rSplit = 0; //Even split for external if at all
-    ctx->mFBUpdate[dpy] = IFBUpdate::getObject(ctx->dpyAttr[dpy].xres,
-            rSplit, dpy);
-    ctx->mMDPComp[dpy] =  MDPComp::getObject(ctx->dpyAttr[dpy].xres,
-            rSplit, dpy);
+    ctx->mFBUpdate[dpy] = IFBUpdate::getObject(ctx, dpy);
+    ctx->mMDPComp[dpy] =  MDPComp::getObject(ctx, dpy);
     int compositionType =
                 qdutils::QCCompositionType::getInstance().getCompositionType();
     if (compositionType & (qdutils::COMPOSITION_TYPE_DYN |
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index ffaa9cb..5ea79b5 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -129,7 +129,6 @@
     ctx->mMDP.version = qdutils::MDPVersion::getInstance().getMDPVersion();
     ctx->mMDP.hasOverlay = qdutils::MDPVersion::getInstance().hasOverlay();
     ctx->mMDP.panel = qdutils::MDPVersion::getInstance().getPanelType();
-    const int rightSplit = qdutils::MDPVersion::getInstance().getRightSplit();
     overlay::Overlay::initOverlay();
     ctx->mOverlay = overlay::Overlay::getInstance();
     ctx->mRotMgr = new RotMgr();
@@ -138,8 +137,7 @@
     //For external it could get created and destroyed multiple times depending
     //on what external we connect to.
     ctx->mFBUpdate[HWC_DISPLAY_PRIMARY] =
-        IFBUpdate::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres,
-                rightSplit, HWC_DISPLAY_PRIMARY);
+        IFBUpdate::getObject(ctx, HWC_DISPLAY_PRIMARY);
 
     // Check if the target supports copybit compostion (dyn/mdp/c2d) to
     // decide if we need to open the copybit module.
@@ -164,8 +162,7 @@
     ctx->dpyAttr[HWC_DISPLAY_VIRTUAL].mDownScaleMode = false;
 
     ctx->mMDPComp[HWC_DISPLAY_PRIMARY] =
-         MDPComp::getObject(ctx->dpyAttr[HWC_DISPLAY_PRIMARY].xres,
-                rightSplit, HWC_DISPLAY_PRIMARY);
+         MDPComp::getObject(ctx, HWC_DISPLAY_PRIMARY);
     ctx->dpyAttr[HWC_DISPLAY_PRIMARY].connected = true;
 
     for (uint32_t i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
@@ -174,7 +171,7 @@
     }
 
     MDPComp::init(ctx);
-    ctx->mAD = new AssertiveDisplay();
+    ctx->mAD = new AssertiveDisplay(ctx);
 
     ctx->vstate.enable = false;
     ctx->vstate.fakevsync = false;
@@ -1193,7 +1190,7 @@
     }
 }
 
-int configureLowRes(hwc_context_t *ctx, hwc_layer_1_t *layer,
+int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy, eMdpFlags& mdpFlags, eZorder& z,
         eIsFg& isFg, const eDest& dest, Rotator **rot) {
 
@@ -1253,13 +1250,6 @@
     setMdpFlags(layer, mdpFlags, downscale, transform);
     trimLayer(ctx, dpy, transform, crop, dst);
 
-    //Will do something only if feature enabled and conditions suitable
-    //hollow call otherwise
-    if(ctx->mAD->prepare(ctx, crop, whf, hnd)) {
-        overlay::Writeback *wb = overlay::Writeback::getInstance();
-        whf.format = wb->getOutputFormat();
-    }
-
     if(isYuvBuffer(hnd) && //if 90 component or downscale, use rot
             ((transform & HWC_TRANSFORM_ROT_90) || downscale)) {
         *rot = ctx->mRotMgr->getNext();
@@ -1291,7 +1281,36 @@
     return 0;
 }
 
-int configureHighRes(hwc_context_t *ctx, hwc_layer_1_t *layer,
+//Helper to 1) Ensure crops dont have gaps 2) Ensure L and W are even
+static void sanitizeSourceCrop(hwc_rect_t& cropL, hwc_rect_t& cropR,
+        private_handle_t *hnd) {
+    if(cropL.right - cropL.left) {
+        if(isYuvBuffer(hnd)) {
+            //Always safe to even down left
+            ovutils::even_floor(cropL.left);
+            //If right is even, automatically width is even, since left is
+            //already even
+            ovutils::even_floor(cropL.right);
+        }
+        //Make sure there are no gaps between left and right splits if the layer
+        //is spread across BOTH halves
+        if(cropR.right - cropR.left) {
+            cropR.left = cropL.right;
+        }
+    }
+
+    if(cropR.right - cropR.left) {
+        if(isYuvBuffer(hnd)) {
+            //Always safe to even down left
+            ovutils::even_floor(cropR.left);
+            //If right is even, automatically width is even, since left is
+            //already even
+            ovutils::even_floor(cropR.right);
+        }
+    }
+}
+
+int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer,
         const int& dpy, eMdpFlags& mdpFlagsL, eZorder& z,
         eIsFg& isFg, const eDest& lDest, const eDest& rDest,
         Rotator **rot) {
@@ -1339,6 +1358,12 @@
 
 
     setMdpFlags(layer, mdpFlagsL, 0, transform);
+
+    if(lDest != OV_INVALID && rDest != OV_INVALID) {
+        //Enable overfetch
+        setMdpFlags(mdpFlagsL, OV_MDSS_MDP_DUAL_PIPE);
+    }
+
     trimLayer(ctx, dpy, transform, crop, dst);
 
     //Will do something only if feature enabled and conditions suitable
@@ -1366,8 +1391,8 @@
     eMdpFlags mdpFlagsR = mdpFlagsL;
     setMdpFlags(mdpFlagsR, OV_MDSS_MDP_RIGHT_MIXER);
 
-    hwc_rect_t tmp_cropL, tmp_dstL;
-    hwc_rect_t tmp_cropR, tmp_dstR;
+    hwc_rect_t tmp_cropL = {0}, tmp_dstL = {0};
+    hwc_rect_t tmp_cropR = {0}, tmp_dstR = {0};
 
     const int lSplit = getLeftSplit(ctx, dpy);
 
@@ -1384,6 +1409,8 @@
         qhwc::calculate_crop_rects(tmp_cropR, tmp_dstR, scissor, 0);
     }
 
+    sanitizeSourceCrop(tmp_cropL, tmp_cropR, hnd);
+
     //When buffer is H-flipped, contents of mixer config also needs to swapped
     //Not needed if the layer is confined to one half of the screen.
     //If rotator has been used then it has also done the flips, so ignore them.
@@ -1466,6 +1493,18 @@
     return lSplit;
 }
 
+bool isDisplaySplit(hwc_context_t* ctx, int dpy) {
+    if(ctx->dpyAttr[dpy].xres > qdutils::MAX_DISPLAY_DIM) {
+        return true;
+    }
+    //For testing we could split primary via device tree values
+    if(dpy == HWC_DISPLAY_PRIMARY &&
+        qdutils::MDPVersion::getInstance().getRightSplit()) {
+        return true;
+    }
+    return false;
+}
+
 void BwcPM::setBwc(hwc_context_t *ctx, const hwc_rect_t& crop,
             const hwc_rect_t& dst, const int& transform,
             ovutils::eMdpFlags& mdpFlags) {
diff --git a/libhwcomposer/hwc_utils.h b/libhwcomposer/hwc_utils.h
index 5695f28..d77673b 100644
--- a/libhwcomposer/hwc_utils.h
+++ b/libhwcomposer/hwc_utils.h
@@ -233,13 +233,13 @@
         hwc_rect_t& crop);
 
 //Routine to configure low resolution panels (<= 2048 width)
-int configureLowRes(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
+int configureNonSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
         ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
         ovutils::eIsFg& isFg, const ovutils::eDest& dest,
         overlay::Rotator **rot);
 
 //Routine to configure high resolution panels (> 2048 width)
-int configureHighRes(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
+int configureSplit(hwc_context_t *ctx, hwc_layer_1_t *layer, const int& dpy,
         ovutils::eMdpFlags& mdpFlags, ovutils::eZorder& z,
         ovutils::eIsFg& isFg, const ovutils::eDest& lDest,
         const ovutils::eDest& rDest, overlay::Rotator **rot);
@@ -254,6 +254,8 @@
 
 int getLeftSplit(hwc_context_t *ctx, const int& dpy);
 
+bool isDisplaySplit(hwc_context_t* ctx, int dpy);
+
 // Inline utility functions
 static inline bool isSkipLayer(const hwc_layer_1_t* l) {
     return (UNLIKELY(l && (l->flags & HWC_SKIP_LAYER)));
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index e49a50c..a9b7e6a 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -77,6 +77,10 @@
 #define MDP_OV_PIPE_FORCE_DMA 0x4000
 #endif
 
+#ifndef MDSS_MDP_DUAL_PIPE
+#define MDSS_MDP_DUAL_PIPE 0x200
+#endif
+
 #define FB_DEVICE_TEMPLATE "/dev/graphics/fb%u"
 
 namespace overlay {
@@ -265,6 +269,7 @@
     OV_MDSS_MDP_RIGHT_MIXER = MDSS_MDP_RIGHT_MIXER,
     OV_MDP_PP_EN = MDP_OVERLAY_PP_CFG_EN,
     OV_MDSS_MDP_BWC_EN = MDP_BWC_EN,
+    OV_MDSS_MDP_DUAL_PIPE = MDSS_MDP_DUAL_PIPE,
 };
 
 enum eZorder {
diff --git a/libqdutils/mdp_version.cpp b/libqdutils/mdp_version.cpp
index 1dd317f..4a695d3 100644
--- a/libqdutils/mdp_version.cpp
+++ b/libqdutils/mdp_version.cpp
@@ -166,5 +166,12 @@
     return false;
 }
 
+bool MDPVersion::is8x74v2() {
+    if( mMdpRev >= MDSS_MDP_HW_REV_102 && mMdpRev < MDSS_MDP_HW_REV_103) {
+        return true;
+    }
+    return false;
+}
+
 }; //namespace qdutils
 
diff --git a/libqdutils/mdp_version.h b/libqdutils/mdp_version.h
index 316899f..8d23b2d 100644
--- a/libqdutils/mdp_version.h
+++ b/libqdutils/mdp_version.h
@@ -54,9 +54,10 @@
 };
 
 enum mdp_rev {
-    MDSS_MDP_HW_REV_100 = 0x10000000,
+    MDSS_MDP_HW_REV_100 = 0x10000000, //8974 v1
     MDSS_MDP_HW_REV_101 = 0x10010000, //8x26
-    MDSS_MDP_HW_REV_102 = 0x10020000,
+    MDSS_MDP_HW_REV_102 = 0x10020000, //8974 v2
+    MDSS_MDP_HW_REV_103 = 0x10030000, //Future
 };
 
 enum {
@@ -101,6 +102,7 @@
     uint32_t getMaxMDPDownscale();
     bool supportsBWC();
     bool is8x26();
+    bool is8x74v2();
     int getLeftSplit() { return mSplit.left(); }
     int getRightSplit() { return mSplit.right(); }
 private: