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