hwc: Add support for perf display hint

- Set the perf hint when there is only one updating layer, which helps
  in reducing cpu params and thus reduce power.
- This feature is enabled with the property persist.mdpcomp_perfhint,
  which is set to a positive value, which will be the window of frames
  before the perf hint is set

CRs-fixed: 765460
Change-Id: Ie21e1cd201afab16bedd3c750ea3b0230769969a
diff --git a/libhwcomposer/hwc_mdpcomp.cpp b/libhwcomposer/hwc_mdpcomp.cpp
index a5bf0b5..569f5d1 100644
--- a/libhwcomposer/hwc_mdpcomp.cpp
+++ b/libhwcomposer/hwc_mdpcomp.cpp
@@ -19,6 +19,7 @@
 #include <math.h>
 #include "hwc_mdpcomp.h"
 #include <sys/ioctl.h>
+#include <dlfcn.h>
 #include "hdmi.h"
 #include "qdMetaData.h"
 #include "mdp_version.h"
@@ -50,6 +51,12 @@
 int MDPComp::sMaxSecLayers = 1;
 bool MDPComp::enablePartialUpdateForMDP3 = false;
 bool MDPComp::sIsPartialUpdateActive = true;
+void *MDPComp::sLibPerfHint = NULL;
+int MDPComp::sPerfLockHandle = 0;
+int (*MDPComp::sPerfLockAcquire)(int, int, int*, int) = NULL;
+int (*MDPComp::sPerfLockRelease)(int value) = NULL;
+int MDPComp::sPerfHintWindow = -1;
+
 MDPComp* MDPComp::getObject(hwc_context_t *ctx, const int& dpy) {
     if(qdutils::MDPVersion::getInstance().isSrcSplit()) {
         sSrcSplitEnabled = true;
@@ -194,6 +201,14 @@
 
     sIsPartialUpdateActive = getPartialUpdatePref(ctx);
 
+    if(property_get("persist.mdpcomp_perfhint", property, "-1") > 0) {
+        int val = atoi(property);
+        if(val > 0 && loadPerfLib()) {
+            sPerfHintWindow = val;
+            ALOGI("PerfHintWindow = %d", sPerfHintWindow);
+        }
+    }
+
     return true;
 }
 
@@ -1895,25 +1910,38 @@
     return true;
 }
 
+// Checks only if videos or single layer(RGB) is updating
+// which is used for setting dynamic fps or perf hint for single
+// layer video playback
+bool MDPComp::onlyVideosUpdating(hwc_context_t *ctx,
+                                hwc_display_contents_1_t* list) {
+    bool support = false;
+    FrameInfo frame;
+    frame.reset(mCurrentFrame.layerCount);
+    memset(&frame.drop, 0, sizeof(frame.drop));
+    frame.dropCount = 0;
+    ALOGD_IF(isDebug(), "%s: Update Cache and YUVInfo", __FUNCTION__);
+    updateLayerCache(ctx, list, frame);
+    updateYUV(ctx, list, false /*secure only*/, frame);
+    // There are only updating YUV layers or there is single RGB
+    // Layer(Youtube)
+    if((ctx->listStats[mDpy].yuvCount == frame.mdpCount) ||
+                                        (frame.layerCount == 1)) {
+        support = true;
+    }
+    return support;
+}
+
 void MDPComp::setDynRefreshRate(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
     //For primary display, set the dynamic refreshrate
     if(!mDpy && qdutils::MDPVersion::getInstance().isDynFpsSupported() &&
                                         ctx->mUseMetaDataRefreshRate) {
-        FrameInfo frame;
-        frame.reset(mCurrentFrame.layerCount);
-        memset(&frame.drop, 0, sizeof(frame.drop));
-        frame.dropCount = 0;
-        ALOGD_IF(isDebug(), "%s: Update Cache and YUVInfo for Dyn Refresh Rate",
-                 __FUNCTION__);
-        updateLayerCache(ctx, list, frame);
-        updateYUV(ctx, list, false /*secure only*/, frame);
         uint32_t refreshRate = ctx->dpyAttr[mDpy].refreshRate;
         MDPVersion& mdpHw = MDPVersion::getInstance();
         if(sIdleFallBack) {
             //Set minimum panel refresh rate during idle timeout
             refreshRate = mdpHw.getMinFpsSupported();
-        } else if((ctx->listStats[mDpy].yuvCount == frame.mdpCount) ||
-                                (frame.layerCount == 1)) {
+        } else if(onlyVideosUpdating(ctx, list)) {
             //Set the new fresh rate, if there is only one updating YUV layer
             //or there is one single RGB layer with this request
             refreshRate = ctx->listStats[mDpy].refreshRateRequest;
@@ -2031,6 +2059,7 @@
 #ifdef DYNAMIC_FPS
     setDynRefreshRate(ctx, list);
 #endif
+    setPerfHint(ctx, list);
 
     mCachedFrame.cacheAll(list);
     mCachedFrame.updateCounts(mCurrentFrame);
@@ -2817,5 +2846,66 @@
     sIsPartialUpdateActive = enable;
     return 0;
 }
+
+bool MDPComp::loadPerfLib() {
+    char perfLibPath[PROPERTY_VALUE_MAX] = {0};
+    bool success = false;
+    if((property_get("ro.vendor.extension_library", perfLibPath, NULL) <= 0)) {
+        ALOGE("vendor library not set in ro.vendor.extension_library");
+        return false;
+    }
+
+    sLibPerfHint = dlopen(perfLibPath, RTLD_NOW);
+    if(sLibPerfHint) {
+        *(void **)&sPerfLockAcquire = dlsym(sLibPerfHint, "perf_lock_acq");
+        *(void **)&sPerfLockRelease = dlsym(sLibPerfHint, "perf_lock_rel");
+        if (!sPerfLockAcquire || !sPerfLockRelease) {
+            ALOGE("Failed to load symbols for perfLock");
+            dlclose(sLibPerfHint);
+            sLibPerfHint = NULL;
+            return false;
+        }
+        success = true;
+        ALOGI("Successfully Loaded perf hint API's");
+    } else {
+        ALOGE("Failed to open %s : %s", perfLibPath, dlerror());
+    }
+    return success;
+}
+
+void MDPComp::setPerfHint(hwc_context_t *ctx, hwc_display_contents_1_t* list) {
+    if ((sPerfHintWindow < 0) || mDpy || !sLibPerfHint) {
+        return;
+    }
+    static int count = sPerfHintWindow;
+    static int perflockFlag = 0;
+
+    /* Send hint to mpctl when single layer is updated
+     * for a successful number of windows. Hint release
+     * happens immediately upon multiple layer update.
+     */
+    if (onlyVideosUpdating(ctx, list)) {
+        if(count) {
+            count--;
+        }
+    } else {
+        if (perflockFlag) {
+            perflockFlag = 0;
+            sPerfLockRelease(sPerfLockHandle);
+        }
+        count = sPerfHintWindow;
+    }
+    if (count == 0 && !perflockFlag) {
+        int perfHint = 0x4501; // 45-display layer hint, 01-Enable
+        sPerfLockHandle = sPerfLockAcquire(0 /*handle*/, 0/*duration*/,
+                                    &perfHint, sizeof(perfHint)/sizeof(int));
+        if(sPerfLockHandle < 0) {
+            ALOGE("Perf Lock Acquire Failed");
+        } else {
+            perflockFlag = 1;
+        }
+    }
+}
+
 }; //namespace