SF: more DispSync improvements.
Pass the reference time to DispSyncThread. Since the phase offset is calculated using timestamps relative to the reference time, we must also adjust the phase offset by the same reference time when computing the next refresh time. Always reset phase offset to zero when updating the reference time because the reference time equals the first timestamp. After beginResync() we need to keep HW vsync enabled until the model is updated. Bug: 25113115 Change-Id: I8eae227bee91c24a99bf8e57fbebceb98d29c77d Test: check in systrace that app/sf vsync events have correct phase
This commit is contained in:
parent
95cda3b92f
commit
179bd77ab6
@ -57,15 +57,17 @@ public:
|
|||||||
mStop(false),
|
mStop(false),
|
||||||
mPeriod(0),
|
mPeriod(0),
|
||||||
mPhase(0),
|
mPhase(0),
|
||||||
|
mReferenceTime(0),
|
||||||
mWakeupLatency(0) {
|
mWakeupLatency(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~DispSyncThread() {}
|
virtual ~DispSyncThread() {}
|
||||||
|
|
||||||
void updateModel(nsecs_t period, nsecs_t phase) {
|
void updateModel(nsecs_t period, nsecs_t phase, nsecs_t referenceTime) {
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
mPeriod = period;
|
mPeriod = period;
|
||||||
mPhase = phase;
|
mPhase = phase;
|
||||||
|
mReferenceTime = referenceTime;
|
||||||
mCond.signal();
|
mCond.signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,7 +249,7 @@ private:
|
|||||||
ref = lastEventTime;
|
ref = lastEventTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsecs_t phase = mPhase + listener.mPhase;
|
nsecs_t phase = mReferenceTime + mPhase + listener.mPhase;
|
||||||
nsecs_t t = (((ref - phase) / mPeriod) + 1) * mPeriod + phase;
|
nsecs_t t = (((ref - phase) / mPeriod) + 1) * mPeriod + phase;
|
||||||
|
|
||||||
if (t - listener.mLastEventTime < mPeriod / 2) {
|
if (t - listener.mLastEventTime < mPeriod / 2) {
|
||||||
@ -267,6 +269,7 @@ private:
|
|||||||
|
|
||||||
nsecs_t mPeriod;
|
nsecs_t mPeriod;
|
||||||
nsecs_t mPhase;
|
nsecs_t mPhase;
|
||||||
|
nsecs_t mReferenceTime;
|
||||||
nsecs_t mWakeupLatency;
|
nsecs_t mWakeupLatency;
|
||||||
|
|
||||||
Vector<EventListener> mEventListeners;
|
Vector<EventListener> mEventListeners;
|
||||||
@ -315,9 +318,11 @@ DispSync::~DispSync() {}
|
|||||||
void DispSync::reset() {
|
void DispSync::reset() {
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
|
|
||||||
|
mPhase = 0;
|
||||||
|
mReferenceTime = 0;
|
||||||
|
mModelUpdated = false;
|
||||||
mNumResyncSamples = 0;
|
mNumResyncSamples = 0;
|
||||||
mFirstResyncSample = 0;
|
mFirstResyncSample = 0;
|
||||||
mResyncReferenceTime = 0;
|
|
||||||
mNumResyncSamplesSincePresent = 0;
|
mNumResyncSamplesSincePresent = 0;
|
||||||
resetErrorLocked();
|
resetErrorLocked();
|
||||||
}
|
}
|
||||||
@ -343,12 +348,13 @@ bool DispSync::addPresentFence(const sp<Fence>& fence) {
|
|||||||
|
|
||||||
updateErrorLocked();
|
updateErrorLocked();
|
||||||
|
|
||||||
return mPeriod == 0 || mError > kErrorThreshold;
|
return !mModelUpdated || mError > kErrorThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispSync::beginResync() {
|
void DispSync::beginResync() {
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
|
|
||||||
|
mModelUpdated = false;
|
||||||
mNumResyncSamples = 0;
|
mNumResyncSamples = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,7 +364,8 @@ bool DispSync::addResyncSample(nsecs_t timestamp) {
|
|||||||
size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
|
size_t idx = (mFirstResyncSample + mNumResyncSamples) % MAX_RESYNC_SAMPLES;
|
||||||
mResyncSamples[idx] = timestamp;
|
mResyncSamples[idx] = timestamp;
|
||||||
if (mNumResyncSamples == 0) {
|
if (mNumResyncSamples == 0) {
|
||||||
mResyncReferenceTime = timestamp;
|
mPhase = 0;
|
||||||
|
mReferenceTime = timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
|
if (mNumResyncSamples < MAX_RESYNC_SAMPLES) {
|
||||||
@ -382,7 +389,7 @@ bool DispSync::addResyncSample(nsecs_t timestamp) {
|
|||||||
return mThread->hasAnyEventListeners();
|
return mThread->hasAnyEventListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
return mPeriod == 0 || mError > kErrorThreshold;
|
return !mModelUpdated || mError > kErrorThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispSync::endResync() {
|
void DispSync::endResync() {
|
||||||
@ -411,7 +418,8 @@ void DispSync::setPeriod(nsecs_t period) {
|
|||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
mPeriod = period;
|
mPeriod = period;
|
||||||
mPhase = 0;
|
mPhase = 0;
|
||||||
mThread->updateModel(mPeriod, mPhase);
|
mReferenceTime = 0;
|
||||||
|
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsecs_t DispSync::getPeriod() {
|
nsecs_t DispSync::getPeriod() {
|
||||||
@ -436,7 +444,7 @@ void DispSync::updateModelLocked() {
|
|||||||
double scale = 2.0 * M_PI / double(mPeriod);
|
double scale = 2.0 * M_PI / double(mPeriod);
|
||||||
for (size_t i = 0; i < mNumResyncSamples; i++) {
|
for (size_t i = 0; i < mNumResyncSamples; i++) {
|
||||||
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
|
size_t idx = (mFirstResyncSample + i) % MAX_RESYNC_SAMPLES;
|
||||||
nsecs_t sample = mResyncSamples[idx] - mResyncReferenceTime;
|
nsecs_t sample = mResyncSamples[idx] - mReferenceTime;
|
||||||
double samplePhase = double(sample % mPeriod) * scale;
|
double samplePhase = double(sample % mPeriod) * scale;
|
||||||
sampleAvgX += cos(samplePhase);
|
sampleAvgX += cos(samplePhase);
|
||||||
sampleAvgY += sin(samplePhase);
|
sampleAvgY += sin(samplePhase);
|
||||||
@ -459,12 +467,13 @@ void DispSync::updateModelLocked() {
|
|||||||
// Artificially inflate the period if requested.
|
// Artificially inflate the period if requested.
|
||||||
mPeriod += mPeriod * mRefreshSkipCount;
|
mPeriod += mPeriod * mRefreshSkipCount;
|
||||||
|
|
||||||
mThread->updateModel(mPeriod, mPhase);
|
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
|
||||||
|
mModelUpdated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispSync::updateErrorLocked() {
|
void DispSync::updateErrorLocked() {
|
||||||
if (mPeriod == 0) {
|
if (!mModelUpdated) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,7 +485,7 @@ void DispSync::updateErrorLocked() {
|
|||||||
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] - mResyncReferenceTime;
|
nsecs_t sample = mPresentTimes[i] - mReferenceTime;
|
||||||
if (sample > mPhase) {
|
if (sample > mPhase) {
|
||||||
nsecs_t sampleErr = (sample - mPhase) % period;
|
nsecs_t sampleErr = (sample - mPhase) % period;
|
||||||
if (sampleErr > period / 2) {
|
if (sampleErr > period / 2) {
|
||||||
@ -510,7 +519,8 @@ void DispSync::resetErrorLocked() {
|
|||||||
nsecs_t DispSync::computeNextRefresh(int periodOffset) const {
|
nsecs_t DispSync::computeNextRefresh(int periodOffset) const {
|
||||||
Mutex::Autolock lock(mMutex);
|
Mutex::Autolock lock(mMutex);
|
||||||
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
|
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
|
||||||
return (((now - mPhase) / mPeriod) + periodOffset + 1) * mPeriod + mPhase;
|
nsecs_t phase = mReferenceTime + mPhase;
|
||||||
|
return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DispSync::dump(String8& result) const {
|
void DispSync::dump(String8& result) const {
|
||||||
|
@ -146,15 +146,21 @@ private:
|
|||||||
// number of nanoseconds from time 0 to the first vsync event.
|
// number of nanoseconds from time 0 to the first vsync event.
|
||||||
nsecs_t mPhase;
|
nsecs_t mPhase;
|
||||||
|
|
||||||
|
// mReferenceTime is the reference time of the modeled vsync events.
|
||||||
|
// It is the nanosecond timestamp of the first vsync event after a resync.
|
||||||
|
nsecs_t mReferenceTime;
|
||||||
|
|
||||||
// mError is the computed model error. It is based on the difference
|
// mError is the computed model error. It is based on the difference
|
||||||
// between the estimated vsync event times and those observed in the
|
// between the estimated vsync event times and those observed in the
|
||||||
// mPresentTimes array.
|
// mPresentTimes array.
|
||||||
nsecs_t mError;
|
nsecs_t mError;
|
||||||
|
|
||||||
|
// Whether we have updated the vsync event model since the last resync.
|
||||||
|
bool mModelUpdated;
|
||||||
|
|
||||||
// These member variables are the state used during the resynchronization
|
// These member variables are the state used during the resynchronization
|
||||||
// process to store information about the hardware vsync event times used
|
// process to store information about the hardware vsync event times used
|
||||||
// to compute the model.
|
// to compute the model.
|
||||||
nsecs_t mResyncReferenceTime;
|
|
||||||
nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES];
|
nsecs_t mResyncSamples[MAX_RESYNC_SAMPLES];
|
||||||
size_t mFirstResyncSample;
|
size_t mFirstResyncSample;
|
||||||
size_t mNumResyncSamples;
|
size_t mNumResyncSamples;
|
||||||
|
Loading…
Reference in New Issue
Block a user