1 /*
2 * Copyright (c) 2022 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 "memory/rs_memory_snapshot.h"
17 #include "render/rs_image_cache.h"
18 #include "pixel_map.h"
19
20 namespace OHOS {
21 namespace Rosen {
22 // modify the RSImageCache instance as global to extend life cycle, fix destructor crash
23 static RSImageCache gRSImageCacheInstance;
24
Instance()25 RSImageCache& RSImageCache::Instance()
26 {
27 return gRSImageCacheInstance;
28 }
29
CacheDrawingImage(uint64_t uniqueId,std::shared_ptr<Drawing::Image> img)30 void RSImageCache::CacheDrawingImage(uint64_t uniqueId, std::shared_ptr<Drawing::Image> img)
31 {
32 if (img && uniqueId > 0) {
33 std::lock_guard<std::mutex> lock(mutex_);
34 drawingImageCache_.emplace(uniqueId, std::make_pair(img, 0));
35 }
36 }
37
GetDrawingImageCache(uint64_t uniqueId) const38 std::shared_ptr<Drawing::Image> RSImageCache::GetDrawingImageCache(uint64_t uniqueId) const
39 {
40 std::lock_guard<std::mutex> lock(mutex_);
41 auto it = drawingImageCache_.find(uniqueId);
42 if (it != drawingImageCache_.end()) {
43 return it->second.first;
44 }
45 return nullptr;
46 }
47
IncreaseDrawingImageCacheRefCount(uint64_t uniqueId)48 void RSImageCache::IncreaseDrawingImageCacheRefCount(uint64_t uniqueId)
49 {
50 std::lock_guard<std::mutex> lock(mutex_);
51 auto it = drawingImageCache_.find(uniqueId);
52 if (it != drawingImageCache_.end()) {
53 it->second.second++;
54 }
55 }
56
ReleaseDrawingImageCache(uint64_t uniqueId)57 void RSImageCache::ReleaseDrawingImageCache(uint64_t uniqueId)
58 {
59 // release the Drawing::Image if no RSImage holds it
60 std::lock_guard<std::mutex> lock(mutex_);
61 auto it = drawingImageCache_.find(uniqueId);
62 if (it != drawingImageCache_.end()) {
63 it->second.second--;
64 if (it->second.first == nullptr || it->second.second == 0) {
65 drawingImageCache_.erase(it);
66 }
67 }
68 }
69
CachePixelMap(uint64_t uniqueId,std::shared_ptr<Media::PixelMap> pixelMap)70 void RSImageCache::CachePixelMap(uint64_t uniqueId, std::shared_ptr<Media::PixelMap> pixelMap)
71 {
72 if (pixelMap && uniqueId > 0) {
73 {
74 std::lock_guard<std::mutex> lock(mutex_);
75 pixelMapCache_.emplace(uniqueId, std::make_pair(pixelMap, 0));
76 }
77 auto type = pixelMap->GetAllocatorType();
78 pid_t pid = uniqueId >> 32; // right shift 32 bit to restore pid
79 if (type != Media::AllocatorType::DMA_ALLOC && pid) {
80 auto realSize = type == Media::AllocatorType::SHARE_MEM_ALLOC
81 ? pixelMap->GetCapacity() / 2 // rs only counts half of the SHARE_MEM_ALLOC memory
82 : pixelMap->GetCapacity();
83 MemorySnapshot::Instance().AddCpuMemory(pid, realSize);
84 }
85 }
86 }
87
GetPixelMapCache(uint64_t uniqueId) const88 std::shared_ptr<Media::PixelMap> RSImageCache::GetPixelMapCache(uint64_t uniqueId) const
89 {
90 std::lock_guard<std::mutex> lock(mutex_);
91 auto it = pixelMapCache_.find(uniqueId);
92 if (it != pixelMapCache_.end()) {
93 return it->second.first;
94 }
95 return nullptr;
96 }
97
IncreasePixelMapCacheRefCount(uint64_t uniqueId)98 void RSImageCache::IncreasePixelMapCacheRefCount(uint64_t uniqueId)
99 {
100 std::lock_guard<std::mutex> lock(mutex_);
101 auto it = pixelMapCache_.find(uniqueId);
102 if (it != pixelMapCache_.end()) {
103 it->second.second++;
104 }
105 }
106
CollectUniqueId(uint64_t uniqueId)107 void RSImageCache::CollectUniqueId(uint64_t uniqueId)
108 {
109 std::unique_lock<std::mutex> lock(uniqueIdListMutex_);
110 uniqueIdList_.push_back(uniqueId);
111 }
112
ReleaseUniqueIdList()113 void RSImageCache::ReleaseUniqueIdList()
114 {
115 std::list<uint64_t> clearList;
116 {
117 std::unique_lock<std::mutex> lock(uniqueIdListMutex_);
118 uniqueIdList_.swap(clearList);
119 }
120 for (const auto& uniqueId : clearList) {
121 ReleasePixelMapCache(uniqueId);
122 }
123 }
124
CheckUniqueIdIsEmpty()125 bool RSImageCache::CheckUniqueIdIsEmpty()
126 {
127 if (uniqueIdListMutex_.try_lock()) {
128 if (uniqueIdList_.empty()) {
129 uniqueIdListMutex_.unlock();
130 return true;
131 }
132 uniqueIdListMutex_.unlock();
133 }
134 return false;
135 }
136
ReleasePixelMapCache(uint64_t uniqueId)137 void RSImageCache::ReleasePixelMapCache(uint64_t uniqueId)
138 {
139 std::shared_ptr<Media::PixelMap> pixelMap = nullptr;
140 {
141 // release the pixelMap if no RSImage holds it
142 std::lock_guard<std::mutex> lock(mutex_);
143 auto it = pixelMapCache_.find(uniqueId);
144 if (it != pixelMapCache_.end()) {
145 it->second.second--;
146 if (it->second.first == nullptr || it->second.second == 0) {
147 pixelMap = it->second.first;
148 bool shouldCount = pixelMap && pixelMap->GetAllocatorType() != Media::AllocatorType::DMA_ALLOC;
149 pid_t pid = uniqueId >> 32; // right shift 32 bit to restore pid
150 if (shouldCount && pid) {
151 auto realSize = pixelMap->GetAllocatorType() == Media::AllocatorType::SHARE_MEM_ALLOC
152 ? pixelMap->GetCapacity() / 2 // rs only counts half of the SHARE_MEM_ALLOC memory
153 : pixelMap->GetCapacity();
154 MemorySnapshot::Instance().RemoveCpuMemory(pid, realSize);
155 }
156 pixelMapCache_.erase(it);
157 ReleaseDrawingImageCacheByPixelMapId(uniqueId);
158 }
159 } else {
160 ReleaseDrawingImageCacheByPixelMapId(uniqueId);
161 }
162 }
163 pixelMap.reset();
164 }
165
CheckRefCntAndReleaseImageCache(uint64_t uniqueId,std::shared_ptr<Media::PixelMap> & pixelMapIn,const std::shared_ptr<Drawing::Image> & image)166 int RSImageCache::CheckRefCntAndReleaseImageCache(uint64_t uniqueId, std::shared_ptr<Media::PixelMap>& pixelMapIn,
167 const std::shared_ptr<Drawing::Image>& image)
168 {
169 std::shared_ptr<Media::PixelMap> pixelMap = nullptr;
170 constexpr int IMAGE_USE_COUNT_FOR_PURGE = 2;
171 int refCount = IMAGE_USE_COUNT_FOR_PURGE;
172 if (!pixelMapIn || !image) {
173 return refCount;
174 }
175 {
176 // release the pixelMap if no RSImage holds it
177 std::lock_guard<std::mutex> lock(mutex_);
178 int originUseCount = static_cast<int>(image.use_count());
179 if (originUseCount > IMAGE_USE_COUNT_FOR_PURGE) {
180 return originUseCount; // skip purge if multi object holds this image
181 }
182 auto it = pixelMapCache_.find(uniqueId);
183 if (it != pixelMapCache_.end()) {
184 if (it->second.second > 1) {
185 return it->second.second; // skip purge if multi object holds this pixelMap
186 }
187 pixelMap = it->second.first;
188 if (pixelMap != pixelMapIn) {
189 return refCount; // skip purge if pixelMap mismatch
190 }
191 bool shouldCount = pixelMap && pixelMap->GetAllocatorType() != Media::AllocatorType::DMA_ALLOC;
192 pid_t pid = uniqueId >> 32; // right shift 32 bit to restore pid
193 if (shouldCount && pid) {
194 auto realSize = pixelMap->GetAllocatorType() == Media::AllocatorType::SHARE_MEM_ALLOC
195 ? pixelMap->GetCapacity() / 2 // rs only counts half of the SHARE_MEM_ALLOC memory
196 : pixelMap->GetCapacity();
197 MemorySnapshot::Instance().RemoveCpuMemory(pid, realSize);
198 }
199 pixelMapCache_.erase(it);
200 }
201 ReleaseDrawingImageCacheByPixelMapId(uniqueId);
202 refCount = image.use_count();
203 #ifdef ROSEN_OHOS
204 if (refCount == 1) { // purge pixelMap & image only if no more reference
205 pixelMapIn->UnMap();
206 }
207 #endif
208 }
209 pixelMap.reset();
210 return refCount;
211 }
212
CacheRenderDrawingImageByPixelMapId(uint64_t uniqueId,std::shared_ptr<Drawing::Image> img,pid_t tid)213 void RSImageCache::CacheRenderDrawingImageByPixelMapId(uint64_t uniqueId,
214 std::shared_ptr<Drawing::Image> img, pid_t tid)
215 {
216 if (uniqueId > 0 && img) {
217 std::lock_guard<std::mutex> lock(mapMutex_);
218 pixelMapIdRelatedDrawingImageCache_[uniqueId][tid] = img;
219 }
220 }
221
GetRenderDrawingImageCacheByPixelMapId(uint64_t uniqueId,pid_t tid) const222 std::shared_ptr<Drawing::Image> RSImageCache::GetRenderDrawingImageCacheByPixelMapId(uint64_t uniqueId, pid_t tid) const
223 {
224 std::lock_guard<std::mutex> lock(mapMutex_);
225 auto it = pixelMapIdRelatedDrawingImageCache_.find(uniqueId);
226 if (it != pixelMapIdRelatedDrawingImageCache_.end()) {
227 auto innerIt = it->second.find(tid);
228 if (innerIt != it->second.end()) {
229 return innerIt->second;
230 }
231 }
232 return nullptr;
233 }
234
ReleaseDrawingImageCacheByPixelMapId(uint64_t uniqueId)235 void RSImageCache::ReleaseDrawingImageCacheByPixelMapId(uint64_t uniqueId)
236 {
237 std::lock_guard<std::mutex> lock(mapMutex_);
238 auto it = pixelMapIdRelatedDrawingImageCache_.find(uniqueId);
239 if (it != pixelMapIdRelatedDrawingImageCache_.end()) {
240 pixelMapIdRelatedDrawingImageCache_.erase(it);
241 }
242 }
243 } // namespace Rosen
244 } // namespace OHOS
245