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