hwc: Add support for bandwidth check

Add support for checking whether the current frame's required
bandwidth can be handled by MDP.

The max limit is configurable via a property and the value is
derived from simulation runs and profiling

Conflicts:
	libhwcomposer/hwc_mdpcomp.cpp

Change-Id: I46b46c346973fcb6487a8a656268171470ce69b9
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index 85450d2..8956be5 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -42,6 +42,8 @@
 bool MDPComp::sEnabled = false;
 bool MDPComp::sEnableMixedMode = true;
 int MDPComp::sMaxPipesPerMixer = MAX_PIPES_PER_MIXER;
+float MDPComp::sMaxBw = 2.3f;
+uint32_t MDPComp::sCompBytesClaimed = 0;
 
 MDPComp* MDPComp::getObject(const int& width, const int& rightSplit,
         const int& dpy) {
@@ -125,6 +127,13 @@
             sMaxPipesPerMixer = min(val, MAX_PIPES_PER_MIXER);
     }
 
+    if(property_get("debug.mdpcomp.bw", property, "0") > 0) {
+        float val = atof(property);
+        if(val > 0.0f) {
+            sMaxBw = val;
+        }
+    }
+
     if(ctx->mMDP.panel != MIPI_CMD_PANEL) {
         // Idle invalidation is not necessary on command mode panels
         long idle_timeout = DEFAULT_IDLE_TIME;
@@ -497,6 +506,12 @@
         return false;
     }
 
+    uint32_t size = calcMDPBytesRead(ctx, list);
+    if(!bandwidthCheck(ctx, size)) {
+        ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
+        return false;
+    }
+
     return true;
 }
 
@@ -525,6 +540,12 @@
         return false;
     }
 
+    uint32_t size = calcMDPBytesRead(ctx, list);
+    if(!bandwidthCheck(ctx, size)) {
+        ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
+        return false;
+    }
+
     return true;
 }
 
@@ -552,6 +573,12 @@
         return false;
     }
 
+    uint32_t size = calcMDPBytesRead(ctx, list);
+    if(!bandwidthCheck(ctx, size)) {
+        ALOGD_IF(isDebug(), "%s: Exceeds bandwidth",__FUNCTION__);
+        return false;
+    }
+
     return true;
 }
 
@@ -753,7 +780,46 @@
     return true;
 }
 
+uint32_t MDPComp::calcMDPBytesRead(hwc_context_t *ctx,
+        hwc_display_contents_1_t* list) {
+    uint32_t size = 0;
+
+    for (uint32_t i = 0; i < list->numHwLayers - 1; i++) {
+        if(!mCurrentFrame.isFBComposed[i]) {
+            hwc_layer_1_t* layer = &list->hwLayers[i];
+            private_handle_t *hnd = (private_handle_t *)layer->handle;
+            hwc_rect_t crop = layer->sourceCrop;
+            float bpp = ((float)hnd->size) / (hnd->width * hnd->height);
+            size += bpp * ((crop.right - crop.left) *
+                    (crop.bottom - crop.top));
+        }
+    }
+
+    if(mCurrentFrame.fbCount) {
+        hwc_layer_1_t* layer = &list->hwLayers[list->numHwLayers - 1];
+        private_handle_t *hnd = (private_handle_t *)layer->handle;
+        size += hnd->size;
+    }
+
+    return size;
+}
+
+bool MDPComp::bandwidthCheck(hwc_context_t *ctx, const uint32_t& size) {
+    //Will be added for other targets if we run into bandwidth issues and when
+    //we have profiling data to set an upper limit.
+    if(qdutils::MDPVersion::getInstance().is8x74v2()) {
+        const uint32_t ONE_GIG = 1024 * 1024 * 1024;
+        double panelRefRate =
+                1000000000.0 / ctx->dpyAttr[mDpy].vsync_period;
+        if((size + sCompBytesClaimed) > ((sMaxBw / panelRefRate) * ONE_GIG)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 int MDPComp::prepare(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    int ret = 0;
     const int numLayers = ctx->listStats[mDpy].numAppLayers;
 
     //reset old data
@@ -765,7 +831,8 @@
         mCachedFrame.updateCounts(mCurrentFrame);
         ALOGD_IF(isDebug(), "%s: Number of App layers exceeded the limit ",
                 __FUNCTION__);
-        return -1;
+        ret = -1;
+        goto exit;
     }
 
     //Hard conditions, if not met, cannot do MDP comp
@@ -773,7 +840,8 @@
         ALOGD_IF( isDebug(),"%s: MDP Comp not possible for this frame",
                 __FUNCTION__);
         reset(numLayers, list);
-        return -1;
+        ret = -1;
+        goto exit;
     }
 
     //Check whether layers marked for MDP Composition is actually doable.
@@ -786,14 +854,16 @@
                 ALOGE("%s configure framebuffer failed", __func__);
                 reset(numLayers, list);
                 ctx->mOverlay->clear(mDpy);
-                return -1;
+                ret = -1;
+                goto exit;
             }
         }
         //Acquire and Program MDP pipes
         if(!programMDP(ctx, list)) {
             reset(numLayers, list);
             ctx->mOverlay->clear(mDpy);
-            return -1;
+            ret = -1;
+            goto exit;
         } else { //Success
             //Any change in composition types needs an FB refresh
             mCurrentFrame.needsRedraw = false;
@@ -825,17 +895,20 @@
                 ALOGE("%s configure framebuffer failed", __func__);
                 reset(numLayers, list);
                 ctx->mOverlay->clear(mDpy);
-                return -1;
+                ret = -1;
+                goto exit;
             }
         }
         if(!programYUV(ctx, list)) {
             reset(numLayers, list);
             ctx->mOverlay->clear(mDpy);
-            return -1;
+            ret = -1;
+            goto exit;
         }
     } else {
         reset(numLayers, list);
-        return -1;
+        ret = -1;
+        goto exit;
     }
 
     //UpdateLayerFlags
@@ -850,7 +923,9 @@
         ALOGE("%s",sDump.string());
     }
 
-    return 0;
+exit:
+    sCompBytesClaimed += calcMDPBytesRead(ctx, list);
+    return ret;
 }
 
 //=============MDPCompLowRes===================================================