When adding event listener, use fuzzy window for last event time.
* We track the last callback time anyways, so there's no risk of
double-firing
* Without this we might risk missing a dispsync event. E.g., if vsyncs
are at T and T+11, and we're considering SF events with +1 offset, then
SF will fire at T+1. If we immediately deregister the SF listener, then
re-register later at T+13, we miss the event at T+12. But we would
probably be ok to fire at T+13 anyways.
Note that the old last event time inference did allow for this.
See change I742b30a8d28780a44592c4d3077f33d23cf65789...
listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;
...with +2/+6 offsets and 16.6ms period, then if SF registers at +7ms
after vsync, then last event time is inferred to be T-1.3ms, and with
reference time T-16.6ms, then the next computed event time ends up being
(floor(((T-1.3) - (T-16.6) - 6)/16.6) + 1)* 16.6 + 6 + T-16.6, which ends up
being T+6ms, which would immediately cause a wakeup. So this change
reintroduces that behavior while keeping the math right.
Bug: 128918820
Test: systrace
Change-Id: If45be5a579628045ba3d9bfe282bf8831fdb5275
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 5296da9..43fe32b 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -211,13 +211,14 @@
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;
+ listener.mLastEventTime = predictedReference + phaseCorrection;
+ // If we're very close in time to the predicted last event time,
+ // then we need to back up the last event time so that we can
+ // attempt to fire an event immediately.
+ //
+ // Otherwise, keep the last event time that we predicted.
+ if (isShorterThanPeriod(now - listener.mLastEventTime)) {
+ listener.mLastEventTime -= mPeriod;
}
} else {
listener.mLastEventTime = now + mPhase - mWakeupLatency;
@@ -314,7 +315,7 @@
// Sanity check that the duration is close enough in length to a period without
// falling into double-rate vsyncs.
- bool isCloseToPeriod(nsecs_t duration) {
+ bool isShorterThanPeriod(nsecs_t duration) {
// Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
return duration < (3 * mPeriod) / 5;
}
@@ -330,7 +331,7 @@
nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
if (t < now) {
- if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
+ if (isShorterThanPeriod(now - eventListener.mLastCallbackTime)) {
eventListener.mLastEventTime = t;
eventListener.mLastCallbackTime = now;
ALOGV("[%s] [%s] Skipping event due to model error", mName,
@@ -391,7 +392,7 @@
// Check that it's been slightly more than half a period since the last
// event so that we don't accidentally fall into double-rate vsyncs
- if (isCloseToPeriod(t - listener.mLastEventTime)) {
+ if (isShorterThanPeriod(t - listener.mLastEventTime)) {
t += mPeriod;
ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
}