blob: ca7c3c25f7e3a274e8565a8bec901c6e359f8bad [file] [log] [blame]
Vishnu Nair59f6d2d2022-10-05 16:59:56 -07001/*
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
Vishnu Naira02943f2023-06-03 13:44:46 -070019#define LOG_TAG "SurfaceFlinger"
Vishnu Nair59f6d2d2022-10-05 16:59:56 -070020#define ATRACE_TAG ATRACE_TAG_GRAPHICS
21
22#include <cutils/trace.h>
23#include <utils/Log.h>
Vishnu Nair73cc9fd2023-04-18 11:18:07 -070024#include <utils/Trace.h>
Vishnu Nair59f6d2d2022-10-05 16:59:56 -070025
26#include "TransactionHandler.h"
27
Vishnu Nairaf6d2972022-11-18 06:26:38 +000028namespace android::surfaceflinger::frontend {
Vishnu Nair59f6d2d2022-10-05 16:59:56 -070029
30void 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
Vishnu Nair4d9cef92023-06-24 22:34:41 +000036void TransactionHandler::collectTransactions() {
Vishnu Nair59f6d2d2022-10-05 16:59:56 -070037 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 }
Vishnu Nair4d9cef92023-06-24 22:34:41 +000045}
Vishnu Nair59f6d2d2022-10-05 16:59:56 -070046
Vishnu Nair4d9cef92023-06-24 22:34:41 +000047std::vector<TransactionState> TransactionHandler::flushTransactions() {
Vishnu Nair59f6d2d2022-10-05 16:59:56 -070048 // Collect transaction that are ready to be applied.
49 std::vector<TransactionState> transactions;
50 TransactionFlushState flushState;
51 flushState.queueProcessTime = systemTime();
52 // Transactions with a buffer pending on a barrier may be on a different applyToken
53 // than the transaction which satisfies our barrier. In fact this is the exact use case
54 // that the primitive is designed for. This means we may first process
55 // the barrier dependent transaction, determine it ineligible to complete
56 // and then satisfy in a later inner iteration of flushPendingTransactionQueues.
57 // The barrier dependent transaction was eligible to be presented in this frame
58 // but we would have prevented it without case. To fix this we continually
59 // loop through flushPendingTransactionQueues until we perform an iteration
60 // where the number of transactionsPendingBarrier doesn't change. This way
61 // we can continue to resolve dependency chains of barriers as far as possible.
62 int lastTransactionsPendingBarrier = 0;
63 int transactionsPendingBarrier = 0;
64 do {
65 lastTransactionsPendingBarrier = transactionsPendingBarrier;
66 // Collect transactions that are ready to be applied.
67 transactionsPendingBarrier = flushPendingTransactionQueues(transactions, flushState);
68 } while (lastTransactionsPendingBarrier != transactionsPendingBarrier);
69
Vishnu Nairf01a6f12023-04-03 22:34:17 +000070 applyUnsignaledBufferTransaction(transactions, flushState);
71
Vishnu Nair59f6d2d2022-10-05 16:59:56 -070072 mPendingTransactionCount.fetch_sub(transactions.size());
73 ATRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
74 return transactions;
75}
76
Vishnu Nairf01a6f12023-04-03 22:34:17 +000077void TransactionHandler::applyUnsignaledBufferTransaction(
78 std::vector<TransactionState>& transactions, TransactionFlushState& flushState) {
Vishnu Nair73cc9fd2023-04-18 11:18:07 -070079 if (!flushState.queueWithUnsignaledBuffer) {
Vishnu Nairf01a6f12023-04-03 22:34:17 +000080 return;
81 }
82
Vishnu Nair73cc9fd2023-04-18 11:18:07 -070083 // only apply an unsignaled buffer transaction if it's the first one
84 if (!transactions.empty()) {
85 ATRACE_NAME("fence unsignaled");
Vishnu Nairf01a6f12023-04-03 22:34:17 +000086 return;
87 }
88
89 auto it = mPendingTransactionQueues.find(flushState.queueWithUnsignaledBuffer);
90 LOG_ALWAYS_FATAL_IF(it == mPendingTransactionQueues.end(),
91 "Could not find queue with unsignaled buffer!");
92
93 auto& queue = it->second;
94 popTransactionFromPending(transactions, flushState, queue);
95 if (queue.empty()) {
96 it = mPendingTransactionQueues.erase(it);
97 }
98}
99
100void TransactionHandler::popTransactionFromPending(std::vector<TransactionState>& transactions,
101 TransactionFlushState& flushState,
102 std::queue<TransactionState>& queue) {
103 auto& transaction = queue.front();
104 // Transaction is ready move it from the pending queue.
105 flushState.firstTransaction = false;
106 removeFromStalledTransactions(transaction.id);
107 transactions.emplace_back(std::move(transaction));
108 queue.pop();
109
110 auto& readyToApplyTransaction = transactions.back();
111 readyToApplyTransaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
112 const bool frameNumberChanged =
113 state.bufferData->flags.test(BufferData::BufferDataChange::frameNumberChanged);
114 if (frameNumberChanged) {
115 flushState.bufferLayersReadyToPresent.emplace_or_replace(state.surface.get(),
116 state.bufferData->frameNumber);
117 } else {
118 // Barrier function only used for BBQ which always includes a frame number.
119 // This value only used for barrier logic.
120 flushState.bufferLayersReadyToPresent
121 .emplace_or_replace(state.surface.get(), std::numeric_limits<uint64_t>::max());
122 }
123 });
124}
125
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700126TransactionHandler::TransactionReadiness TransactionHandler::applyFilters(
127 TransactionFlushState& flushState) {
128 auto ready = TransactionReadiness::Ready;
129 for (auto& filter : mTransactionReadyFilters) {
130 auto perFilterReady = filter(flushState);
131 switch (perFilterReady) {
132 case TransactionReadiness::NotReady:
133 case TransactionReadiness::NotReadyBarrier:
134 return perFilterReady;
135
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000136 case TransactionReadiness::NotReadyUnsignaled:
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700137 // If one of the filters allows latching an unsignaled buffer, latch this ready
138 // state.
139 ready = perFilterReady;
140 break;
141 case TransactionReadiness::Ready:
142 continue;
143 }
144 }
145 return ready;
146}
147
148int TransactionHandler::flushPendingTransactionQueues(std::vector<TransactionState>& transactions,
149 TransactionFlushState& flushState) {
150 int transactionsPendingBarrier = 0;
151 auto it = mPendingTransactionQueues.begin();
152 while (it != mPendingTransactionQueues.end()) {
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000153 auto& [applyToken, queue] = *it;
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700154 while (!queue.empty()) {
155 auto& transaction = queue.front();
156 flushState.transaction = &transaction;
157 auto ready = applyFilters(flushState);
158 if (ready == TransactionReadiness::NotReadyBarrier) {
159 transactionsPendingBarrier++;
160 break;
161 } else if (ready == TransactionReadiness::NotReady) {
162 break;
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000163 } else if (ready == TransactionReadiness::NotReadyUnsignaled) {
164 // We maybe able to latch this transaction if it's the only transaction
165 // ready to be applied.
166 flushState.queueWithUnsignaledBuffer = applyToken;
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700167 break;
168 }
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000169 // ready == TransactionReadiness::Ready
170 popTransactionFromPending(transactions, flushState, queue);
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700171 }
172
173 if (queue.empty()) {
174 it = mPendingTransactionQueues.erase(it);
175 } else {
176 it = std::next(it, 1);
177 }
178 }
179 return transactionsPendingBarrier;
180}
181
182void TransactionHandler::addTransactionReadyFilter(TransactionFilter&& filter) {
183 mTransactionReadyFilters.emplace_back(std::move(filter));
184}
185
186bool TransactionHandler::hasPendingTransactions() {
187 return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty();
188}
189
Patrick Williamsf1e5df12022-10-17 21:37:42 +0000190void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId,
Patrick Williams090ad062023-08-08 12:30:10 -0500191 StalledTransactionInfo stalledTransactionInfo) {
192 std::lock_guard lock{mStalledMutex};
193 mStalledTransactions.emplace(transactionId, std::move(stalledTransactionInfo));
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700194}
195
Patrick Williams090ad062023-08-08 12:30:10 -0500196void TransactionHandler::removeFromStalledTransactions(uint64_t transactionId) {
197 std::lock_guard lock{mStalledMutex};
198 mStalledTransactions.erase(transactionId);
199}
200
201std::optional<TransactionHandler::StalledTransactionInfo>
202TransactionHandler::getStalledTransactionInfo(pid_t pid) {
203 std::lock_guard lock{mStalledMutex};
204 for (auto [_, stalledTransactionInfo] : mStalledTransactions) {
205 if (pid == stalledTransactionInfo.pid) {
206 return stalledTransactionInfo;
207 }
208 }
209 return std::nullopt;
210}
211
212void TransactionHandler::onLayerDestroyed(uint32_t layerId) {
213 std::lock_guard lock{mStalledMutex};
214 for (auto it = mStalledTransactions.begin(); it != mStalledTransactions.end();) {
215 if (it->second.layerId == layerId) {
216 it = mStalledTransactions.erase(it);
217 } else {
218 it++;
219 }
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700220 }
221}
Patrick Williams090ad062023-08-08 12:30:10 -0500222
Vishnu Nairaf6d2972022-11-18 06:26:38 +0000223} // namespace android::surfaceflinger::frontend