Correct DispSync model when registering listeners
* First event should be mapped to a predicted last event time
* Phase offset timing should be lock-step with the period update.
Bug: 124383894
Test: systrace
Change-Id: I742b30a8d28780a44592c4d3077f33d23cf65789
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 798d1a4..5b08aab 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -201,8 +201,26 @@
listener.mCallback = callback;
// We want to allow the firstmost future event to fire without
- // allowing any past events to fire
- listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;
+ // allowing any past events to fire. To do this extrapolate from
+ // mReferenceTime the most recent hardware vsync, and pin the
+ // last event time there.
+ const nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
+ if (mPeriod != 0) {
+ const nsecs_t baseTime = now - mReferenceTime;
+ const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
+ const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
+ const nsecs_t phaseCorrection = mPhase + listener.mPhase;
+ const nsecs_t predictedLastEventTime = predictedReference + phaseCorrection;
+ if (predictedLastEventTime > now) {
+ // Make sure that the last event time does not exceed the current time.
+ // If it would, then back the last event time by a period.
+ listener.mLastEventTime = predictedLastEventTime - mPeriod;
+ } else {
+ listener.mLastEventTime = predictedLastEventTime;
+ }
+ } else {
+ listener.mLastEventTime = now + mPhase - mWakeupLatency;
+ }
mEventListeners.push_back(listener);