diff options
author | Jorim Jaggi <jjaggi@google.com> | 2018-05-23 23:44:06 +0200 |
---|---|---|
committer | Jorim Jaggi <jjaggi@google.com> | 2018-05-25 14:38:38 +0200 |
commit | 9053521815dc4cbe3d2ab21096e05d33386dd5da (patch) | |
tree | 7415b2136bbbdf39b13480ed21f04ab4fd04616d | |
parent | 996fe51a15fa3416494dc81cbea8252f72741200 (diff) | |
download | native-9053521815dc4cbe3d2ab21096e05d33386dd5da.tar.gz |
Keep early vsync-offsets for at least two frames after transaction
Imagine the following sequence, in which vsync-sf is usually 4ms
behind vsync-app.
- Vsync-app fires. The app sends a transaction with early wakeup.
- Vsync-sf fires immediately after early wakeup is received,
before the regular 4ms delay.
- Vsync-sf resets itself to vsync-app+4ms as the transaction was
handled.
- Repeat 1, but now the app was a bit delayed and sends the early
wakeup late, such that the time used to do GL comp isn't enough to
avoid jank.
To fix this, we apply a low pass filter for transaction-caused
early wake and keep it early for at least 2 frames.
Test: Open/close apps, inspect systraces and verify wake-up times
Bug: 78611607
Change-Id: I74b0d88a4d95ca5b6d24950e14e3d6a9379f2714
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 2 | ||||
-rw-r--r-- | services/surfaceflinger/VSyncModulator.h | 36 |
2 files changed, 32 insertions, 6 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 9117207544..a73ac12ff3 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -1535,7 +1535,7 @@ void SurfaceFlinger::handleMessageRefresh() { mHadClientComposition = mHadClientComposition || getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId()); } - mVsyncModulator.setLastFrameUsedRenderEngine(mHadClientComposition); + mVsyncModulator.onRefreshed(mHadClientComposition); mLayersWithQueuedFrames.clear(); } diff --git a/services/surfaceflinger/VSyncModulator.h b/services/surfaceflinger/VSyncModulator.h index 3e5800e2a2..d526313994 100644 --- a/services/surfaceflinger/VSyncModulator.h +++ b/services/surfaceflinger/VSyncModulator.h @@ -28,6 +28,12 @@ namespace android { * Modulates the vsync-offsets depending on current SurfaceFlinger state. */ class VSyncModulator { +private: + + // Number of frames we'll keep the early phase offsets once they are activated. This acts as a + // low-pass filter in case the client isn't quick enough in sending new transactions. + const int MIN_EARLY_FRAME_COUNT = 2; + public: enum TransactionStart { @@ -55,6 +61,11 @@ public: } void setTransactionStart(TransactionStart transactionStart) { + + if (transactionStart == TransactionStart::EARLY) { + mRemainingEarlyFrameCount = MIN_EARLY_FRAME_COUNT; + } + // An early transaction stays an early transaction. if (transactionStart == mTransactionStart || mTransactionStart == TransactionStart::EARLY) { return; @@ -69,10 +80,19 @@ public: updatePhaseOffsets(); } - void setLastFrameUsedRenderEngine(bool re) { - if (re == mLastFrameUsedRenderEngine) return; - mLastFrameUsedRenderEngine = re; - updatePhaseOffsets(); + void onRefreshed(bool usedRenderEngine) { + bool updatePhaseOffsetsNeeded = false; + if (mRemainingEarlyFrameCount > 0) { + mRemainingEarlyFrameCount--; + updatePhaseOffsetsNeeded = true; + } + if (usedRenderEngine != mLastFrameUsedRenderEngine) { + mLastFrameUsedRenderEngine = usedRenderEngine; + updatePhaseOffsetsNeeded = true; + } + if (updatePhaseOffsetsNeeded) { + updatePhaseOffsets(); + } } private: @@ -82,7 +102,7 @@ private: // Do not change phase offsets if disabled. if (mEarlyPhaseOffset == mLatePhaseOffset) return; - if (mTransactionStart == TransactionStart::EARLY || mLastFrameUsedRenderEngine) { + if (shouldUseEarlyOffset()) { if (mPhaseOffset != mEarlyPhaseOffset) { if (mEventThread) { mEventThread->setPhaseOffset(mEarlyPhaseOffset); @@ -99,12 +119,18 @@ private: } } + bool shouldUseEarlyOffset() { + return mTransactionStart == TransactionStart::EARLY || mLastFrameUsedRenderEngine + || mRemainingEarlyFrameCount > 0; + } + nsecs_t mLatePhaseOffset = 0; nsecs_t mEarlyPhaseOffset = 0; EventThread* mEventThread = nullptr; std::atomic<nsecs_t> mPhaseOffset = 0; std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL; std::atomic<bool> mLastFrameUsedRenderEngine = false; + std::atomic<int> mRemainingEarlyFrameCount = 0; }; } // namespace android |