DO NOT MERGE - 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 (cherry-pick from master I00039c22a55750e74035644c63800e4bee1c774a) Change-Id: I9ef5539fa7da953dd97f88e7fa39be0dc20b6889
This commit is contained in:
parent
e950661f45
commit
740fde1f82
@ -53,10 +53,7 @@ class DispSyncThread: public Thread {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
DispSyncThread():
|
DispSyncThread():
|
||||||
mLowPowerMode(false),
|
|
||||||
mStop(false),
|
mStop(false),
|
||||||
mLastVsyncSent(false),
|
|
||||||
mLastBufferFull(false),
|
|
||||||
mPeriod(0),
|
mPeriod(0),
|
||||||
mPhase(0),
|
mPhase(0),
|
||||||
mWakeupLatency(0) {
|
mWakeupLatency(0) {
|
||||||
@ -140,18 +137,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (callbackInvocations.size() > 0) {
|
if (callbackInvocations.size() > 0) {
|
||||||
if (mLowPowerMode) {
|
fireCallbackInvocations(callbackInvocations);
|
||||||
if (!mLastVsyncSent || !mLastBufferFull) {
|
|
||||||
fireCallbackInvocations(callbackInvocations);
|
|
||||||
mLastVsyncSent = true;
|
|
||||||
} else
|
|
||||||
mLastVsyncSent = false;
|
|
||||||
} else {
|
|
||||||
fireCallbackInvocations(callbackInvocations);
|
|
||||||
}
|
|
||||||
mLastBufferFull = true;
|
|
||||||
} else {
|
|
||||||
mLastBufferFull = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +191,6 @@ public:
|
|||||||
return !mEventListeners.empty();
|
return !mEventListeners.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mLowPowerMode;
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct EventListener {
|
struct EventListener {
|
||||||
@ -278,8 +263,6 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool mStop;
|
bool mStop;
|
||||||
bool mLastVsyncSent;
|
|
||||||
bool mLastBufferFull;
|
|
||||||
|
|
||||||
nsecs_t mPeriod;
|
nsecs_t mPeriod;
|
||||||
nsecs_t mPhase;
|
nsecs_t mPhase;
|
||||||
@ -304,8 +287,10 @@ private:
|
|||||||
bool mParity;
|
bool mParity;
|
||||||
};
|
};
|
||||||
|
|
||||||
DispSync::DispSync() {
|
DispSync::DispSync() :
|
||||||
mThread = new DispSyncThread();
|
mRefreshSkipCount(0),
|
||||||
|
mThread(new DispSyncThread()) {
|
||||||
|
|
||||||
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
|
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
@ -404,8 +389,11 @@ status_t DispSync::addEventListener(nsecs_t phase,
|
|||||||
return mThread->addEventListener(phase, callback);
|
return mThread->addEventListener(phase, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispSync::setLowPowerMode(bool enabled) {
|
void DispSync::setRefreshSkipCount(int count) {
|
||||||
mThread->mLowPowerMode = enabled;
|
Mutex::Autolock lock(mMutex);
|
||||||
|
ALOGD("setRefreshSkipCount(%d)", count);
|
||||||
|
mRefreshSkipCount = count;
|
||||||
|
updateModelLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t DispSync::removeEventListener(const sp<Callback>& callback) {
|
status_t DispSync::removeEventListener(const sp<Callback>& callback) {
|
||||||
@ -456,6 +444,9 @@ void DispSync::updateModelLocked() {
|
|||||||
ATRACE_INT64("DispSync:Phase", mPhase);
|
ATRACE_INT64("DispSync:Phase", mPhase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Artificially inflate the period if requested.
|
||||||
|
mPeriod += mPeriod * mRefreshSkipCount;
|
||||||
|
|
||||||
mThread->updateModel(mPeriod, mPhase);
|
mThread->updateModel(mPeriod, mPhase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -465,15 +456,19 @@ void DispSync::updateErrorLocked() {
|
|||||||
return;
|
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;
|
int numErrSamples = 0;
|
||||||
nsecs_t sqErrSum = 0;
|
nsecs_t sqErrSum = 0;
|
||||||
|
|
||||||
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
|
for (size_t i = 0; i < NUM_PRESENT_SAMPLES; i++) {
|
||||||
nsecs_t sample = mPresentTimes[i];
|
nsecs_t sample = mPresentTimes[i];
|
||||||
if (sample > mPhase) {
|
if (sample > mPhase) {
|
||||||
nsecs_t sampleErr = (sample - mPhase) % mPeriod;
|
nsecs_t sampleErr = (sample - mPhase) % period;
|
||||||
if (sampleErr > mPeriod / 2) {
|
if (sampleErr > period / 2) {
|
||||||
sampleErr -= mPeriod;
|
sampleErr -= period;
|
||||||
}
|
}
|
||||||
sqErrSum += sampleErr * sampleErr;
|
sqErrSum += sampleErr * sampleErr;
|
||||||
numErrSamples++;
|
numErrSamples++;
|
||||||
@ -510,8 +505,8 @@ void DispSync::dump(String8& result) const {
|
|||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
result.appendFormat("present fences are %s\n",
|
result.appendFormat("present fences are %s\n",
|
||||||
kIgnorePresentFences ? "ignored" : "used");
|
kIgnorePresentFences ? "ignored" : "used");
|
||||||
result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps)\n",
|
result.appendFormat("mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n",
|
||||||
mPeriod, 1000000000.0 / mPeriod);
|
mPeriod, 1000000000.0 / mPeriod, mRefreshSkipCount);
|
||||||
result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase);
|
result.appendFormat("mPhase: %" PRId64 " ns\n", mPhase);
|
||||||
result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n",
|
result.appendFormat("mError: %" PRId64 " ns (sqrt=%.1f)\n",
|
||||||
mError, sqrt(mError));
|
mError, sqrt(mError));
|
||||||
|
@ -67,6 +67,7 @@ public:
|
|||||||
DispSync();
|
DispSync();
|
||||||
~DispSync();
|
~DispSync();
|
||||||
|
|
||||||
|
// reset clears the resync samples and error value.
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
// addPresentFence adds a fence for use in validating the current vsync
|
// 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.
|
// turned on. It should NOT be used after that.
|
||||||
void setPeriod(nsecs_t period);
|
void setPeriod(nsecs_t period);
|
||||||
|
|
||||||
// Setting the low power mode reduces the frame rate to half of the default
|
// setRefreshSkipCount specifies an additional number of refresh
|
||||||
void setLowPowerMode(bool enabled);
|
// 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
|
// addEventListener registers a callback to be called repeatedly at the
|
||||||
// given phase offset from the hardware vsync events. The callback is
|
// given phase offset from the hardware vsync events. The callback is
|
||||||
@ -161,6 +165,8 @@ private:
|
|||||||
nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES];
|
nsecs_t mPresentTimes[NUM_PRESENT_SAMPLES];
|
||||||
size_t mPresentSampleOffset;
|
size_t mPresentSampleOffset;
|
||||||
|
|
||||||
|
int mRefreshSkipCount;
|
||||||
|
|
||||||
// mThread is the thread from which all the callbacks are called.
|
// mThread is the thread from which all the callbacks are called.
|
||||||
sp<DispSyncThread> mThread;
|
sp<DispSyncThread> mThread;
|
||||||
|
|
||||||
|
@ -2682,11 +2682,8 @@ status_t SurfaceFlinger::onTransact(
|
|||||||
// This is an experimental interface
|
// This is an experimental interface
|
||||||
// Needs to be shifted to proper binder interface when we productize
|
// Needs to be shifted to proper binder interface when we productize
|
||||||
case 1016: {
|
case 1016: {
|
||||||
mPrimaryDispSync.setLowPowerMode(true);
|
n = data.readInt32();
|
||||||
return NO_ERROR;
|
mPrimaryDispSync.setRefreshSkipCount(n);
|
||||||
}
|
|
||||||
case 1017: {
|
|
||||||
mPrimaryDispSync.setLowPowerMode(false);
|
|
||||||
return NO_ERROR;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user