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