Loading services/surfaceflinger/SurfaceFlinger.cpp +72 −56 Original line number Diff line number Diff line Loading @@ -3647,19 +3647,11 @@ bool SurfaceFlinger::stopTransactionProcessing( return false; } bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { // 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<TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. std::unordered_set<sp<IBinder>, SpHash<IBinder>> bufferLayersReadyToPresent; std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions; { Mutex::Autolock _l(mStateLock); { Mutex::Autolock _l(mQueueLock); // Collect transactions from pending transaction queue. void SurfaceFlinger::flushPendingTransactionQueues( std::vector<TransactionState>& transactions, std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent, std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions, bool tryApplyUnsignaled) { auto it = mPendingTransactionQueues.begin(); while (it != mPendingTransactionQueues.end()) { auto& [applyToken, transactionQueue] = *it; Loading @@ -3675,8 +3667,8 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { transaction.isAutoTimestamp, transaction.desiredPresentTime, transaction.originUid, transaction.states, bufferLayersReadyToPresent, transactions.size()); bufferLayersReadyToPresent, transactions.size(), tryApplyUnsignaled); ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); if (ready == TransactionReadiness::NotReady) { setTransactionFlags(eTransactionFlushNeeded); Loading @@ -3701,21 +3693,39 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { it = std::next(it, 1); } } } bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { // 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<TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. std::unordered_set<sp<IBinder>, SpHash<IBinder>> bufferLayersReadyToPresent; std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions; { Mutex::Autolock _l(mStateLock); { Mutex::Autolock _l(mQueueLock); // First collect transactions from the pending transaction queues. // We are not allowing unsignaled buffers here as we want to // collect all the transactions from applyTokens that are ready first. flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, applyTokensWithUnsignaledTransactions, /*tryApplyUnsignaled*/ false); // Collect transactions from current transaction queue or queue to pending transactions. // 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 the transactions that are ready to apply. // Second, collect transactions from the transaction queue. // Here as well we are not allowing unsignaled buffers for the same // reason as above. while (!mTransactionQueue.empty()) { auto& transaction = mTransactionQueue.front(); const bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) != mPendingTransactionQueues.end(); const auto ready = [&]() REQUIRES(mStateLock) { if (pendingTransactions || stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) { ATRACE_NAME("pendingTransactions || stopTransactionProcessing"); if (pendingTransactions) { ATRACE_NAME("pendingTransactions"); return TransactionReadiness::NotReady; } Loading @@ -3724,7 +3734,8 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { transaction.desiredPresentTime, transaction.originUid, transaction.states, bufferLayersReadyToPresent, transactions.size()); transactions.size(), /*tryApplyUnsignaled*/ false); }(); ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); if (ready == TransactionReadiness::NotReady) { Loading @@ -3733,16 +3744,21 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { bufferLayersReadyToPresent.insert(state.surface); }); const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled); if (appliedUnsignaled) { applyTokensWithUnsignaledTransactions.insert(transaction.applyToken); } transactions.emplace_back(std::move(transaction)); } mTransactionQueue.pop_front(); ATRACE_INT("TransactionQueue", mTransactionQueue.size()); } // We collected all transactions that could apply without latching unsignaled buffers. // If we are allowing latch unsignaled of some form, now it's the time to go over the // transactions that were not applied and try to apply them unsignaled. if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, applyTokensWithUnsignaledTransactions, /*tryApplyUnsignaled*/ true); } return applyTransactions(transactions, vsyncId); } } Loading Loading @@ -3850,7 +3866,7 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent, size_t totalTXapplied) const -> TransactionReadiness { size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness { ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId); const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Do not present if the desiredPresentTime has not passed unless it is more than one second Loading Loading @@ -3887,7 +3903,7 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied( continue; } const bool allowLatchUnsignaled = const bool allowLatchUnsignaled = tryApplyUnsignaled && shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied); ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(), allowLatchUnsignaled ? "true" : "false"); Loading services/surfaceflinger/SurfaceFlinger.h +7 −1 Original line number Diff line number Diff line Loading @@ -750,6 +750,12 @@ private: // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); void flushPendingTransactionQueues( std::vector<TransactionState>& transactions, std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent, std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions, bool tryApplyUnsignaled) REQUIRES(mStateLock, mQueueLock); uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions) REQUIRES(mStateLock); Loading Loading @@ -780,7 +786,7 @@ private: const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent, size_t totalTXapplied) const REQUIRES(mStateLock); size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock); static LatchUnsignaledConfig getLatchUnsignaledConfig(); bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&, size_t numStates, size_t totalTXapplied) const; Loading services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +52 −5 Original line number Diff line number Diff line Loading @@ -551,13 +551,52 @@ TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSignaledFromTheQueue) { kExpectedTransactionsPending); } TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemoveSignaledWithUnsignaledIntact) { TEST_F(LatchUnsignaledAutoSingleLayerTest, UnsignaledNotAppliedWhenThereAreSignaled_UnsignaledFirst) { const sp<IBinder> kApplyToken1 = IInterface::asBinder(TransactionCompletedListener::getIInstance()); const sp<IBinder> kApplyToken2 = sp<BBinder>::make(); const sp<IBinder> kApplyToken3 = sp<BBinder>::make(); const auto kLayerId1 = 1; const auto kLayerId2 = 2; const auto kExpectedTransactionsApplied = 1u; const auto kExpectedTransactionsApplied = 2u; const auto kExpectedTransactionsPending = 1u; const auto unsignaledTransaction = createTransactionInfo(kApplyToken1, { createComposerState(kLayerId1, fence(Fence::Status::Unsignaled), layer_state_t::eBufferChanged), }); const auto signaledTransaction = createTransactionInfo(kApplyToken2, { createComposerState(kLayerId2, fence(Fence::Status::Signaled), layer_state_t::eBufferChanged), }); const auto signaledTransaction2 = createTransactionInfo(kApplyToken3, { createComposerState(kLayerId2, fence(Fence::Status::Signaled), layer_state_t::eBufferChanged), }); setTransactionStates({unsignaledTransaction, signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied, kExpectedTransactionsPending); } TEST_F(LatchUnsignaledAutoSingleLayerTest, UnsignaledNotAppliedWhenThereAreSignaled_SignaledFirst) { const sp<IBinder> kApplyToken1 = IInterface::asBinder(TransactionCompletedListener::getIInstance()); const sp<IBinder> kApplyToken2 = sp<BBinder>::make(); const sp<IBinder> kApplyToken3 = sp<BBinder>::make(); const auto kLayerId1 = 1; const auto kLayerId2 = 2; const auto kExpectedTransactionsApplied = 2u; const auto kExpectedTransactionsPending = 1u; const auto signaledTransaction = Loading @@ -567,15 +606,23 @@ TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemoveSignaledWithUnsignaledInt fence(Fence::Status::Signaled), layer_state_t::eBufferChanged), }); const auto unsignaledTransaction = const auto signaledTransaction2 = createTransactionInfo(kApplyToken2, { createComposerState(kLayerId1, fence(Fence::Status::Signaled), layer_state_t::eBufferChanged), }); const auto unsignaledTransaction = createTransactionInfo(kApplyToken3, { createComposerState(kLayerId2, fence(Fence::Status::Unsignaled), layer_state_t::eBufferChanged), }); setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied, kExpectedTransactionsPending); setTransactionStates({signaledTransaction, signaledTransaction2, unsignaledTransaction}, kExpectedTransactionsApplied, kExpectedTransactionsPending); } TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueueSameApplyToken) { Loading Loading
services/surfaceflinger/SurfaceFlinger.cpp +72 −56 Original line number Diff line number Diff line Loading @@ -3647,19 +3647,11 @@ bool SurfaceFlinger::stopTransactionProcessing( return false; } bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { // 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<TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. std::unordered_set<sp<IBinder>, SpHash<IBinder>> bufferLayersReadyToPresent; std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions; { Mutex::Autolock _l(mStateLock); { Mutex::Autolock _l(mQueueLock); // Collect transactions from pending transaction queue. void SurfaceFlinger::flushPendingTransactionQueues( std::vector<TransactionState>& transactions, std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent, std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions, bool tryApplyUnsignaled) { auto it = mPendingTransactionQueues.begin(); while (it != mPendingTransactionQueues.end()) { auto& [applyToken, transactionQueue] = *it; Loading @@ -3675,8 +3667,8 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { transaction.isAutoTimestamp, transaction.desiredPresentTime, transaction.originUid, transaction.states, bufferLayersReadyToPresent, transactions.size()); bufferLayersReadyToPresent, transactions.size(), tryApplyUnsignaled); ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); if (ready == TransactionReadiness::NotReady) { setTransactionFlags(eTransactionFlushNeeded); Loading @@ -3701,21 +3693,39 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { it = std::next(it, 1); } } } bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { // 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<TransactionState> transactions; // Layer handles that have transactions with buffers that are ready to be applied. std::unordered_set<sp<IBinder>, SpHash<IBinder>> bufferLayersReadyToPresent; std::unordered_set<sp<IBinder>, SpHash<IBinder>> applyTokensWithUnsignaledTransactions; { Mutex::Autolock _l(mStateLock); { Mutex::Autolock _l(mQueueLock); // First collect transactions from the pending transaction queues. // We are not allowing unsignaled buffers here as we want to // collect all the transactions from applyTokens that are ready first. flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, applyTokensWithUnsignaledTransactions, /*tryApplyUnsignaled*/ false); // Collect transactions from current transaction queue or queue to pending transactions. // 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 the transactions that are ready to apply. // Second, collect transactions from the transaction queue. // Here as well we are not allowing unsignaled buffers for the same // reason as above. while (!mTransactionQueue.empty()) { auto& transaction = mTransactionQueue.front(); const bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) != mPendingTransactionQueues.end(); const auto ready = [&]() REQUIRES(mStateLock) { if (pendingTransactions || stopTransactionProcessing(applyTokensWithUnsignaledTransactions)) { ATRACE_NAME("pendingTransactions || stopTransactionProcessing"); if (pendingTransactions) { ATRACE_NAME("pendingTransactions"); return TransactionReadiness::NotReady; } Loading @@ -3724,7 +3734,8 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { transaction.desiredPresentTime, transaction.originUid, transaction.states, bufferLayersReadyToPresent, transactions.size()); transactions.size(), /*tryApplyUnsignaled*/ false); }(); ATRACE_INT("TransactionReadiness", static_cast<int>(ready)); if (ready == TransactionReadiness::NotReady) { Loading @@ -3733,16 +3744,21 @@ bool SurfaceFlinger::flushTransactionQueues(int64_t vsyncId) { transaction.traverseStatesWithBuffers([&](const layer_state_t& state) { bufferLayersReadyToPresent.insert(state.surface); }); const bool appliedUnsignaled = (ready == TransactionReadiness::ReadyUnsignaled); if (appliedUnsignaled) { applyTokensWithUnsignaledTransactions.insert(transaction.applyToken); } transactions.emplace_back(std::move(transaction)); } mTransactionQueue.pop_front(); ATRACE_INT("TransactionQueue", mTransactionQueue.size()); } // We collected all transactions that could apply without latching unsignaled buffers. // If we are allowing latch unsignaled of some form, now it's the time to go over the // transactions that were not applied and try to apply them unsignaled. if (enableLatchUnsignaledConfig != LatchUnsignaledConfig::Disabled) { flushPendingTransactionQueues(transactions, bufferLayersReadyToPresent, applyTokensWithUnsignaledTransactions, /*tryApplyUnsignaled*/ true); } return applyTransactions(transactions, vsyncId); } } Loading Loading @@ -3850,7 +3866,7 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied( const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent, size_t totalTXapplied) const -> TransactionReadiness { size_t totalTXapplied, bool tryApplyUnsignaled) const -> TransactionReadiness { ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64, info.vsyncId); const nsecs_t expectedPresentTime = mExpectedPresentTime.load(); // Do not present if the desiredPresentTime has not passed unless it is more than one second Loading Loading @@ -3887,7 +3903,7 @@ auto SurfaceFlinger::transactionIsReadyToBeApplied( continue; } const bool allowLatchUnsignaled = const bool allowLatchUnsignaled = tryApplyUnsignaled && shouldLatchUnsignaled(layer, s, states.size(), totalTXapplied); ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(), allowLatchUnsignaled ? "true" : "false"); Loading
services/surfaceflinger/SurfaceFlinger.h +7 −1 Original line number Diff line number Diff line Loading @@ -750,6 +750,12 @@ private: // Returns true if there is at least one transaction that needs to be flushed bool transactionFlushNeeded(); void flushPendingTransactionQueues( std::vector<TransactionState>& transactions, std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent, std::unordered_set<sp<IBinder>, SpHash<IBinder>>& applyTokensWithUnsignaledTransactions, bool tryApplyUnsignaled) REQUIRES(mStateLock, mQueueLock); uint32_t setClientStateLocked(const FrameTimelineInfo&, ComposerState&, int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, uint32_t permissions) REQUIRES(mStateLock); Loading Loading @@ -780,7 +786,7 @@ private: const FrameTimelineInfo& info, bool isAutoTimestamp, int64_t desiredPresentTime, uid_t originUid, const Vector<ComposerState>& states, const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& bufferLayersReadyToPresent, size_t totalTXapplied) const REQUIRES(mStateLock); size_t totalTXapplied, bool tryApplyUnsignaled) const REQUIRES(mStateLock); static LatchUnsignaledConfig getLatchUnsignaledConfig(); bool shouldLatchUnsignaled(const sp<Layer>& layer, const layer_state_t&, size_t numStates, size_t totalTXapplied) const; Loading
services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp +52 −5 Original line number Diff line number Diff line Loading @@ -551,13 +551,52 @@ TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemovesSignaledFromTheQueue) { kExpectedTransactionsPending); } TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemoveSignaledWithUnsignaledIntact) { TEST_F(LatchUnsignaledAutoSingleLayerTest, UnsignaledNotAppliedWhenThereAreSignaled_UnsignaledFirst) { const sp<IBinder> kApplyToken1 = IInterface::asBinder(TransactionCompletedListener::getIInstance()); const sp<IBinder> kApplyToken2 = sp<BBinder>::make(); const sp<IBinder> kApplyToken3 = sp<BBinder>::make(); const auto kLayerId1 = 1; const auto kLayerId2 = 2; const auto kExpectedTransactionsApplied = 1u; const auto kExpectedTransactionsApplied = 2u; const auto kExpectedTransactionsPending = 1u; const auto unsignaledTransaction = createTransactionInfo(kApplyToken1, { createComposerState(kLayerId1, fence(Fence::Status::Unsignaled), layer_state_t::eBufferChanged), }); const auto signaledTransaction = createTransactionInfo(kApplyToken2, { createComposerState(kLayerId2, fence(Fence::Status::Signaled), layer_state_t::eBufferChanged), }); const auto signaledTransaction2 = createTransactionInfo(kApplyToken3, { createComposerState(kLayerId2, fence(Fence::Status::Signaled), layer_state_t::eBufferChanged), }); setTransactionStates({unsignaledTransaction, signaledTransaction, signaledTransaction2}, kExpectedTransactionsApplied, kExpectedTransactionsPending); } TEST_F(LatchUnsignaledAutoSingleLayerTest, UnsignaledNotAppliedWhenThereAreSignaled_SignaledFirst) { const sp<IBinder> kApplyToken1 = IInterface::asBinder(TransactionCompletedListener::getIInstance()); const sp<IBinder> kApplyToken2 = sp<BBinder>::make(); const sp<IBinder> kApplyToken3 = sp<BBinder>::make(); const auto kLayerId1 = 1; const auto kLayerId2 = 2; const auto kExpectedTransactionsApplied = 2u; const auto kExpectedTransactionsPending = 1u; const auto signaledTransaction = Loading @@ -567,15 +606,23 @@ TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_RemoveSignaledWithUnsignaledInt fence(Fence::Status::Signaled), layer_state_t::eBufferChanged), }); const auto unsignaledTransaction = const auto signaledTransaction2 = createTransactionInfo(kApplyToken2, { createComposerState(kLayerId1, fence(Fence::Status::Signaled), layer_state_t::eBufferChanged), }); const auto unsignaledTransaction = createTransactionInfo(kApplyToken3, { createComposerState(kLayerId2, fence(Fence::Status::Unsignaled), layer_state_t::eBufferChanged), }); setTransactionStates({signaledTransaction, unsignaledTransaction}, kExpectedTransactionsApplied, kExpectedTransactionsPending); setTransactionStates({signaledTransaction, signaledTransaction2, unsignaledTransaction}, kExpectedTransactionsApplied, kExpectedTransactionsPending); } TEST_F(LatchUnsignaledAutoSingleLayerTest, Flush_KeepsTransactionInTheQueueSameApplyToken) { Loading