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 "C2VdaPooledBlockPool"
7 
8 #include <v4l2_codec2/plugin_store/C2VdaPooledBlockPool.h>
9 
10 #include <time.h>
11 
12 #include <C2BlockInternal.h>
13 #include <bufferpool/BufferPoolTypes.h>
14 #include <log/log.h>
15 
16 namespace android {
17 namespace {
18 // The wait time for another try to fetch a buffer from bufferpool.
19 const int64_t kFetchRetryDelayUs = 10 * 1000;
20 
GetNowUs()21 int64_t GetNowUs() {
22     struct timespec t;
23     t.tv_sec = 0;
24     t.tv_nsec = 0;
25     clock_gettime(CLOCK_MONOTONIC, &t);
26     int64_t nsecs = static_cast<int64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
27     return nsecs / 1000ll;
28 }
29 }  // namespace
30 
31 using android::hardware::media::bufferpool::BufferPoolData;
32 
33 // static
getBufferIdFromGraphicBlock(const C2Block2D & block)34 std::optional<uint32_t> C2VdaPooledBlockPool::getBufferIdFromGraphicBlock(const C2Block2D& block) {
35     std::shared_ptr<_C2BlockPoolData> blockPoolData =
36             _C2BlockFactory::GetGraphicBlockPoolData(block);
37     if (blockPoolData->getType() != _C2BlockPoolData::TYPE_BUFFERPOOL) {
38         ALOGE("Obtained C2GraphicBlock is not bufferpool-backed.");
39         return std::nullopt;
40     }
41     std::shared_ptr<BufferPoolData> bpData;
42     if (!_C2BlockFactory::GetBufferPoolData(blockPoolData, &bpData) || !bpData) {
43         ALOGE("BufferPoolData unavailable in block.");
44         return std::nullopt;
45     }
46     return bpData->mId;
47 }
48 
49 // Tries to fetch a buffer from bufferpool. When the size of |mBufferIds| is smaller than
50 // |mBufferCount|, pass the obtained buffer to caller and record its ID in BufferPoolData to
51 // |mBufferIds|. When the size of |mBufferIds| is equal to |mBufferCount|, pass the obtained
52 // buffer only if its ID is included in |mBufferIds|. Otherwise, discard the buffer and
53 // return C2_TIMED_OUT.
fetchGraphicBlock(uint32_t width,uint32_t height,uint32_t format,C2MemoryUsage usage,std::shared_ptr<C2GraphicBlock> * block)54 c2_status_t C2VdaPooledBlockPool::fetchGraphicBlock(uint32_t width, uint32_t height,
55                                                     uint32_t format, C2MemoryUsage usage,
56                                                     std::shared_ptr<C2GraphicBlock>* block) {
57     ALOG_ASSERT(block != nullptr);
58     std::lock_guard<std::mutex> lock(mMutex);
59 
60     if (mNextFetchTimeUs != 0) {
61         int delayUs = GetNowUs() - mNextFetchTimeUs;
62         if (delayUs > 0) {
63             ::usleep(delayUs);
64         }
65         mNextFetchTimeUs = 0;
66     }
67 
68     std::shared_ptr<C2GraphicBlock> fetchBlock;
69     c2_status_t err =
70             C2PooledBlockPool::fetchGraphicBlock(width, height, format, usage, &fetchBlock);
71     if (err != C2_OK) {
72         ALOGE("Failed at C2PooledBlockPool::fetchGraphicBlock: %d", err);
73         return err;
74     }
75 
76     std::optional<uint32_t> bufferId = getBufferIdFromGraphicBlock(*fetchBlock);
77     if (!bufferId) {
78         ALOGE("Failed to getBufferIdFromGraphicBlock");
79         return C2_CORRUPTED;
80     }
81 
82     if (mBufferIds.size() < mBufferCount) {
83         mBufferIds.insert(*bufferId);
84     }
85 
86     if (mBufferIds.find(*bufferId) != mBufferIds.end()) {
87         ALOGV("Returned buffer id = %u", *bufferId);
88         *block = std::move(fetchBlock);
89         return C2_OK;
90     }
91     ALOGV("No buffer could be recycled now, wait for another try...");
92     mNextFetchTimeUs = GetNowUs() + kFetchRetryDelayUs;
93     return C2_TIMED_OUT;
94 }
95 
requestNewBufferSet(int32_t bufferCount)96 c2_status_t C2VdaPooledBlockPool::requestNewBufferSet(int32_t bufferCount) {
97     if (bufferCount <= 0) {
98         ALOGE("Invalid requested buffer count = %d", bufferCount);
99         return C2_BAD_VALUE;
100     }
101 
102     std::lock_guard<std::mutex> lock(mMutex);
103     mBufferIds.clear();
104     mBufferCount = bufferCount;
105     return C2_OK;
106 }
107 
108 }  // namespace android
109