blob: fa8eb3cf135d23bc1c0a12651f24c9b7ae4aaea6 [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
36std::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
Vishnu Nairf01a6f12023-04-03 22:34:17 +000068 applyUnsignaledBufferTransaction(transactions, flushState);
69
Vishnu Nair59f6d2d2022-10-05 16:59:56 -070070 mPendingTransactionCount.fetch_sub(transactions.size());
71 ATRACE_INT("TransactionQueue", static_cast<int>(mPendingTransactionCount.load()));
72 return transactions;
73}
74
Vishnu Nairf01a6f12023-04-03 22:34:17 +000075void TransactionHandler::applyUnsignaledBufferTransaction(
76 std::vector<TransactionState>& transactions, TransactionFlushState& flushState) {
Vishnu Nair73cc9fd2023-04-18 11:18:07 -070077 if (!flushState.queueWithUnsignaledBuffer) {
Vishnu Nairf01a6f12023-04-03 22:34:17 +000078 return;
79 }
80
Vishnu Nair73cc9fd2023-04-18 11:18:07 -070081 // only apply an unsignaled buffer transaction if it's the first one
82 if (!transactions.empty()) {
83 ATRACE_NAME("fence unsignaled");
Vishnu Nairf01a6f12023-04-03 22:34:17 +000084 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
98void 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
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700124TransactionHandler::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
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000134 case TransactionReadiness::NotReadyUnsignaled:
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700135 // 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
146int TransactionHandler::flushPendingTransactionQueues(std::vector<TransactionState>& transactions,
147 TransactionFlushState& flushState) {
148 int transactionsPendingBarrier = 0;
149 auto it = mPendingTransactionQueues.begin();
150 while (it != mPendingTransactionQueues.end()) {
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000151 auto& [applyToken, queue] = *it;
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700152 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;
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000161 } 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;
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700165 break;
166 }
Vishnu Nairf01a6f12023-04-03 22:34:17 +0000167 // ready == TransactionReadiness::Ready
168 popTransactionFromPending(transactions, flushState, queue);
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700169 }
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
180void TransactionHandler::addTransactionReadyFilter(TransactionFilter&& filter) {
181 mTransactionReadyFilters.emplace_back(std::move(filter));
182}
183
184bool TransactionHandler::hasPendingTransactions() {
185 return !mPendingTransactionQueues.empty() || !mLocklessTransactionQueue.isEmpty();
186}
187
Patrick Williamsf1e5df12022-10-17 21:37:42 +0000188void TransactionHandler::onTransactionQueueStalled(uint64_t transactionId,
189 sp<ITransactionCompletedListener>& listener,
190 const std::string& reason) {
191 if (std::find(mStalledTransactions.begin(), mStalledTransactions.end(), transactionId) !=
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700192 mStalledTransactions.end()) {
193 return;
194 }
195
Patrick Williamsf1e5df12022-10-17 21:37:42 +0000196 mStalledTransactions.push_back(transactionId);
Huihong Luoffee3bc2023-01-17 16:14:35 +0000197 listener->onTransactionQueueStalled(String8(reason.c_str()));
Vishnu Nair59f6d2d2022-10-05 16:59:56 -0700198}
199
200void TransactionHandler::removeFromStalledTransactions(uint64_t id) {
201 auto it = std::find(mStalledTransactions.begin(), mStalledTransactions.end(), id);
202 if (it != mStalledTransactions.end()) {
203 mStalledTransactions.erase(it);
204 }
205}
Vishnu Nairaf6d2972022-11-18 06:26:38 +0000206} // namespace android::surfaceflinger::frontend