hwc: Avoid redoing GPU comp under certain conditions

* When the ambient light changes, pp-daemon will invoke multiple
screen-refresh cycles for LUT convergence needed for
PP algorithms.

* When this happens during static screen usecase, there would
be frequent switches from gpu-comp(due to idlescreen-fallback)
to mdpcomp and back. This results in increase in power numbers
due to increased composition cycles.

* To resolve this, do the following:

a) If frame 'n' is composed using GPU and frame 'n+1' is same
as frame 'n' in terms of input layers contents, avoid any
composition needed for frame 'n+1'. Mark the composition type
for all the layers as HWC_OVERLAY and push the GPU composed
content of frame 'n' for 'n+1' too.

b) Donot do (a) if the any of the incoming layers is marked as
skip or HWC_GEOMETRY_CHANGED flag is set in layer list.

c) Limit (a) to only primary and when secondary is not connected
so that display output expectations during secondary pause-resume
can be met.

* This saves ~10ma during static screen usecase when ambient
light is frequently changing.

Change-Id: I6ca4ab3bf194ffe71191cc661086a14d3e2c26b3
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index b130193..f6d8276 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -40,7 +40,6 @@
 
 IdleInvalidator *MDPComp::sIdleInvalidator = NULL;
 bool MDPComp::sIdleFallBack = false;
-bool MDPComp::sHandleTimeout = false;
 bool MDPComp::sDebugLogs = false;
 bool MDPComp::sEnabled = false;
 bool MDPComp::sEnableMixedMode = true;
@@ -220,12 +219,13 @@
 }
 
 void MDPComp::reset() {
-    sHandleTimeout = false;
+    mPrevModeOn = mModeOn;
     mModeOn = false;
 }
 
 void MDPComp::timeout_handler(void *udata) {
     struct hwc_context_t* ctx = (struct hwc_context_t*)(udata);
+    bool handleTimeout = false;
 
     if(!ctx) {
         ALOGE("%s: received empty data in timer callback", __FUNCTION__);
@@ -233,8 +233,16 @@
     }
 
     ctx->mDrawLock.lock();
-    // Handle timeout event only if the previous composition is MDP or MIXED.
-    if(!sHandleTimeout) {
+
+    /* Handle timeout event only if the previous composition
+       on any display is MDP or MIXED*/
+    for(int i = 0; i < HWC_NUM_DISPLAY_TYPES; i++) {
+        if(ctx->mMDPComp[i])
+            handleTimeout =
+                    ctx->mMDPComp[i]->isMDPComp() || handleTimeout;
+    }
+
+    if(!handleTimeout) {
         ALOGD_IF(isDebug(), "%s:Do not handle this timeout", __FUNCTION__);
         ctx->mDrawLock.unlock();
         return;
@@ -387,6 +395,25 @@
     return true;
 }
 
+bool MDPComp::LayerCache::isSameFrame(hwc_context_t *ctx, int dpy,
+                                      hwc_display_contents_1_t* list) {
+
+    if(layerCount != ctx->listStats[dpy].numAppLayers)
+        return false;
+
+    if((list->flags & HWC_GEOMETRY_CHANGED) ||
+       isSkipPresent(ctx, dpy)) {
+        return false;
+    }
+
+    for(int i = 0; i < layerCount; i++) {
+        if(hnd[i] != list->hwLayers[i].handle)
+            return false;
+    }
+
+    return true;
+}
+
 bool MDPComp::isSupportedForMDPComp(hwc_context_t *ctx, hwc_layer_1_t* layer) {
     private_handle_t *hnd = (private_handle_t *)layer->handle;
     if((has90Transform(layer) and (not isRotationDoable(ctx, hnd))) ||
@@ -2036,6 +2063,20 @@
         ctx->mAnimationState[mDpy] = ANIMATION_STOPPED;
     }
 
+    if(!mDpy and !isSecondaryConnected(ctx) and !mPrevModeOn and
+       mCachedFrame.isSameFrame(ctx,mDpy,list)) {
+
+        ALOGD_IF(isDebug(),"%s: Avoid new composition",__FUNCTION__);
+        mCurrentFrame.needsRedraw = false;
+        setMDPCompLayerFlags(ctx, list);
+        mCachedFrame.updateCounts(mCurrentFrame);
+#ifdef DYNAMIC_FPS
+        setDynRefreshRate(ctx, list);
+#endif
+        return -1;
+
+    }
+
     //Hard conditions, if not met, cannot do MDP comp
     if(isFrameDoable(ctx)) {
         generateROI(ctx, list);
@@ -2245,11 +2286,6 @@
         return true;
     }
 
-    // Set the Handle timeout to true for MDP or MIXED composition.
-    if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount) {
-        sHandleTimeout = true;
-    }
-
     overlay::Overlay& ov = *ctx->mOverlay;
     LayerProp *layerProp = ctx->layerProp[mDpy];
 
@@ -2507,13 +2543,6 @@
         return true;
     }
 
-    // Set the Handle timeout to true for MDP or MIXED composition.
-    if(sIdleInvalidator && !sIdleFallBack && mCurrentFrame.mdpCount &&
-            !(needs3DComposition(ctx, HWC_DISPLAY_PRIMARY) ||
-                needs3DComposition(ctx, HWC_DISPLAY_EXTERNAL))) {
-        sHandleTimeout = true;
-    }
-
     overlay::Overlay& ov = *ctx->mOverlay;
     LayerProp *layerProp = ctx->layerProp[mDpy];
 
diff --git a/libhwcomposer/hwc_mdpcomp.h b/libhwcomposer/hwc_mdpcomp.h
index 7752384..676bf24 100644
--- a/libhwcomposer/hwc_mdpcomp.h
+++ b/libhwcomposer/hwc_mdpcomp.h
@@ -45,6 +45,7 @@
     /* dumpsys */
     void dump(android::String8& buf, hwc_context_t *ctx);
     bool isGLESOnlyComp() { return (mCurrentFrame.mdpCount == 0); }
+    bool isMDPComp() { return mModeOn; }
     int drawOverlap(hwc_context_t *ctx, hwc_display_contents_1_t* list);
     static MDPComp* getObject(hwc_context_t *ctx, const int& dpy);
     /* Handler to invoke frame redraw on Idle Timer expiry */
@@ -141,6 +142,8 @@
         void updateCounts(const FrameInfo&);
         bool isSameFrame(const FrameInfo& curFrame,
                          hwc_display_contents_1_t* list);
+        bool isSameFrame(hwc_context_t *ctx, int dpy,
+                                        hwc_display_contents_1_t* list);
     };
 
     /* allocates pipe from pipe book */
@@ -260,8 +263,6 @@
     static int sSimulationFlags;
     static bool sDebugLogs;
     static bool sIdleFallBack;
-    /* Handles the timeout event from kernel, if the value is set to true */
-    static bool sHandleTimeout;
     static int sMaxPipesPerMixer;
     static bool sSrcSplitEnabled;
     static IdleInvalidator *sIdleInvalidator;
@@ -273,6 +274,7 @@
     static bool sEnableYUVsplit;
     bool mModeOn; // if prepare happened
     bool allocSplitVGPipes(hwc_context_t *ctx, int index);
+    bool mPrevModeOn; //if previous prepare happened
     //Enable Partial Update for MDP3 targets
     static bool enablePartialUpdateForMDP3;
     static void *sLibPerfHint;