OSDN Git Service

DO NOT MERGE - Replace "lower power mode" experiment
authorAndy McFadden <fadden@android.com>
Tue, 10 Jun 2014 21:43:32 +0000 (14:43 -0700)
committerRuchi Kandoi <kandoiruchi@google.com>
Thu, 12 Jun 2014 01:34:41 +0000 (01:34 +0000)
This replaces the previous low-power mode experiment, which
discarded refresh events, with a new experiment that alters
the refresh period.

(see also I2849e5ea335c0d2509fea1c315392bce7f20451d )

The feature is enabled by specifying a nonzero value for the
"refresh skip count", which indicates the number of periods
to skip.  For example, the command:

  adb shell service call SurfaceFlinger 1016 i32 1

sets a skip count of '1', yielding a 30Hz refresh rate on a device
with a 60Hz display.  Changing the last value to '2' would set the
refresh to 20Hz.  '0' returns to the default behavior.

Bug 15523257

(cherry-pick from master I00039c22a55750e74035644c63800e4bee1c774a)

Change-Id: I9ef5539fa7da953dd97f88e7fa39be0dc20b6889

services/surfaceflinger/DispSync.cpp
services/surfaceflinger/DispSync.h
services/surfaceflinger/SurfaceFlinger.cpp

index c60834e..12da9a5 100644 (file)
@@ -53,10 +53,7 @@ class DispSyncThread: public Thread {
 public:
 
     DispSyncThread():
-            mLowPowerMode(false),
             mStop(false),
-            mLastVsyncSent(false),
-            mLastBufferFull(false),
             mPeriod(0),
             mPhase(0),
             mWakeupLatency(0) {
@@ -140,18 +137,7 @@ public:
             }
 
             if (callbackInvocations.size() > 0) {
-                if (mLowPowerMode) {
-                    if (!mLastVsyncSent || !mLastBufferFull) {
-                        fireCallbackInvocations(callbackInvocations);
-                        mLastVsyncSent = true;
-                    } else
-                        mLastVsyncSent = false;
-                } else {
-                    fireCallbackInvocations(callbackInvocations);
-                }
-                mLastBufferFull = true;
-            } else {
-                mLastBufferFull = false;
+                fireCallbackInvocations(callbackInvocations);
             }
         }
 
@@ -205,7 +191,6 @@ public:
         return !mEventListeners.empty();
     }
 
-    bool mLowPowerMode;
 private:
 
     struct EventListener {
@@ -278,8 +263,6 @@ private:
     }
 
     bool mStop;
-    bool mLastVsyncSent;
-    bool mLastBufferFull;
 
     nsecs_t mPeriod;
     nsecs_t mPhase;
@@ -304,8 +287,10 @@ private:
     bool mParity;
 };
 
-DispSync::DispSync() {
-    mThread = new DispSyncThread();
+DispSync::DispSync() :
+        mRefreshSkipCount(0),
+        mThread(new DispSyncThread()) {
+
     mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
 
     reset();
@@ -404,8 +389,11 @@ status_t DispSync::addEventListener(nsecs_t phase,
     return mThread->addEventListener(phase, callback);
 }
 
-void DispSync::setLowPowerMode(bool enabled) {
-    mThread->mLowPowerMode = enabled;
+void DispSync::setRefreshSkipCount(int count) {
+    Mutex::Autolock lock(mMutex);
+    ALOGD("setRefreshSkipCount(%d)", count);
+    mRefreshSkipCount = count;
+    updateModelLocked();
 }
 
 status_t DispSync::removeEventListener(const sp<Callback>& callback) {
@@ -456,6 +444,9 @@ void DispSync::updateModelLocked() {
             ATRACE_INT64("DispSync:Phase", mPhase);
         }
 
+        // Artificially inflate the period if requested.
+        mPeriod += mPeriod * mRefreshSkipCount;
+
         mThread->updateModel(mPeriod, mPhase);
     }
 }
@@ -465,15 +456,19 @@ void DispSync::updateErrorLocked() {
         return;
     }
 
+    // Need to compare present fences against the un-adjusted refresh period,
+    // since they might arrive between two events.
+    nsecs_t period = mPeriod / (1 + mRefreshSkipCount);
+
     int numErrSamples = 0;
     nsecs_t sqErrSum = 0;
 
     for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
         nsecs_t sample = mPresentTimes[i];
         if (sample > mPhase) {
-            nsecs_t sampleErr = (sample - mPhase) % mPeriod;
-            if (sampleErr > mPeriod / 2) {
-                sampleErr -= mPeriod;
+            nsecs_t sampleErr = (sample - mPhase) % period;
+            if (sampleErr > period / 2) {
+                sampleErr -= period;
             }
             sqErrSum += sampleErr * sampleErr;
             numErrSamples++;
@@ -510,8 +505,8 @@ void DispSync::dump(String8& result) const {
     Mutex::Autolock lock(mMutex);
     result.appendFormat("present fences are %s\n",
             kIgnorePresentFences ? "ignored" : "used");
-    result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps)\n",
-            mPeriod, 1000000000.0 / mPeriod);
+    result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n",
+            mPeriod, 1000000000.0 / mPeriod, mRefreshSkipCount);
     result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase);
     result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n",
             mError, sqrt(mError));
index 5106bc8..7a26df3 100644 (file)
@@ -67,6 +67,7 @@ public:
     DispSync();
     ~DispSync();
 
+    // reset clears the resync samples and error value.
     void reset();
 
     // addPresentFence adds a fence for use in validating the current vsync
@@ -100,8 +101,11 @@ public:
     // turned on.  It should NOT be used after that.
     void setPeriod(nsecs_t period);
 
-    // Setting the low power mode reduces the frame rate to half of the default
-    void setLowPowerMode(bool enabled);
+    // setRefreshSkipCount specifies an additional number of refresh
+    // cycles to skip.  For example, on a 60Hz display, a skip count of 1
+    // will result in events happening at 30Hz.  Default is zero.  The idea
+    // is to sacrifice smoothness for battery life.
+    void setRefreshSkipCount(int count);
 
     // addEventListener registers a callback to be called repeatedly at the
     // given phase offset from the hardware vsync events.  The callback is
@@ -161,6 +165,8 @@ private:
     nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES];
     size_t mPresentSampleOffset;
 
+    int mRefreshSkipCount;
+
     // mThread is the thread from which all the callbacks are called.
     sp<DispSyncThread> mThread;
 
index 1d7c3c6..13953a2 100644 (file)
@@ -2682,11 +2682,8 @@ status_t SurfaceFlinger::onTransact(
             // This is an experimental interface
             // Needs to be shifted to proper binder interface when we productize
             case 1016: {
-                mPrimaryDispSync.setLowPowerMode(true);
-                return NO_ERROR;
-            }
-            case 1017: {
-                mPrimaryDispSync.setLowPowerMode(false);
+                n = data.readInt32();
+                mPrimaryDispSync.setRefreshSkipCount(n);
                 return NO_ERROR;
             }
         }