diff options
author | 2021-09-20 21:07:45 +0000 | |
---|---|---|
committer | 2021-11-02 18:04:47 +0000 | |
commit | 4d48f9092b1209ad871969613e37ae19cb506d3c (patch) | |
tree | a8586fffc7a8df07616b916abc173bf6fc1efc93 | |
parent | c0f27677e429d2c0381429e1ca7222ca763931b6 (diff) |
Latch Unsignaled when only a single layer is being updated.
Three conditions are introduced.
DISABLED (Default for now): This is when latch unsignaled is completely disabled.
AUTO: This is when we will latch for the single layer update. Further refinements will be done in b/200284381
ALWAYS: This will latch unsignaled no matter what the change is.
BUG: 198189193
Test: Did the manual test and
atest libsurfaceflinger_unittest
atest MockFence_test
atest libgui_test
Change-Id: I0c0b475ba4a093275fac23a986fc610ea462f73e
-rw-r--r-- | libs/ui/include/ui/Fence.h | 2 | ||||
-rw-r--r-- | libs/ui/include_mock/ui/MockFence.h | 1 | ||||
-rw-r--r-- | libs/ui/tests/MockFence_test.cpp | 12 | ||||
-rw-r--r-- | services/surfaceflinger/BufferQueueLayer.cpp | 2 | ||||
-rw-r--r-- | services/surfaceflinger/BufferStateLayer.cpp | 2 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 149 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 15 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h | 1 | ||||
-rw-r--r-- | services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp | 416 |
9 files changed, 562 insertions, 38 deletions
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h index 7634007771..9aae145c04 100644 --- a/libs/ui/include/ui/Fence.h +++ b/libs/ui/include/ui/Fence.h @@ -124,7 +124,7 @@ public: // getStatus() returns whether the fence has signaled yet. Prefer this to // getSignalTime() or wait() if all you care about is whether the fence has // signaled. - inline Status getStatus() { + virtual inline Status getStatus() { // The sync_wait call underlying wait() has been measured to be // significantly faster than the sync_fence_info call underlying // getSignalTime(), which might otherwise appear to be the more obvious diff --git a/libs/ui/include_mock/ui/MockFence.h b/libs/ui/include_mock/ui/MockFence.h index 162ec02455..71adee4fbc 100644 --- a/libs/ui/include_mock/ui/MockFence.h +++ b/libs/ui/include_mock/ui/MockFence.h @@ -27,6 +27,7 @@ public: virtual ~MockFence() = default; MOCK_METHOD(nsecs_t, getSignalTime, (), (const, override)); + MOCK_METHOD(Status, getStatus, (), (override)); }; }; // namespace android::mock diff --git a/libs/ui/tests/MockFence_test.cpp b/libs/ui/tests/MockFence_test.cpp index 6e520b1aee..40dddc3cf2 100644 --- a/libs/ui/tests/MockFence_test.cpp +++ b/libs/ui/tests/MockFence_test.cpp @@ -42,4 +42,16 @@ TEST_F(MockFenceTest, getSignalTime) { EXPECT_EQ(1234, fence->getSignalTime()); } +TEST_F(MockFenceTest, getStatus) { + sp<Fence> fence = getFenceForTesting(); + + EXPECT_CALL(getMockFence(), getStatus).WillOnce(Return(Fence::Status::Unsignaled)); + EXPECT_EQ(Fence::Status::Unsignaled, fence->getStatus()); + + EXPECT_CALL(getMockFence(), getStatus).WillOnce(Return(Fence::Status::Signaled)); + EXPECT_EQ(Fence::Status::Signaled, fence->getStatus()); + + EXPECT_CALL(getMockFence(), getStatus).WillOnce(Return(Fence::Status::Invalid)); + EXPECT_EQ(Fence::Status::Invalid, fence->getStatus()); +} } // namespace android::ui diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp index 4e5d2d03b0..8aecec131f 100644 --- a/services/surfaceflinger/BufferQueueLayer.cpp +++ b/services/surfaceflinger/BufferQueueLayer.cpp @@ -118,7 +118,7 @@ bool BufferQueueLayer::isBufferDue(nsecs_t expectedPresentTime) const { bool BufferQueueLayer::fenceHasSignaled() const { Mutex::Autolock lock(mQueueItemLock); - if (SurfaceFlinger::enableLatchUnsignaled) { + if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { return true; } diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp index c0753f9d47..f7f96ab1b1 100644 --- a/services/surfaceflinger/BufferStateLayer.cpp +++ b/services/surfaceflinger/BufferStateLayer.cpp @@ -630,7 +630,7 @@ FloatRect BufferStateLayer::computeSourceBounds(const FloatRect& parentBounds) c // Interface implementation for BufferLayer // ----------------------------------------------------------------------- bool BufferStateLayer::fenceHasSignaled() const { - if (SurfaceFlinger::enableLatchUnsignaled) { + if (SurfaceFlinger::enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { return true; } diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 8d7221c1dc..9b1677478d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -341,7 +341,7 @@ Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRG ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888; bool SurfaceFlinger::useFrameRateApi; bool SurfaceFlinger::enableSdrDimming; -bool SurfaceFlinger::enableLatchUnsignaled; +LatchUnsignaledConfig SurfaceFlinger::enableLatchUnsignaledConfig; std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) { switch(displayColorSetting) { @@ -501,7 +501,17 @@ SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipI // Debug property overrides ro. property enableSdrDimming = property_get_bool("debug.sf.enable_sdr_dimming", enable_sdr_dimming(false)); - enableLatchUnsignaled = base::GetBoolProperty("debug.sf.latch_unsignaled"s, false); + enableLatchUnsignaledConfig = getLatchUnsignaledConfig(); +} + +LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() { + if (base::GetBoolProperty("debug.sf.latch_unsignaled"s, false)) { + return LatchUnsignaledConfig::Always; + } else if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) { + return LatchUnsignaledConfig::Auto; + } else { + return LatchUnsignaledConfig::Disabled; + } } SurfaceFlinger::~SurfaceFlinger() = default; @@ -3421,29 +3431,34 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t mask, TransactionSchedule } bool SurfaceFlinger::flushTransactionQueues() { - bool needsTraversal = false; // to prevent onHandleDestroyed from being called while the lock is held, // we must keep a copy of the transactions (specifically the composer // states) around outside the scope of the lock - std::vector<const TransactionState> transactions; + std::vector<TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> bufferLayersReadyToPresent; { Mutex::Autolock _l(mStateLock); { Mutex::Autolock _l(mQueueLock); + // allowLatchUnsignaled acts as a filter condition when latch unsignaled is either auto + // or always. auto: in this case we let buffer latch unsignaled if we have only one + // applyToken and if only first transaction is latch unsignaled. If more than one + // applyToken we don't latch unsignaled. + bool allowLatchUnsignaled = allowedLatchUnsignaled(); + bool isFirstUnsignaledTransactionApplied = false; // Collect transactions from pending transaction queue. auto it = mPendingTransactionQueues.begin(); while (it != mPendingTransactionQueues.end()) { auto& [applyToken, transactionQueue] = *it; - while (!transactionQueue.empty()) { auto& transaction = transactionQueue.front(); if (!transactionIsReadyToBeApplied(transaction.frameTimelineInfo, transaction.isAutoTimestamp, transaction.desiredPresentTime, transaction.originUid, transaction.states, - bufferLayersReadyToPresent)) { + bufferLayersReadyToPresent, + allowLatchUnsignaled)) { setTransactionFlags(eTransactionFlushNeeded); break; } @@ -3452,6 +3467,14 @@ bool SurfaceFlinger::flushTransactionQueues() { }); transactions.emplace_back(std::move(transaction)); transactionQueue.pop(); + if (allowLatchUnsignaled && + enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) { + // if allowLatchUnsignaled && we are in LatchUnsignaledConfig::Auto + // then we should have only one applyToken for processing. + // so we can stop further transactions on this applyToken. + isFirstUnsignaledTransactionApplied = true; + break; + } } if (transactionQueue.empty()) { @@ -3463,52 +3486,115 @@ bool SurfaceFlinger::flushTransactionQueues() { } // Collect transactions from current transaction queue or queue to pending transactions. - // Case 1: push to pending when transactionIsReadyToBeApplied is false. + // Case 1: push to pending when transactionIsReadyToBeApplied is false + // or the first transaction was unsignaled. // Case 2: push to pending when there exist a pending queue. - // Case 3: others are ready to apply. + // Case 3: others are the transactions that are ready to apply. while (!mTransactionQueue.empty()) { auto& transaction = mTransactionQueue.front(); bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) != mPendingTransactionQueues.end(); - if (pendingTransactions || + if (isFirstUnsignaledTransactionApplied || pendingTransactions || !transactionIsReadyToBeApplied(transaction.frameTimelineInfo, transaction.isAutoTimestamp, transaction.desiredPresentTime, transaction.originUid, transaction.states, - bufferLayersReadyToPresent)) { + bufferLayersReadyToPresent, + allowLatchUnsignaled)) { mPendingTransactionQueues[transaction.applyToken].push(std::move(transaction)); } else { transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { bufferLayersReadyToPresent.insert(state.surface); }); transactions.emplace_back(std::move(transaction)); + if (allowLatchUnsignaled && + enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto) { + isFirstUnsignaledTransactionApplied = true; + } } - mTransactionQueue.pop(); + mTransactionQueue.pop_front(); ATRACE_INT("TransactionQueue", mTransactionQueue.size()); } + + return applyTransactions(transactions); } + } +} - // Now apply all transactions. - for (const auto& transaction : transactions) { - needsTraversal |= - applyTransactionState(transaction.frameTimelineInfo, transaction.states, - transaction.displays, transaction.flags, - transaction.inputWindowCommands, - transaction.desiredPresentTime, - transaction.isAutoTimestamp, transaction.buffer, - transaction.postTime, transaction.permissions, - transaction.hasListenerCallbacks, - transaction.listenerCallbacks, transaction.originPid, - transaction.originUid, transaction.id); - if (transaction.transactionCommittedSignal) { - mTransactionCommittedSignals.emplace_back( - std::move(transaction.transactionCommittedSignal)); - } +bool SurfaceFlinger::applyTransactions(std::vector<TransactionState>& transactions) { + bool needsTraversal = false; + // Now apply all transactions. + for (const auto& transaction : transactions) { + needsTraversal |= + applyTransactionState(transaction.frameTimelineInfo, transaction.states, + transaction.displays, transaction.flags, + transaction.inputWindowCommands, + transaction.desiredPresentTime, transaction.isAutoTimestamp, + transaction.buffer, transaction.postTime, + transaction.permissions, transaction.hasListenerCallbacks, + transaction.listenerCallbacks, transaction.originPid, + transaction.originUid, transaction.id); + if (transaction.transactionCommittedSignal) { + mTransactionCommittedSignals.emplace_back( + std::move(transaction.transactionCommittedSignal)); } - } // unlock mStateLock + } return needsTraversal; } +bool SurfaceFlinger::allowedLatchUnsignaled() { + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Disabled) { + return false; + } + // Always mode matches the current latch unsignaled behavior. + // This behavior is currently used by the partners and we would like + // to keep it until we are completely migrated to Auto mode successfully + // and we we have our fallback based implementation in place. + if (enableLatchUnsignaledConfig == LatchUnsignaledConfig::Always) { + return true; + } + + // if enableLatchUnsignaledConfig == LatchUnsignaledConfig::Auto + // we don't latch unsignaled if more than one applyToken, as it can backpressure + // the other transactions. + if (mPendingTransactionQueues.size() > 1) { + return false; + } + std::optional<sp<IBinder>> applyToken = std::nullopt; + bool isPendingTransactionQueuesItem = false; + if (!mPendingTransactionQueues.empty()) { + applyToken = mPendingTransactionQueues.begin()->first; + isPendingTransactionQueuesItem = true; + } + + for (const auto& item : mTransactionQueue) { + if (!applyToken.has_value()) { + applyToken = item.applyToken; + } else if (applyToken.has_value() && applyToken != item.applyToken) { + return false; + } + } + + if (isPendingTransactionQueuesItem) { + return checkTransactionCanLatchUnsignaled( + mPendingTransactionQueues.begin()->second.front()); + } else if (applyToken.has_value()) { + return checkTransactionCanLatchUnsignaled((mTransactionQueue.front())); + } + return false; +} + +bool SurfaceFlinger::checkTransactionCanLatchUnsignaled(const TransactionState& transaction) { + if (transaction.states.size() == 1) { + const auto& state = transaction.states.begin()->state; + return (state.flags & ~layer_state_t::eBufferChanged) == 0 && + state.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged) && + state.bufferData.acquireFence && + state.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled; + } + return false; +} + bool SurfaceFlinger::transactionFlushNeeded() { Mutex::Autolock _l(mQueueLock); return !mPendingTransactionQueues.empty() || !mTransactionQueue.empty(); @@ -3540,7 +3626,8 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& - bufferLayersReadyToPresent) const { + bufferLayersReadyToPresent, + bool allowLatchUnsignaled) const { ATRACE_CALL(); const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Do not present if the desiredPresentTime has not passed unless it is more than one second @@ -3567,7 +3654,7 @@ bool SurfaceFlinger::transactionIsReadyToBeApplied( const layer_state_t& s = state.state; const bool acquireFenceChanged = s.bufferData.flags.test(BufferData::BufferDataChange::fenceChanged); - if (acquireFenceChanged && s.bufferData.acquireFence && !enableLatchUnsignaled && + if (acquireFenceChanged && s.bufferData.acquireFence && !allowLatchUnsignaled && s.bufferData.acquireFence->getStatus() == Fence::Status::Unsignaled) { ATRACE_NAME("fence unsignaled"); return false; @@ -3628,7 +3715,7 @@ void SurfaceFlinger::queueTransaction(TransactionState& state) { : CountDownLatch::eSyncTransaction)); } - mTransactionQueue.emplace(state); + mTransactionQueue.emplace_back(state); ATRACE_INT("TransactionQueue", mTransactionQueue.size()); const auto schedule = [](uint32_t flags) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 276c7f6bfe..97fddf2930 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -135,6 +135,8 @@ enum { eTransactionMask = 0x1f, }; +enum class LatchUnsignaledConfig { Always, Auto, Disabled }; + using DisplayColorSetting = compositionengine::OutputColorSetting; struct SurfaceFlingerBE { @@ -257,7 +259,7 @@ public: // being treated as native display brightness static bool enableSdrDimming; - static bool enableLatchUnsignaled; + static LatchUnsignaledConfig enableLatchUnsignaledConfig; // must be called before clients can connect void init() ANDROID_API; @@ -751,7 +753,14 @@ private: const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& - bufferLayersReadyToPresent) const REQUIRES(mStateLock); + bufferLayersReadyToPresent, + bool allowLatchUnsignaled) const REQUIRES(mStateLock); + static LatchUnsignaledConfig getLatchUnsignaledConfig(); + bool latchUnsignaledIsAllowed(std::vector<TransactionState>& transactions) REQUIRES(mStateLock); + bool allowedLatchUnsignaled() REQUIRES(mQueueLock, mStateLock); + bool checkTransactionCanLatchUnsignaled(const TransactionState& transaction) + REQUIRES(mStateLock); + bool applyTransactions(std::vector<TransactionState>& transactions) REQUIRES(mStateLock); uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock); uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands) REQUIRES(mStateLock); @@ -1242,7 +1251,7 @@ private: Condition mTransactionQueueCV; std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mPendingTransactionQueues GUARDED_BY(mQueueLock); - std::queue<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock); + std::deque<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock); /* * Feature prototyping */ diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index c23fcc7d58..9832372a86 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -375,6 +375,7 @@ public: auto& getTransactionQueue() { return mFlinger->mTransactionQueue; } auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; } + auto& getTransactionCommittedSignals() { return mFlinger->mTransactionCommittedSignals; } auto setTransactionState( const FrameTimelineInfo& frameTimelineInfo, const Vector<ComposerState>& states, diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp index 05551b4701..8caadfbf85 100644 --- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp @@ -24,8 +24,8 @@ #include <gtest/gtest.h> #include <gui/SurfaceComposerClient.h> #include <log/log.h> +#include <ui/MockFence.h> #include <utils/String8.h> - #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/MockEventThread.h" @@ -74,6 +74,13 @@ public: EXPECT_CALL(*mVSyncTracker, currentPeriod()) .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)); + EXPECT_CALL(*mFenceUnsignaled, getStatus()) + .WillRepeatedly(Return(Fence::Status::Unsignaled)); + EXPECT_CALL(*mFenceUnsignaled2, getStatus()) + .WillRepeatedly(Return(Fence::Status::Unsignaled)); + EXPECT_CALL(*mFenceSignaled, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled)); + EXPECT_CALL(*mFenceSignaled2, getStatus()).WillRepeatedly(Return(Fence::Status::Signaled)); + mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>()); mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController), std::unique_ptr<mock::VSyncTracker>(mVSyncTracker), @@ -88,6 +95,10 @@ public: mock::MessageQueue* mMessageQueue = new mock::MessageQueue(); mock::VsyncController* mVsyncController = new mock::VsyncController(); mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker(); + mock::MockFence* mFenceUnsignaled = new mock::MockFence(); + mock::MockFence* mFenceSignaled = new mock::MockFence(); + mock::MockFence* mFenceUnsignaled2 = new mock::MockFence(); + mock::MockFence* mFenceSignaled2 = new mock::MockFence(); struct TransactionInfo { Vector<ComposerState> states; @@ -124,6 +135,15 @@ public: transaction.frameTimelineInfo = frameTimelineInfo; } + void setupSingleWithComposer(TransactionInfo& transaction, uint32_t flags, + bool syncInputWindows, int64_t desiredPresentTime, + bool isAutoTimestamp, const FrameTimelineInfo& frameTimelineInfo, + const Vector<ComposerState>* states) { + setupSingle(transaction, flags, syncInputWindows, desiredPresentTime, isAutoTimestamp, + frameTimelineInfo); + transaction.states = *states; + } + void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) { ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); EXPECT_CALL(*mMessageQueue, scheduleCommit()).Times(1); @@ -245,6 +265,188 @@ public: EXPECT_EQ(0u, transactionQueue.size()); } + void Flush_removesUnsignaledFromTheQueue(Vector<ComposerState> state1, + Vector<ComposerState> state2, + bool updateApplyToken = true) { + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + + TransactionInfo transactionA; + setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state1); + + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, + transactionA.displays, transactionA.flags, + transactionA.applyToken, transactionA.inputWindowCommands, + transactionA.desiredPresentTime, transactionA.isAutoTimestamp, + transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionA.id); + + TransactionInfo transactionB; + if (updateApplyToken) { + transactionB.applyToken = sp<IBinder>(); + } + setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state2); + mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, + transactionB.displays, transactionB.flags, + transactionB.applyToken, transactionB.inputWindowCommands, + transactionB.desiredPresentTime, transactionB.isAutoTimestamp, + transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionB.id); + + mFlinger.flushTransactionQueues(); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size()); + } + + void Flush_removesFromTheQueue(const Vector<ComposerState>& state) { + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + + TransactionInfo transaction; + setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state); + + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, + transaction.displays, transaction.flags, + transaction.applyToken, transaction.inputWindowCommands, + transaction.desiredPresentTime, transaction.isAutoTimestamp, + transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transaction.id); + + mFlinger.flushTransactionQueues(); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(1u, mFlinger.getTransactionCommittedSignals().size()); + } + + void Flush_keepsInTheQueue(const Vector<ComposerState>& state) { + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + + TransactionInfo transaction; + setupSingleWithComposer(transaction, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ systemTime(), /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state); + + mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states, + transaction.displays, transaction.flags, + transaction.applyToken, transaction.inputWindowCommands, + transaction.desiredPresentTime, transaction.isAutoTimestamp, + transaction.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transaction.id); + + mFlinger.flushTransactionQueues(); + EXPECT_EQ(1u, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size()); + } + + void Flush_KeepsUnsignaledInTheQueue(const Vector<ComposerState>& state1, + const Vector<ComposerState>& state2, + bool updateApplyToken = true, + uint32_t pendingTransactionQueueSize = 1u) { + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + auto time = systemTime(); + TransactionInfo transactionA; + TransactionInfo transactionB; + setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state1); + setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state2); + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, + transactionA.displays, transactionA.flags, + transactionA.applyToken, transactionA.inputWindowCommands, + transactionA.desiredPresentTime, transactionA.isAutoTimestamp, + transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionA.id); + if (updateApplyToken) { + transactionB.applyToken = sp<IBinder>(); + } + mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, + transactionB.displays, transactionB.flags, + transactionB.applyToken, transactionB.inputWindowCommands, + transactionB.desiredPresentTime, transactionB.isAutoTimestamp, + transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionB.id); + + mFlinger.flushTransactionQueues(); + EXPECT_EQ(pendingTransactionQueueSize, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + } + + void Flush_removesSignaledFromTheQueue(const Vector<ComposerState>& state1, + const Vector<ComposerState>& state2) { + ASSERT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + + auto time = systemTime(); + TransactionInfo transactionA; + TransactionInfo transactionB; + setupSingleWithComposer(transactionA, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state1); + setupSingleWithComposer(transactionB, ISurfaceComposer::eSynchronous, + /*syncInputWindows*/ false, + /*desiredPresentTime*/ time, /*isAutoTimestamp*/ true, + FrameTimelineInfo{}, &state2); + mFlinger.setTransactionState(transactionA.frameTimelineInfo, transactionA.states, + transactionA.displays, transactionA.flags, + transactionA.applyToken, transactionA.inputWindowCommands, + transactionA.desiredPresentTime, transactionA.isAutoTimestamp, + transactionA.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionA.id); + mFlinger.setTransactionState(transactionB.frameTimelineInfo, transactionB.states, + transactionB.displays, transactionB.flags, + transactionB.applyToken, transactionB.inputWindowCommands, + transactionB.desiredPresentTime, transactionB.isAutoTimestamp, + transactionB.uncacheBuffer, mHasListenerCallbacks, mCallbacks, + transactionB.id); + + mFlinger.flushTransactionQueues(); + EXPECT_EQ(0u, mFlinger.getPendingTransactionQueue().size()); + EXPECT_EQ(0u, mFlinger.getTransactionQueue().size()); + EXPECT_EQ(2ul, mFlinger.getTransactionCommittedSignals().size()); + } + + static Vector<ComposerState> createComposerStateVector(const ComposerState& state1, + const ComposerState& state2) { + Vector<ComposerState> states; + states.push_back(state1); + states.push_back(state2); + return states; + } + + static Vector<ComposerState> createComposerStateVector(const ComposerState& state) { + Vector<ComposerState> states; + states.push_back(state); + return states; + } + + static ComposerState createComposerState(int layerId, sp<Fence> fence, + uint32_t stateFlags = layer_state_t::eBufferChanged) { + ComposerState composer_state; + composer_state.state.bufferData.acquireFence = std::move(fence); + composer_state.state.layerId = layerId; + composer_state.state.bufferData.flags = BufferData::BufferDataChange::fenceChanged; + composer_state.state.flags = stateFlags; + return composer_state; + } + bool mHasListenerCallbacks = false; std::vector<ListenerCallbacks> mCallbacks; int mTransactionNumber = 0; @@ -327,4 +529,216 @@ TEST_F(TransactionApplicationTest, FromHandle) { auto ret = mFlinger.fromHandle(badHandle); EXPECT_EQ(nullptr, ret.promote().get()); } + +TEST_F(TransactionApplicationTest, Flush_RemovesSingleSignaledFromTheQueue_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSingleUnSignaledFromTheQueue_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, + Flush_KeepsUnSignaledInTheQueue_NonBufferCropChange_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_keepsInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled, layer_state_t::eCropChanged))); +} + +TEST_F(TransactionApplicationTest, + Flush_KeepsUnSignaledInTheQueue_NonBufferChangeClubed_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_keepsInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled, + layer_state_t::eCropChanged | layer_state_t::eBufferChanged))); +} + +TEST_F(TransactionApplicationTest, + Flush_KeepsInTheQueueSameApplyTokenMultiState_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_keepsInTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 1, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_MultipleStateTransaction_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_keepsInTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 2, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_removesSignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled2))); +} + +TEST_F(TransactionApplicationTest, Flush_RemoveSignaledWithUnsignaledIntact_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceUnsignaled))); + EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, + Flush_KeepsTransactionInTheQueueSameApplyToken_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled)), + /*updateApplyToken*/ false); + EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, Flush_KeepsTransactionInTheQueue_LatchUnsignaled_Auto) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Auto; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceUnsignaled)), + /*updateApplyToken*/ true, + /*pendingTransactionQueueSize*/ 2u); + EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueue_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_keepsInTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueSameLayerId_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_keepsInTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 1, mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_KeepsInTheQueueDifferentLayerId_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_keepsInTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 2, mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_removesSignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled2))); +} + +TEST_F(TransactionApplicationTest, + Flush_KeepInTheQueueDifferentApplyToken_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled))); + EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, Flush_KeepInTheQueueSameApplyToken_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceUnsignaled)), + /*updateApplyToken*/ false); + EXPECT_EQ(1ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, Flush_KeepInTheUnsignaledTheQueue_LatchUnsignaled_Disabled) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Disabled; + Flush_KeepsUnsignaledInTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceUnsignaled)), + /*updateApplyToken*/ false); + EXPECT_EQ(0ul, mFlinger.getTransactionCommittedSignals().size()); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueue_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesFromTheQueueSameLayerId_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 1, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, + Flush_RemovesFromTheQueueDifferentLayerId_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesFromTheQueue( + createComposerStateVector(createComposerState(/*layerId*/ 1, mFenceUnsignaled), + createComposerState(/*layerId*/ 2, mFenceSignaled))); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesSignaledFromTheQueue_LatchUnSignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesSignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled2))); +} + +TEST_F(TransactionApplicationTest, + Flush_RemovesFromTheQueueDifferentApplyToken_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesUnsignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, mFenceSignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, + mFenceUnsignaled))); +} + +TEST_F(TransactionApplicationTest, + Flush_RemovesUnsignaledFromTheQueueSameApplyToken_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesUnsignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, + mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, mFenceSignaled)), + /*updateApplyToken*/ false); +} + +TEST_F(TransactionApplicationTest, Flush_RemovesUnsignaledFromTheQueue_LatchUnsignaled_Always) { + SurfaceFlinger::enableLatchUnsignaledConfig = LatchUnsignaledConfig::Always; + Flush_removesUnsignaledFromTheQueue(createComposerStateVector( + createComposerState(/*layerId*/ 1, + mFenceUnsignaled)), + createComposerStateVector( + createComposerState(/*layerId*/ 2, + mFenceUnsignaled))); +} + } // namespace android |