1 /*
2  * Copyright (C) 2019 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 #undef LOG_TAG
18 #define LOG_TAG "BLASTBufferQueue"
19 
20 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
21 //#define LOG_NDEBUG 0
22 
23 #include <gui/BLASTBufferQueue.h>
24 #include <gui/BufferItemConsumer.h>
25 #include <gui/BufferQueueConsumer.h>
26 #include <gui/BufferQueueCore.h>
27 #include <gui/BufferQueueProducer.h>
28 #include <gui/GLConsumer.h>
29 #include <gui/IProducerListener.h>
30 #include <gui/Surface.h>
31 #include <utils/Singleton.h>
32 #include <utils/Trace.h>
33 
34 #include <private/gui/ComposerService.h>
35 
36 #include <chrono>
37 
38 using namespace std::chrono_literals;
39 
40 namespace {
boolToString(bool b)41 inline const char* boolToString(bool b) {
42     return b ? "true" : "false";
43 }
44 } // namespace
45 
46 namespace android {
47 
48 // Macros to include adapter info in log messages
49 #define BQA_LOGD(x, ...) \
50     ALOGD("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
51 #define BQA_LOGV(x, ...) \
52     ALOGV("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
53 // enable logs for a single layer
54 //#define BQA_LOGV(x, ...) \
55 //    ALOGV_IF((strstr(mName.c_str(), "SurfaceView") != nullptr), "[%s](f:%u,a:%u) " x, \
56 //              mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
57 #define BQA_LOGE(x, ...) \
58     ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
59 
onDisconnect()60 void BLASTBufferItemConsumer::onDisconnect() {
61     Mutex::Autolock lock(mMutex);
62     mPreviouslyConnected = mCurrentlyConnected;
63     mCurrentlyConnected = false;
64     if (mPreviouslyConnected) {
65         mDisconnectEvents.push(mCurrentFrameNumber);
66     }
67     mFrameEventHistory.onDisconnect();
68 }
69 
addAndGetFrameTimestamps(const NewFrameEventsEntry * newTimestamps,FrameEventHistoryDelta * outDelta)70 void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
71                                                        FrameEventHistoryDelta* outDelta) {
72     Mutex::Autolock lock(mMutex);
73     if (newTimestamps) {
74         // BufferQueueProducer only adds a new timestamp on
75         // queueBuffer
76         mCurrentFrameNumber = newTimestamps->frameNumber;
77         mFrameEventHistory.addQueue(*newTimestamps);
78     }
79     if (outDelta) {
80         // frame event histories will be processed
81         // only after the producer connects and requests
82         // deltas for the first time.  Forward this intent
83         // to SF-side to turn event processing back on
84         mPreviouslyConnected = mCurrentlyConnected;
85         mCurrentlyConnected = true;
86         mFrameEventHistory.getAndResetDelta(outDelta);
87     }
88 }
89 
updateFrameTimestamps(uint64_t frameNumber,nsecs_t refreshStartTime,const sp<Fence> & glDoneFence,const sp<Fence> & presentFence,const sp<Fence> & prevReleaseFence,CompositorTiming compositorTiming,nsecs_t latchTime,nsecs_t dequeueReadyTime)90 void BLASTBufferItemConsumer::updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime,
91                                                     const sp<Fence>& glDoneFence,
92                                                     const sp<Fence>& presentFence,
93                                                     const sp<Fence>& prevReleaseFence,
94                                                     CompositorTiming compositorTiming,
95                                                     nsecs_t latchTime, nsecs_t dequeueReadyTime) {
96     Mutex::Autolock lock(mMutex);
97 
98     // if the producer is not connected, don't bother updating,
99     // the next producer that connects won't access this frame event
100     if (!mCurrentlyConnected) return;
101     std::shared_ptr<FenceTime> glDoneFenceTime = std::make_shared<FenceTime>(glDoneFence);
102     std::shared_ptr<FenceTime> presentFenceTime = std::make_shared<FenceTime>(presentFence);
103     std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(prevReleaseFence);
104 
105     mFrameEventHistory.addLatch(frameNumber, latchTime);
106     mFrameEventHistory.addRelease(frameNumber, dequeueReadyTime, std::move(releaseFenceTime));
107     mFrameEventHistory.addPreComposition(frameNumber, refreshStartTime);
108     mFrameEventHistory.addPostComposition(frameNumber, glDoneFenceTime, presentFenceTime,
109                                           compositorTiming);
110 }
111 
getConnectionEvents(uint64_t frameNumber,bool * needsDisconnect)112 void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect) {
113     bool disconnect = false;
114     Mutex::Autolock lock(mMutex);
115     while (!mDisconnectEvents.empty() && mDisconnectEvents.front() <= frameNumber) {
116         disconnect = true;
117         mDisconnectEvents.pop();
118     }
119     if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
120 }
121 
onSidebandStreamChanged()122 void BLASTBufferItemConsumer::onSidebandStreamChanged() {
123     sp<BLASTBufferQueue> bbq = mBLASTBufferQueue.promote();
124     if (bbq != nullptr) {
125         sp<NativeHandle> stream = getSidebandStream();
126         bbq->setSidebandStream(stream);
127     }
128 }
129 
BLASTBufferQueue(const std::string & name)130 BLASTBufferQueue::BLASTBufferQueue(const std::string& name)
131       : mSurfaceControl(nullptr),
132         mSize(1, 1),
133         mRequestedSize(mSize),
134         mFormat(PIXEL_FORMAT_RGBA_8888),
135         mNextTransaction(nullptr) {
136     createBufferQueue(&mProducer, &mConsumer);
137     // since the adapter is in the client process, set dequeue timeout
138     // explicitly so that dequeueBuffer will block
139     mProducer->setDequeueTimeout(std::numeric_limits<int64_t>::max());
140 
141     // safe default, most producers are expected to override this
142     mProducer->setMaxDequeuedBufferCount(2);
143     mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
144                                                       GraphicBuffer::USAGE_HW_COMPOSER |
145                                                               GraphicBuffer::USAGE_HW_TEXTURE,
146                                                       1, false, this);
147     static int32_t id = 0;
148     mName = name + "#" + std::to_string(id);
149     auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id);
150     mQueuedBufferTrace = "QueuedBuffer - " + mName + "BLAST#" + std::to_string(id);
151     id++;
152     mBufferItemConsumer->setName(String8(consumerName.c_str()));
153     mBufferItemConsumer->setFrameAvailableListener(this);
154     mBufferItemConsumer->setBufferFreedListener(this);
155 
156     ComposerService::getComposerService()->getMaxAcquiredBufferCount(&mMaxAcquiredBuffers);
157     mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxAcquiredBuffers);
158     mNumAcquired = 0;
159     mNumFrameAvailable = 0;
160     BQA_LOGV("BLASTBufferQueue created");
161 }
162 
BLASTBufferQueue(const std::string & name,const sp<SurfaceControl> & surface,int width,int height,int32_t format)163 BLASTBufferQueue::BLASTBufferQueue(const std::string& name, const sp<SurfaceControl>& surface,
164                                    int width, int height, int32_t format)
165       : BLASTBufferQueue(name) {
166     update(surface, width, height, format);
167 }
168 
~BLASTBufferQueue()169 BLASTBufferQueue::~BLASTBufferQueue() {
170     if (mPendingTransactions.empty()) {
171         return;
172     }
173     BQA_LOGE("Applying pending transactions on dtor %d",
174              static_cast<uint32_t>(mPendingTransactions.size()));
175     SurfaceComposerClient::Transaction t;
176     for (auto& [targetFrameNumber, transaction] : mPendingTransactions) {
177         t.merge(std::move(transaction));
178     }
179     t.apply();
180 }
181 
update(const sp<SurfaceControl> & surface,uint32_t width,uint32_t height,int32_t format,SurfaceComposerClient::Transaction * outTransaction)182 void BLASTBufferQueue::update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height,
183                               int32_t format, SurfaceComposerClient::Transaction* outTransaction) {
184     std::unique_lock _lock{mMutex};
185     if (mFormat != format) {
186         mFormat = format;
187         mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
188     }
189 
190     SurfaceComposerClient::Transaction t;
191     const bool setBackpressureFlag = !SurfaceControl::isSameSurface(mSurfaceControl, surface);
192     bool applyTransaction = false;
193 
194     // Always update the native object even though they might have the same layer handle, so we can
195     // get the updated transform hint from WM.
196     mSurfaceControl = surface;
197     if (mSurfaceControl != nullptr) {
198         if (setBackpressureFlag) {
199             t.setFlags(mSurfaceControl, layer_state_t::eEnableBackpressure,
200                        layer_state_t::eEnableBackpressure);
201             applyTransaction = true;
202         }
203         mTransformHint = mSurfaceControl->getTransformHint();
204         mBufferItemConsumer->setTransformHint(mTransformHint);
205     }
206     BQA_LOGV("update width=%d height=%d format=%d mTransformHint=%d", width, height, format,
207              mTransformHint);
208 
209     ui::Size newSize(width, height);
210     if (mRequestedSize != newSize) {
211         mRequestedSize.set(newSize);
212         mBufferItemConsumer->setDefaultBufferSize(mRequestedSize.width, mRequestedSize.height);
213         if (mLastBufferInfo.scalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
214             // If the buffer supports scaling, update the frame immediately since the client may
215             // want to scale the existing buffer to the new size.
216             mSize = mRequestedSize;
217             SurfaceComposerClient::Transaction* destFrameTransaction =
218                     (outTransaction) ? outTransaction : &t;
219             if (mSurfaceControl != nullptr) {
220                 destFrameTransaction->setDestinationFrame(mSurfaceControl,
221                                                           Rect(0, 0, newSize.getWidth(),
222                                                                newSize.getHeight()));
223             }
224             applyTransaction = true;
225         }
226     }
227     if (applyTransaction) {
228         t.setApplyToken(mApplyToken).apply();
229     }
230 }
231 
findMatchingStat(const std::vector<SurfaceControlStats> & stats,const sp<SurfaceControl> & sc)232 static std::optional<SurfaceControlStats> findMatchingStat(
233         const std::vector<SurfaceControlStats>& stats, const sp<SurfaceControl>& sc) {
234     for (auto stat : stats) {
235         if (SurfaceControl::isSameSurface(sc, stat.surfaceControl)) {
236             return stat;
237         }
238     }
239     return std::nullopt;
240 }
241 
transactionCommittedCallbackThunk(void * context,nsecs_t latchTime,const sp<Fence> & presentFence,const std::vector<SurfaceControlStats> & stats)242 static void transactionCommittedCallbackThunk(void* context, nsecs_t latchTime,
243                                               const sp<Fence>& presentFence,
244                                               const std::vector<SurfaceControlStats>& stats) {
245     if (context == nullptr) {
246         return;
247     }
248     sp<BLASTBufferQueue> bq = static_cast<BLASTBufferQueue*>(context);
249     bq->transactionCommittedCallback(latchTime, presentFence, stats);
250 }
251 
transactionCommittedCallback(nsecs_t,const sp<Fence> &,const std::vector<SurfaceControlStats> & stats)252 void BLASTBufferQueue::transactionCommittedCallback(nsecs_t /*latchTime*/,
253                                                     const sp<Fence>& /*presentFence*/,
254                                                     const std::vector<SurfaceControlStats>& stats) {
255     {
256         std::unique_lock _lock{mMutex};
257         ATRACE_CALL();
258         BQA_LOGV("transactionCommittedCallback");
259         if (!mSurfaceControlsWithPendingCallback.empty()) {
260             sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front();
261             std::optional<SurfaceControlStats> stat = findMatchingStat(stats, pendingSC);
262             if (stat) {
263                 uint64_t currFrameNumber = stat->frameEventStats.frameNumber;
264 
265                 // We need to check if we were waiting for a transaction callback in order to
266                 // process any pending buffers and unblock. It's possible to get transaction
267                 // callbacks for previous requests so we need to ensure the frame from this
268                 // transaction callback matches the last acquired buffer. Since acquireNextBuffer
269                 // will stop processing buffers when mWaitForTransactionCallback is set, we know
270                 // that mLastAcquiredFrameNumber is the frame we're waiting on.
271                 // We also want to check if mNextTransaction is null because it's possible another
272                 // sync request came in while waiting, but it hasn't started processing yet. In that
273                 // case, we don't actually want to flush the frames in between since they will get
274                 // processed and merged with the sync transaction and released earlier than if they
275                 // were sent to SF
276                 if (mWaitForTransactionCallback && mNextTransaction == nullptr &&
277                     currFrameNumber >= mLastAcquiredFrameNumber) {
278                     mWaitForTransactionCallback = false;
279                     flushShadowQueueLocked();
280                 }
281             } else {
282                 BQA_LOGE("Failed to find matching SurfaceControl in transactionCommittedCallback");
283             }
284         } else {
285             BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
286                      "empty.");
287         }
288 
289         decStrong((void*)transactionCommittedCallbackThunk);
290     }
291 }
292 
transactionCallbackThunk(void * context,nsecs_t latchTime,const sp<Fence> & presentFence,const std::vector<SurfaceControlStats> & stats)293 static void transactionCallbackThunk(void* context, nsecs_t latchTime,
294                                      const sp<Fence>& presentFence,
295                                      const std::vector<SurfaceControlStats>& stats) {
296     if (context == nullptr) {
297         return;
298     }
299     sp<BLASTBufferQueue> bq = static_cast<BLASTBufferQueue*>(context);
300     bq->transactionCallback(latchTime, presentFence, stats);
301 }
302 
transactionCallback(nsecs_t,const sp<Fence> &,const std::vector<SurfaceControlStats> & stats)303 void BLASTBufferQueue::transactionCallback(nsecs_t /*latchTime*/, const sp<Fence>& /*presentFence*/,
304                                            const std::vector<SurfaceControlStats>& stats) {
305     std::function<void(int64_t)> transactionCompleteCallback = nullptr;
306     uint64_t currFrameNumber = 0;
307 
308     {
309         std::unique_lock _lock{mMutex};
310         ATRACE_CALL();
311         BQA_LOGV("transactionCallback");
312 
313         if (!mSurfaceControlsWithPendingCallback.empty()) {
314             sp<SurfaceControl> pendingSC = mSurfaceControlsWithPendingCallback.front();
315             mSurfaceControlsWithPendingCallback.pop();
316             std::optional<SurfaceControlStats> statsOptional = findMatchingStat(stats, pendingSC);
317             if (statsOptional) {
318                 SurfaceControlStats stat = *statsOptional;
319                 mTransformHint = stat.transformHint;
320                 mBufferItemConsumer->setTransformHint(mTransformHint);
321                 BQA_LOGV("updated mTransformHint=%d", mTransformHint);
322                 // Update frametime stamps if the frame was latched and presented, indicated by a
323                 // valid latch time.
324                 if (stat.latchTime > 0) {
325                     mBufferItemConsumer
326                             ->updateFrameTimestamps(stat.frameEventStats.frameNumber,
327                                                     stat.frameEventStats.refreshStartTime,
328                                                     stat.frameEventStats.gpuCompositionDoneFence,
329                                                     stat.presentFence, stat.previousReleaseFence,
330                                                     stat.frameEventStats.compositorTiming,
331                                                     stat.latchTime,
332                                                     stat.frameEventStats.dequeueReadyTime);
333                 }
334                 currFrameNumber = stat.frameEventStats.frameNumber;
335 
336                 if (mTransactionCompleteCallback &&
337                     currFrameNumber >= mTransactionCompleteFrameNumber) {
338                     if (currFrameNumber > mTransactionCompleteFrameNumber) {
339                         BQA_LOGE("transactionCallback received for a newer framenumber=%" PRIu64
340                                  " than expected=%" PRIu64,
341                                  currFrameNumber, mTransactionCompleteFrameNumber);
342                     }
343                     transactionCompleteCallback = std::move(mTransactionCompleteCallback);
344                     mTransactionCompleteFrameNumber = 0;
345                 }
346                 std::vector<ReleaseCallbackId> staleReleases;
347                 for (const auto& [key, value]: mSubmitted) {
348                     if (currFrameNumber > key.framenumber) {
349                         staleReleases.push_back(key);
350                     }
351                 }
352                 for (const auto& staleRelease : staleReleases) {
353                     releaseBufferCallbackLocked(staleRelease, stat.previousReleaseFence ? stat.previousReleaseFence : Fence::NO_FENCE,
354                                                 stat.transformHint, stat.currentMaxAcquiredBufferCount);
355                 }
356             } else {
357                 BQA_LOGE("Failed to find matching SurfaceControl in transactionCallback");
358             }
359         } else {
360             BQA_LOGE("No matching SurfaceControls found: mSurfaceControlsWithPendingCallback was "
361                      "empty.");
362         }
363 
364 
365         decStrong((void*)transactionCallbackThunk);
366     }
367 
368     if (transactionCompleteCallback) {
369         transactionCompleteCallback(currFrameNumber);
370     }
371 }
372 
373 // Unlike transactionCallbackThunk the release buffer callback does not extend the life of the
374 // BBQ. This is because if the BBQ is destroyed, then the buffers will be released by the client.
375 // So we pass in a weak pointer to the BBQ and if it still alive, then we release the buffer.
376 // Otherwise, this is a no-op.
releaseBufferCallbackThunk(wp<BLASTBufferQueue> context,const ReleaseCallbackId & id,const sp<Fence> & releaseFence,uint32_t transformHint,uint32_t currentMaxAcquiredBufferCount)377 static void releaseBufferCallbackThunk(wp<BLASTBufferQueue> context, const ReleaseCallbackId& id,
378                                        const sp<Fence>& releaseFence, uint32_t transformHint,
379                                        uint32_t currentMaxAcquiredBufferCount) {
380     sp<BLASTBufferQueue> blastBufferQueue = context.promote();
381     if (blastBufferQueue) {
382         blastBufferQueue->releaseBufferCallback(id, releaseFence, transformHint,
383                                                 currentMaxAcquiredBufferCount);
384     } else {
385         ALOGV("releaseBufferCallbackThunk %s blastBufferQueue is dead", id.to_string().c_str());
386     }
387 }
388 
flushShadowQueueLocked()389 void BLASTBufferQueue::flushShadowQueueLocked() {
390     BQA_LOGV("flushShadowQueueLocked");
391     int numFramesToFlush = mNumFrameAvailable;
392     while (numFramesToFlush > 0) {
393         acquireNextBufferLocked(std::nullopt);
394         numFramesToFlush--;
395     }
396 }
397 
flushShadowQueue()398 void BLASTBufferQueue::flushShadowQueue() {
399     std::unique_lock _lock{mMutex};
400     flushShadowQueueLocked();
401 }
402 
releaseBufferCallback(const ReleaseCallbackId & id,const sp<Fence> & releaseFence,uint32_t transformHint,uint32_t currentMaxAcquiredBufferCount)403 void BLASTBufferQueue::releaseBufferCallback(const ReleaseCallbackId& id,
404                                              const sp<Fence>& releaseFence, uint32_t transformHint,
405                                              uint32_t currentMaxAcquiredBufferCount) {
406     std::unique_lock _lock{mMutex};
407     releaseBufferCallbackLocked(id, releaseFence, transformHint, currentMaxAcquiredBufferCount);
408 }
409 
releaseBufferCallbackLocked(const ReleaseCallbackId & id,const sp<Fence> & releaseFence,uint32_t transformHint,uint32_t currentMaxAcquiredBufferCount)410 void BLASTBufferQueue::releaseBufferCallbackLocked(const ReleaseCallbackId& id,
411                                                    const sp<Fence>& releaseFence, uint32_t transformHint,
412                                                    uint32_t currentMaxAcquiredBufferCount) {
413     ATRACE_CALL();
414     BQA_LOGV("releaseBufferCallback %s", id.to_string().c_str());
415 
416     if (mSurfaceControl != nullptr) {
417         mTransformHint = transformHint;
418         mSurfaceControl->setTransformHint(transformHint);
419         mBufferItemConsumer->setTransformHint(mTransformHint);
420         BQA_LOGV("updated mTransformHint=%d", mTransformHint);
421     }
422 
423     // Calculate how many buffers we need to hold before we release them back
424     // to the buffer queue. This will prevent higher latency when we are running
425     // on a lower refresh rate than the max supported. We only do that for EGL
426     // clients as others don't care about latency
427     const bool isEGL = [&] {
428         const auto it = mSubmitted.find(id);
429         return it != mSubmitted.end() && it->second.mApi == NATIVE_WINDOW_API_EGL;
430     }();
431 
432     const auto numPendingBuffersToHold =
433             isEGL ? std::max(0u, mMaxAcquiredBuffers - currentMaxAcquiredBufferCount) : 0;
434     auto rb = ReleasedBuffer{id, releaseFence};
435     if (std::find(mPendingRelease.begin(), mPendingRelease.end(), rb) == mPendingRelease.end()) {
436         mPendingRelease.emplace_back(rb);
437     }
438 
439     // Release all buffers that are beyond the ones that we need to hold
440     while (mPendingRelease.size() > numPendingBuffersToHold) {
441         const auto releaseBuffer = mPendingRelease.front();
442         mPendingRelease.pop_front();
443         auto it = mSubmitted.find(releaseBuffer.callbackId);
444         if (it == mSubmitted.end()) {
445             BQA_LOGE("ERROR: releaseBufferCallback without corresponding submitted buffer %s",
446                      releaseBuffer.callbackId.to_string().c_str());
447             return;
448         }
449         mNumAcquired--;
450         BQA_LOGV("released %s", id.to_string().c_str());
451         mBufferItemConsumer->releaseBuffer(it->second, releaseBuffer.releaseFence);
452         mSubmitted.erase(it);
453         // Don't process the transactions here if mWaitForTransactionCallback is set. Instead, let
454         // onFrameAvailable handle processing them since it will merge with the nextTransaction.
455         if (!mWaitForTransactionCallback) {
456             acquireNextBufferLocked(std::nullopt);
457         }
458     }
459 
460     ATRACE_INT("PendingRelease", mPendingRelease.size());
461     ATRACE_INT(mQueuedBufferTrace.c_str(),
462                mNumFrameAvailable + mNumAcquired - mPendingRelease.size());
463     mCallbackCV.notify_all();
464 }
465 
acquireNextBufferLocked(const std::optional<SurfaceComposerClient::Transaction * > transaction)466 void BLASTBufferQueue::acquireNextBufferLocked(
467         const std::optional<SurfaceComposerClient::Transaction*> transaction) {
468     ATRACE_CALL();
469     // If the next transaction is set, we want to guarantee the our acquire will not fail, so don't
470     // include the extra buffer when checking if we can acquire the next buffer.
471     const bool includeExtraAcquire = !transaction;
472     const bool maxAcquired = maxBuffersAcquired(includeExtraAcquire);
473     if (mNumFrameAvailable == 0 || maxAcquired) {
474         BQA_LOGV("Can't process next buffer maxBuffersAcquired=%s", boolToString(maxAcquired));
475         return;
476     }
477 
478     if (mSurfaceControl == nullptr) {
479         BQA_LOGE("ERROR : surface control is null");
480         return;
481     }
482 
483     SurfaceComposerClient::Transaction localTransaction;
484     bool applyTransaction = true;
485     SurfaceComposerClient::Transaction* t = &localTransaction;
486     if (transaction) {
487         t = *transaction;
488         applyTransaction = false;
489     }
490 
491     BufferItem bufferItem;
492 
493     status_t status =
494             mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
495     if (status == BufferQueue::NO_BUFFER_AVAILABLE) {
496         BQA_LOGV("Failed to acquire a buffer, err=NO_BUFFER_AVAILABLE");
497         return;
498     } else if (status != OK) {
499         BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str());
500         return;
501     }
502     auto buffer = bufferItem.mGraphicBuffer;
503     mNumFrameAvailable--;
504 
505     if (buffer == nullptr) {
506         mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
507         BQA_LOGE("Buffer was empty");
508         return;
509     }
510 
511     if (rejectBuffer(bufferItem)) {
512         BQA_LOGE("rejecting buffer:active_size=%dx%d, requested_size=%dx%d "
513                  "buffer{size=%dx%d transform=%d}",
514                  mSize.width, mSize.height, mRequestedSize.width, mRequestedSize.height,
515                  buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
516         mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
517         acquireNextBufferLocked(transaction);
518         return;
519     }
520 
521     mNumAcquired++;
522     mLastAcquiredFrameNumber = bufferItem.mFrameNumber;
523     ReleaseCallbackId releaseCallbackId(buffer->getId(), mLastAcquiredFrameNumber);
524     mSubmitted[releaseCallbackId] = bufferItem;
525 
526     bool needsDisconnect = false;
527     mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect);
528 
529     // if producer disconnected before, notify SurfaceFlinger
530     if (needsDisconnect) {
531         t->notifyProducerDisconnect(mSurfaceControl);
532     }
533 
534     // Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
535     incStrong((void*)transactionCallbackThunk);
536 
537     const bool updateDestinationFrame = mRequestedSize != mSize;
538     mSize = mRequestedSize;
539     Rect crop = computeCrop(bufferItem);
540     mLastBufferInfo.update(true /* hasBuffer */, bufferItem.mGraphicBuffer->getWidth(),
541                            bufferItem.mGraphicBuffer->getHeight(), bufferItem.mTransform,
542                            bufferItem.mScalingMode, crop);
543 
544     auto releaseBufferCallback =
545             std::bind(releaseBufferCallbackThunk, wp<BLASTBufferQueue>(this) /* callbackContext */,
546                       std::placeholders::_1, std::placeholders::_2, std::placeholders::_3,
547                       std::placeholders::_4);
548     t->setBuffer(mSurfaceControl, buffer, releaseCallbackId, releaseBufferCallback);
549     t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
550     t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
551     t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
552     t->setAcquireFence(mSurfaceControl,
553                        bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
554     t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
555 
556     mSurfaceControlsWithPendingCallback.push(mSurfaceControl);
557 
558     if (updateDestinationFrame) {
559         t->setDestinationFrame(mSurfaceControl, Rect(0, 0, mSize.getWidth(), mSize.getHeight()));
560     }
561     t->setBufferCrop(mSurfaceControl, crop);
562     t->setTransform(mSurfaceControl, bufferItem.mTransform);
563     t->setTransformToDisplayInverse(mSurfaceControl, bufferItem.mTransformToDisplayInverse);
564     if (!bufferItem.mIsAutoTimestamp) {
565         t->setDesiredPresentTime(bufferItem.mTimestamp);
566     }
567     t->setFrameNumber(mSurfaceControl, bufferItem.mFrameNumber);
568 
569     if (!mNextFrameTimelineInfoQueue.empty()) {
570         t->setFrameTimelineInfo(mNextFrameTimelineInfoQueue.front());
571         mNextFrameTimelineInfoQueue.pop();
572     }
573 
574     if (mAutoRefresh != bufferItem.mAutoRefresh) {
575         t->setAutoRefresh(mSurfaceControl, bufferItem.mAutoRefresh);
576         mAutoRefresh = bufferItem.mAutoRefresh;
577     }
578     {
579         std::unique_lock _lock{mTimestampMutex};
580         auto dequeueTime = mDequeueTimestamps.find(buffer->getId());
581         if (dequeueTime != mDequeueTimestamps.end()) {
582             Parcel p;
583             p.writeInt64(dequeueTime->second);
584             t->setMetadata(mSurfaceControl, METADATA_DEQUEUE_TIME, p);
585             mDequeueTimestamps.erase(dequeueTime);
586         }
587     }
588 
589     auto mergeTransaction =
590             [&t, currentFrameNumber = bufferItem.mFrameNumber](
591                     std::tuple<uint64_t, SurfaceComposerClient::Transaction> pendingTransaction) {
592                 auto& [targetFrameNumber, transaction] = pendingTransaction;
593                 if (currentFrameNumber < targetFrameNumber) {
594                     return false;
595                 }
596                 t->merge(std::move(transaction));
597                 return true;
598             };
599 
600     mPendingTransactions.erase(std::remove_if(mPendingTransactions.begin(),
601                                               mPendingTransactions.end(), mergeTransaction),
602                                mPendingTransactions.end());
603 
604     if (applyTransaction) {
605         t->setApplyToken(mApplyToken).apply();
606     }
607 
608     BQA_LOGV("acquireNextBufferLocked size=%dx%d mFrameNumber=%" PRIu64
609              " applyTransaction=%s mTimestamp=%" PRId64 "%s mPendingTransactions.size=%d"
610              " graphicBufferId=%" PRIu64 "%s transform=%d",
611              mSize.width, mSize.height, bufferItem.mFrameNumber, boolToString(applyTransaction),
612              bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp ? "(auto)" : "",
613              static_cast<uint32_t>(mPendingTransactions.size()), bufferItem.mGraphicBuffer->getId(),
614              bufferItem.mAutoRefresh ? " mAutoRefresh" : "", bufferItem.mTransform);
615 }
616 
computeCrop(const BufferItem & item)617 Rect BLASTBufferQueue::computeCrop(const BufferItem& item) {
618     if (item.mScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
619         return GLConsumer::scaleDownCrop(item.mCrop, mSize.width, mSize.height);
620     }
621     return item.mCrop;
622 }
623 
acquireAndReleaseBuffer()624 void BLASTBufferQueue::acquireAndReleaseBuffer() {
625     BufferItem bufferItem;
626     status_t status =
627             mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
628     if (status != OK) {
629         BQA_LOGE("Failed to acquire a buffer in acquireAndReleaseBuffer, err=%s",
630                  statusToString(status).c_str());
631         return;
632     }
633     mNumFrameAvailable--;
634     mBufferItemConsumer->releaseBuffer(bufferItem, bufferItem.mFence);
635 }
636 
onFrameAvailable(const BufferItem & item)637 void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
638     ATRACE_CALL();
639     std::unique_lock _lock{mMutex};
640 
641     const bool nextTransactionSet = mNextTransaction != nullptr;
642     BQA_LOGV("onFrameAvailable-start nextTransactionSet=%s", boolToString(nextTransactionSet));
643     if (nextTransactionSet) {
644         if (mWaitForTransactionCallback) {
645             // We are waiting on a previous sync's transaction callback so allow another sync
646             // transaction to proceed.
647             //
648             // We need to first flush out the transactions that were in between the two syncs.
649             // We do this by merging them into mNextTransaction so any buffer merging will get
650             // a release callback invoked. The release callback will be async so we need to wait
651             // on max acquired to make sure we have the capacity to acquire another buffer.
652             if (maxBuffersAcquired(false /* includeExtraAcquire */)) {
653                 BQA_LOGD("waiting to flush shadow queue...");
654                 mCallbackCV.wait(_lock);
655             }
656             while (mNumFrameAvailable > 0) {
657                 // flush out the shadow queue
658                 acquireAndReleaseBuffer();
659             }
660         }
661 
662         while (maxBuffersAcquired(false /* includeExtraAcquire */)) {
663             BQA_LOGD("waiting for free buffer.");
664             mCallbackCV.wait(_lock);
665         }
666     }
667 
668     // add to shadow queue
669     mNumFrameAvailable++;
670     if (mWaitForTransactionCallback && mNumFrameAvailable == 2) {
671         acquireAndReleaseBuffer();
672     }
673     ATRACE_INT(mQueuedBufferTrace.c_str(),
674                mNumFrameAvailable + mNumAcquired - mPendingRelease.size());
675 
676     BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s", item.mFrameNumber,
677              boolToString(nextTransactionSet));
678 
679     if (nextTransactionSet) {
680         acquireNextBufferLocked(std::move(mNextTransaction));
681 
682         // Only need a commit callback when syncing to ensure the buffer that's synced has been sent
683         // to SF
684         incStrong((void*)transactionCommittedCallbackThunk);
685         mNextTransaction->addTransactionCommittedCallback(transactionCommittedCallbackThunk,
686                                                           static_cast<void*>(this));
687 
688         mNextTransaction = nullptr;
689         mWaitForTransactionCallback = true;
690     } else if (!mWaitForTransactionCallback) {
691         acquireNextBufferLocked(std::nullopt);
692     }
693 }
694 
onFrameReplaced(const BufferItem & item)695 void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) {
696     BQA_LOGV("onFrameReplaced framenumber=%" PRIu64, item.mFrameNumber);
697     // Do nothing since we are not storing unacquired buffer items locally.
698 }
699 
onFrameDequeued(const uint64_t bufferId)700 void BLASTBufferQueue::onFrameDequeued(const uint64_t bufferId) {
701     std::unique_lock _lock{mTimestampMutex};
702     mDequeueTimestamps[bufferId] = systemTime();
703 };
704 
onFrameCancelled(const uint64_t bufferId)705 void BLASTBufferQueue::onFrameCancelled(const uint64_t bufferId) {
706     std::unique_lock _lock{mTimestampMutex};
707     mDequeueTimestamps.erase(bufferId);
708 };
709 
setNextTransaction(SurfaceComposerClient::Transaction * t)710 void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
711     std::lock_guard _lock{mMutex};
712     mNextTransaction = t;
713 }
714 
rejectBuffer(const BufferItem & item)715 bool BLASTBufferQueue::rejectBuffer(const BufferItem& item) {
716     if (item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE) {
717         // Only reject buffers if scaling mode is freeze.
718         return false;
719     }
720 
721     uint32_t bufWidth = item.mGraphicBuffer->getWidth();
722     uint32_t bufHeight = item.mGraphicBuffer->getHeight();
723 
724     // Take the buffer's orientation into account
725     if (item.mTransform & ui::Transform::ROT_90) {
726         std::swap(bufWidth, bufHeight);
727     }
728     ui::Size bufferSize(bufWidth, bufHeight);
729     if (mRequestedSize != mSize && mRequestedSize == bufferSize) {
730         return false;
731     }
732 
733     // reject buffers if the buffer size doesn't match.
734     return mSize != bufferSize;
735 }
736 
setTransactionCompleteCallback(uint64_t frameNumber,std::function<void (int64_t)> && transactionCompleteCallback)737 void BLASTBufferQueue::setTransactionCompleteCallback(
738         uint64_t frameNumber, std::function<void(int64_t)>&& transactionCompleteCallback) {
739     std::lock_guard _lock{mMutex};
740     if (transactionCompleteCallback == nullptr) {
741         mTransactionCompleteCallback = nullptr;
742     } else {
743         mTransactionCompleteCallback = std::move(transactionCompleteCallback);
744         mTransactionCompleteFrameNumber = frameNumber;
745     }
746 }
747 
748 // Check if we have acquired the maximum number of buffers.
749 // Consumer can acquire an additional buffer if that buffer is not droppable. Set
750 // includeExtraAcquire is true to include this buffer to the count. Since this depends on the state
751 // of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE.
maxBuffersAcquired(bool includeExtraAcquire) const752 bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const {
753     int maxAcquiredBuffers = mMaxAcquiredBuffers + (includeExtraAcquire ? 2 : 1);
754     return mNumAcquired == maxAcquiredBuffers;
755 }
756 
757 class BBQSurface : public Surface {
758 private:
759     std::mutex mMutex;
760     sp<BLASTBufferQueue> mBbq;
761     bool mDestroyed = false;
762 
763 public:
BBQSurface(const sp<IGraphicBufferProducer> & igbp,bool controlledByApp,const sp<IBinder> & scHandle,const sp<BLASTBufferQueue> & bbq)764     BBQSurface(const sp<IGraphicBufferProducer>& igbp, bool controlledByApp,
765                const sp<IBinder>& scHandle, const sp<BLASTBufferQueue>& bbq)
766           : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}
767 
allocateBuffers()768     void allocateBuffers() override {
769         uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth;
770         uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight;
771         auto gbp = getIGraphicBufferProducer();
772         std::thread ([reqWidth, reqHeight, gbp=getIGraphicBufferProducer(),
773                       reqFormat=mReqFormat, reqUsage=mReqUsage] () {
774             gbp->allocateBuffers(reqWidth, reqHeight,
775                                  reqFormat, reqUsage);
776 
777         }).detach();
778     }
779 
setFrameRate(float frameRate,int8_t compatibility,int8_t changeFrameRateStrategy)780     status_t setFrameRate(float frameRate, int8_t compatibility,
781                           int8_t changeFrameRateStrategy) override {
782         std::unique_lock _lock{mMutex};
783         if (mDestroyed) {
784             return DEAD_OBJECT;
785         }
786         if (!ValidateFrameRate(frameRate, compatibility, changeFrameRateStrategy,
787                                "BBQSurface::setFrameRate")) {
788             return BAD_VALUE;
789         }
790         return mBbq->setFrameRate(frameRate, compatibility, changeFrameRateStrategy);
791     }
792 
setFrameTimelineInfo(const FrameTimelineInfo & frameTimelineInfo)793     status_t setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) override {
794         std::unique_lock _lock{mMutex};
795         if (mDestroyed) {
796             return DEAD_OBJECT;
797         }
798         return mBbq->setFrameTimelineInfo(frameTimelineInfo);
799     }
800 
destroy()801     void destroy() override {
802         Surface::destroy();
803 
804         std::unique_lock _lock{mMutex};
805         mDestroyed = true;
806         mBbq = nullptr;
807     }
808 };
809 
810 // TODO: Can we coalesce this with frame updates? Need to confirm
811 // no timing issues.
setFrameRate(float frameRate,int8_t compatibility,bool shouldBeSeamless)812 status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility,
813                                         bool shouldBeSeamless) {
814     std::unique_lock _lock{mMutex};
815     SurfaceComposerClient::Transaction t;
816 
817     return t.setFrameRate(mSurfaceControl, frameRate, compatibility, shouldBeSeamless).apply();
818 }
819 
setFrameTimelineInfo(const FrameTimelineInfo & frameTimelineInfo)820 status_t BLASTBufferQueue::setFrameTimelineInfo(const FrameTimelineInfo& frameTimelineInfo) {
821     std::unique_lock _lock{mMutex};
822     mNextFrameTimelineInfoQueue.push(frameTimelineInfo);
823     return OK;
824 }
825 
setSidebandStream(const sp<NativeHandle> & stream)826 void BLASTBufferQueue::setSidebandStream(const sp<NativeHandle>& stream) {
827     std::unique_lock _lock{mMutex};
828     SurfaceComposerClient::Transaction t;
829 
830     t.setSidebandStream(mSurfaceControl, stream).apply();
831 }
832 
getSurface(bool includeSurfaceControlHandle)833 sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
834     std::unique_lock _lock{mMutex};
835     sp<IBinder> scHandle = nullptr;
836     if (includeSurfaceControlHandle && mSurfaceControl) {
837         scHandle = mSurfaceControl->getHandle();
838     }
839     return new BBQSurface(mProducer, true, scHandle, this);
840 }
841 
mergeWithNextTransaction(SurfaceComposerClient::Transaction * t,uint64_t frameNumber)842 void BLASTBufferQueue::mergeWithNextTransaction(SurfaceComposerClient::Transaction* t,
843                                                 uint64_t frameNumber) {
844     std::lock_guard _lock{mMutex};
845     if (mLastAcquiredFrameNumber >= frameNumber) {
846         // Apply the transaction since we have already acquired the desired frame.
847         t->apply();
848     } else {
849         mPendingTransactions.emplace_back(frameNumber, *t);
850         // Clear the transaction so it can't be applied elsewhere.
851         t->clear();
852     }
853 }
854 
855 // Maintains a single worker thread per process that services a list of runnables.
856 class AsyncWorker : public Singleton<AsyncWorker> {
857 private:
858     std::thread mThread;
859     bool mDone = false;
860     std::deque<std::function<void()>> mRunnables;
861     std::mutex mMutex;
862     std::condition_variable mCv;
run()863     void run() {
864         std::unique_lock<std::mutex> lock(mMutex);
865         while (!mDone) {
866             while (!mRunnables.empty()) {
867                 std::deque<std::function<void()>> runnables = std::move(mRunnables);
868                 mRunnables.clear();
869                 lock.unlock();
870                 // Run outside the lock since the runnable might trigger another
871                 // post to the async worker.
872                 execute(runnables);
873                 lock.lock();
874             }
875             mCv.wait(lock);
876         }
877     }
878 
execute(std::deque<std::function<void ()>> & runnables)879     void execute(std::deque<std::function<void()>>& runnables) {
880         while (!runnables.empty()) {
881             std::function<void()> runnable = runnables.front();
882             runnables.pop_front();
883             runnable();
884         }
885     }
886 
887 public:
AsyncWorker()888     AsyncWorker() : Singleton<AsyncWorker>() { mThread = std::thread(&AsyncWorker::run, this); }
889 
~AsyncWorker()890     ~AsyncWorker() {
891         mDone = true;
892         mCv.notify_all();
893         if (mThread.joinable()) {
894             mThread.join();
895         }
896     }
897 
post(std::function<void ()> runnable)898     void post(std::function<void()> runnable) {
899         std::unique_lock<std::mutex> lock(mMutex);
900         mRunnables.emplace_back(std::move(runnable));
901         mCv.notify_one();
902     }
903 };
904 ANDROID_SINGLETON_STATIC_INSTANCE(AsyncWorker);
905 
906 // Asynchronously calls ProducerListener functions so we can emulate one way binder calls.
907 class AsyncProducerListener : public BnProducerListener {
908 private:
909     const sp<IProducerListener> mListener;
910 
911 public:
AsyncProducerListener(const sp<IProducerListener> & listener)912     AsyncProducerListener(const sp<IProducerListener>& listener) : mListener(listener) {}
913 
onBufferReleased()914     void onBufferReleased() override {
915         AsyncWorker::getInstance().post([listener = mListener]() { listener->onBufferReleased(); });
916     }
917 
onBuffersDiscarded(const std::vector<int32_t> & slots)918     void onBuffersDiscarded(const std::vector<int32_t>& slots) override {
919         AsyncWorker::getInstance().post(
920                 [listener = mListener, slots = slots]() { listener->onBuffersDiscarded(slots); });
921     }
922 };
923 
924 // Extends the BufferQueueProducer to create a wrapper around the listener so the listener calls
925 // can be non-blocking when the producer is in the client process.
926 class BBQBufferQueueProducer : public BufferQueueProducer {
927 public:
BBQBufferQueueProducer(const sp<BufferQueueCore> & core)928     BBQBufferQueueProducer(const sp<BufferQueueCore>& core)
929           : BufferQueueProducer(core, false /* consumerIsSurfaceFlinger*/) {}
930 
connect(const sp<IProducerListener> & listener,int api,bool producerControlledByApp,QueueBufferOutput * output)931     status_t connect(const sp<IProducerListener>& listener, int api, bool producerControlledByApp,
932                      QueueBufferOutput* output) override {
933         if (!listener) {
934             return BufferQueueProducer::connect(listener, api, producerControlledByApp, output);
935         }
936 
937         return BufferQueueProducer::connect(new AsyncProducerListener(listener), api,
938                                             producerControlledByApp, output);
939     }
940 
query(int what,int * value)941     int query(int what, int* value) override {
942         if (what == NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER) {
943             *value = 1;
944             return NO_ERROR;
945         }
946         return BufferQueueProducer::query(what, value);
947     }
948 };
949 
950 // Similar to BufferQueue::createBufferQueue but creates an adapter specific bufferqueue producer.
951 // This BQP allows invoking client specified ProducerListeners and invoke them asynchronously,
952 // emulating one way binder call behavior. Without this, if the listener calls back into the queue,
953 // we can deadlock.
createBufferQueue(sp<IGraphicBufferProducer> * outProducer,sp<IGraphicBufferConsumer> * outConsumer)954 void BLASTBufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
955                                          sp<IGraphicBufferConsumer>* outConsumer) {
956     LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BLASTBufferQueue: outProducer must not be NULL");
957     LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BLASTBufferQueue: outConsumer must not be NULL");
958 
959     sp<BufferQueueCore> core(new BufferQueueCore());
960     LOG_ALWAYS_FATAL_IF(core == nullptr, "BLASTBufferQueue: failed to create BufferQueueCore");
961 
962     sp<IGraphicBufferProducer> producer(new BBQBufferQueueProducer(core));
963     LOG_ALWAYS_FATAL_IF(producer == nullptr,
964                         "BLASTBufferQueue: failed to create BBQBufferQueueProducer");
965 
966     sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
967     consumer->setAllowExtraAcquire(true);
968     LOG_ALWAYS_FATAL_IF(consumer == nullptr,
969                         "BLASTBufferQueue: failed to create BufferQueueConsumer");
970 
971     *outProducer = producer;
972     *outConsumer = consumer;
973 }
974 
convertBufferFormat(PixelFormat & format)975 PixelFormat BLASTBufferQueue::convertBufferFormat(PixelFormat& format) {
976     PixelFormat convertedFormat = format;
977     switch (format) {
978         case PIXEL_FORMAT_TRANSPARENT:
979         case PIXEL_FORMAT_TRANSLUCENT:
980             convertedFormat = PIXEL_FORMAT_RGBA_8888;
981             break;
982         case PIXEL_FORMAT_OPAQUE:
983             convertedFormat = PIXEL_FORMAT_RGBX_8888;
984             break;
985     }
986     return convertedFormat;
987 }
988 
getLastTransformHint() const989 uint32_t BLASTBufferQueue::getLastTransformHint() const {
990     if (mSurfaceControl != nullptr) {
991         return mSurfaceControl->getTransformHint();
992     } else {
993         return 0;
994     }
995 }
996 
getLastAcquiredFrameNum()997 uint64_t BLASTBufferQueue::getLastAcquiredFrameNum() {
998     std::unique_lock _lock{mMutex};
999     return mLastAcquiredFrameNumber;
1000 }
1001 
1002 } // namespace android
1003