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