public:
DispSyncThread():
- mLowPowerMode(false),
mStop(false),
- mLastVsyncSent(false),
- mLastBufferFull(false),
mPeriod(0),
mPhase(0),
mWakeupLatency(0) {
}
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);
}
}
return !mEventListeners.empty();
}
- bool mLowPowerMode;
private:
struct EventListener {
}
bool mStop;
- bool mLastVsyncSent;
- bool mLastBufferFull;
nsecs_t mPeriod;
nsecs_t mPhase;
bool mParity;
};
-DispSync::DispSync() {
- mThread = new DispSyncThread();
+DispSync::DispSync() :
+ mRefreshSkipCount(0),
+ mThread(new DispSyncThread()) {
+
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
reset();
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) {
ATRACE_INT64("DispSync:Phase", mPhase);
}
+ // Artificially inflate the period if requested.
+ mPeriod += mPeriod * mRefreshSkipCount;
+
mThread->updateModel(mPeriod, mPhase);
}
}
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++;
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));
DispSync();
~DispSync();
+ // reset clears the resync samples and error value.
void reset();
// addPresentFence adds a fence for use in validating the current vsync
// 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
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;