1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 //#define LOG_NDEBUG 0
6 #define LOG_TAG "C2VdaBqBlockPool"
7
8 #include <v4l2_codec2/plugin_store/C2VdaBqBlockPool.h>
9
10 #include <errno.h>
11
12 #include <chrono>
13 #include <mutex>
14 #include <thread>
15
16 #include <C2AllocatorGralloc.h>
17 #include <C2BlockInternal.h>
18 #include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
19 #include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
20 #include <base/callback.h>
21 #include <log/log.h>
22 #include <system/window.h>
23 #include <types.h>
24 #include <ui/BufferQueueDefs.h>
25
26 #include <v4l2_codec2/plugin_store/V4L2AllocatorId.h>
27
28 namespace android {
29 namespace {
30
31 // The wait time for acquire fence in milliseconds.
32 constexpr int kFenceWaitTimeMs = 10;
33 // The timeout limit of acquiring lock of timed_mutex in milliseconds.
34 constexpr std::chrono::milliseconds kTimedMutexTimeoutMs = std::chrono::milliseconds(500);
35
36 } // namespace
37
38 using namespace std::chrono_literals;
39
40 using ::android::C2AndroidMemoryUsage;
41 using ::android::Fence;
42 using ::android::GraphicBuffer;
43 using ::android::sp;
44 using ::android::status_t;
45 using ::android::BufferQueueDefs::BUFFER_NEEDS_REALLOCATION;
46 using ::android::BufferQueueDefs::NUM_BUFFER_SLOTS;
47 using ::android::BufferQueueDefs::RELEASE_ALL_BUFFERS;
48 using ::android::hardware::hidl_handle;
49 using ::android::hardware::Return;
50
51 using HBuffer = ::android::hardware::graphics::common::V1_2::HardwareBuffer;
52 using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::Status;
53 using HGraphicBufferProducer =
54 ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer;
55 using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0::IProducerListener;
56 using HConnectionType = hardware::graphics::bufferqueue::V2_0::ConnectionType;
57 using HQueueBufferOutput =
58 ::android::hardware::graphics::bufferqueue::V2_0::IGraphicBufferProducer::QueueBufferOutput;
59
60 using ::android::hardware::graphics::bufferqueue::V2_0::utils::b2h;
61 using ::android::hardware::graphics::bufferqueue::V2_0::utils::h2b;
62 using ::android::hardware::graphics::bufferqueue::V2_0::utils::HFenceWrapper;
63
asC2Error(int32_t err)64 static c2_status_t asC2Error(int32_t err) {
65 switch (err) {
66 case android::NO_ERROR:
67 return C2_OK;
68 case android::NO_INIT:
69 return C2_NO_INIT;
70 case android::BAD_VALUE:
71 return C2_BAD_VALUE;
72 case android::TIMED_OUT:
73 return C2_TIMED_OUT;
74 case android::WOULD_BLOCK:
75 return C2_BLOCKING;
76 case android::NO_MEMORY:
77 return C2_NO_MEMORY;
78 }
79 return C2_CORRUPTED;
80 }
81
82 class H2BGraphicBufferProducer {
83 public:
H2BGraphicBufferProducer(sp<HGraphicBufferProducer> base)84 explicit H2BGraphicBufferProducer(sp<HGraphicBufferProducer> base) : mBase(base) {}
85 ~H2BGraphicBufferProducer() = default;
86
requestBuffer(int slot,sp<GraphicBuffer> * buf)87 status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) {
88 bool converted = false;
89 status_t status = UNKNOWN_ERROR;
90 Return<void> transResult = mBase->requestBuffer(
91 slot, [&converted, &status, buf](HStatus hStatus, HBuffer const& hBuffer,
92 uint32_t generationNumber) {
93 converted = h2b(hStatus, &status) && h2b(hBuffer, buf);
94 if (*buf) {
95 (*buf)->setGenerationNumber(generationNumber);
96 }
97 });
98
99 if (!transResult.isOk()) {
100 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
101 return FAILED_TRANSACTION;
102 }
103 if (!converted) {
104 ALOGE("%s(): corrupted transaction.", __func__);
105 return FAILED_TRANSACTION;
106 }
107 if (status != android::NO_ERROR) {
108 ALOGE("%s() failed: %d", __func__, status);
109 }
110 return status;
111 }
112
setMaxDequeuedBufferCount(int maxDequeuedBuffers)113 status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) {
114 status_t status = UNKNOWN_ERROR;
115 Return<HStatus> transResult =
116 mBase->setMaxDequeuedBufferCount(static_cast<int32_t>(maxDequeuedBuffers));
117
118 if (!transResult.isOk()) {
119 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
120 return FAILED_TRANSACTION;
121 }
122 if (!h2b(static_cast<HStatus>(transResult), &status)) {
123 ALOGE("%s(): corrupted transaction.", __func__);
124 return FAILED_TRANSACTION;
125 }
126 if (status != android::NO_ERROR) {
127 ALOGE("%s() failed: %d", __func__, status);
128 }
129 return status;
130 }
131
dequeueBuffer(uint32_t width,uint32_t height,uint32_t pixelFormat,C2AndroidMemoryUsage androidUsage,int * slot,sp<Fence> * fence)132 status_t dequeueBuffer(uint32_t width, uint32_t height, uint32_t pixelFormat,
133 C2AndroidMemoryUsage androidUsage, int* slot, sp<Fence>* fence) {
134 using Input = HGraphicBufferProducer::DequeueBufferInput;
135 using Output = HGraphicBufferProducer::DequeueBufferOutput;
136 Input input{width, height, pixelFormat, androidUsage.asGrallocUsage()};
137
138 bool converted = false;
139 status_t status = UNKNOWN_ERROR;
140 Return<void> transResult = mBase->dequeueBuffer(
141 input, [&converted, &status, &slot, &fence](HStatus hStatus, int32_t hSlot,
142 Output const& hOutput) {
143 converted = h2b(hStatus, &status);
144 if (!converted || status != android::NO_ERROR) {
145 return;
146 }
147
148 *slot = hSlot;
149 if (hOutput.bufferNeedsReallocation) {
150 status = BUFFER_NEEDS_REALLOCATION;
151 }
152 converted = h2b(hOutput.fence, fence);
153 });
154
155 if (!transResult.isOk()) {
156 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
157 return FAILED_TRANSACTION;
158 }
159 if (!converted) {
160 ALOGE("%s(): corrupted transaction.", __func__);
161 return FAILED_TRANSACTION;
162 }
163 if (status != android::NO_ERROR && status != BUFFER_NEEDS_REALLOCATION &&
164 status != android::TIMED_OUT) {
165 ALOGE("%s() failed: %d", __func__, status);
166 }
167 return status;
168 }
169
detachBuffer(int slot)170 status_t detachBuffer(int slot) {
171 status_t status = UNKNOWN_ERROR;
172 Return<HStatus> transResult = mBase->detachBuffer(static_cast<int32_t>(slot));
173
174 if (!transResult.isOk()) {
175 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
176 return FAILED_TRANSACTION;
177 }
178 if (!h2b(static_cast<HStatus>(transResult), &status)) {
179 ALOGE("%s(): corrupted transaction.", __func__);
180 return FAILED_TRANSACTION;
181 }
182 if (status != android::NO_ERROR) {
183 ALOGE("%s() failed: %d", __func__, status);
184 }
185 return status;
186 }
187
attachBuffer(const sp<GraphicBuffer> & buffer,int * outSlot)188 status_t attachBuffer(const sp<GraphicBuffer>& buffer, int* outSlot) {
189 HBuffer hBuffer;
190 uint32_t hGenerationNumber;
191 if (!b2h(buffer, &hBuffer, &hGenerationNumber)) {
192 ALOGE("%s: invalid input buffer.", __func__);
193 return BAD_VALUE;
194 }
195
196 bool converted = false;
197 status_t status = UNKNOWN_ERROR;
198 Return<void> transResult = mBase->attachBuffer(
199 hBuffer, hGenerationNumber,
200 [&converted, &status, outSlot](HStatus hStatus, int32_t hSlot,
201 bool releaseAllBuffers) {
202 converted = h2b(hStatus, &status);
203 *outSlot = static_cast<int>(hSlot);
204 if (converted && releaseAllBuffers && status == android::NO_ERROR) {
205 status = RELEASE_ALL_BUFFERS;
206 }
207 });
208
209 if (!transResult.isOk()) {
210 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
211 return FAILED_TRANSACTION;
212 }
213 if (!converted) {
214 ALOGE("%s(): corrupted transaction.", __func__);
215 return FAILED_TRANSACTION;
216 }
217 if (status != android::NO_ERROR) {
218 ALOGE("%s() failed: %d", __func__, status);
219 }
220 return status;
221 }
222
cancelBuffer(int slot,const sp<Fence> & fence)223 status_t cancelBuffer(int slot, const sp<Fence>& fence) {
224 HFenceWrapper hFenceWrapper;
225 if (!b2h(fence, &hFenceWrapper)) {
226 ALOGE("%s(): corrupted input fence.", __func__);
227 return UNKNOWN_ERROR;
228 }
229
230 status_t status = UNKNOWN_ERROR;
231 Return<HStatus> transResult =
232 mBase->cancelBuffer(static_cast<int32_t>(slot), hFenceWrapper.getHandle());
233
234 if (!transResult.isOk()) {
235 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
236 return FAILED_TRANSACTION;
237 }
238 if (!h2b(static_cast<HStatus>(transResult), &status)) {
239 ALOGE("%s(): corrupted transaction.", __func__);
240 return FAILED_TRANSACTION;
241 }
242 if (status != android::NO_ERROR) {
243 ALOGE("%s() failed: %d", __func__, status);
244 }
245 return status;
246 }
247
query(int what,int * value)248 int query(int what, int* value) {
249 int result = 0;
250 Return<void> transResult =
251 mBase->query(static_cast<int32_t>(what), [&result, value](int32_t r, int32_t v) {
252 result = static_cast<int>(r);
253 *value = static_cast<int>(v);
254 });
255
256 if (!transResult.isOk()) {
257 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
258 return FAILED_TRANSACTION;
259 }
260 return result;
261 }
262
allowAllocation(bool allow)263 status_t allowAllocation(bool allow) {
264 status_t status = UNKNOWN_ERROR;
265 Return<HStatus> transResult = mBase->allowAllocation(allow);
266
267 if (!transResult.isOk()) {
268 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
269 return FAILED_TRANSACTION;
270 }
271 if (!h2b(static_cast<HStatus>(transResult), &status)) {
272 ALOGE("%s(): corrupted transaction.", __func__);
273 return FAILED_TRANSACTION;
274 }
275 if (status != android::NO_ERROR) {
276 ALOGW("%s() failed: %d", __func__, status);
277 }
278 return status;
279 }
280
getUniqueId(uint64_t * outId) const281 status_t getUniqueId(uint64_t* outId) const {
282 Return<uint64_t> transResult = mBase->getUniqueId();
283
284 if (!transResult.isOk()) {
285 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
286 return FAILED_TRANSACTION;
287 }
288
289 *outId = static_cast<uint64_t>(transResult);
290 return android::NO_ERROR;
291 }
292
293 // android::IProducerListener cannot be depended by vendor library, so we use HProducerListener
294 // directly.
connect(sp<HProducerListener> const & hListener,int32_t api,bool producerControlledByApp)295 status_t connect(sp<HProducerListener> const& hListener, int32_t api,
296 bool producerControlledByApp) {
297 bool converted = false;
298 status_t status = UNKNOWN_ERROR;
299 // hack(b/146409777): We pass self-defined api, so we don't use b2h() here.
300 Return<void> transResult = mBase->connect(
301 hListener, static_cast<HConnectionType>(api), producerControlledByApp,
302 [&converted, &status](HStatus hStatus, HQueueBufferOutput const& /* hOutput */) {
303 converted = h2b(hStatus, &status);
304 });
305
306 if (!transResult.isOk()) {
307 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
308 return FAILED_TRANSACTION;
309 }
310 if (!converted) {
311 ALOGE("%s(): corrupted transaction.", __func__);
312 return FAILED_TRANSACTION;
313 }
314 return status;
315 }
316
setDequeueTimeout(nsecs_t timeout)317 status_t setDequeueTimeout(nsecs_t timeout) {
318 status_t status = UNKNOWN_ERROR;
319 Return<HStatus> transResult = mBase->setDequeueTimeout(static_cast<int64_t>(timeout));
320
321 if (!transResult.isOk()) {
322 ALOGE("%s(): transaction failed: %s", __func__, transResult.description().c_str());
323 return FAILED_TRANSACTION;
324 }
325 if (!h2b(static_cast<HStatus>(transResult), &status)) {
326 ALOGE("%s(): corrupted transaction.", __func__);
327 return FAILED_TRANSACTION;
328 }
329 return status;
330 }
331
332 private:
333 const sp<HGraphicBufferProducer> mBase;
334 };
335
336 // This class is used to notify the listener when a certain event happens.
337 class EventNotifier : public virtual android::RefBase {
338 public:
339 class Listener {
340 public:
341 virtual ~Listener() = default;
342
343 // Called by EventNotifier when a certain event happens.
344 virtual void onEventNotified() = 0;
345 };
346
EventNotifier(const std::shared_ptr<Listener> & listener)347 explicit EventNotifier(const std::shared_ptr<Listener>& listener) : mListener(listener) {}
348 virtual ~EventNotifier() = default;
349
350 protected:
notify()351 void notify() {
352 ALOGV("%s()", __func__);
353 std::shared_ptr<Listener> listener = mListener.lock();
354 if (listener) {
355 listener->onEventNotified();
356 }
357 }
358
359 std::weak_ptr<Listener> mListener;
360 };
361
362 // Notifies the listener when the connected IGBP releases buffers.
363 class BufferReleasedNotifier : public EventNotifier, public HProducerListener {
364 public:
365 using EventNotifier::EventNotifier;
366 ~BufferReleasedNotifier() override = default;
367
368 // HProducerListener implementation
onBuffersReleased(uint32_t count)369 Return<void> onBuffersReleased(uint32_t count) override {
370 ALOGV("%s(%u)", __func__, count);
371 if (count > 0) {
372 notify();
373 }
374 return {};
375 }
376 };
377
378 /**
379 * BlockPoolData implementation for C2VdaBqBlockPool. The life cycle of this object should be as
380 * long as its accompanied C2GraphicBlock.
381 *
382 * When C2VdaBqBlockPoolData is created, |mShared| is false, and the owner of the accompanied
383 * C2GraphicBlock is the component that called fetchGraphicBlock(). If this is released before
384 * sharing, the destructor will call detachBuffer() to BufferQueue to free the slot.
385 *
386 * When the accompanied C2GraphicBlock is going to share to client from component, component should
387 * call MarkBlockPoolDataAsShared() to set |mShared| to true, and then this will be released after
388 * the transition of C2GraphicBlock across HIDL interface. At this time, the destructor will not
389 * call detachBuffer().
390 */
391 struct C2VdaBqBlockPoolData : public _C2BlockPoolData {
392 // This type should be a different value than what _C2BlockPoolData::type_t has defined.
393 static constexpr int kTypeVdaBufferQueue = TYPE_BUFFERQUEUE + 256;
394
395 C2VdaBqBlockPoolData(uint64_t producerId, int32_t slotId,
396 const std::shared_ptr<C2VdaBqBlockPool::Impl>& pool);
397 C2VdaBqBlockPoolData() = delete;
398
399 // If |mShared| is false, call detach buffer to BufferQueue via |mPool|
400 virtual ~C2VdaBqBlockPoolData() override;
401
getTypeandroid::C2VdaBqBlockPoolData402 type_t getType() const override { return static_cast<type_t>(kTypeVdaBufferQueue); }
403
404 bool mShared = false; // whether is shared from component to client.
405 const uint64_t mProducerId;
406 const int32_t mSlotId;
407 const std::shared_ptr<C2VdaBqBlockPool::Impl> mPool;
408 };
409
MarkBlockPoolDataAsShared(const C2ConstGraphicBlock & sharedBlock)410 c2_status_t MarkBlockPoolDataAsShared(const C2ConstGraphicBlock& sharedBlock) {
411 std::shared_ptr<_C2BlockPoolData> data = _C2BlockFactory::GetGraphicBlockPoolData(sharedBlock);
412 if (!data || data->getType() != C2VdaBqBlockPoolData::kTypeVdaBufferQueue) {
413 // Skip this functtion if |sharedBlock| is not fetched from C2VdaBqBlockPool.
414 return C2_OMITTED;
415 }
416 const std::shared_ptr<C2VdaBqBlockPoolData> poolData =
417 std::static_pointer_cast<C2VdaBqBlockPoolData>(data);
418 if (poolData->mShared) {
419 ALOGE("C2VdaBqBlockPoolData(id=%" PRIu64 ", slot=%d) is already marked as shared...",
420 poolData->mProducerId, poolData->mSlotId);
421 return C2_BAD_STATE;
422 }
423 poolData->mShared = true;
424 return C2_OK;
425 }
426
427 // static
getBufferIdFromGraphicBlock(const C2Block2D & block)428 std::optional<uint32_t> C2VdaBqBlockPool::getBufferIdFromGraphicBlock(const C2Block2D& block) {
429 uint32_t width, height, format, stride, igbp_slot, generation;
430 uint64_t usage, igbp_id;
431 android::_UnwrapNativeCodec2GrallocMetadata(block.handle(), &width, &height, &format, &usage,
432 &stride, &generation, &igbp_id, &igbp_slot);
433 ALOGV("Unwrap Metadata: igbp[%" PRIu64 ", %u] (%u*%u, fmt %#x, usage %" PRIx64 ", stride %u)",
434 igbp_id, igbp_slot, width, height, format, usage, stride);
435 return igbp_slot;
436 }
437
438 class C2VdaBqBlockPool::Impl : public std::enable_shared_from_this<C2VdaBqBlockPool::Impl>,
439 public EventNotifier::Listener {
440 public:
441 using HGraphicBufferProducer = C2VdaBqBlockPool::HGraphicBufferProducer;
442
443 explicit Impl(const std::shared_ptr<C2Allocator>& allocator);
444 // TODO: should we detach buffers on producer if any on destructor?
445 ~Impl() = default;
446
447 // EventNotifier::Listener implementation.
448 void onEventNotified() override;
449
450 c2_status_t fetchGraphicBlock(uint32_t width, uint32_t height, uint32_t format,
451 C2MemoryUsage usage,
452 std::shared_ptr<C2GraphicBlock>* block /* nonnull */);
453 void setRenderCallback(const C2BufferQueueBlockPool::OnRenderCallback& renderCallback);
454 void configureProducer(const sp<HGraphicBufferProducer>& producer);
455 c2_status_t requestNewBufferSet(int32_t bufferCount);
456 c2_status_t updateGraphicBlock(bool willCancel, uint32_t oldSlot, uint32_t* newSlot,
457 std::shared_ptr<C2GraphicBlock>* block /* nonnull */);
458 c2_status_t getMinBuffersForDisplay(size_t* bufferCount);
459 bool setNotifyBlockAvailableCb(::base::OnceClosure cb);
460
461 private:
462 friend struct C2VdaBqBlockPoolData;
463
464 // Requested buffer formats.
465 struct BufferFormat {
BufferFormatandroid::C2VdaBqBlockPool::Impl::BufferFormat466 BufferFormat(uint32_t width, uint32_t height, uint32_t pixelFormat,
467 C2AndroidMemoryUsage androidUsage)
468 : mWidth(width), mHeight(height), mPixelFormat(pixelFormat), mUsage(androidUsage) {}
469 BufferFormat() = default;
470
471 uint32_t mWidth = 0;
472 uint32_t mHeight = 0;
473 uint32_t mPixelFormat = 0;
474 C2AndroidMemoryUsage mUsage = C2MemoryUsage(0);
475 };
476
477 // For C2VdaBqBlockPoolData to detach corresponding slot buffer from BufferQueue.
478 void detachBuffer(uint64_t producerId, int32_t slotId);
479
480 // Queries the generation and usage flags from the given producer by dequeuing and requesting a
481 // buffer (the buffer is then detached and freed).
482 c2_status_t queryGenerationAndUsage(H2BGraphicBufferProducer* const producer, uint32_t width,
483 uint32_t height, uint32_t pixelFormat,
484 C2AndroidMemoryUsage androidUsage, uint32_t* generation,
485 uint64_t* usage);
486
487 // Switches producer and transfers allocated buffers from old producer to the new one.
488 bool switchProducer(H2BGraphicBufferProducer* const newProducer, uint64_t newProducerId);
489
490 const std::shared_ptr<C2Allocator> mAllocator;
491
492 std::unique_ptr<H2BGraphicBufferProducer> mProducer;
493 uint64_t mProducerId;
494 C2BufferQueueBlockPool::OnRenderCallback mRenderCallback;
495
496 // Function mutex to lock at the start of each API function call for protecting the
497 // synchronization of all member variables.
498 std::mutex mMutex;
499 // The mutex of excluding the procedures of configuring producer and allocating buffers. They
500 // should be blocked mutually. Set the timeout for acquiring lock in case of any deadlock.
501 // Configuring producer: configureProducer() called by CCodec.
502 // Allocating buffers: requestNewBufferSet(), then a loop of fetchGraphicBlock() called by
503 // compoenent until |mSlotAllocations|.size() equals |mBuffersRequested|.
504 std::timed_mutex mConfigureProducerAndAllocateBuffersMutex;
505 // The unique lock of the procedure of allocating buffers. It should be locked in the beginning
506 // of requestNewBufferSet() and unlock in the end of the loop of fetchGraphicBlock(). Note that
507 // all calls should be in the same thread.
508 std::unique_lock<std::timed_mutex> mAllocateBuffersLock;
509
510 // The map restored C2GraphicAllocation from corresponding slot index.
511 std::map<int32_t, std::shared_ptr<C2GraphicAllocation>> mSlotAllocations;
512 // Number of buffers requested on requestNewBufferSet() call.
513 size_t mBuffersRequested;
514 // Currently requested buffer formats.
515 BufferFormat mBufferFormat;
516 // The map recorded the slot indices from old producer to new producer.
517 std::map<int32_t, int32_t> mProducerChangeSlotMap;
518 // The counter for representing the buffer count in client. Only used in producer switching
519 // case. It will be reset in switchProducer(), and accumulated in updateGraphicBlock() routine.
520 uint32_t mBuffersInClient = 0u;
521 // The indicator to record if producer has been switched. Set to true when producer is switched.
522 // Toggle off when requestNewBufferSet() is called. We forcedly detach all slots to make sure
523 // all slots are available, except the ones owned by client.
524 bool mProducerSwitched = false;
525
526 // Listener for buffer release events.
527 sp<EventNotifier> mFetchBufferNotifier;
528
529 std::mutex mBufferReleaseMutex;
530 // Set to true when the buffer release event is triggered after dequeueing
531 // buffer from IGBP times out.
532 bool mBufferReleasedAfterTimedOut GUARDED_BY(mBufferReleaseMutex) = false;
533 // The callback to notify the caller the buffer is available.
534 ::base::OnceClosure mNotifyBlockAvailableCb GUARDED_BY(mBufferReleaseMutex);
535 };
536
Impl(const std::shared_ptr<C2Allocator> & allocator)537 C2VdaBqBlockPool::Impl::Impl(const std::shared_ptr<C2Allocator>& allocator)
538 : mAllocator(allocator),
539 mAllocateBuffersLock(mConfigureProducerAndAllocateBuffersMutex, std::defer_lock),
540 mBuffersRequested(0u) {}
541
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)542 c2_status_t C2VdaBqBlockPool::Impl::fetchGraphicBlock(
543 uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
544 std::shared_ptr<C2GraphicBlock>* block /* nonnull */) {
545 ALOGV("%s()", __func__);
546 std::lock_guard<std::mutex> lock(mMutex);
547
548 if (!mProducer) {
549 // Producer will not be configured in byte-buffer mode. Allocate buffers from allocator
550 // directly as a basic graphic block pool.
551 std::shared_ptr<C2GraphicAllocation> alloc;
552 c2_status_t err = mAllocator->newGraphicAllocation(width, height, format, usage, &alloc);
553 if (err != C2_OK) {
554 return err;
555 }
556 *block = _C2BlockFactory::CreateGraphicBlock(alloc);
557 return C2_OK;
558 }
559
560 // The existence of |mProducerChangeSlotMap| indicates producer is just switched. Use return
561 // code C2_BAD_STATE to inform the component to handle the procedure of producer change.
562 // TODO(johnylin): consider to inform producer change to component in an active way.
563 if (!mProducerChangeSlotMap.empty()) {
564 return C2_BAD_STATE;
565 }
566
567 C2AndroidMemoryUsage androidUsage = usage;
568 uint32_t pixelFormat = format;
569 int32_t slot;
570 sp<Fence> fence = new Fence();
571 status_t status =
572 mProducer->dequeueBuffer(width, height, pixelFormat, androidUsage, &slot, &fence);
573 // The C2VdaBqBlockPool does not fully own the bufferqueue. After buffers are dequeued here,
574 // they are passed into the codec2 framework, processed, and eventually queued into the
575 // bufferqueue. The C2VdaBqBlockPool cannot determine exactly when a buffer gets queued.
576 // However, if every buffer is being processed by the codec2 framework, then dequeueBuffer()
577 // will return INVALID_OPERATION because of an attempt to dequeue too many buffers.
578 // The C2VdaBqBlockPool cannot prevent this from happening, so just map it to TIMED_OUT
579 // and let the C2VdaBqBlockPool's caller's timeout retry logic handle the failure.
580 if (status == android::INVALID_OPERATION) {
581 status = android::TIMED_OUT;
582 }
583 if (status == android::TIMED_OUT) {
584 std::lock_guard<std::mutex> lock(mBufferReleaseMutex);
585 mBufferReleasedAfterTimedOut = false;
586 }
587 if (status != android::NO_ERROR && status != BUFFER_NEEDS_REALLOCATION) {
588 return asC2Error(status);
589 }
590
591 // Wait for acquire fence if we get one.
592 if (fence) {
593 status_t fenceStatus = fence->wait(kFenceWaitTimeMs);
594 if (fenceStatus != android::NO_ERROR) {
595 if (mProducer->cancelBuffer(slot, fence) != android::NO_ERROR) {
596 return C2_CORRUPTED;
597 }
598
599 if (fenceStatus == -ETIME) { // fence wait timed out
600 ALOGV("%s(): buffer (slot=%d) fence wait timed out", __func__, slot);
601 return C2_TIMED_OUT;
602 }
603 ALOGE("buffer fence wait error: %d", fenceStatus);
604 return asC2Error(fenceStatus);
605 }
606
607 if (mRenderCallback) {
608 nsecs_t signalTime = fence->getSignalTime();
609 if (signalTime >= 0 && signalTime < INT64_MAX) {
610 mRenderCallback(mProducerId, slot, signalTime);
611 } else {
612 ALOGV("got fence signal time of %" PRId64 " nsec", signalTime);
613 }
614 }
615 }
616
617 auto iter = mSlotAllocations.find(slot);
618 if (iter == mSlotAllocations.end()) {
619 if (mSlotAllocations.size() >= mBuffersRequested) {
620 // The dequeued slot has a pre-allocated buffer whose size and format is as same as
621 // currently requested (but was not dequeued during allocation cycle). Just detach it to
622 // free this slot. And try dequeueBuffer again.
623 ALOGD("dequeued a new slot index but already allocated enough buffers. Detach it.");
624
625 if (mProducer->detachBuffer(slot) != android::NO_ERROR) {
626 return C2_CORRUPTED;
627 }
628 return C2_TIMED_OUT;
629 }
630 if (status != BUFFER_NEEDS_REALLOCATION) {
631 // The dequeued slot has a pre-allocated buffer whose size and format is as same as
632 // currently requested, so there is no BUFFER_NEEDS_REALLOCATION flag. However since the
633 // buffer reference is already dropped, still call requestBuffer to re-allocate then.
634 // Add a debug note here for tracking.
635 ALOGD("dequeued a new slot index without BUFFER_NEEDS_REALLOCATION flag.");
636 }
637
638 // Call requestBuffer to allocate buffer for the slot and obtain the reference.
639 sp<GraphicBuffer> slotBuffer = new GraphicBuffer();
640 status = mProducer->requestBuffer(slot, &slotBuffer);
641 if (status != android::NO_ERROR) {
642 if (mProducer->cancelBuffer(slot, fence) != android::NO_ERROR) {
643 return C2_CORRUPTED;
644 }
645 return asC2Error(status);
646 }
647
648 // Convert GraphicBuffer to C2GraphicAllocation and wrap producer id and slot index
649 ALOGV("buffer wraps { producer id: %" PRIu64 ", slot: %d }", mProducerId, slot);
650 C2Handle* c2Handle = android::WrapNativeCodec2GrallocHandle(
651 slotBuffer->handle, slotBuffer->width, slotBuffer->height, slotBuffer->format,
652 slotBuffer->usage, slotBuffer->stride, slotBuffer->getGenerationNumber(),
653 mProducerId, slot);
654 if (!c2Handle) {
655 ALOGE("WrapNativeCodec2GrallocHandle failed");
656 return C2_NO_MEMORY;
657 }
658
659 std::shared_ptr<C2GraphicAllocation> alloc;
660 c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc);
661 if (err != C2_OK) {
662 ALOGE("priorGraphicAllocation failed: %d", err);
663 return err;
664 }
665
666 mSlotAllocations[slot] = std::move(alloc);
667 if (mSlotAllocations.size() == mBuffersRequested) {
668 // Already allocated enough buffers, set allowAllocation to false to restrict the
669 // eligible slots to allocated ones for future dequeue.
670 status = mProducer->allowAllocation(false);
671 if (status != android::NO_ERROR) {
672 return asC2Error(status);
673 }
674 // Store buffer formats for future usage.
675 mBufferFormat = BufferFormat(width, height, pixelFormat, androidUsage);
676 ALOG_ASSERT(mAllocateBuffersLock.owns_lock());
677 mAllocateBuffersLock.unlock();
678 }
679 }
680
681 auto poolData = std::make_shared<C2VdaBqBlockPoolData>(mProducerId, slot, shared_from_this());
682 *block = _C2BlockFactory::CreateGraphicBlock(mSlotAllocations[slot], std::move(poolData));
683 return C2_OK;
684 }
685
onEventNotified()686 void C2VdaBqBlockPool::Impl::onEventNotified() {
687 ALOGV("%s()", __func__);
688 ::base::OnceClosure outputCb;
689 {
690 std::lock_guard<std::mutex> lock(mBufferReleaseMutex);
691
692 mBufferReleasedAfterTimedOut = true;
693 if (mNotifyBlockAvailableCb) {
694 outputCb = std::move(mNotifyBlockAvailableCb);
695 }
696 }
697
698 // Calling the callback outside the lock to avoid the deadlock.
699 if (outputCb) {
700 std::move(outputCb).Run();
701 }
702 }
703
queryGenerationAndUsage(H2BGraphicBufferProducer * const producer,uint32_t width,uint32_t height,uint32_t pixelFormat,C2AndroidMemoryUsage androidUsage,uint32_t * generation,uint64_t * usage)704 c2_status_t C2VdaBqBlockPool::Impl::queryGenerationAndUsage(
705 H2BGraphicBufferProducer* const producer, uint32_t width, uint32_t height,
706 uint32_t pixelFormat, C2AndroidMemoryUsage androidUsage, uint32_t* generation,
707 uint64_t* usage) {
708 ALOGV("queryGenerationAndUsage");
709 sp<Fence> fence = new Fence();
710 int32_t status;
711 int32_t slot;
712
713 status = producer->dequeueBuffer(width, height, pixelFormat, androidUsage, &slot, &fence);
714 if (status != android::NO_ERROR && status != BUFFER_NEEDS_REALLOCATION) {
715 return asC2Error(status);
716 }
717
718 // Wait for acquire fence if we get one.
719 if (fence) {
720 status_t fenceStatus = fence->wait(kFenceWaitTimeMs);
721 if (fenceStatus != android::NO_ERROR) {
722 if (producer->cancelBuffer(slot, fence) != android::NO_ERROR) {
723 return C2_CORRUPTED;
724 }
725 if (fenceStatus == -ETIME) { // fence wait timed out
726 ALOGV("%s(): buffer (slot=%d) fence wait timed out", __func__, slot);
727 return C2_TIMED_OUT;
728 }
729 ALOGE("buffer fence wait error: %d", fenceStatus);
730 return asC2Error(fenceStatus);
731 }
732 }
733
734 // Call requestBuffer to allocate buffer for the slot and obtain the reference.
735 // Get generation number here.
736 sp<GraphicBuffer> slotBuffer = new GraphicBuffer();
737 status = producer->requestBuffer(slot, &slotBuffer);
738
739 // Detach and delete the temporary buffer.
740 if (producer->detachBuffer(slot) != android::NO_ERROR) {
741 return C2_CORRUPTED;
742 }
743
744 // Check requestBuffer return flag.
745 if (status != android::NO_ERROR) {
746 return asC2Error(status);
747 }
748
749 // Get generation number and usage from the slot buffer.
750 *usage = slotBuffer->getUsage();
751 *generation = slotBuffer->getGenerationNumber();
752 ALOGV("Obtained from temp buffer: generation = %u, usage = %" PRIu64 "", *generation, *usage);
753 return C2_OK;
754 }
755
setRenderCallback(const C2BufferQueueBlockPool::OnRenderCallback & renderCallback)756 void C2VdaBqBlockPool::Impl::setRenderCallback(
757 const C2BufferQueueBlockPool::OnRenderCallback& renderCallback) {
758 ALOGV("setRenderCallback");
759 std::lock_guard<std::mutex> lock(mMutex);
760 mRenderCallback = renderCallback;
761 }
762
requestNewBufferSet(int32_t bufferCount)763 c2_status_t C2VdaBqBlockPool::Impl::requestNewBufferSet(int32_t bufferCount) {
764 if (bufferCount <= 0) {
765 ALOGE("Invalid requested buffer count = %d", bufferCount);
766 return C2_BAD_VALUE;
767 }
768
769 if (!mAllocateBuffersLock.try_lock_for(kTimedMutexTimeoutMs)) {
770 ALOGE("Cannot acquire allocate buffers / configure producer lock over %" PRId64 " ms...",
771 static_cast<int64_t>(kTimedMutexTimeoutMs.count()));
772 return C2_BLOCKING;
773 }
774
775 std::lock_guard<std::mutex> lock(mMutex);
776 if (!mProducer) {
777 ALOGD("No HGraphicBufferProducer is configured...");
778 return C2_NO_INIT;
779 }
780
781 if (mProducerSwitched) {
782 // Some slots can be occupied by buffers transferred from the old producer. They will not
783 // used in the current producer. Free the slots of the buffers here. But we cannot find a
784 // slot is associated with the staled buffer. We free all slots whose associated buffers
785 // are not owned by client.
786 ALOGI("requestNewBufferSet: detachBuffer all slots forcedly");
787 for (int32_t slot = 0; slot < static_cast<int32_t>(NUM_BUFFER_SLOTS); ++slot) {
788 if (mSlotAllocations.find(slot) != mSlotAllocations.end()) {
789 // Skip detaching the buffer which is owned by client now.
790 continue;
791 }
792 status_t status = mProducer->detachBuffer(slot);
793 if (status == android::NO_INIT) {
794 // No more active buffer slot. Break the loop now.
795 break;
796 } else if (status != android::NO_ERROR) {
797 return C2_CORRUPTED;
798 }
799 }
800 mProducerSwitched = false;
801 }
802
803 ALOGV("Requested new buffer count: %d, still dequeued buffer count: %zu", bufferCount,
804 mSlotAllocations.size());
805
806 // The remained slot indices in |mSlotAllocations| now are still dequeued (un-available).
807 // maxDequeuedBufferCount should be set to "new requested buffer count" + "still dequeued buffer
808 // count" to make sure it has enough available slots to request buffer from.
809 status_t status = mProducer->setMaxDequeuedBufferCount(bufferCount + mSlotAllocations.size());
810 if (status != android::NO_ERROR) {
811 return asC2Error(status);
812 }
813
814 // Release all remained slot buffer references here. CCodec should either cancel or queue its
815 // owned buffers from this set before the next resolution change.
816 mSlotAllocations.clear();
817 mProducerChangeSlotMap.clear();
818 mBuffersRequested = static_cast<size_t>(bufferCount);
819
820 status = mProducer->allowAllocation(true);
821 if (status != android::NO_ERROR) {
822 return asC2Error(status);
823 }
824 return C2_OK;
825 }
826
configureProducer(const sp<HGraphicBufferProducer> & producer)827 void C2VdaBqBlockPool::Impl::configureProducer(const sp<HGraphicBufferProducer>& producer) {
828 ALOGV("configureProducer");
829 if (producer == nullptr) {
830 ALOGE("input producer is nullptr...");
831 return;
832 }
833
834 std::unique_lock<std::timed_mutex> configureProducerLock(
835 mConfigureProducerAndAllocateBuffersMutex, std::defer_lock);
836 if (!configureProducerLock.try_lock_for(kTimedMutexTimeoutMs)) {
837 ALOGE("Cannot acquire configure producer / allocate buffers lock over %" PRId64 " ms...",
838 static_cast<int64_t>(kTimedMutexTimeoutMs.count()));
839 return;
840 }
841
842 std::lock_guard<std::mutex> lock(mMutex);
843 auto newProducer = std::make_unique<H2BGraphicBufferProducer>(producer);
844 uint64_t producerId;
845 if (newProducer->getUniqueId(&producerId) != android::NO_ERROR) {
846 return;
847 }
848
849 if (mProducer && mProducerId != producerId) {
850 ALOGI("Producer (Surface) is going to switch... ( %" PRIu64 " -> %" PRIu64 " )",
851 mProducerId, producerId);
852 if (!switchProducer(newProducer.get(), producerId)) {
853 mProducerChangeSlotMap.clear();
854 return;
855 }
856 } else {
857 mSlotAllocations.clear();
858 }
859
860 if (newProducer->setDequeueTimeout(0) != android::NO_ERROR) {
861 ALOGE("%s(): failed to setDequeueTimeout(0)", __func__);
862 return;
863 }
864
865 // hack(b/146409777): Try to connect ARC-specific listener first.
866 sp<BufferReleasedNotifier> listener = new BufferReleasedNotifier(shared_from_this());
867 if (newProducer->connect(listener, 'ARC\0', false) == android::NO_ERROR) {
868 ALOGI("connected to ARC-specific IGBP listener.");
869 mFetchBufferNotifier = listener;
870 }
871
872 // HGraphicBufferProducer could (and should) be replaced if the client has set a new generation
873 // number to producer. The old HGraphicBufferProducer will be disconnected and deprecated then.
874 mProducer = std::move(newProducer);
875 mProducerId = producerId;
876 }
877
switchProducer(H2BGraphicBufferProducer * const newProducer,uint64_t newProducerId)878 bool C2VdaBqBlockPool::Impl::switchProducer(H2BGraphicBufferProducer* const newProducer,
879 uint64_t newProducerId) {
880 if (mAllocator->getId() == android::V4L2AllocatorId::SECURE_GRAPHIC) {
881 // TODO(johnylin): support this when we meet the use case in the future.
882 ALOGE("Switch producer for secure buffer is not supported...");
883 return false;
884 }
885
886 // Set maxDequeuedBufferCount to new producer.
887 // Just like requestNewBufferSet(), maxDequeuedBufferCount should be set to "requested buffer
888 // count" + "buffer count in client" to make sure it has enough available slots to request
889 // buffers from.
890 // "Requested buffer count" could be obtained by the size of |mSlotAllocations|. However, it is
891 // not able to know "buffer count in client" in blockpool's aspect. The alternative solution is
892 // to set the worse case first, which is equal to the size of |mSlotAllocations|. And in the end
893 // of updateGraphicBlock() routine, we could get the arbitrary "buffer count in client" by
894 // counting the calls of updateGraphicBlock(willCancel=true). Then we set maxDequeuedBufferCount
895 // again to the correct value.
896 if (newProducer->setMaxDequeuedBufferCount(mSlotAllocations.size() * 2) != android::NO_ERROR) {
897 return false;
898 }
899
900 // Reset "buffer count in client". It will be accumulated in updateGraphicBlock() routine.
901 mBuffersInClient = 0;
902
903 // Set allowAllocation to new producer.
904 if (newProducer->allowAllocation(true) != android::NO_ERROR) {
905 return false;
906 }
907
908 // Get a buffer from the new producer to get the generation number and usage of new producer.
909 // While attaching buffers, generation number and usage must be aligned to the producer.
910 uint32_t newGeneration;
911 uint64_t newUsage;
912 c2_status_t err = queryGenerationAndUsage(newProducer, mBufferFormat.mWidth,
913 mBufferFormat.mHeight, mBufferFormat.mPixelFormat,
914 mBufferFormat.mUsage, &newGeneration, &newUsage);
915 if (err != C2_OK) {
916 ALOGE("queryGenerationAndUsage failed: %d", err);
917 return false;
918 }
919
920 // Attach all buffers to new producer.
921 mProducerChangeSlotMap.clear();
922 int32_t slot;
923 std::map<int32_t, std::shared_ptr<C2GraphicAllocation>> newSlotAllocations;
924 for (auto iter = mSlotAllocations.begin(); iter != mSlotAllocations.end(); ++iter) {
925 // Convert C2GraphicAllocation to GraphicBuffer.
926 uint32_t width, height, format, stride, igbp_slot, generation;
927 uint64_t usage, igbp_id;
928 android::_UnwrapNativeCodec2GrallocMetadata(iter->second->handle(), &width, &height,
929 &format, &usage, &stride, &generation, &igbp_id,
930 &igbp_slot);
931 native_handle_t* grallocHandle =
932 android::UnwrapNativeCodec2GrallocHandle(iter->second->handle());
933
934 // Update generation number and usage.
935 sp<GraphicBuffer> graphicBuffer =
936 new GraphicBuffer(grallocHandle, GraphicBuffer::CLONE_HANDLE, width, height, format,
937 1, newUsage, stride);
938 if (graphicBuffer->initCheck() != android::NO_ERROR) {
939 ALOGE("Failed to create GraphicBuffer: %d", graphicBuffer->initCheck());
940 return false;
941 }
942 graphicBuffer->setGenerationNumber(newGeneration);
943 native_handle_delete(grallocHandle);
944
945 if (newProducer->attachBuffer(graphicBuffer, &slot) != android::NO_ERROR) {
946 return false;
947 }
948 // Convert back to C2GraphicAllocation wrapping new producer id, generation number, usage
949 // and slot index.
950 ALOGV("buffer wraps { producer id: %" PRIu64 ", slot: %d }", newProducerId, slot);
951 C2Handle* c2Handle = android::WrapNativeCodec2GrallocHandle(
952 graphicBuffer->handle, width, height, format, newUsage, stride, newGeneration,
953 newProducerId, slot);
954 if (!c2Handle) {
955 ALOGE("WrapNativeCodec2GrallocHandle failed");
956 return false;
957 }
958 std::shared_ptr<C2GraphicAllocation> alloc;
959 c2_status_t err = mAllocator->priorGraphicAllocation(c2Handle, &alloc);
960 if (err != C2_OK) {
961 ALOGE("priorGraphicAllocation failed: %d", err);
962 return false;
963 }
964
965 // Store to |newSlotAllocations| and also store old-to-new producer slot map.
966 ALOGV("Transfered buffer from old producer to new, slot prev: %d -> new %d", iter->first,
967 slot);
968 newSlotAllocations[slot] = std::move(alloc);
969 mProducerChangeSlotMap[iter->first] = slot;
970 }
971
972 // Set allowAllocation to false so producer could not allocate new buffers.
973 if (newProducer->allowAllocation(false) != android::NO_ERROR) {
974 ALOGE("allowAllocation(false) failed");
975 return false;
976 }
977
978 // Try to detach all buffers from old producer.
979 for (const auto& slotAllocation : mSlotAllocations) {
980 status_t status = mProducer->detachBuffer(slotAllocation.first);
981 if (status != android::NO_ERROR) {
982 ALOGW("detachBuffer slot=%d from old producer failed: %d", slotAllocation.first,
983 status);
984 }
985 }
986
987 mSlotAllocations = std::move(newSlotAllocations);
988 return true;
989 }
990
updateGraphicBlock(bool willCancel,uint32_t oldSlot,uint32_t * newSlot,std::shared_ptr<C2GraphicBlock> * block)991 c2_status_t C2VdaBqBlockPool::Impl::updateGraphicBlock(
992 bool willCancel, uint32_t oldSlot, uint32_t* newSlot,
993 std::shared_ptr<C2GraphicBlock>* block /* nonnull */) {
994 std::lock_guard<std::mutex> lock(mMutex);
995
996 if (mProducerChangeSlotMap.empty()) {
997 ALOGD("A new buffer set is requested right after producer change, no more update needed.");
998 return C2_CANCELED;
999 }
1000
1001 auto it = mProducerChangeSlotMap.find(static_cast<int32_t>(oldSlot));
1002 if (it == mProducerChangeSlotMap.end()) {
1003 ALOGE("Cannot find old slot = %u in map...", oldSlot);
1004 return C2_NOT_FOUND;
1005 }
1006
1007 int32_t slot = it->second;
1008 *newSlot = static_cast<uint32_t>(slot);
1009 mProducerChangeSlotMap.erase(it);
1010
1011 if (willCancel) {
1012 sp<Fence> fence = new Fence();
1013 // The old C2GraphicBlock might be owned by client. Cancel this slot.
1014 if (mProducer->cancelBuffer(slot, fence) != android::NO_ERROR) {
1015 return C2_CORRUPTED;
1016 }
1017 // Client might try to attach the old buffer to the current producer on client's end,
1018 // although it is useless for us anymore. However it will still occupy an available slot.
1019 mBuffersInClient++;
1020 } else {
1021 // The old C2GraphicBlock is still owned by component, replace by the new one and keep this
1022 // slot dequeued.
1023 auto poolData =
1024 std::make_shared<C2VdaBqBlockPoolData>(mProducerId, slot, shared_from_this());
1025 *block = _C2BlockFactory::CreateGraphicBlock(mSlotAllocations[slot], std::move(poolData));
1026 }
1027
1028 if (mProducerChangeSlotMap.empty()) {
1029 // The updateGraphicBlock() routine is about to finish.
1030 // Set the correct maxDequeuedBufferCount to producer, which is "requested buffer count" +
1031 // "buffer count in client".
1032 ALOGV("Requested buffer count: %zu, buffer count in client: %u", mSlotAllocations.size(),
1033 mBuffersInClient);
1034 if (mProducer->setMaxDequeuedBufferCount(mSlotAllocations.size() + mBuffersInClient) !=
1035 android::NO_ERROR) {
1036 return C2_CORRUPTED;
1037 }
1038 mProducerSwitched = true;
1039 }
1040
1041 return C2_OK;
1042 }
1043
getMinBuffersForDisplay(size_t * bufferCount)1044 c2_status_t C2VdaBqBlockPool::Impl::getMinBuffersForDisplay(size_t* bufferCount) {
1045 std::lock_guard<std::mutex> lock(mMutex);
1046 if (!mProducer) {
1047 ALOGD("No HGraphicBufferProducer is configured...");
1048 return C2_NO_INIT;
1049 }
1050
1051 int32_t status, value;
1052 status = mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &value);
1053 if (status != android::NO_ERROR) {
1054 ALOGE("query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS) failed: %d", status);
1055 return asC2Error(status);
1056 }
1057 if (value <= 0) {
1058 ALOGE("Illegal value of NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = %d", value);
1059 return C2_BAD_VALUE;
1060 }
1061 *bufferCount = static_cast<size_t>(value);
1062 return C2_OK;
1063 }
1064
detachBuffer(uint64_t producerId,int32_t slotId)1065 void C2VdaBqBlockPool::Impl::detachBuffer(uint64_t producerId, int32_t slotId) {
1066 ALOGV("detachBuffer: producer id = %" PRIu64 ", slot = %d", producerId, slotId);
1067 std::lock_guard<std::mutex> lock(mMutex);
1068 if (producerId == mProducerId && mProducer) {
1069 if (mProducer->detachBuffer(slotId) != android::NO_ERROR) {
1070 return;
1071 }
1072
1073 auto it = mSlotAllocations.find(slotId);
1074 // It may happen that the slot is not included in |mSlotAllocations|, which means it is
1075 // released after resolution change.
1076 if (it != mSlotAllocations.end()) {
1077 mSlotAllocations.erase(it);
1078 }
1079 }
1080 }
1081
setNotifyBlockAvailableCb(::base::OnceClosure cb)1082 bool C2VdaBqBlockPool::Impl::setNotifyBlockAvailableCb(::base::OnceClosure cb) {
1083 ALOGV("%s()", __func__);
1084 if (mFetchBufferNotifier == nullptr) {
1085 return false;
1086 }
1087
1088 ::base::OnceClosure outputCb;
1089 {
1090 std::lock_guard<std::mutex> lock(mBufferReleaseMutex);
1091
1092 // If there is any buffer released after dequeueBuffer() timed out, then we could notify the
1093 // caller directly.
1094 if (mBufferReleasedAfterTimedOut) {
1095 outputCb = std::move(cb);
1096 } else {
1097 mNotifyBlockAvailableCb = std::move(cb);
1098 }
1099 }
1100
1101 // Calling the callback outside the lock to avoid the deadlock.
1102 if (outputCb) {
1103 std::move(outputCb).Run();
1104 }
1105 return true;
1106 }
1107
C2VdaBqBlockPool(const std::shared_ptr<C2Allocator> & allocator,const local_id_t localId)1108 C2VdaBqBlockPool::C2VdaBqBlockPool(const std::shared_ptr<C2Allocator>& allocator,
1109 const local_id_t localId)
1110 : C2BufferQueueBlockPool(allocator, localId), mLocalId(localId), mImpl(new Impl(allocator)) {}
1111
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)1112 c2_status_t C2VdaBqBlockPool::fetchGraphicBlock(
1113 uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
1114 std::shared_ptr<C2GraphicBlock>* block /* nonnull */) {
1115 if (mImpl) {
1116 return mImpl->fetchGraphicBlock(width, height, format, usage, block);
1117 }
1118 return C2_NO_INIT;
1119 }
1120
setRenderCallback(const C2BufferQueueBlockPool::OnRenderCallback & renderCallback)1121 void C2VdaBqBlockPool::setRenderCallback(
1122 const C2BufferQueueBlockPool::OnRenderCallback& renderCallback) {
1123 if (mImpl) {
1124 mImpl->setRenderCallback(renderCallback);
1125 }
1126 }
1127
requestNewBufferSet(int32_t bufferCount)1128 c2_status_t C2VdaBqBlockPool::requestNewBufferSet(int32_t bufferCount) {
1129 if (mImpl) {
1130 return mImpl->requestNewBufferSet(bufferCount);
1131 }
1132 return C2_NO_INIT;
1133 }
1134
configureProducer(const sp<HGraphicBufferProducer> & producer)1135 void C2VdaBqBlockPool::configureProducer(const sp<HGraphicBufferProducer>& producer) {
1136 if (mImpl) {
1137 mImpl->configureProducer(producer);
1138 }
1139 }
1140
updateGraphicBlock(bool willCancel,uint32_t oldSlot,uint32_t * newSlot,std::shared_ptr<C2GraphicBlock> * block)1141 c2_status_t C2VdaBqBlockPool::updateGraphicBlock(
1142 bool willCancel, uint32_t oldSlot, uint32_t* newSlot,
1143 std::shared_ptr<C2GraphicBlock>* block /* nonnull */) {
1144 if (mImpl) {
1145 return mImpl->updateGraphicBlock(willCancel, oldSlot, newSlot, block);
1146 }
1147 return C2_NO_INIT;
1148 }
1149
getMinBuffersForDisplay(size_t * bufferCount)1150 c2_status_t C2VdaBqBlockPool::getMinBuffersForDisplay(size_t* bufferCount) {
1151 if (mImpl) {
1152 return mImpl->getMinBuffersForDisplay(bufferCount);
1153 }
1154 return C2_NO_INIT;
1155 }
1156
setNotifyBlockAvailableCb(::base::OnceClosure cb)1157 bool C2VdaBqBlockPool::setNotifyBlockAvailableCb(::base::OnceClosure cb) {
1158 if (mImpl) {
1159 return mImpl->setNotifyBlockAvailableCb(std::move(cb));
1160 }
1161 return false;
1162 }
1163
C2VdaBqBlockPoolData(uint64_t producerId,int32_t slotId,const std::shared_ptr<C2VdaBqBlockPool::Impl> & pool)1164 C2VdaBqBlockPoolData::C2VdaBqBlockPoolData(uint64_t producerId, int32_t slotId,
1165 const std::shared_ptr<C2VdaBqBlockPool::Impl>& pool)
1166 : mProducerId(producerId), mSlotId(slotId), mPool(pool) {}
1167
~C2VdaBqBlockPoolData()1168 C2VdaBqBlockPoolData::~C2VdaBqBlockPoolData() {
1169 if (mShared || !mPool) {
1170 return;
1171 }
1172 mPool->detachBuffer(mProducerId, mSlotId);
1173 }
1174
1175 } // namespace android
1176