Replace "lower power mode" experiment
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 Change-Id: I00039c22a55750e74035644c63800e4bee1c774a
This commit is contained in:
parent
5167ec68fe
commit
645b1f7ffb
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user