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 #include <atomic>
20 #if defined(NEW_SKIA) && (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
21 #include <condition_variable>
22 
23 #include "event_handler.h"
24 #include "draw/canvas.h"
25 #include "draw/surface.h"
26 #include "utils/rect.h"
27 
28 #include "common/rs_macros.h"
29 #include "common/rs_rect.h"
30 #include "pipeline/rs_dirty_region_manager.h"
31 #include "pipeline/rs_paint_filter_canvas.h"
32 #include "platform/common/rs_system_properties.h"
33 #include "render/rs_filter.h"
34 
35 namespace OHOS {
36 namespace Rosen {
37 class RSDrawingFilter;
38 // Note: we don't care about if the filter will be applied to background or foreground, the caller should take care of
39 // this. This means if both background and foreground need to apply filter, the caller should create two
40 // RSFilterCacheManager, pass the correct dirty region, and call the DrawFilter() in correct order.
41 // Warn: Using filter cache in multi-thread environment may cause GPU memory leak or invalid textures.
42 class RSB_EXPORT RSFilterCacheManager final {
43 public:
44     RSFilterCacheManager() = default;
45     ~RSFilterCacheManager() = default;
46     RSFilterCacheManager(const RSFilterCacheManager&) = delete;
47     RSFilterCacheManager(const RSFilterCacheManager&&) = delete;
48     RSFilterCacheManager& operator=(const RSFilterCacheManager&) = delete;
49     RSFilterCacheManager& operator=(const RSFilterCacheManager&&) = delete;
50 
51     // Call these functions during the prepare phase to validate the cache state with the filter, if filter region is
52     // intersected with cached region, and if cached region is intersected with dirty region.
53     void UpdateCacheStateWithFilterHash(const std::shared_ptr<RSFilter>& filter);
54     void UpdateCacheStateWithFilterRegion(); // call when filter region out of cached region.
55     bool UpdateCacheStateWithDirtyRegion(
56         const RSDirtyRegionManager& dirtyManager); // call when dirty region intersects with cached region.
57     void UpdateCacheStateWithDirtyRegion();
58     const RectI& GetCachedImageRegion() const;
59     FilterCacheType GetCachedType() const;
60 
61     struct DrawFilterParams {
62         bool needSnapshotOutset;
63         bool shouldClearFilteredCache;
64     };
65 
66     // Call this function during the process phase to apply the filter. Depending on the cache state, it may either
67     // regenerate the cache or reuse the existing cache.
68     // Note: If srcRect or dstRect is empty, we'll use the DeviceClipRect as the corresponding rect.
69     void DrawFilter(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter,
70         const DrawFilterParams params = { true, false }, const std::optional<Drawing::RectI>& srcRect = std::nullopt,
71         const std::optional<Drawing::RectI>& dstRect = std::nullopt);
72 
73     // This function is similar to DrawFilter(), but instead of drawing anything on the canvas, it simply returns the
74     // cache data. This is used with effect component in RSPropertiesPainter::DrawBackgroundEffect.
75     const std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> GeneratedCachedEffectData(RSPaintFilterCanvas& canvas,
76         const std::shared_ptr<RSDrawingFilter>& filter, const std::optional<Drawing::RectI>& srcRect = std::nullopt,
77         const std::optional<Drawing::RectI>& dstRect = std::nullopt);
78 
79     uint8_t CalcDirectionBias(const Drawing::Matrix& mat);
80     enum CacheType : uint8_t {
81         CACHE_TYPE_NONE              = 0,
82         CACHE_TYPE_SNAPSHOT          = 1,
83         CACHE_TYPE_FILTERED_SNAPSHOT = 2,
84         CACHE_TYPE_BOTH              = CACHE_TYPE_SNAPSHOT | CACHE_TYPE_FILTERED_SNAPSHOT,
85     };
86 
87     // Call this function to manually invalidate the cache. The next time DrawFilter() is called, it will regenerate the
88     // cache.
89     void ReleaseCacheOffTree();
90     void StopFilterPartialRender();
91     void InvalidateFilterCache(FilterCacheType clearType = FilterCacheType::BOTH);
92 
93     // To reduce memory usage, clear one of the cached images.
94     void CompactFilterCache(bool shouldClearFilteredCache);
95 
IsCacheValid()96     inline bool IsCacheValid() const
97     {
98         return cachedSnapshot_ != nullptr || cachedFilteredSnapshot_ != nullptr;
99     }
100 
101     static bool GetFilterInvalid();
102     static void SetFilterInvalid(bool invalidFilter);
103 
104 private:
105     void TakeSnapshot(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter,
106         const Drawing::RectI& srcRect);
107     void GenerateFilteredSnapshot(
108         RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& dstRect);
109     bool DrawFilterWithoutSnapshot(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter,
110         const Drawing::RectI& src, const Drawing::RectI& dst, bool shouldClearFilteredCache);
111     void DrawCachedFilteredSnapshot(RSPaintFilterCanvas& canvas, const Drawing::RectI& dstRect) const;
112     // Validate the input srcRect and dstRect, and return the validated rects.
113     std::tuple<Drawing::RectI, Drawing::RectI> ValidateParams(RSPaintFilterCanvas& canvas,
114         const std::optional<Drawing::RectI>& srcRect, const std::optional<Drawing::RectI>& dstRect);
115     inline static void ClipVisibleRect(RSPaintFilterCanvas& canvas);
116     // Check if the cache is valid in current GrContext, since FilterCache will never be used in multi-thread
117     // environment, we don't need to attempt to reattach SkImages.
118     void CheckCachedImages(RSPaintFilterCanvas& canvas);
119 
120     const char* GetCacheState() const;
121 
122     // We keep both the snapshot and filtered snapshot in the cache, and clear unneeded one in next frame.
123     // Note: rect in cachedSnapshot_ and cachedFilteredSnapshot_ is in device coordinate.
124     std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedSnapshot_ = nullptr;
125     std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> cachedFilteredSnapshot_ = nullptr;
126 
127     // Hash of previous filter, used to determine if we need to invalidate cachedFilteredSnapshot_.
128     uint32_t cachedFilterHash_ = 0;
129     // Cache age, used to determine if we can delay the cache update.
130     int cacheUpdateInterval_ = 0;
131     // Whether we need to purge the cache after this frame.
132     bool pendingPurge_ = false;
133     // Region of the cached image, used to determine if we need to invalidate the cache.
134     RectI snapshotRegion_; // Note: in device coordinate.
135 
136     // This flag is used to notify unirender_thread need to clear gpu memory.
137     static inline std::atomic_bool filterInvalid_ = false;
138 };
139 } // namespace Rosen
140 } // namespace OHOS
141 #endif
142 
143 #endif // RENDER_SERVICE_BASE_PROPERTY_RS_FILTER_CACHE_MANAGER_H
144