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