SurfaceFlinger: fix deferred transactions for buffers with timestamps
A deferred transaction needs to wait until the buffer is ready
to be latched. This means that the buffer needs to be:
1. Done with rendering (fence has signaled)
2. Present timestamp is within the boundary of the next vsync
Test: Screen rotation with Chrome
Bug: 130785247
Change-Id: I8def1f10ea3d5c253ab14fa3aa4445588fc2ba8b
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index e226136..528bfb1 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -94,8 +94,6 @@
// Skip this if we're in shared buffer mode and the queue is empty,
// since in that case we'll just return the shared buffer.
if (expectedPresent != 0 && !mCore->mQueue.empty()) {
- const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second
-
// The 'expectedPresent' argument indicates when the buffer is expected
// to be presented on-screen. If the buffer's desired present time is
// earlier (less) than expectedPresent -- meaning it will be displayed
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index aa13c0c..7db69ec 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -171,6 +171,9 @@
// End functions required for backwards compatibility
+ // Value used to determine if present time is valid.
+ constexpr static int MAX_REASONABLE_NSEC = 1'000'000'000ULL; // 1 second
+
private:
sp<BufferQueueCore> mCore;
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4ea587d..06caf1e 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -534,11 +534,13 @@
// transaction
void BufferLayer::notifyAvailableFrames() {
- auto headFrameNumber = getHeadFrameNumber();
- bool headFenceSignaled = fenceHasSignaled();
+ const auto headFrameNumber = getHeadFrameNumber();
+ const bool headFenceSignaled = fenceHasSignaled();
+ const bool presentTimeIsCurrent = framePresentTimeIsCurrent();
Mutex::Autolock lock(mLocalSyncPointMutex);
for (auto& point : mLocalSyncPoints) {
- if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled) {
+ if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled &&
+ presentTimeIsCurrent) {
point->setFrameAvailable();
}
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index dc103cb..b679380 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -114,6 +114,7 @@
// -----------------------------------------------------------------------
private:
virtual bool fenceHasSignaled() const = 0;
+ virtual bool framePresentTimeIsCurrent() const = 0;
virtual nsecs_t getDesiredPresentTime() = 0;
virtual std::shared_ptr<FenceTime> getCurrentFenceTime() const = 0;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index ff5f271..5d729f5 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -19,6 +19,7 @@
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <gui/BufferQueueConsumer.h>
#include <system/window.h>
#include "BufferQueueLayer.h"
@@ -133,6 +134,15 @@
return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
}
+bool BufferQueueLayer::framePresentTimeIsCurrent() const {
+ if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
+ return true;
+ }
+
+ Mutex::Autolock lock(mQueueItemLock);
+ return mQueueItems[0].mTimestamp <= mFlinger->mScheduler->expectedPresentTime();
+}
+
nsecs_t BufferQueueLayer::getDesiredPresentTime() {
return mConsumer->getTimestamp();
}
@@ -185,7 +195,37 @@
uint64_t BufferQueueLayer::getFrameNumber() const {
Mutex::Autolock lock(mQueueItemLock);
- return mQueueItems[0].mFrameNumber;
+ uint64_t frameNumber = mQueueItems[0].mFrameNumber;
+
+ // The head of the queue will be dropped if there are signaled and timely frames behind it
+ nsecs_t expectedPresentTime = mFlinger->mScheduler->expectedPresentTime();
+
+ if (isRemovedFromCurrentState()) {
+ expectedPresentTime = 0;
+ }
+
+ for (int i = 1; i < mQueueItems.size(); i++) {
+ const bool fenceSignaled =
+ mQueueItems[i].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
+ if (!fenceSignaled) {
+ break;
+ }
+
+ // We don't drop frames without explicit timestamps
+ if (mQueueItems[i].mIsAutoTimestamp) {
+ break;
+ }
+
+ const nsecs_t desiredPresent = mQueueItems[i].mTimestamp;
+ if (desiredPresent < expectedPresentTime - BufferQueueConsumer::MAX_REASONABLE_NSEC ||
+ desiredPresent > expectedPresentTime) {
+ break;
+ }
+
+ frameNumber = mQueueItems[i].mFrameNumber;
+ }
+
+ return frameNumber;
}
bool BufferQueueLayer::getAutoRefresh() const {
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index a2aad17..7def33a 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -61,6 +61,7 @@
// -----------------------------------------------------------------------
public:
bool fenceHasSignaled() const override;
+ bool framePresentTimeIsCurrent() const override;
private:
nsecs_t getDesiredPresentTime() override;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index dabc683..30848d6 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -374,6 +374,14 @@
return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
}
+bool BufferStateLayer::framePresentTimeIsCurrent() const {
+ if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
+ return true;
+ }
+
+ return mDesiredPresentTime <= mFlinger->mScheduler->expectedPresentTime();
+}
+
nsecs_t BufferStateLayer::getDesiredPresentTime() {
return mDesiredPresentTime;
}
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 13186dd..4e2bc45 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -101,6 +101,7 @@
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
+ bool framePresentTimeIsCurrent() const override;
private:
nsecs_t getDesiredPresentTime() override;