1 /*
2 * Copyright (c) 2025 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 "hardware/jpeg_dma_pool.h"
17 #include <chrono>
18 #include <sys/mman.h>
19 namespace OHOS::ImagePlugin {
20 using namespace OHOS::HDI::Codec::Image::V2_1;
21
22 constexpr uint32_t DMA_POOL_SIZE = 1024 * 1024; /* the size of DMA Pool is 1M */
23 constexpr uint32_t DMA_POOL_ALIGN_SIZE = 32 * 1024; /* Input buffer alignment size is 32K */
24
GetInstance()25 DmaPool& DmaPool::GetInstance()
26 {
27 static DmaPool singleton;
28 return singleton;
29 }
30
AllocBufferInDmaPool(sptr<ICodecImage> hwDecoder,ImagePlugin::InputDataStream * srcStream,CodecImageBuffer & inBuffer,PureStreamInfo streamInfo,DmaBufferInfo & bufferInfo)31 bool DmaPool::AllocBufferInDmaPool(sptr<ICodecImage> hwDecoder, ImagePlugin::InputDataStream* srcStream,
32 CodecImageBuffer& inBuffer, PureStreamInfo streamInfo, DmaBufferInfo& bufferInfo)
33 {
34 std::lock_guard<std::mutex> lock(dmaPoolMtx_);
35 // step1. decide whether to alloc dma pool
36 if (!Init(hwDecoder)) {
37 JPEG_HW_LOGE("failed to init dma pool");
38 return false;
39 }
40 // step2. determine whether remainCapacity_ is sufficient
41 bufferInfo.allocatedBufferSize = ((streamInfo.dataSize + DMA_POOL_ALIGN_SIZE - 1) / DMA_POOL_ALIGN_SIZE)
42 * DMA_POOL_ALIGN_SIZE;
43 bufferInfo.allocatedBufferOffsetOfPool = remainOffset_;
44 if (bufferInfo.allocatedBufferSize > remainCapacity_) {
45 JPEG_HW_LOGI("The space left in dma pool isn't enough");
46 return false;
47 }
48 // step3. try to copy src data to alloc buffer in dma pool
49 if (!CopySrcToDmaPool(srcStream, streamInfo, bufferInfo)) {
50 return false;
51 }
52 // step4. try to packing bufferhandle to inbuffer
53 if (!PackingBufferHandle(bufferInfo, inBuffer)) {
54 return false;
55 }
56 // step5. try to alloc buffer in dmapool
57 UpdateDmaPoolInfo(streamInfo, bufferInfo);
58 return true;
59 }
60
Init(sptr<ICodecImage> hwDecoder)61 bool DmaPool::Init(sptr<ICodecImage> hwDecoder)
62 {
63 if (inited_) {
64 return true;
65 }
66 CodecImageBuffer tempPool{};
67 int32_t ret = hwDecoder->AllocateInBuffer(tempPool, DMA_POOL_SIZE, CODEC_IMAGE_JPEG);
68 if (ret != HDF_SUCCESS || tempPool.buffer == nullptr) {
69 JPEG_HW_LOGE("failed to allocate dma pool, err=%{public}d", ret);
70 return false;
71 }
72 bufferHandle_ = tempPool.buffer->GetBufferHandle();
73 if (bufferHandle_ == nullptr) {
74 JPEG_HW_LOGE("dma pool bufferHandle is null");
75 return false;
76 }
77 bufferHandle_->virAddr = mmap(nullptr, DMA_POOL_SIZE, PROT_READ | PROT_WRITE,
78 MAP_SHARED, bufferHandle_->fd, 0);
79 if (bufferHandle_->virAddr == MAP_FAILED) {
80 JPEG_HW_LOGE("failed to map dma pool");
81 return false;
82 }
83 std::thread lifeManageThread([this] {this->RunDmaPoolDestroy();});
84 if (!lifeManageThread.joinable()) {
85 if (munmap(bufferHandle_->virAddr, DMA_POOL_SIZE) != 0) {
86 JPEG_HW_LOGE("failed to unmap dma pool");
87 }
88 JPEG_HW_LOGE("failed to create lifeManageThread_");
89 bufferHandle_ = nullptr;
90 return false;
91 }
92 lifeManageThread.detach();
93 inited_ = true;
94 remainCapacity_ = DMA_POOL_SIZE;
95 nativeBuf_ = tempPool.buffer;
96 JPEG_HW_LOGI("create dma pool success!");
97 return true;
98 }
99
CopySrcToDmaPool(ImagePlugin::InputDataStream * srcStream,PureStreamInfo streamInfo,DmaBufferInfo bufferInfo)100 bool DmaPool::CopySrcToDmaPool(ImagePlugin::InputDataStream* srcStream, PureStreamInfo streamInfo,
101 DmaBufferInfo bufferInfo)
102 {
103 uint32_t positionRecord = srcStream->Tell();
104 srcStream->Seek(streamInfo.dataPos);
105 uint32_t readSize = 0;
106 bool flag = srcStream->Read(streamInfo.dataSize,
107 static_cast<uint8_t*>(bufferHandle_->virAddr) + bufferInfo.allocatedBufferOffsetOfPool,
108 static_cast<uint32_t>(bufferHandle_->size) - bufferInfo.allocatedBufferOffsetOfPool,
109 readSize);
110 srcStream->Seek(positionRecord);
111 if (!flag || readSize != streamInfo.dataSize) {
112 JPEG_HW_LOGE("failed to read input data, readSize=%{public}u", readSize);
113 return false;
114 }
115 return true;
116 }
117
PackingBufferHandle(DmaBufferInfo bufferInfo,CodecImageBuffer & inBuffer)118 bool DmaPool::PackingBufferHandle(DmaBufferInfo bufferInfo, CodecImageBuffer& inBuffer)
119 {
120 BufferHandle* curHandle = new (std::nothrow) BufferHandle;
121 if (curHandle == nullptr) {
122 JPEG_HW_LOGE("failed to new bufferHandle!");
123 return false;
124 }
125 curHandle->fd = bufferHandle_->fd;
126 curHandle->size = static_cast<int32_t>(bufferInfo.allocatedBufferSize);
127 curHandle->width = static_cast<int32_t>(bufferInfo.allocatedBufferSize);
128 curHandle->stride = static_cast<int32_t>(bufferInfo.allocatedBufferSize);
129 curHandle->height = 1;
130 curHandle->reserveFds = 0;
131 curHandle->reserveInts = 0;
132 inBuffer.buffer = new NativeBuffer();
133 inBuffer.buffer->SetBufferHandle(curHandle, true, [this](BufferHandle* freeBuffer) {
134 delete freeBuffer;
135 });
136 inBuffer.bufferRole = CODEC_IMAGE_JPEG;
137 return true;
138 }
139
UpdateDmaPoolInfo(PureStreamInfo streamInfo,DmaBufferInfo bufferInfo)140 void DmaPool::UpdateDmaPoolInfo(PureStreamInfo streamInfo, DmaBufferInfo bufferInfo)
141 {
142 remainCapacity_ -= bufferInfo.allocatedBufferSize;
143 remainOffset_ += bufferInfo.allocatedBufferSize;
144 usedSpace_[remainOffset_] = bufferInfo.allocatedBufferSize;
145 activeTime_ = std::chrono::steady_clock::now();
146 JPEG_HW_LOGI("upadteSpaceInfo: aligend size:%{public}u buffer usedOffset:%{public}u usedNum:%{public}zu",
147 bufferInfo.allocatedBufferSize, bufferInfo.allocatedBufferOffsetOfPool, usedSpace_.size());
148 }
149
RunDmaPoolDestroy()150 void DmaPool::RunDmaPoolDestroy()
151 {
152 using namespace std::literals;
153 std::unique_lock<std::mutex> lck(dmaPoolMtx_);
154 /* Destroy the DMA pool if it is not used for more than 10s */
155 while (true) {
156 bool ret = dmaPoolCond_.wait_for(lck, 5s, [this]() {
157 auto curTime = std::chrono::steady_clock::now();
158 auto diffDuration = std::chrono::duration_cast<std::chrono::seconds>(curTime - activeTime_);
159 return usedSpace_.empty() && diffDuration >= 10s;
160 });
161 if (ret) {
162 break;
163 }
164 JPEG_HW_LOGI("wait to destroy dma pool");
165 }
166 if (bufferHandle_ != nullptr && bufferHandle_->virAddr != nullptr) {
167 if (munmap(bufferHandle_->virAddr, DMA_POOL_SIZE) != 0) {
168 JPEG_HW_LOGE("failed to unmap dma pool");
169 }
170 } else {
171 JPEG_HW_LOGE("dma pool bufferhandle or viraddr is nullptr!");
172 }
173 inited_ = false;
174 remainCapacity_ = 0;
175 remainOffset_ = 0;
176 nativeBuf_ = nullptr;
177 bufferHandle_ = nullptr;
178 JPEG_HW_LOGI("dma pool destroyed!");
179 return;
180 }
181
RecycleBufferInDmaPool(DmaBufferInfo bufferInfo)182 void DmaPool::RecycleBufferInDmaPool(DmaBufferInfo bufferInfo)
183 {
184 std::lock_guard<std::mutex> lock(dmaPoolMtx_);
185 activeTime_ = std::chrono::steady_clock::now();
186 uint32_t endOffset = bufferInfo.allocatedBufferOffsetOfPool + bufferInfo.allocatedBufferSize;
187 // 1.push used space to release space
188 auto it = usedSpace_.find(endOffset);
189 if (it != usedSpace_.end()) {
190 releaseSpace_[endOffset] = bufferInfo.allocatedBufferSize;
191 usedSpace_.erase(it);
192 }
193
194 // 2.recycle continuous release space adjacent to remainOffset_
195 while (true) {
196 auto it = releaseSpace_.find(remainOffset_);
197 if (it != releaseSpace_.end()) {
198 remainOffset_ -= it->second;
199 remainCapacity_ += it->second;
200 releaseSpace_.erase(it);
201 continue;
202 }
203 break;
204 }
205 JPEG_HW_LOGI("remainCapacity_: size:%{public}u remainOffset_:%{public}u unRecycleNum:%{public}zu + %{public}zu",
206 remainCapacity_, remainOffset_, usedSpace_.size(), releaseSpace_.size());
207 }
208 }