• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 #ifndef RENDER_SERVICE_BASE_PROPERTY_RS_FILTER_CACHE_MANAGER_H
17 #define RENDER_SERVICE_BASE_PROPERTY_RS_FILTER_CACHE_MANAGER_H
18 
19 #if defined(NEW_SKIA) && (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
20 #include <condition_variable>
21 #include <mutex>
22 
23 #include "event_handler.h"
24 #ifndef USE_ROSEN_DRAWING
25 #include "include/core/SkImageInfo.h"
26 #include "include/core/SkRect.h"
27 #include "include/core/SkRefCnt.h"
28 #include "include/core/SkSurface.h"
29 #include "include/gpu/GrBackendSurface.h"
30 #else
31 #include "draw/canvas.h"
32 #include "draw/surface.h"
33 #include "utils/rect.h"
34 #endif
35 
36 #include "common/rs_macros.h"
37 #include "common/rs_rect.h"
38 #include "pipeline/rs_dirty_region_manager.h"
39 #include "pipeline/rs_paint_filter_canvas.h"
40 #include "pipeline/rs_uni_render_judgement.h"
41 #include "platform/common/rs_system_properties.h"
42 #include "render/rs_filter.h"
43 
44 namespace OHOS {
45 namespace Rosen {
46 #ifndef USE_ROSEN_DRAWING
47 class RSSkiaFilter;
48 #else
49 class RSDrawingFilter;
50 #endif
51 // Note: we don't care about if the filter will be applied to background or foreground, the caller should take care of
52 // this. This means if both background and foreground need to apply filter, the caller should create two
53 // RSFilterCacheManager, pass the correct dirty region, and call the DrawFilter() in correct order.
54 // Warn: Using filter cache in multi-thread environment may cause GPU memory leak or invalid textures.
55 class RSFilterCacheManager final {
56 public:
57     static bool SoloTaskPrepare;
58     RSFilterCacheManager() = default;
59     ~RSFilterCacheManager() = default;
60     RSFilterCacheManager(const RSFilterCacheManager&) = delete;
61     RSFilterCacheManager(const RSFilterCacheManager&&) = delete;
62     RSFilterCacheManager& operator=(const RSFilterCacheManager&) = delete;
63     RSFilterCacheManager& operator=(const RSFilterCacheManager&&) = delete;
64 
65     // Call these functions during the prepare phase to validate the cache state with the filter, if filter region is
66     // intersected with cached region, and if cached region is intersected with dirty region.
67     void UpdateCacheStateWithFilterHash(const std::shared_ptr<RSFilter>& filter);
68     void UpdateCacheStateWithFilterRegion(); // call when filter region out of cached region.
69     bool UpdateCacheStateWithDirtyRegion(
70         const RSDirtyRegionManager& dirtyManager); // call when dirty region intersects with cached region.
71     const RectI& GetCachedImageRegion() const;
72 
73 #ifndef USE_ROSEN_DRAWING
74     // Call this function during the process phase to apply the filter. Depending on the cache state, it may either
75     // regenerate the cache or reuse the existing cache.
76     // Note: If srcRect or dstRect is empty, we'll use the DeviceClipRect as the corresponding rect.
77     void DrawFilter(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSSkiaFilter>& filter,
78         const bool needSnapshotOutset = true, const std::optional<SkIRect>& srcRect = std::nullopt,
79         const std::optional<SkIRect>& dstRect = std::nullopt);
80 
81     // This function is similar to DrawFilter(), but instead of drawing anything on the canvas, it simply returns the
82     // cache data. This is used with effect component in RSPropertiesPainter::DrawBackgroundEffect.
83     const std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> GeneratedCachedEffectData(RSPaintFilterCanvas& canvas,
84         const std::shared_ptr<RSSkiaFilter>& filter, const std::optional<SkIRect>& srcRect = std::nullopt,
85         const std::optional<SkIRect>& dstRect = std::nullopt,
86         const std::tuple<bool, bool>& forceCacheFlags = std::make_tuple(false, false));
87 
88     static bool IsNearlyFullScreen(SkISize imageSize, int32_t canvasWidth, int32_t canvasHeight);
89     void PostPartialFilterRenderTask(const std::shared_ptr<RSSkiaFilter>& filter, const SkIRect& dstRect);
90     void PostPartialFilterRenderInit(const std::shared_ptr<RSSkiaFilter>& filter, const SkIRect& dstRect,
91         int32_t canvasWidth, int32_t canvasHeight);
92 #else
93     // Call this function during the process phase to apply the filter. Depending on the cache state, it may either
94     // regenerate the cache or reuse the existing cache.
95     // Note: If srcRect or dstRect is empty, we'll use the DeviceClipRect as the corresponding rect.
96     void DrawFilter(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter,
97         const bool needSnapshotOutset = true, const std::optional<Drawing::RectI>& srcRect = std::nullopt,
98         const std::optional<Drawing::RectI>& dstRect = std::nullopt);
99 
100     // This function is similar to DrawFilter(), but instead of drawing anything on the canvas, it simply returns the
101     // cache data. This is used with effect component in RSPropertiesPainter::DrawBackgroundEffect.
102     const std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> GeneratedCachedEffectData(RSPaintFilterCanvas& canvas,
103         const std::shared_ptr<RSDrawingFilter>& filter, const std::optional<Drawing::RectI>& srcRect = std::nullopt,
104         const std::optional<Drawing::RectI>& dstRect = std::nullopt,
105         const std::tuple<bool, bool>& forceCacheFlags = std::make_tuple(false, false));
106 
107     static bool IsNearlyFullScreen(Drawing::RectI imageSize, int32_t canvasWidth, int32_t canvasHeight);
108     void PostPartialFilterRenderTask(const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& dstRect);
109     void PostPartialFilterRenderInit(const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& dstRect,
110         int32_t canvasWidth, int32_t canvasHeight);
111 #endif
112     enum CacheType : uint8_t {
113         CACHE_TYPE_NONE              = 0,
114         CACHE_TYPE_SNAPSHOT          = 1,
115         CACHE_TYPE_FILTERED_SNAPSHOT = 2,
116         CACHE_TYPE_BOTH              = CACHE_TYPE_SNAPSHOT | CACHE_TYPE_FILTERED_SNAPSHOT,
117     };
118 
119     // Call this function to manually invalidate the cache. The next time DrawFilter() is called, it will regenerate the
120     // cache.
121     void InvalidateCache(CacheType cacheType = CacheType::CACHE_TYPE_BOTH);
122     void ReleaseCacheOffTree();
123 
IsCacheValid()124     inline bool IsCacheValid() const
125     {
126         return cachedSnapshot_ != nullptr || cachedFilteredSnapshot_ != nullptr;
127     }
128 
129 private:
130     class RSFilterCacheTask : public RSFilter::RSFilterTask {
131     public:
132         static const bool FilterPartialRenderEnabled;
133         bool isFirstInit_ = true;
134         bool needClearSurface_ = false;
135         std::atomic<bool> isTaskRelease_ = false;
136         std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedFirstFilter_ = nullptr;
137         std::mutex grBackendTextureMutex_;
138         RSFilterCacheTask() = default;
139         virtual ~RSFilterCacheTask() = default;
140 #ifndef USE_ROSEN_DRAWING
141         bool InitSurface(GrRecordingContext* grContext) override;
142 #else
143         std::atomic<Drawing::ColorType> cacheBackendTextureColorType_;
144         bool InitSurface(Drawing::GPUContext* grContext) override;
145 #endif
146         bool Render() override;
147         bool SaveFilteredImage() override;
148         void SwapInit() override;
149         bool SetDone() override;
GetStatus()150         CacheProcessStatus GetStatus() const
151         {
152             return cacheProcessStatus_.load();
153         }
154 
SetStatus(CacheProcessStatus cacheProcessStatus)155         void SetStatus(CacheProcessStatus cacheProcessStatus)
156         {
157             cacheProcessStatus_.store(cacheProcessStatus);
158         }
159 
160 #ifndef USE_ROSEN_DRAWING
InitTask(std::shared_ptr<RSSkiaFilter> filter,std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedSnapshot,const SkIRect & dstRect)161         void InitTask(std::shared_ptr<RSSkiaFilter> filter,
162             std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedSnapshot, const SkIRect& dstRect)
163         {
164             needClearSurface_ = (dstRectBefore_.width() != dstRect.width() ||
165                 dstRectBefore_.height() != dstRect.height());
166             filterBefore_ = filter;
167             cachedSnapshotBefore_ = cachedSnapshot;
168             snapshotSizeBefore_ = cachedSnapshot->cachedRect_.size();
169             dstRectBefore_ = dstRect;
170         }
171 
GetResultTexture()172         GrBackendTexture GetResultTexture() const
173         {
174             return cacheCompletedBackendTexture_;
175         }
176 
GetDstRect()177         SkIRect GetDstRect() const
178         {
179             return dstRect_;
180         }
181 #else
InitTask(std::shared_ptr<RSDrawingFilter> filter,std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedSnapshot,const Drawing::RectI & dstRect)182         void InitTask(std::shared_ptr<RSDrawingFilter> filter,
183             std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedSnapshot, const Drawing::RectI& dstRect)
184         {
185             needClearSurface_ = (dstRectBefore_.GetWidth() != dstRect.GetWidth() ||
186                 dstRectBefore_.GetHeight() != dstRect.GetHeight());
187             filterBefore_ = filter;
188             cachedSnapshotBefore_ = cachedSnapshot;
189             snapshotSizeBefore_ = cachedSnapshot->cachedRect_;
190             dstRectBefore_ = dstRect;
191         }
192 
GetResultTexture()193         Drawing::BackendTexture GetResultTexture() const
194         {
195             return cacheCompletedBackendTexture_;
196         }
197 
GetDstRect()198         Drawing::RectI GetDstRect() const
199         {
200             return dstRect_;
201         }
202 #endif
203 
Reset()204         void Reset()
205         {
206             cachedSnapshotBefore_.reset();
207         }
208 
ResetInTask()209         void ResetInTask()
210         {
211             cachedSnapshotInTask_.reset();
212             dstRectBefore_ = { 0, 0, 0, 0 };
213             dstRect_ = { 0, 0, 0, 0 };
214         }
215 
ResetGrContext()216         void ResetGrContext()
217         {
218             cacheSurface_ = nullptr;
219             cacheCompletedSurface_ = nullptr;
220             RSFilter::clearGpuContext();
221             isTaskRelease_.store(false);
222         }
223 
Notify()224         void Notify()
225         {
226             cvParallelRender_.notify_one();
227         }
228 
GetHandler()229         std::shared_ptr<OHOS::AppExecFwk::EventHandler> GetHandler()
230         {
231             return handler_;
232         }
233 
IsCompleted()234         bool IsCompleted()
235         {
236             return isCompleted_;
237         }
238 
SetCompleted(bool val)239         void SetCompleted(bool val)
240         {
241             isCompleted_ = val;
242         }
243 
SwapTexture()244         void SwapTexture()
245         {
246             std::swap(resultBackendTexture_, cacheCompletedBackendTexture_);
247             std::swap(cacheSurface_, cacheCompletedSurface_);
248         }
249 
250     private:
251 #ifndef USE_ROSEN_DRAWING
252         GrBackendTexture cacheBackendTexture_;
253         GrBackendTexture resultBackendTexture_;
254         GrBackendTexture cacheCompletedBackendTexture_;
255         sk_sp<SkSurface> cacheSurface_ = nullptr;
256         sk_sp<SkSurface> cacheCompletedSurface_ = nullptr;
257         SkISize snapshotSize_;
258         SkISize snapshotSizeBefore_;
259         SkIRect dstRect_;
260         SkIRect dstRectBefore_;
261         std::shared_ptr<RSSkiaFilter> filter_ = nullptr;
262         std::shared_ptr<RSSkiaFilter> filterBefore_ = nullptr;
263 #else
264         Drawing::BackendTexture cacheBackendTexture_;
265         Drawing::BackendTexture resultBackendTexture_;
266         Drawing::BackendTexture cacheCompletedBackendTexture_;
267         std::shared_ptr<Drawing::Surface> cacheSurface_ = nullptr;
268         std::shared_ptr<Drawing::Surface> cacheCompletedSurface_ = nullptr;
269         Drawing::RectI snapshotSize_;
270         Drawing::RectI snapshotSizeBefore_;
271         Drawing::RectI dstRect_;
272         Drawing::RectI dstRectBefore_;
273         std::shared_ptr<RSDrawingFilter> filter_ = nullptr;
274         std::shared_ptr<RSDrawingFilter> filterBefore_ = nullptr;
275 #endif
276         std::atomic<CacheProcessStatus> cacheProcessStatus_ = CacheProcessStatus::WAITING;
277         std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedSnapshotInTask_ = nullptr;
278         std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedSnapshotBefore_ = nullptr;
279         std::condition_variable cvParallelRender_;
280         std::shared_ptr<OHOS::AppExecFwk::EventHandler> handler_ = nullptr;
281         bool isCompleted_ = false;
282     };
283 
284 #ifndef USE_ROSEN_DRAWING
285     void TakeSnapshot(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSSkiaFilter>& filter,
286         const SkIRect& srcRect, const bool needSnapshotOutset = true);
287     void GenerateFilteredSnapshot(
288         RSPaintFilterCanvas& canvas, const std::shared_ptr<RSSkiaFilter>& filter, const SkIRect& dstRect);
289     void FilterPartialRender(
290         RSPaintFilterCanvas& canvas, const std::shared_ptr<RSSkiaFilter>& filter, const SkIRect& dstRect);
291     void DrawCachedFilteredSnapshot(RSPaintFilterCanvas& canvas, const SkIRect& dstRect) const;
292     // Validate the input srcRect and dstRect, and return the validated rects.
293     std::tuple<SkIRect, SkIRect> ValidateParams(RSPaintFilterCanvas& canvas,
294         const std::optional<SkIRect>& srcRect, const std::optional<SkIRect>& dstRect,
295         const std::tuple<bool, bool>& forceCacheFlags = std::make_tuple(false, false));
296 #else
297     void TakeSnapshot(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter,
298         const Drawing::RectI& srcRect, const bool needSnapshotOutset = true);
299     void GenerateFilteredSnapshot(
300         RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& dstRect);
301     void FilterPartialRender(
302         RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& dstRect);
303     void DrawCachedFilteredSnapshot(RSPaintFilterCanvas& canvas, const Drawing::RectI& dstRect) const;
304     // Validate the input srcRect and dstRect, and return the validated rects.
305     std::tuple<Drawing::RectI, Drawing::RectI> ValidateParams(RSPaintFilterCanvas& canvas,
306         const std::optional<Drawing::RectI>& srcRect, const std::optional<Drawing::RectI>& dstRect,
307         const std::tuple<bool, bool>& forceCacheFlags = std::make_tuple(false, false));
308 #endif
309     inline static void ClipVisibleRect(RSPaintFilterCanvas& canvas);
310     // Check if the cache is valid in current GrContext, since FilterCache will never be used in multi-thread
311     // environment, we don't need to attempt to reattach SkImages.
312     void CheckCachedImages(RSPaintFilterCanvas& canvas);
313     // To reduce memory usage, clear one of the cached images.
314     inline void CompactCache(bool shouldClearFilteredCache);
315 
316     const char* GetCacheState() const;
317 
318     // We keep both the snapshot and filtered snapshot in the cache, and clear unneeded one in next frame.
319     // Note: rect in cachedSnapshot_ and cachedFilteredSnapshot_ is in device coordinate.
320     std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedSnapshot_ = nullptr;
321     std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedFilteredSnapshot_ = nullptr;
322     bool newCache_ = true;
323 
324     // Hash of previous filter, used to determine if we need to invalidate cachedFilteredSnapshot_.
325     uint32_t cachedFilterHash_ = 0;
326     // Cache age, used to determine if we can delay the cache update.
327     int cacheUpdateInterval_ = 0;
328     // Whether we need to purge the cache after this frame.
329     bool pendingPurge_ = false;
330     // Region of the cached image, used to determine if we need to invalidate the cache.
331     RectI snapshotRegion_; // Note: in device coordinate.
332 
333     std::shared_ptr<RSFilterCacheTask> task_ = std::make_shared<RSFilterCacheTask>();
334 };
335 } // namespace Rosen
336 } // namespace OHOS
337 #endif
338 
339 #endif // RENDER_SERVICE_BASE_PROPERTY_RS_FILTER_CACHE_MANAGER_H
340