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