1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "buffer_pool.h"
17 #include <chrono>
18 #include "buffer_adapter.h"
19 #include "image_buffer.h"
20 #include "buffer_tracking.h"
21
22 namespace OHOS::Camera {
BufferPool()23 BufferPool::BufferPool()
24 {
25 CAMERA_LOGI("BufferPool construct");
26 }
27
~BufferPool()28 BufferPool::~BufferPool()
29 {
30 DestroyBuffer();
31 }
32
Init(const uint32_t width,const uint32_t height,const uint64_t usage,const uint32_t bufferFormat,const uint32_t count,const int32_t bufferSourceType)33 RetCode BufferPool::Init(const uint32_t width,
34 const uint32_t height,
35 const uint64_t usage,
36 const uint32_t bufferFormat,
37 const uint32_t count,
38 const int32_t bufferSourceType)
39 {
40 bufferWidth_ = width;
41 bufferHeight_ = height;
42 bufferUsage_ = usage;
43 bufferFormat_ = bufferFormat;
44 bufferCount_ = count;
45 bufferSourceType_ = bufferSourceType;
46
47 if (bufferSourceType_ == CAMERA_BUFFER_SOURCE_TYPE_EXTERNAL) {
48 CAMERA_LOGI("buffers are from external source");
49 return RC_OK;
50 }
51
52 BufferAllocatorFactory* factory = BufferAllocatorFactory::GetInstance();
53 if (factory == nullptr) {
54 CAMERA_LOGE("buffer allocator factory is null");
55 return RC_ERROR;
56 }
57
58 bufferAllocator_ = factory->GetBufferAllocator(bufferSourceType_);
59 if (bufferAllocator_ == nullptr) {
60 CAMERA_LOGI("can't find buffer allocator");
61 return RC_ERROR;
62 }
63
64 if (bufferAllocator_->Init() != RC_OK) {
65 return RC_ERROR;
66 }
67
68 return PrepareBuffer();
69 }
70
PrepareBuffer()71 RetCode BufferPool::PrepareBuffer()
72 {
73 if (bufferSourceType_ == CAMERA_BUFFER_SOURCE_TYPE_EXTERNAL) {
74 CAMERA_LOGI("no need allocate buffer");
75 return RC_OK;
76 }
77
78 if (bufferAllocator_ == nullptr) {
79 CAMERA_LOGE("bufferAllocator_ is nullptr");
80 return RC_ERROR;
81 }
82
83 for (uint32_t i = 0; i < bufferCount_; i++) {
84 std::shared_ptr<IBuffer> buffer =
85 bufferAllocator_->AllocBuffer(bufferWidth_, bufferHeight_, bufferUsage_, bufferFormat_);
86 if (buffer == nullptr) {
87 CAMERA_LOGE("alloc buffer failed");
88 return RC_ERROR;
89 }
90 if (RC_OK != bufferAllocator_->MapBuffer(buffer)) {
91 CAMERA_LOGE("map buffer failed");
92 return RC_ERROR;
93 }
94 buffer->SetIndex(i);
95 buffer->SetPoolId(poolId_);
96
97 {
98 std::unique_lock<std::mutex> l(lock_);
99 idleList_.emplace_back(buffer);
100 }
101 }
102
103 return RC_OK;
104 }
105
DestroyBuffer()106 RetCode BufferPool::DestroyBuffer()
107 {
108 if (bufferSourceType_ == CAMERA_BUFFER_SOURCE_TYPE_EXTERNAL) {
109 std::unique_lock<std::mutex> l(lock_);
110 idleList_.clear();
111 busyList_.clear();
112 return RC_OK;
113 }
114
115 if (bufferAllocator_ == nullptr) {
116 CAMERA_LOGE("bufferAllocator_ is nullptr");
117 return RC_ERROR;
118 }
119
120 {
121 std::unique_lock<std::mutex> l(lock_);
122
123 for (auto it : idleList_) {
124 RetCode ret = bufferAllocator_->UnmapBuffer(it);
125 if (ret != RC_OK) {
126 CAMERA_LOGE("unmap (%{public}d) buffer failed", it->GetIndex());
127 }
128 ret = bufferAllocator_->FreeBuffer(it);
129 if (ret != RC_OK) {
130 CAMERA_LOGE("free (%{public}d) buffer failed", it->GetIndex());
131 }
132 }
133 idleList_.clear();
134
135 if (busyList_.size() > 0) {
136 CAMERA_LOGE("%{public}zu buffer(s) is/are in use.", busyList_.size());
137 }
138 for (auto it : busyList_) {
139 RetCode ret = bufferAllocator_->UnmapBuffer(it);
140 if (ret != RC_OK) {
141 CAMERA_LOGE("unmap (%{public}d) buffer failed", it->GetIndex());
142 }
143 ret = bufferAllocator_->FreeBuffer(it);
144 if (ret != RC_OK) {
145 CAMERA_LOGE("free (%{public}d) buffer failed", it->GetIndex());
146 }
147 }
148 busyList_.clear();
149 }
150
151 return RC_OK;
152 }
153
AddBuffer(std::shared_ptr<IBuffer> & buffer)154 RetCode BufferPool::AddBuffer(std::shared_ptr<IBuffer>& buffer)
155 {
156 std::unique_lock<std::mutex> l(lock_);
157 buffer->SetPoolId(poolId_);
158 idleList_.emplace_back(buffer);
159 cv_.notify_one();
160 return RC_OK;
161 }
162
AcquireBuffer(int timeout)163 std::shared_ptr<IBuffer> BufferPool::AcquireBuffer(int timeout)
164 {
165 std::unique_lock<std::mutex> l(lock_);
166
167 // return buffer immediately, if idle buffer is available;
168 if (!idleList_.empty()) {
169 auto it = idleList_.begin();
170 auto buffer = *it;
171 busyList_.splice(busyList_.begin(), idleList_, it);
172 CAMERA_LOGV("acquire buffer immediately, index = %{public}d", buffer->GetIndex());
173 return *it;
174 }
175
176 // wait all the time, till idle list is available.
177 if (timeout < 0) {
178 cv_.wait(l, [this] {
179 return !idleList_.empty() || stop_;
180 });
181 if (!idleList_.empty()) {
182 auto it = idleList_.begin();
183 auto buffer = *it;
184 busyList_.splice(busyList_.begin(), idleList_, it);
185 CAMERA_LOGV("acquire buffer wait all the time, index = %{public}d", buffer->GetIndex());
186 return *it;
187 }
188 }
189
190 // wait for timeout, or idle list is available.
191 if (timeout > 0) {
192 if (cv_.wait_for(l, std::chrono::seconds(timeout), [this] {
193 return !idleList_.empty() || stop_;
194 }) == false) {
195 CAMERA_LOGE("wait idle buffer timeout");
196 return nullptr;
197 }
198 if (!idleList_.empty()) {
199 auto it = idleList_.begin();
200 auto buffer = *it;
201 busyList_.splice(busyList_.begin(), idleList_, it);
202 CAMERA_LOGV("acquire buffer wait %{public}ds, index = %{public}d", timeout, buffer->GetIndex());
203 return *it;
204 }
205 }
206
207 // timeout == 0. return nullptr buffer immediately, although idle buffer is not available.
208 return nullptr;
209 }
210
ReturnBuffer(std::shared_ptr<IBuffer> & buffer)211 RetCode BufferPool::ReturnBuffer(std::shared_ptr<IBuffer>& buffer)
212 {
213 std::unique_lock<std::mutex> l(lock_);
214
215 auto it = std::find(busyList_.begin(), busyList_.end(), buffer);
216 if (it == busyList_.end()) {
217 CAMERA_LOGE("fatal error, busy list is empty, cannot return buffer.");
218 return RC_ERROR;
219 }
220
221 if (bufferSourceType_ == CAMERA_BUFFER_SOURCE_TYPE_EXTERNAL) {
222 busyList_.erase(it);
223 cv_.notify_one();
224 return RC_OK;
225 }
226
227 if (trackingId_ >= 0) {
228 POOL_REPORT_BUFFER_LOCATION(trackingId_, buffer->GetFrameNumber());
229 }
230
231 idleList_.splice(idleList_.end(), busyList_, it);
232 cv_.notify_one();
233
234 return RC_OK;
235 }
236
EnableTracking(const int32_t id)237 void BufferPool::EnableTracking(const int32_t id)
238 {
239 trackingId_ = id;
240 return;
241 }
242
SetId(const int64_t id)243 void BufferPool::SetId(const int64_t id)
244 {
245 poolId_ = id;
246 }
247
NotifyStop()248 void BufferPool::NotifyStop()
249 {
250 std::unique_lock<std::mutex> l(lock_);
251 stop_ = true;
252 cv_.notify_all();
253 }
254
NotifyStart()255 void BufferPool::NotifyStart()
256 {
257 std::unique_lock<std::mutex> l(lock_);
258 stop_ = false;
259 cv_.notify_all();
260 }
261
ClearBuffers()262 void BufferPool::ClearBuffers()
263 {
264 DestroyBuffer();
265 }
266
GetIdleBufferCount()267 uint32_t BufferPool::GetIdleBufferCount()
268 {
269 std::unique_lock<std::mutex> l(lock_);
270 return idleList_.size();
271 }
272 } // namespace OHOS::Camera
273