SurfaceFlinger: fix reference time for transactions
Sometimes the reference time used when applying the transaction
is incorrect as the expected present time calculated in the past
is just before the real vsync. This fix is adding half vsync period
to the previous expected present time to avoid this.
Bug: 170502573
Test: atest FrameRateOverrideHostTest
Change-Id: Ib90238810a2f6a82e04a4375ea347f8e05425775
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5d08328..89442ac 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1440,7 +1440,9 @@
status_t SurfaceFlinger::injectVSync(nsecs_t when) {
Mutex::Autolock lock(mStateLock);
- const auto expectedPresent = calculateExpectedPresentTime(when);
+ DisplayStatInfo stats;
+ mScheduler->getDisplayStatInfo(&stats, when);
+ const auto expectedPresent = calculateExpectedPresentTime(stats);
return mScheduler->injectVSync(when, /*expectedVSyncTime=*/expectedPresent,
/*deadlineTimestamp=*/expectedPresent)
? NO_ERROR
@@ -1719,9 +1721,7 @@
return fence->getSignalTime();
}
-nsecs_t SurfaceFlinger::calculateExpectedPresentTime(nsecs_t now) const {
- DisplayStatInfo stats;
- mScheduler->getDisplayStatInfo(&stats, now);
+nsecs_t SurfaceFlinger::calculateExpectedPresentTime(DisplayStatInfo stats) const {
// Inflate the expected present time if we're targetting the next vsync.
return mVsyncModulator->getVsyncConfig().sfOffset > 0 ? stats.vsyncTime
: stats.vsyncTime + stats.vsyncPeriod;
@@ -3362,11 +3362,17 @@
const bool pendingTransactions = itr != mTransactionQueues.end();
// Expected present time is computed and cached on invalidate, so it may be stale.
if (!pendingTransactions) {
+ const auto now = systemTime();
+ const bool nextVsyncPending = now < mExpectedPresentTime.load();
+ DisplayStatInfo stats;
+ mScheduler->getDisplayStatInfo(&stats, now);
+ mExpectedPresentTime = calculateExpectedPresentTime(stats);
// The transaction might arrive just before the next vsync but after
// invalidate was called. In that case we need to get the next vsync
// afterwards.
- const auto referenceTime = std::max(mExpectedPresentTime.load(), systemTime());
- mExpectedPresentTime = calculateExpectedPresentTime(referenceTime);
+ if (nextVsyncPending) {
+ mExpectedPresentTime += stats.vsyncPeriod;
+ }
}
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index db75312..7dfa326 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -950,7 +950,7 @@
// Calculates the expected present time for this frame. For negative offsets, performs a
// correction using the predicted vsync for the next frame instead.
- nsecs_t calculateExpectedPresentTime(nsecs_t now) const;
+ nsecs_t calculateExpectedPresentTime(DisplayStatInfo) const;
/*
* Display identification