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