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