SurfaceFlinger: Layer::shouldPresentNow should consider early frames
Move the decision whether to latch a buffer or not based on
the expected present time (that is whether a frame is considered too
early or out of vsync phase) from Layer::latchBuffer to
Layer::shouldPresentNow as the code assumes that Layer::latchBuffer would
not fail based on the expected present.
Bug: 176755514
Bug: 176416352
Test: atest CtsViewTestCases:android.view.cts.ASurfaceControlTest
Test: atest FrameRateOverrideHostTest
Change-Id: Ib83bda41c824549011f12fa5414263c8b03032e4
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 6561707..424a8b3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -389,33 +389,58 @@
mBufferInfo.mFrameLatencyNeeded = true;
}
+bool BufferLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {
+ // If this is not a valid vsync for the layer's uid, return and try again later
+ const bool isVsyncValidForUid =
+ mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid);
+ if (!isVsyncValidForUid) {
+ ATRACE_NAME("!isVsyncValidForUid");
+ return false;
+ }
+
+ // AutoRefresh layers and sideband streams should always be presented
+ if (getSidebandStreamChanged() || getAutoRefresh()) {
+ return true;
+ }
+
+ // If the next planned present time is not current, return and try again later
+ if (frameIsEarly(expectedPresentTime)) {
+ ATRACE_NAME("frameIsEarly()");
+ return false;
+ }
+
+ // If this layer doesn't have a frame is shouldn't be presented
+ if (!hasFrameUpdate()) {
+ return false;
+ }
+
+ // Defer to the derived class to decide whether the next buffer is due for
+ // presentation.
+ return isBufferDue(expectedPresentTime);
+}
+
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()) {
+ if (!presentTime.has_value()) {
return false;
}
- return presentTime >= expectedPresentTime &&
- presentTime - expectedPresentTime >= kEarlyLatchVsyncThreshold.count();
+ 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();
- // If this is not a valid vsync for the layer's uid, return and try again later
- const bool isVsyncValidForUid =
- mFlinger->mScheduler->isVsyncValid(expectedPresentTime, mOwnerUid);
- if (!isVsyncValidForUid) {
- ATRACE_NAME("!isVsyncValidForUid");
- mFlinger->setTransactionFlags(eTraversalNeeded);
- return false;
- }
-
bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
if (refreshRequired) {
@@ -435,12 +460,6 @@
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 5cd9a7c..2118f4a 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -175,12 +175,24 @@
void setTransformHint(ui::Transform::RotationFlags displayTransformHint) override;
// Transform hint provided to the producer. This must be accessed holding
- /// the mStateLock.
+ // the mStateLock.
ui::Transform::RotationFlags mTransformHint = ui::Transform::ROT_0;
bool getAutoRefresh() const { return mAutoRefresh; }
bool getSidebandStreamChanged() const { return mSidebandStreamChanged; }
+ // Returns true if the next buffer should be presented at the expected present time
+ bool shouldPresentNow(nsecs_t expectedPresentTime) const final;
+
+ // Returns true if the next buffer should be presented at the expected present time,
+ // overridden by BufferStateLayer and BufferQueueLayer for implementation
+ // specific logic
+ virtual bool isBufferDue(nsecs_t /*expectedPresentTime*/) const = 0;
+
+ // Returns true if the next frame is considered too early to present
+ // at the given expectedPresentTime
+ bool frameIsEarly(nsecs_t expectedPresentTime) const;
+
std::atomic<bool> mAutoRefresh{false};
std::atomic<bool> mSidebandStreamChanged{false};
@@ -225,13 +237,8 @@
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;
+ // Returns the predicted present time of the next frame if available
+ virtual std::optional<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
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 04cec4f..32e6b10 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -100,15 +100,7 @@
return mQueuedFrames;
}
-bool BufferQueueLayer::shouldPresentNow(nsecs_t expectedPresentTime) const {
- if (getSidebandStreamChanged() || getAutoRefresh()) {
- return true;
- }
-
- if (!hasFrameUpdate()) {
- return false;
- }
-
+bool BufferQueueLayer::isBufferDue(nsecs_t expectedPresentTime) const {
Mutex::Autolock lock(mQueueItemLock);
const int64_t addedTime = mQueueItems[0].item.mTimestamp;
@@ -223,16 +215,16 @@
return mQueuedFrames > 0;
}
-nsecs_t BufferQueueLayer::nextPredictedPresentTime() const {
+std::optional<nsecs_t> BufferQueueLayer::nextPredictedPresentTime() const {
Mutex::Autolock lock(mQueueItemLock);
if (mQueueItems.empty()) {
- return 0;
+ return std::nullopt;
}
const auto& bufferData = mQueueItems[0];
if (!bufferData.item.mIsAutoTimestamp || !bufferData.surfaceFrame) {
- return 0;
+ return std::nullopt;
}
return bufferData.surfaceFrame->getPredictions().presentTime;
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 2347d8c..0e8fdbe 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -53,7 +53,8 @@
int32_t getQueuedFrameCount() const override;
- bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
+ // Returns true if the next buffer should be presented at the expected present time
+ bool isBufferDue(nsecs_t expectedPresentTime) const override;
// Implements BufferLayer.
bool fenceHasSignaled() const override;
@@ -116,7 +117,7 @@
// Temporary - Used only for LEGACY camera mode.
uint32_t getProducerStickyTransform() const;
- nsecs_t nextPredictedPresentTime() const override;
+ std::optional<nsecs_t> nextPredictedPresentTime() const override;
sp<BufferLayerConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index bca1c69..ad08f82 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -212,14 +212,6 @@
}
}
-bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
- if (getSidebandStreamChanged() || getAutoRefresh()) {
- return true;
- }
-
- return hasFrameUpdate();
-}
-
bool BufferStateLayer::willPresentCurrentTransaction() const {
// Returns true if the most recent Transaction applied to CurrentState will be presented.
return (getSidebandStreamChanged() || getAutoRefresh() ||
@@ -602,9 +594,9 @@
return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
}
-nsecs_t BufferStateLayer::nextPredictedPresentTime() const {
+std::optional<nsecs_t> BufferStateLayer::nextPredictedPresentTime() const {
if (!getDrawingState().isAutoTimestamp || !mSurfaceFrame) {
- return 0;
+ return std::nullopt;
}
return mSurfaceFrame->getPredictions().presentTime;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 6414e6b..bc508e3 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -45,7 +45,7 @@
void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
const CompositorTiming& compositorTiming) override;
- bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
+ bool isBufferDue(nsecs_t /*expectedPresentTime*/) const override { return true; }
uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override {
return flags;
@@ -152,7 +152,7 @@
bool bufferNeedsFiltering() const override;
- nsecs_t nextPredictedPresentTime() const override;
+ std::optional<nsecs_t> nextPredictedPresentTime() const override;
static const std::array<float, 16> IDENTITY_MATRIX;