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 sfBuffer_.clear();
113 sfSize_.clear();
114 return RC_OK;
115 }
116
117 if (bufferAllocator_ == nullptr) {
118 CAMERA_LOGE("bufferAllocator_ is nullptr");
119 return RC_ERROR;
120 }
121
122 {
123 std::unique_lock<std::mutex> l(lock_);
124
125 for (auto it : idleList_) {
126 RetCode ret = bufferAllocator_->UnmapBuffer(it);
127 if (ret != RC_OK) {
128 CAMERA_LOGE("unmap (%{public}d) buffer failed", it->GetIndex());
129 }
130 ret = bufferAllocator_->FreeBuffer(it);
131 if (ret != RC_OK) {
132 CAMERA_LOGE("free (%{public}d) buffer failed", it->GetIndex());
133 }
134 }
135 idleList_.clear();
136
137 if (busyList_.size() > 0) {
138 CAMERA_LOGE("%{public}zu buffer(s) is/are in use.", busyList_.size());
139 }
140 for (auto it : busyList_) {
141 RetCode ret = bufferAllocator_->UnmapBuffer(it);
142 if (ret != RC_OK) {
143 CAMERA_LOGE("unmap (%{public}d) buffer failed", it->GetIndex());
144 }
145 ret = bufferAllocator_->FreeBuffer(it);
146 if (ret != RC_OK) {
147 CAMERA_LOGE("free (%{public}d) buffer failed", it->GetIndex());
148 }
149 }
150 busyList_.clear();
151 sfBuffer_.clear();
152 sfSize_.clear();
153 }
154
155 return RC_OK;
156 }
157
AddBuffer(std::shared_ptr<IBuffer> & buffer)158 RetCode BufferPool::AddBuffer(std::shared_ptr<IBuffer>& buffer)
159 {
160 std::unique_lock<std::mutex> l(lock_);
161 buffer->SetPoolId(poolId_);
162 idleList_.emplace_back(buffer);
163 cv_.notify_one();
164 return RC_OK;
165 }
166
AcquireBuffer(int timeout)167 std::shared_ptr<IBuffer> BufferPool::AcquireBuffer(int timeout)
168 {
169 std::unique_lock<std::mutex> l(lock_);
170
171 // return buffer immediately, if idle buffer is available;
172 if (!idleList_.empty()) {
173 auto it = idleList_.begin();
174 auto buffer = *it;
175 busyList_.splice(busyList_.begin(), idleList_, it);
176 CAMERA_LOGV("acquire buffer immediately, index = %{public}d", buffer->GetIndex());
177 return *it;
178 }
179
180 // wait all the time, till idle list is available.
181 if (timeout < 0) {
182 cv_.wait(l, [this] {
183 return !idleList_.empty() || stop_;
184 });
185 if (!idleList_.empty()) {
186 auto it = idleList_.begin();
187 auto buffer = *it;
188 busyList_.splice(busyList_.begin(), idleList_, it);
189 CAMERA_LOGV("acquire buffer wait all the time, index = %{public}d", buffer->GetIndex());
190 return *it;
191 }
192 }
193
194 // wait for timeout, or idle list is available.
195 if (timeout > 0) {
196 if (cv_.wait_for(l, std::chrono::seconds(timeout), [this] {
197 return !idleList_.empty() || stop_;
198 }) == false) {
199 CAMERA_LOGE("wait idle buffer timeout");
200 return nullptr;
201 }
202 if (!idleList_.empty()) {
203 auto it = idleList_.begin();
204 auto buffer = *it;
205 busyList_.splice(busyList_.begin(), idleList_, it);
206 CAMERA_LOGV("acquire buffer wait %{public}ds, index = %{public}d", timeout, buffer->GetIndex());
207 return *it;
208 }
209 }
210
211 // timeout == 0. return nullptr buffer immediately, although idle buffer is not available.
212 return nullptr;
213 }
214
ReturnBuffer(std::shared_ptr<IBuffer> & buffer)215 RetCode BufferPool::ReturnBuffer(std::shared_ptr<IBuffer>& buffer)
216 {
217 std::unique_lock<std::mutex> l(lock_);
218
219 auto it = std::find(busyList_.begin(), busyList_.end(), buffer);
220 if (it == busyList_.end()) {
221 CAMERA_LOGE("fatal error, busy list is empty, cannot return buffer.");
222 return RC_ERROR;
223 }
224
225 if (bufferSourceType_ == CAMERA_BUFFER_SOURCE_TYPE_EXTERNAL) {
226 busyList_.erase(it);
227 cv_.notify_one();
228 return RC_OK;
229 }
230
231 if (trackingId_ >= 0) {
232 POOL_REPORT_BUFFER_LOCATION(trackingId_, buffer->GetFrameNumber());
233 }
234
235 idleList_.splice(idleList_.end(), busyList_, it);
236 cv_.notify_one();
237
238 return RC_OK;
239 }
240
EnableTracking(const int32_t id)241 void BufferPool::EnableTracking(const int32_t id)
242 {
243 trackingId_ = id;
244 return;
245 }
246
SetId(const int64_t id)247 void BufferPool::SetId(const int64_t id)
248 {
249 poolId_ = id;
250 }
251
NotifyStop()252 void BufferPool::NotifyStop()
253 {
254 std::unique_lock<std::mutex> l(lock_);
255 stop_ = true;
256 cv_.notify_all();
257 }
258
NotifyStart()259 void BufferPool::NotifyStart()
260 {
261 std::unique_lock<std::mutex> l(lock_);
262 stop_ = false;
263 cv_.notify_all();
264 }
265
ClearBuffers()266 void BufferPool::ClearBuffers()
267 {
268 DestroyBuffer();
269 }
270
GetIdleBufferCount()271 uint32_t BufferPool::GetIdleBufferCount()
272 {
273 std::unique_lock<std::mutex> l(lock_);
274 return idleList_.size();
275 }
setSFBuffer(std::shared_ptr<IBuffer> & buffer)276 void BufferPool::setSFBuffer(std::shared_ptr<IBuffer>& buffer)
277 {
278 sfBuffer_.insert(std::make_pair(buffer->GetIndex(), static_cast<uint8_t *>(buffer->GetVirAddress())));
279 sfSize_.insert(std::make_pair(buffer->GetIndex(), buffer->GetSize()));
280 forkBufferId_ = buffer->GetIndex();
281 }
282
getSFBuffer(int32_t index)283 std::map<int32_t, uint8_t*> BufferPool::getSFBuffer(int32_t index)
284 {
285 std::map<int32_t, uint8_t*> sizeVirMap;
286 auto iterMap = sfBuffer_.find(index);
287 if (iterMap == sfBuffer_.end()) {
288 CAMERA_LOGE("std::map sfBuffer_ no buffer->GetIndex()\n");
289 return sizeVirMap;
290 }
291
292 auto iterSizeMap = sfSize_.find(index);
293 if (iterSizeMap == sfSize_.end()) {
294 CAMERA_LOGE("std::map sfSize_ no buffer->GetIndex()\n");
295 return sizeVirMap;
296 }
297 sizeVirMap[iterSizeMap->second] = iterMap->second;
298 return sizeVirMap;
299 }
300
GetForkBufferId()301 int32_t BufferPool::GetForkBufferId()
302 {
303 return forkBufferId_;
304 }
305
SetForkBufferId(int32_t index)306 void BufferPool::SetForkBufferId(int32_t index)
307 {
308 forkBufferId_ = index;
309 }
310
GetIsFork()311 bool BufferPool::GetIsFork()
312 {
313 return isFork_;
314 }
315
SetIsFork(bool isFork)316 void BufferPool::SetIsFork(bool isFork)
317 {
318 isFork_ = isFork;
319 }
320 } // namespace OHOS::Camera
321