• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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