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