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