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