blob: a209cad6122a6c7c478f652e95bbaca3f77ebde7 [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
19#define LOG_TAG "TransactionHandler"
20#define ATRACE_TAG ATRACE_TAG_GRAPHICS
21
22#include <cutils/trace.h>
23#include <utils/Log.h>
24
25#include "TransactionHandler.h"
26
Vishnu Nairaf6d2972022-11-18 06:26:38 +000027namespace android::surfaceflinger::frontend {
Vishnu Nair59f6d2d2022-10-05 16:59:56 -070028
29void TransactionHandler::queueTransaction(TransactionState&& state) {
30 mLocklessTransactionQueue.push(std::move(state));
31 mPendingTransactionCount.fetch_add(1);
32 ATRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
33}
34
35std::vector<TransactionState> TransactionHandler::flushTransactions() {
36 while (!mLocklessTransactionQueue.isEmpty()) {
37 auto maybeTransaction = mLocklessTransactionQueue.pop();
38 if (!maybeTransaction.has_value()) {
39 break;
40 }
41 auto transaction = maybeTransaction.value();
42 mPendingTransactionQueues[transaction.applyToken].emplace(std::move(transaction));
43 }
44
45 // Collect transaction that are ready to be applied.
46 std::vector<TransactionState> transactions;
47 TransactionFlushState flushState;
48 flushState.queueProcessTime = systemTime();
49 // Transactions with a buffer pending on a barrier may be on a different applyToken
50 // than the transaction which satisfies our barrier. In fact this is the exact use case
51 // that the primitive is designed for. This means we may first process
52 // the barrier dependent transaction, determine it ineligible to complete
53 // and then satisfy in a later inner iteration of flushPendingTransactionQueues.
54 // The barrier dependent transaction was eligible to be presented in this frame
55 // but we would have prevented it without case. To fix this we continually
56 // loop through flushPendingTransactionQueues until we perform an iteration
57 // where the number of transactionsPendingBarrier doesn't change. This way
58 // we can continue to resolve dependency chains of barriers as far as possible.
59 int lastTransactionsPendingBarrier = 0;
60 int transactionsPendingBarrier = 0;
61 do {
62 lastTransactionsPendingBarrier = transactionsPendingBarrier;
63 // Collect transactions that are ready to be applied.
64 transactionsPendingBarrier = flushPendingTransactionQueues(transactions, flushState);
65 } while (lastTransactionsPendingBarrier != transactionsPendingBarrier);
66
Vishnu Nairf01a6f12023-04-03 22:34:17 +000067 applyUnsignaledBufferTransaction(transactions, flushState);
68
Vishnu Nair59f6d2d2022-10-05 16:59:56 -070069 mPendingTransactionCount.fetch_sub(transactions.size());
70 ATRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
71 return transactions;
72}
73
Vishnu Nairf01a6f12023-04-03 22:34:17 +000074void TransactionHandler::applyUnsignaledBufferTransaction(
75 std::vector<TransactionState>& transactions, TransactionFlushState& flushState) {
76 // only apply an unsignaled buffer transaction if it's the first one
77 if (!transactions.empty()) {
78 return;
79 }
80
81 if (!flushState.queueWithUnsignaledBuffer) {
82 return;
83 }
84
85 auto it = mPendingTransactionQueues.find(flushState.queueWithUnsignaledBuffer);
86 LOG_ALWAYS_FATAL_IF(it == mPendingTransactionQueues.end(),
87 "Could not find queue with unsignaled buffer!");
88
89 auto& queue = it->second;
90 popTransactionFromPending(transactions, flushState, queue);
91 if (queue.empty()) {
92 it = mPendingTransactionQueues.erase(it);
93 }
94}
95
96void TransactionHandler::popTransactionFromPending(std::vector<TransactionState>& transactions,
97 TransactionFlushState& flushState,
98 std::queue<TransactionState>& queue) {
99 auto& transaction = queue.front();
100 // Transaction is ready move it from the pending queue.
101 flushState.firstTransaction = false;
102 removeFromStalledTransactions(transaction.id);
103 transactions.emplace_back(std::move(transaction));
104 queue.pop();
105
106 auto& readyToApplyTransaction = transactions.back();
107 readyToApplyTransaction.traverseStatesWithBuffers([&](const layer_state_t& state) {
108 const bool frameNumberChanged =
109 state.bufferData->flags.test(BufferData::BufferDataChange::frameNumberChanged);
110 if (frameNumberChanged) {
111 flushState.bufferLayersReadyToPresent.emplace_or_replace(state.surface.get(),
112 state.bufferData->frameNumber);
113 } else {
114 // Barrier function only used for BBQ which always includes a frame number.
115 // This value only used for barrier logic.
116 flushState.bufferLayersReadyToPresent
117 .emplace_or_replace(state.surface.get(), std::numeric_limits<uint64_t>::max());
118 }
119 });
120}
121
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700122TransactionHandler::TransactionReadiness TransactionHandler::applyFilters(
123 TransactionFlushState& flushState) {
124 auto ready = TransactionReadiness::Ready;
125 for (auto& filter : mTransactionReadyFilters) {
126 auto perFilterReady = filter(flushState);
127 switch (perFilterReady) {
128 case TransactionReadiness::NotReady:
129 case TransactionReadiness::NotReadyBarrier:
130 return perFilterReady;
131
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000132 case TransactionReadiness::NotReadyUnsignaled:
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700133 // If one of the filters allows latching an unsignaled buffer, latch this ready
134 // state.
135 ready = perFilterReady;
136 break;
137 case TransactionReadiness::Ready:
138 continue;
139 }
140 }
141 return ready;
142}
143
144int TransactionHandler::flushPendingTransactionQueues(std::vector<TransactionState>& transactions,
145 TransactionFlushState& flushState) {
146 int transactionsPendingBarrier = 0;
147 auto it = mPendingTransactionQueues.begin();
148 while (it != mPendingTransactionQueues.end()) {
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000149 auto& [applyToken, queue] = *it;
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700150 while (!queue.empty()) {
151 auto& transaction = queue.front();
152 flushState.transaction = &transaction;
153 auto ready = applyFilters(flushState);
154 if (ready == TransactionReadiness::NotReadyBarrier) {
155 transactionsPendingBarrier++;
156 break;
157 } else if (ready == TransactionReadiness::NotReady) {
158 break;
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000159 } else if (ready == TransactionReadiness::NotReadyUnsignaled) {
160 // We maybe able to latch this transaction if it's the only transaction
161 // ready to be applied.
162 flushState.queueWithUnsignaledBuffer = applyToken;
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700163 break;
164 }
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000165 // ready == TransactionReadiness::Ready
166 popTransactionFromPending(transactions, flushState, queue);
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700167 }
168
169 if (queue.empty()) {
170 it = mPendingTransactionQueues.erase(it);
171 } else {
172 it = std::next(it, 1);
173 }
174 }
175 return transactionsPendingBarrier;
176}
177
178void TransactionHandler::addTransactionReadyFilter(TransactionFilter&& filter) {
179 mTransactionReadyFilters.emplace_back(std::move(filter));
180}
181
182bool TransactionHandler::hasPendingTransactions() {
183 return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty();
184}
185
Patrick Williamsf1e5df12022-10-17 21:37:42 +0000186void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId,
187 sp<ITransactionCompletedListener>& listener,
188 const std::string& reason) {
189 if (std::find(mStalledTransactions.begin(), mStalledTransactions.end(), transactionId) !=
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700190 mStalledTransactions.end()) {
191 return;
192 }
193
Patrick Williamsf1e5df12022-10-17 21:37:42 +0000194 mStalledTransactions.push_back(transactionId);
Huihong Luoffee3bc2023-01-17 16:14:35 +0000195 listener->onTransactionQueueStalled(String8(reason.c_str()));
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700196}
197
198void TransactionHandler::removeFromStalledTransactions(uint64_t id) {
199 auto it = std::find(mStalledTransactions.begin(), mStalledTransactions.end(), id);
200 if (it != mStalledTransactions.end()) {
201 mStalledTransactions.erase(it);
202 }
203}
Vishnu Nairaf6d2972022-11-18 06:26:38 +0000204} // namespace android::surfaceflinger::frontend