SurfaceFlinger: fix early latching of buffers
Use the FrameTimeline::SurfaceFrame predicted present time
to avoid latching a buffer too early (i.e. before the time
SurfaceFlinger planned to latch this buffer when the app requested
a vsync callback).
Bug: 169901895
Test: expand notification shade and observe systrace
Change-Id: I823546992c89f88c0c29b839ce21c79ff1ffcfbd
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index fa75ffa..6561707 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -389,6 +389,20 @@
mBufferInfo.mFrameLatencyNeeded = true;
}
+bool BufferLayer::frameIsEarly(nsecs_t expectedPresentTime) const {
+ // TODO(b/169901895): kEarlyLatchVsyncThreshold should be based on the
+ // vsync period. We can do this change as soon as ag/13100772 is merged.
+ constexpr static std::chrono::nanoseconds kEarlyLatchVsyncThreshold = 5ms;
+
+ const auto presentTime = nextPredictedPresentTime();
+ if (std::abs(presentTime - expectedPresentTime) >= kEarlyLatchMaxThreshold.count()) {
+ return false;
+ }
+
+ return presentTime >= expectedPresentTime &&
+ presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count();
+}
+
bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
nsecs_t expectedPresentTime) {
ATRACE_CALL();
@@ -421,6 +435,12 @@
return false;
}
+ if (frameIsEarly(expectedPresentTime)) {
+ ATRACE_NAME("frameIsEarly()");
+ mFlinger->signalLayerUpdate();
+ return false;
+ }
+
// If the head buffer's acquire fence hasn't signaled yet, return and
// try again later
if (!fenceHasSignaled()) {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 63dfe5f..5cd9a7c 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -224,6 +224,18 @@
std::unique_ptr<compositionengine::LayerFECompositionState> mCompositionState;
FloatRect computeSourceBounds(const FloatRect& parentBounds) const override;
+
+ // Returns true if the next frame is considered too early to present
+ // at the given expectedPresentTime
+ bool frameIsEarly(nsecs_t expectedPresentTime) const;
+
+ // Returns the predicted present time of the next frame if available or
+ // 0 otherwise.
+ virtual nsecs_t nextPredictedPresentTime() const = 0;
+
+ // The amount of time SF can delay a frame if it is considered early based
+ // on the VsyncModulator::VsyncConfig::appWorkDuration
+ static constexpr std::chrono::nanoseconds kEarlyLatchMaxThreshold = 100ms;
};
} // namespace android
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 56d8742..e8e31db 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -222,6 +222,21 @@
return mQueuedFrames > 0;
}
+nsecs_t BufferQueueLayer::nextPredictedPresentTime() const {
+ Mutex::Autolock lock(mQueueItemLock);
+ if (mQueueItems.empty()) {
+ return 0;
+ }
+
+ const auto& bufferData = mQueueItems[0];
+
+ if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) {
+ return 0;
+ }
+
+ return bufferData.surfaceFrame->getPredictions().presentTime;
+}
+
status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
nsecs_t expectedPresentTime) {
// This boolean is used to make sure that SurfaceFlinger's shadow copy
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 3551026..2347d8c 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -116,6 +116,8 @@
// Temporary - Used only for LEGACY camera mode.
uint32_t getProducerStickyTransform() const;
+ nsecs_t nextPredictedPresentTime() const override;
+
sp<BufferLayerConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index df1472d..7ec7f36 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -601,6 +601,14 @@
return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
}
+nsecs_t BufferStateLayer::nextPredictedPresentTime() const {
+ if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) {
+ return 0;
+ }
+
+ return mSurfaceFrame->getPredictions().presentTime;
+}
+
status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
nsecs_t /*expectedPresentTime*/) {
const State& s(getDrawingState());
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 734f647..6414e6b 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -152,6 +152,8 @@
bool bufferNeedsFiltering() const override;
+ nsecs_t nextPredictedPresentTime() const override;
+
static const std::array<float, 16> IDENTITY_MATRIX;
std::unique_ptr<renderengine::Image> mTextureImage;