xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/FrontEnd/TransactionHandler.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2022 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker // #define LOG_NDEBUG 0
18*38e8c45fSAndroid Build Coastguard Worker #undef LOG_TAG
19*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "SurfaceFlinger"
20*38e8c45fSAndroid Build Coastguard Worker #define ATRACE_TAG ATRACE_TAG_GRAPHICS
21*38e8c45fSAndroid Build Coastguard Worker 
22*38e8c45fSAndroid Build Coastguard Worker #include <common/trace.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <cutils/trace.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <utils/Log.h>
25*38e8c45fSAndroid Build Coastguard Worker #include "FrontEnd/LayerLog.h"
26*38e8c45fSAndroid Build Coastguard Worker 
27*38e8c45fSAndroid Build Coastguard Worker #include "TransactionHandler.h"
28*38e8c45fSAndroid Build Coastguard Worker 
29*38e8c45fSAndroid Build Coastguard Worker namespace android::surfaceflinger::frontend {
30*38e8c45fSAndroid Build Coastguard Worker 
queueTransaction(TransactionState && state)31*38e8c45fSAndroid Build Coastguard Worker void TransactionHandler::queueTransaction(TransactionState&& state) {
32*38e8c45fSAndroid Build Coastguard Worker     mLocklessTransactionQueue.push(std::move(state));
33*38e8c45fSAndroid Build Coastguard Worker     mPendingTransactionCount.fetch_add(1);
34*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
35*38e8c45fSAndroid Build Coastguard Worker }
36*38e8c45fSAndroid Build Coastguard Worker 
collectTransactions()37*38e8c45fSAndroid Build Coastguard Worker void TransactionHandler::collectTransactions() {
38*38e8c45fSAndroid Build Coastguard Worker     while (!mLocklessTransactionQueue.isEmpty()) {
39*38e8c45fSAndroid Build Coastguard Worker         auto maybeTransaction = mLocklessTransactionQueue.pop();
40*38e8c45fSAndroid Build Coastguard Worker         if (!maybeTransaction.has_value()) {
41*38e8c45fSAndroid Build Coastguard Worker             break;
42*38e8c45fSAndroid Build Coastguard Worker         }
43*38e8c45fSAndroid Build Coastguard Worker         auto transaction = maybeTransaction.value();
44*38e8c45fSAndroid Build Coastguard Worker         mPendingTransactionQueues[transaction.applyToken].emplace(std::move(transaction));
45*38e8c45fSAndroid Build Coastguard Worker     }
46*38e8c45fSAndroid Build Coastguard Worker }
47*38e8c45fSAndroid Build Coastguard Worker 
flushTransactions()48*38e8c45fSAndroid Build Coastguard Worker std::vector<TransactionState> TransactionHandler::flushTransactions() {
49*38e8c45fSAndroid Build Coastguard Worker     // Collect transaction that are ready to be applied.
50*38e8c45fSAndroid Build Coastguard Worker     std::vector<TransactionState> transactions;
51*38e8c45fSAndroid Build Coastguard Worker     TransactionFlushState flushState;
52*38e8c45fSAndroid Build Coastguard Worker     flushState.queueProcessTime = systemTime();
53*38e8c45fSAndroid Build Coastguard Worker     // Transactions with a buffer pending on a barrier may be on a different applyToken
54*38e8c45fSAndroid Build Coastguard Worker     // than the transaction which satisfies our barrier. In fact this is the exact use case
55*38e8c45fSAndroid Build Coastguard Worker     // that the primitive is designed for. This means we may first process
56*38e8c45fSAndroid Build Coastguard Worker     // the barrier dependent transaction, determine it ineligible to complete
57*38e8c45fSAndroid Build Coastguard Worker     // and then satisfy in a later inner iteration of flushPendingTransactionQueues.
58*38e8c45fSAndroid Build Coastguard Worker     // The barrier dependent transaction was eligible to be presented in this frame
59*38e8c45fSAndroid Build Coastguard Worker     // but we would have prevented it without case. To fix this we continually
60*38e8c45fSAndroid Build Coastguard Worker     // loop through flushPendingTransactionQueues until we perform an iteration
61*38e8c45fSAndroid Build Coastguard Worker     // where the number of transactionsPendingBarrier doesn't change. This way
62*38e8c45fSAndroid Build Coastguard Worker     // we can continue to resolve dependency chains of barriers as far as possible.
63*38e8c45fSAndroid Build Coastguard Worker     int lastTransactionsPendingBarrier = 0;
64*38e8c45fSAndroid Build Coastguard Worker     int transactionsPendingBarrier = 0;
65*38e8c45fSAndroid Build Coastguard Worker     do {
66*38e8c45fSAndroid Build Coastguard Worker         lastTransactionsPendingBarrier = transactionsPendingBarrier;
67*38e8c45fSAndroid Build Coastguard Worker         // Collect transactions that are ready to be applied.
68*38e8c45fSAndroid Build Coastguard Worker         transactionsPendingBarrier = flushPendingTransactionQueues(transactions, flushState);
69*38e8c45fSAndroid Build Coastguard Worker     } while (lastTransactionsPendingBarrier != transactionsPendingBarrier);
70*38e8c45fSAndroid Build Coastguard Worker 
71*38e8c45fSAndroid Build Coastguard Worker     applyUnsignaledBufferTransaction(transactions, flushState);
72*38e8c45fSAndroid Build Coastguard Worker 
73*38e8c45fSAndroid Build Coastguard Worker     mPendingTransactionCount.fetch_sub(transactions.size());
74*38e8c45fSAndroid Build Coastguard Worker     SFTRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
75*38e8c45fSAndroid Build Coastguard Worker     return transactions;
76*38e8c45fSAndroid Build Coastguard Worker }
77*38e8c45fSAndroid Build Coastguard Worker 
applyUnsignaledBufferTransaction(std::vector<TransactionState> & transactions,TransactionFlushState & flushState)78*38e8c45fSAndroid Build Coastguard Worker void TransactionHandler::applyUnsignaledBufferTransaction(
79*38e8c45fSAndroid Build Coastguard Worker         std::vector<TransactionState>& transactions, TransactionFlushState& flushState) {
80*38e8c45fSAndroid Build Coastguard Worker     if (!flushState.queueWithUnsignaledBuffer) {
81*38e8c45fSAndroid Build Coastguard Worker         return;
82*38e8c45fSAndroid Build Coastguard Worker     }
83*38e8c45fSAndroid Build Coastguard Worker 
84*38e8c45fSAndroid Build Coastguard Worker     // only apply an unsignaled buffer transaction if it's the first one
85*38e8c45fSAndroid Build Coastguard Worker     if (!transactions.empty()) {
86*38e8c45fSAndroid Build Coastguard Worker         SFTRACE_NAME("fence unsignaled");
87*38e8c45fSAndroid Build Coastguard Worker         return;
88*38e8c45fSAndroid Build Coastguard Worker     }
89*38e8c45fSAndroid Build Coastguard Worker 
90*38e8c45fSAndroid Build Coastguard Worker     auto it = mPendingTransactionQueues.find(flushState.queueWithUnsignaledBuffer);
91*38e8c45fSAndroid Build Coastguard Worker     LLOG_ALWAYS_FATAL_WITH_TRACE_IF(it == mPendingTransactionQueues.end(),
92*38e8c45fSAndroid Build Coastguard Worker                                     "Could not find queue with unsignaled buffer!");
93*38e8c45fSAndroid Build Coastguard Worker 
94*38e8c45fSAndroid Build Coastguard Worker     auto& queue = it->second;
95*38e8c45fSAndroid Build Coastguard Worker     popTransactionFromPending(transactions, flushState, queue);
96*38e8c45fSAndroid Build Coastguard Worker     if (queue.empty()) {
97*38e8c45fSAndroid Build Coastguard Worker         it = mPendingTransactionQueues.erase(it);
98*38e8c45fSAndroid Build Coastguard Worker     }
99*38e8c45fSAndroid Build Coastguard Worker }
100*38e8c45fSAndroid Build Coastguard Worker 
popTransactionFromPending(std::vector<TransactionState> & transactions,TransactionFlushState & flushState,std::queue<TransactionState> & queue)101*38e8c45fSAndroid Build Coastguard Worker void TransactionHandler::popTransactionFromPending(std::vector<TransactionState>& transactions,
102*38e8c45fSAndroid Build Coastguard Worker                                                    TransactionFlushState& flushState,
103*38e8c45fSAndroid Build Coastguard Worker                                                    std::queue<TransactionState>& queue) {
104*38e8c45fSAndroid Build Coastguard Worker     auto& transaction = queue.front();
105*38e8c45fSAndroid Build Coastguard Worker     // Transaction is ready move it from the pending queue.
106*38e8c45fSAndroid Build Coastguard Worker     flushState.firstTransaction = false;
107*38e8c45fSAndroid Build Coastguard Worker     removeFromStalledTransactions(transaction.id);
108*38e8c45fSAndroid Build Coastguard Worker     transactions.emplace_back(std::move(transaction));
109*38e8c45fSAndroid Build Coastguard Worker     queue.pop();
110*38e8c45fSAndroid Build Coastguard Worker 
111*38e8c45fSAndroid Build Coastguard Worker     auto& readyToApplyTransaction = transactions.back();
112*38e8c45fSAndroid Build Coastguard Worker     readyToApplyTransaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
113*38e8c45fSAndroid Build Coastguard Worker         const bool frameNumberChanged =
114*38e8c45fSAndroid Build Coastguard Worker                 state.bufferData->flags.test(BufferData::BufferDataChange::frameNumberChanged);
115*38e8c45fSAndroid Build Coastguard Worker         if (frameNumberChanged) {
116*38e8c45fSAndroid Build Coastguard Worker             flushState.bufferLayersReadyToPresent.emplace_or_replace(state.surface.get(),
117*38e8c45fSAndroid Build Coastguard Worker                                                                      state.bufferData->frameNumber);
118*38e8c45fSAndroid Build Coastguard Worker         } else {
119*38e8c45fSAndroid Build Coastguard Worker             // Barrier function only used for BBQ which always includes a frame number.
120*38e8c45fSAndroid Build Coastguard Worker             // This value only used for barrier logic.
121*38e8c45fSAndroid Build Coastguard Worker             flushState.bufferLayersReadyToPresent
122*38e8c45fSAndroid Build Coastguard Worker                     .emplace_or_replace(state.surface.get(), std::numeric_limits<uint64_t>::max());
123*38e8c45fSAndroid Build Coastguard Worker         }
124*38e8c45fSAndroid Build Coastguard Worker     });
125*38e8c45fSAndroid Build Coastguard Worker }
126*38e8c45fSAndroid Build Coastguard Worker 
applyFilters(TransactionFlushState & flushState)127*38e8c45fSAndroid Build Coastguard Worker TransactionHandler::TransactionReadiness TransactionHandler::applyFilters(
128*38e8c45fSAndroid Build Coastguard Worker         TransactionFlushState& flushState) {
129*38e8c45fSAndroid Build Coastguard Worker     auto ready = TransactionReadiness::Ready;
130*38e8c45fSAndroid Build Coastguard Worker     for (auto& filter : mTransactionReadyFilters) {
131*38e8c45fSAndroid Build Coastguard Worker         auto perFilterReady = filter(flushState);
132*38e8c45fSAndroid Build Coastguard Worker         switch (perFilterReady) {
133*38e8c45fSAndroid Build Coastguard Worker             case TransactionReadiness::NotReady:
134*38e8c45fSAndroid Build Coastguard Worker             case TransactionReadiness::NotReadyBarrier:
135*38e8c45fSAndroid Build Coastguard Worker                 return perFilterReady;
136*38e8c45fSAndroid Build Coastguard Worker 
137*38e8c45fSAndroid Build Coastguard Worker             case TransactionReadiness::NotReadyUnsignaled:
138*38e8c45fSAndroid Build Coastguard Worker                 // If one of the filters allows latching an unsignaled buffer, latch this ready
139*38e8c45fSAndroid Build Coastguard Worker                 // state.
140*38e8c45fSAndroid Build Coastguard Worker                 ready = perFilterReady;
141*38e8c45fSAndroid Build Coastguard Worker                 break;
142*38e8c45fSAndroid Build Coastguard Worker             case TransactionReadiness::Ready:
143*38e8c45fSAndroid Build Coastguard Worker                 continue;
144*38e8c45fSAndroid Build Coastguard Worker         }
145*38e8c45fSAndroid Build Coastguard Worker     }
146*38e8c45fSAndroid Build Coastguard Worker     return ready;
147*38e8c45fSAndroid Build Coastguard Worker }
148*38e8c45fSAndroid Build Coastguard Worker 
flushPendingTransactionQueues(std::vector<TransactionState> & transactions,TransactionFlushState & flushState)149*38e8c45fSAndroid Build Coastguard Worker int TransactionHandler::flushPendingTransactionQueues(std::vector<TransactionState>& transactions,
150*38e8c45fSAndroid Build Coastguard Worker                                                       TransactionFlushState& flushState) {
151*38e8c45fSAndroid Build Coastguard Worker     int transactionsPendingBarrier = 0;
152*38e8c45fSAndroid Build Coastguard Worker     auto it = mPendingTransactionQueues.begin();
153*38e8c45fSAndroid Build Coastguard Worker     while (it != mPendingTransactionQueues.end()) {
154*38e8c45fSAndroid Build Coastguard Worker         auto& [applyToken, queue] = *it;
155*38e8c45fSAndroid Build Coastguard Worker         while (!queue.empty()) {
156*38e8c45fSAndroid Build Coastguard Worker             auto& transaction = queue.front();
157*38e8c45fSAndroid Build Coastguard Worker             flushState.transaction = &transaction;
158*38e8c45fSAndroid Build Coastguard Worker             auto ready = applyFilters(flushState);
159*38e8c45fSAndroid Build Coastguard Worker             if (ready == TransactionReadiness::NotReadyBarrier) {
160*38e8c45fSAndroid Build Coastguard Worker                 transactionsPendingBarrier++;
161*38e8c45fSAndroid Build Coastguard Worker                 break;
162*38e8c45fSAndroid Build Coastguard Worker             } else if (ready == TransactionReadiness::NotReady) {
163*38e8c45fSAndroid Build Coastguard Worker                 break;
164*38e8c45fSAndroid Build Coastguard Worker             } else if (ready == TransactionReadiness::NotReadyUnsignaled) {
165*38e8c45fSAndroid Build Coastguard Worker                 // We maybe able to latch this transaction if it's the only transaction
166*38e8c45fSAndroid Build Coastguard Worker                 // ready to be applied.
167*38e8c45fSAndroid Build Coastguard Worker                 flushState.queueWithUnsignaledBuffer = applyToken;
168*38e8c45fSAndroid Build Coastguard Worker                 break;
169*38e8c45fSAndroid Build Coastguard Worker             }
170*38e8c45fSAndroid Build Coastguard Worker             // ready == TransactionReadiness::Ready
171*38e8c45fSAndroid Build Coastguard Worker             popTransactionFromPending(transactions, flushState, queue);
172*38e8c45fSAndroid Build Coastguard Worker         }
173*38e8c45fSAndroid Build Coastguard Worker 
174*38e8c45fSAndroid Build Coastguard Worker         if (queue.empty()) {
175*38e8c45fSAndroid Build Coastguard Worker             it = mPendingTransactionQueues.erase(it);
176*38e8c45fSAndroid Build Coastguard Worker         } else {
177*38e8c45fSAndroid Build Coastguard Worker             it = std::next(it, 1);
178*38e8c45fSAndroid Build Coastguard Worker         }
179*38e8c45fSAndroid Build Coastguard Worker     }
180*38e8c45fSAndroid Build Coastguard Worker     return transactionsPendingBarrier;
181*38e8c45fSAndroid Build Coastguard Worker }
182*38e8c45fSAndroid Build Coastguard Worker 
addTransactionReadyFilter(TransactionFilter && filter)183*38e8c45fSAndroid Build Coastguard Worker void TransactionHandler::addTransactionReadyFilter(TransactionFilter&& filter) {
184*38e8c45fSAndroid Build Coastguard Worker     mTransactionReadyFilters.emplace_back(std::move(filter));
185*38e8c45fSAndroid Build Coastguard Worker }
186*38e8c45fSAndroid Build Coastguard Worker 
hasPendingTransactions()187*38e8c45fSAndroid Build Coastguard Worker bool TransactionHandler::hasPendingTransactions() {
188*38e8c45fSAndroid Build Coastguard Worker     return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty();
189*38e8c45fSAndroid Build Coastguard Worker }
190*38e8c45fSAndroid Build Coastguard Worker 
onTransactionQueueStalled(uint64_t transactionId,StalledTransactionInfo stalledTransactionInfo)191*38e8c45fSAndroid Build Coastguard Worker void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId,
192*38e8c45fSAndroid Build Coastguard Worker                                                    StalledTransactionInfo stalledTransactionInfo) {
193*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock{mStalledMutex};
194*38e8c45fSAndroid Build Coastguard Worker     mStalledTransactions.emplace(transactionId, std::move(stalledTransactionInfo));
195*38e8c45fSAndroid Build Coastguard Worker }
196*38e8c45fSAndroid Build Coastguard Worker 
removeFromStalledTransactions(uint64_t transactionId)197*38e8c45fSAndroid Build Coastguard Worker void TransactionHandler::removeFromStalledTransactions(uint64_t transactionId) {
198*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock{mStalledMutex};
199*38e8c45fSAndroid Build Coastguard Worker     mStalledTransactions.erase(transactionId);
200*38e8c45fSAndroid Build Coastguard Worker }
201*38e8c45fSAndroid Build Coastguard Worker 
202*38e8c45fSAndroid Build Coastguard Worker std::optional<TransactionHandler::StalledTransactionInfo>
getStalledTransactionInfo(pid_t pid)203*38e8c45fSAndroid Build Coastguard Worker TransactionHandler::getStalledTransactionInfo(pid_t pid) {
204*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock{mStalledMutex};
205*38e8c45fSAndroid Build Coastguard Worker     for (auto [_, stalledTransactionInfo] : mStalledTransactions) {
206*38e8c45fSAndroid Build Coastguard Worker         if (pid == stalledTransactionInfo.pid) {
207*38e8c45fSAndroid Build Coastguard Worker             return stalledTransactionInfo;
208*38e8c45fSAndroid Build Coastguard Worker         }
209*38e8c45fSAndroid Build Coastguard Worker     }
210*38e8c45fSAndroid Build Coastguard Worker     return std::nullopt;
211*38e8c45fSAndroid Build Coastguard Worker }
212*38e8c45fSAndroid Build Coastguard Worker 
onLayerDestroyed(uint32_t layerId)213*38e8c45fSAndroid Build Coastguard Worker void TransactionHandler::onLayerDestroyed(uint32_t layerId) {
214*38e8c45fSAndroid Build Coastguard Worker     std::lock_guard lock{mStalledMutex};
215*38e8c45fSAndroid Build Coastguard Worker     for (auto it = mStalledTransactions.begin(); it != mStalledTransactions.end();) {
216*38e8c45fSAndroid Build Coastguard Worker         if (it->second.layerId == layerId) {
217*38e8c45fSAndroid Build Coastguard Worker             it = mStalledTransactions.erase(it);
218*38e8c45fSAndroid Build Coastguard Worker         } else {
219*38e8c45fSAndroid Build Coastguard Worker             it++;
220*38e8c45fSAndroid Build Coastguard Worker         }
221*38e8c45fSAndroid Build Coastguard Worker     }
222*38e8c45fSAndroid Build Coastguard Worker }
223*38e8c45fSAndroid Build Coastguard Worker 
224*38e8c45fSAndroid Build Coastguard Worker } // namespace android::surfaceflinger::frontend
225