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