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 #include "property/rs_filter_cache_manager.h"
17 #include "rs_trace.h"
18 #include "render/rs_filter.h"
19
20 #if defined(NEW_SKIA) && (defined(RS_ENABLE_GL) || defined(RS_ENABLE_VK))
21 #include "include/gpu/GrBackendSurface.h"
22 #include "src/image/SkImage_Base.h"
23
24 #include "common/rs_optional_trace.h"
25 #include "platform/common/rs_log.h"
26 #include "platform/common/rs_system_properties.h"
27 #include "render/rs_skia_filter.h"
28
29 namespace OHOS {
30 namespace Rosen {
31 constexpr float PARALLEL_FILTER_RATIO_THRESHOLD = 0.8f;
32 constexpr int AIBAR_CACHE_UPDATE_INTERVAL = 5;
GetCacheState() const33 const char* RSFilterCacheManager::GetCacheState() const
34 {
35 if (cachedFilteredSnapshot_ != nullptr) {
36 return "Filtered image found in cache. Reusing cached result.";
37 } else if (cachedSnapshot_ != nullptr) {
38 return "Snapshot found in cache. Generating filtered image using cached data.";
39 } else {
40 return "No valid cache found.";
41 }
42 }
43
44 #define CHECK_CACHE_PROCESS_STATUS \
45 do { \
46 if (GetStatus() != CacheProcessStatus::DOING) { \
47 return false; \
48 } \
49 } while (false)
50 #ifndef ROSEN_ARKUI_X
51 const bool RSFilterCacheManager::RSFilterCacheTask::FilterPartialRenderEnabled =
52 RSSystemProperties::GetFilterPartialRenderEnabled() && RSUniRenderJudgement::IsUniRender();
53 #else
54 const bool RSFilterCacheManager::RSFilterCacheTask::FilterPartialRenderEnabled = false;
55 #endif
56 bool RSFilterCacheManager::SoloTaskPrepare = true;
IsLargeArea(int width,int height)57 inline static bool IsLargeArea(int width, int height)
58 {
59 // Use configurable threshold to determine if the area is large, and apply different cache policy.
60 // [PLANNING]: dynamically adjust the cache policy (e.g. update interval and cache area expansion) according to the
61 // cache size / dirty region percentage / current frame rate / filter radius.
62 static const auto threshold = RSSystemProperties::GetFilterCacheSizeThreshold();
63 return width > threshold && height > threshold;
64 }
65
66 #ifndef USE_ROSEN_DRAWING
isEqualRect(const SkIRect & src,const RectI & dst)67 inline static bool isEqualRect(const SkIRect& src, const RectI& dst)
68 {
69 return src.x() == dst.GetLeft() && src.y() == dst.GetTop() && src.width() == dst.GetWidth() &&
70 src.height() == dst.GetHeight();
71 }
72 #else
isEqualRect(const Drawing::RectI & src,const RectI & dst)73 inline static bool isEqualRect(const Drawing::RectI& src, const RectI& dst)
74 {
75 return src.GetLeft() == dst.GetLeft() && src.GetTop() == dst.GetTop() && src.GetWidth() == dst.GetWidth() &&
76 src.GetHeight() == dst.GetHeight();
77 }
78 #endif
79
UpdateCacheStateWithFilterHash(const std::shared_ptr<RSFilter> & filter)80 void RSFilterCacheManager::UpdateCacheStateWithFilterHash(const std::shared_ptr<RSFilter>& filter)
81 {
82 RS_OPTIONAL_TRACE_FUNC();
83 auto filterHash = filter->Hash();
84 if (cachedFilteredSnapshot_ == nullptr || cachedFilterHash_ == filterHash) {
85 return;
86 }
87 // filter changed, clear the filtered snapshot.
88 ROSEN_LOGD("RSFilterCacheManager::UpdateCacheStateWithFilterHash Cache expired. Reason: Cached filtered hash "
89 "%{public}X does not match new hash %{public}X.",
90 cachedFilterHash_, filterHash);
91 cachedFilteredSnapshot_.reset();
92 }
93 #ifndef USE_ROSEN_DRAWING
PostPartialFilterRenderInit(const std::shared_ptr<RSSkiaFilter> & filter,const SkIRect & dstRect,int32_t canvasWidth,int32_t canvasHeight)94 void RSFilterCacheManager::PostPartialFilterRenderInit(
95 const std::shared_ptr<RSSkiaFilter>& filter, const SkIRect& dstRect, int32_t canvasWidth, int32_t canvasHeight)
96 #else
97 void RSFilterCacheManager::PostPartialFilterRenderInit(const std::shared_ptr<RSDrawingFilter>& filter,
98 const Drawing::RectI& dstRect, int32_t canvasWidth, int32_t canvasHeight)
99 #endif
100 {
101 RS_OPTIONAL_TRACE_FUNC();
102 task_->SetCompleted(task_->GetStatus() == CacheProcessStatus::DONE);
103 if (task_->GetStatus() == CacheProcessStatus::DOING) {
104 task_->SetCompleted(!task_->isFirstInit_);
105 }
106 if (task_->GetStatus() == CacheProcessStatus::DONE) {
107 task_->Reset();
108 task_->isFirstInit_ = false;
109 task_->SwapTexture();
110 task_->SetStatus(CacheProcessStatus::WAITING);
111 }
112 if (task_->isTaskRelease_.load()) {
113 return;
114 }
115 if (task_->cachedFirstFilter_ != nullptr && task_->isFirstInit_ &&
116 task_->GetStatus() == CacheProcessStatus::DOING) {
117 cachedFilteredSnapshot_ = task_->cachedFirstFilter_;
118 } else {
119 task_->cachedFirstFilter_ = nullptr;
120 }
121 if (RSFilterCacheTask::FilterPartialRenderEnabled &&
122 (cachedSnapshot_ != nullptr && cachedSnapshot_->cachedImage_ != nullptr) &&
123 (cachedFilteredSnapshot_ == nullptr || cachedFilteredSnapshot_->cachedImage_ == nullptr) &&
124 #ifndef USE_ROSEN_DRAWING
125 IsNearlyFullScreen(cachedSnapshot_->cachedRect_.size(), canvasWidth, canvasHeight)) {
126 #else
127 IsNearlyFullScreen(cachedSnapshot_->cachedRect_, canvasWidth, canvasHeight)) {
128 #endif
129 PostPartialFilterRenderTask(filter, dstRect);
130 }
131 }
132
133 void RSFilterCacheManager::UpdateCacheStateWithFilterRegion()
134 {
135 if (!IsCacheValid()) {
136 return;
137 }
138 RS_OPTIONAL_TRACE_FUNC();
139
140 ROSEN_LOGD("RSFilterCacheManager::UpdateCacheStateWithFilterRegion Cache expired. Reason: Filter region is not "
141 "within the cached region.");
142 InvalidateCache();
143 }
144
145 bool RSFilterCacheManager::UpdateCacheStateWithDirtyRegion(const RSDirtyRegionManager& dirtyManager)
146 {
147 if (!IsCacheValid()) {
148 return false;
149 }
150 RS_OPTIONAL_TRACE_FUNC();
151 auto& cachedImageRect = GetCachedImageRegion();
152 if (dirtyManager.currentFrameDirtyRegion_.Intersect(cachedImageRect) ||
153 std::any_of(dirtyManager.visitedDirtyRegions_.begin(), dirtyManager.visitedDirtyRegions_.end(),
154 [&cachedImageRect](const RectI& rect) { return rect.Intersect(cachedImageRect); })) {
155 // The underlying image is affected by the dirty region, determine if the cache should be invalidated by cache
156 // age. [PLANNING]: also take into account the filter radius / cache size / percentage of intersected area.
157 if (cacheUpdateInterval_ > 0) {
158 ROSEN_LOGD("RSFilterCacheManager::UpdateCacheStateWithDirtyRegion Delaying cache "
159 "invalidation for %{public}d frames.",
160 cacheUpdateInterval_);
161 pendingPurge_ = true;
162 } else {
163 InvalidateCache();
164 }
165 return false;
166 }
167 if (pendingPurge_) {
168 ROSEN_LOGD("RSFilterCacheManager::UpdateCacheStateWithDirtyRegion MergeDirtyRect at %{public}d frames",
169 cacheUpdateInterval_);
170 InvalidateCache();
171 return true;
172 } else {
173 return false;
174 }
175 }
176
177 #ifndef USE_ROSEN_DRAWING
178 bool RSFilterCacheManager::RSFilterCacheTask::InitSurface(GrRecordingContext* grContext)
179 #else
180 bool RSFilterCacheManager::RSFilterCacheTask::InitSurface(Drawing::GPUContext* grContext)
181 #endif
182 {
183 RS_OPTIONAL_TRACE_FUNC();
184 if (!needClearSurface_) {
185 return true;
186 }
187 cacheSurface_ = nullptr;
188
189 auto runner = AppExecFwk::EventRunner::Current();
190 handler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
191 #ifndef USE_ROSEN_DRAWING
192 SkImageInfo info = SkImageInfo::MakeN32Premul(dstRect_.width(), dstRect_.height());
193 cacheSurface_ = SkSurface::MakeRenderTarget(grContext, SkBudgeted::kYes, info);
194 #else
195 Drawing::ImageInfo info = Drawing::ImageInfo::MakeN32Premul(dstRect_.GetWidth(), dstRect_.GetHeight());
196 cacheSurface_ = Drawing::Surface::MakeRenderTarget(grContext, true, info);
197 #endif
198 return cacheSurface_ != nullptr;
199 }
200
201 bool RSFilterCacheManager::RSFilterCacheTask::Render()
202 {
203 RS_TRACE_NAME_FMT("RSFilterCacheManager::RSFilterCacheTask::Render:%p", this);
204 ROSEN_LOGD("RSFilterCacheManager::RSFilterCacheTask::Render:%{public}p", this);
205 if (cacheSurface_ == nullptr) {
206 SetStatus(CacheProcessStatus::WAITING);
207 ROSEN_LOGE("RSFilterCacheManager::Render: cacheSurface_ is null");
208 return false;
209 }
210 CHECK_CACHE_PROCESS_STATUS;
211 auto cacheCanvas = std::make_shared<RSPaintFilterCanvas>(cacheSurface_.get());
212 if (cacheCanvas == nullptr) {
213 SetStatus(CacheProcessStatus::WAITING);
214 ROSEN_LOGE("RSFilterCacheManager::Render: cacheCanvas is null");
215 return false;
216 }
217 #ifndef USE_ROSEN_DRAWING
218 GrSurfaceOrigin surfaceOrigin = kTopLeft_GrSurfaceOrigin;
219 #ifdef RS_ENABLE_VK
220 if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
221 RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
222 surfaceOrigin = kTopLeft_GrSurfaceOrigin;
223 } else {
224 surfaceOrigin = kBottomLeft_GrSurfaceOrigin;
225 }
226 #else
227 surfaceOrigin = kBottomLeft_GrSurfaceOrigin;
228 #endif // RS_ENABLE_VK
229 auto threadImage = SkImage::MakeFromTexture(cacheCanvas->recordingContext(), cacheBackendTexture_, surfaceOrigin,
230 kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
231 if (!threadImage) {
232 SetStatus(CacheProcessStatus::WAITING);
233 ROSEN_LOGE("RSFilterCacheManager::Render: threadImage is null");
234 return false;
235 }
236 auto src = SkRect::MakeSize(SkSize::Make(snapshotSize_));
237 auto dst = SkRect::MakeSize(SkSize::Make(dstRect_.size()));
238 #else // USE_ROSEN_DRAWING
239 Drawing::TextureOrigin surfaceOrigin = Drawing::TextureOrigin::TOP_LEFT;
240 #ifdef RS_ENABLE_VK
241 if (RSSystemProperties::GetGpuApiType() == GpuApiType::VULKAN ||
242 RSSystemProperties::GetGpuApiType() == GpuApiType::DDGR) {
243 surfaceOrigin = Drawing::TextureOrigin::TOP_LEFT;
244 } else {
245 surfaceOrigin = Drawing::TextureOrigin::BOTTOM_LEFT;
246 }
247 #else
248 surfaceOrigin = Drawing::TextureOrigin::BOTTOM_LEFT;
249 #endif // RS_ENABLE_VK
250 Drawing::BitmapFormat bitmapFormat = { cacheBackendTextureColorType_.load(),
251 Drawing::AlphaType::ALPHATYPE_PREMUL };
252 auto threadImage = std::make_shared<Drawing::Image>();
253 CHECK_CACHE_PROCESS_STATUS;
254 {
255 std::unique_lock<std::mutex> lock(grBackendTextureMutex_);
256 if (cachedSnapshotInTask_ == nullptr ||
257 !threadImage->BuildFromTexture(*cacheCanvas->GetGPUContext(), cacheBackendTexture_.GetTextureInfo(),
258 surfaceOrigin, bitmapFormat, nullptr)) {
259 SetStatus(CacheProcessStatus::WAITING);
260 ROSEN_LOGE("RSFilterCacheManager::Render: BuildFromTexture is null");
261 return false;
262 }
263 }
264 auto src = Drawing::Rect(0, 0, snapshotSize_.GetWidth(), snapshotSize_.GetHeight());
265 auto dst = Drawing::Rect(0, 0, dstRect_.GetWidth(), dstRect_.GetHeight());
266 #endif // USE_ROSEN_DRAWING
267 CHECK_CACHE_PROCESS_STATUS;
268 filter_->DrawImageRect(*cacheCanvas, threadImage, src, dst);
269 filter_->PostProcess(*cacheCanvas);
270 CHECK_CACHE_PROCESS_STATUS;
271 return true;
272 }
273
274 bool RSFilterCacheManager::RSFilterCacheTask::SaveFilteredImage()
275 {
276 CHECK_CACHE_PROCESS_STATUS;
277 #ifndef USE_ROSEN_DRAWING
278 resultBackendTexture_ =
279 cacheSurface_->getBackendTexture(SkSurface::BackendHandleAccess::kFlushRead_BackendHandleAccess);
280 #else
281 if (cacheSurface_) {
282 resultBackendTexture_ = cacheSurface_->GetBackendTexture();
283 } else {
284 SetStatus(CacheProcessStatus::WAITING);
285 ROSEN_LOGE("RSFilterCacheManager::SaveFilteredImage: cacheSurface_ is null");
286 return false;
287 }
288 #endif
289 CHECK_CACHE_PROCESS_STATUS;
290 return true;
291 }
292
293 void RSFilterCacheManager::RSFilterCacheTask::SwapInit()
294 {
295 RS_OPTIONAL_TRACE_FUNC();
296 std::unique_lock<std::mutex> lock(grBackendTextureMutex_);
297 std::swap(filter_, filterBefore_);
298 std::swap(cachedSnapshotInTask_, cachedSnapshotBefore_);
299 std::swap(snapshotSize_, snapshotSizeBefore_);
300 std::swap(dstRect_, dstRectBefore_);
301 if (cachedSnapshotInTask_ != nullptr) {
302 #ifndef USE_ROSEN_DRAWING
303 cacheBackendTexture_ = cachedSnapshotInTask_->cachedImage_->getBackendTexture(false);
304 #else
305 cacheBackendTexture_ = cachedSnapshotInTask_->cachedImage_->GetBackendTexture(false, nullptr);
306 #endif
307 cacheBackendTextureColorType_ = cachedSnapshotInTask_->cachedImage_->GetColorType();
308 }
309 }
310
311 bool RSFilterCacheManager::RSFilterCacheTask::SetDone()
312 {
313 RS_OPTIONAL_TRACE_FUNC();
314 CHECK_CACHE_PROCESS_STATUS;
315 if (isTaskRelease_.load()) {
316 SetStatus(CacheProcessStatus::WAITING);
317 } else {
318 SetStatus(CacheProcessStatus::DONE);
319 }
320 return true;
321 }
322 #ifndef USE_ROSEN_DRAWING
323 bool RSFilterCacheManager::IsNearlyFullScreen(SkISize imageSize, int32_t canvasWidth, int32_t canvasHeight)
324 #else
325 bool RSFilterCacheManager::IsNearlyFullScreen(Drawing::RectI imageSize, int32_t canvasWidth, int32_t canvasHeight)
326 #endif
327 {
328 RS_OPTIONAL_TRACE_FUNC();
329 auto widthThreshold = static_cast<int32_t>(canvasWidth * PARALLEL_FILTER_RATIO_THRESHOLD);
330 auto heightThreshold = static_cast<int32_t>(canvasHeight * PARALLEL_FILTER_RATIO_THRESHOLD);
331 #ifndef USE_ROSEN_DRAWING
332 return imageSize.width() >= widthThreshold && imageSize.height() >= heightThreshold;
333 #else
334 return imageSize.GetWidth() >= widthThreshold && imageSize.GetHeight() >= heightThreshold;
335 #endif
336 }
337
338 #ifndef USE_ROSEN_DRAWING
339 void RSFilterCacheManager::PostPartialFilterRenderTask(
340 const std::shared_ptr<RSSkiaFilter>& filter, const SkIRect& dstRect)
341 #else
342 void RSFilterCacheManager::PostPartialFilterRenderTask(
343 const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& dstRect)
344 #endif
345 {
346 RS_OPTIONAL_TRACE_FUNC();
347 // Prepare a backup of common resources for threads
348 if (RSFilter::postTask != nullptr && (task_->GetStatus() == CacheProcessStatus::WAITING)) {
349 // Because the screenshot is zoomed out, here you need to zoom in
350 task_->InitTask(filter, cachedSnapshot_, dstRect);
351 task_->SetStatus(CacheProcessStatus::DOING);
352 RSFilter::postTask(task_);
353 } else {
354 ROSEN_LOGD("RSFilterCacheManager::PostPartialFilterRenderTask: postTask is null");
355 }
356 }
357
358 #ifndef USE_ROSEN_DRAWING
359 void RSFilterCacheManager::DrawFilter(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSSkiaFilter>& filter,
360 const bool needSnapshotOutset, const std::optional<SkIRect>& srcRect, const std::optional<SkIRect>& dstRect)
361 #else
362 void RSFilterCacheManager::DrawFilter(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter,
363 const bool needSnapshotOutset, const std::optional<Drawing::RectI>& srcRect,
364 const std::optional<Drawing::RectI>& dstRect)
365 #endif
366 {
367 RS_OPTIONAL_TRACE_FUNC();
368 #ifndef USE_ROSEN_DRAWING
369 if (canvas.getDeviceClipBounds().isEmpty()) {
370 #else
371 if (canvas.GetDeviceClipBounds().IsEmpty()) {
372 #endif
373 return;
374 }
375 const auto& [src, dst] = ValidateParams(canvas, srcRect, dstRect);
376 #ifndef USE_ROSEN_DRAWING
377 if (src.isEmpty() || dst.isEmpty()) {
378 #else
379 if (src.IsEmpty() || dst.IsEmpty()) {
380 #endif
381 return;
382 }
383 RS_TRACE_NAME_FMT("RSFilterCacheManager::DrawFilter status: %s", GetCacheState());
384 CheckCachedImages(canvas);
385 if (!IsCacheValid()) {
386 TakeSnapshot(canvas, filter, src, needSnapshotOutset);
387 } else {
388 --cacheUpdateInterval_;
389 }
390 #ifndef USE_ROSEN_DRAWING
391 auto surface = canvas.getSurface();
392 auto width = surface->width();
393 auto height = surface->height();
394 if (filter->GetFilterType() == RSFilter::LINEAR_GRADIENT_BLUR) {
395 SkMatrix mat = canvas.getTotalMatrix();
396 filter->SetCanvasChange(mat, width, height);
397 }
398 #else
399 auto surface = canvas.GetSurface();
400 auto width = surface->Width();
401 auto height = surface->Height();
402 if (filter->GetFilterType() == RSFilter::LINEAR_GRADIENT_BLUR) {
403 Drawing::Matrix mat = canvas.GetTotalMatrix();
404 filter->SetCanvasChange(mat, width, height);
405 }
406 #endif
407 PostPartialFilterRenderInit(filter, dst, width, height);
408 bool shouldClearFilteredCache = false;
409 if (cachedFilteredSnapshot_ == nullptr || cachedFilteredSnapshot_->cachedImage_ == nullptr) {
410 auto previousFilterHash = cachedFilterHash_;
411 if (RSFilterCacheTask::FilterPartialRenderEnabled && task_->IsCompleted()) {
412 FilterPartialRender(canvas, filter, dst);
413 } else {
414 GenerateFilteredSnapshot(canvas, filter, dst);
415 }
416 newCache_ = true;
417 // If 1. the filter hash matches, 2. the filter region is whole snapshot region, we can safely clear original
418 // snapshot, else we need to clear the filtered snapshot.
419 shouldClearFilteredCache = previousFilterHash != cachedFilterHash_ || !isEqualRect(dst, snapshotRegion_);
420 } else if (RSFilterCacheTask::FilterPartialRenderEnabled && task_->IsCompleted()) {
421 FilterPartialRender(canvas, filter, dst);
422 } else {
423 newCache_ = false;
424 }
425 if (task_->GetStatus() == CacheProcessStatus::DOING && task_->isFirstInit_ &&
426 task_->cachedFirstFilter_ == nullptr) {
427 task_->cachedFirstFilter_ = cachedFilteredSnapshot_;
428 }
429 DrawCachedFilteredSnapshot(canvas, dst);
430 if (filter->GetFilterType() == RSFilter::AIBAR) {
431 shouldClearFilteredCache = false;
432 }
433 task_->SetCompleted(false);
434 // To reduce the memory consumption, we only keep either the cached snapshot or the filtered image.
435 CompactCache(shouldClearFilteredCache);
436 }
437
438 #ifndef USE_ROSEN_DRAWING
439 const std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> RSFilterCacheManager::GeneratedCachedEffectData(
440 RSPaintFilterCanvas& canvas, const std::shared_ptr<RSSkiaFilter>& filter, const std::optional<SkIRect>& srcRect,
441 const std::optional<SkIRect>& dstRect, const std::tuple<bool, bool>& forceCacheFlags)
442 #else
443 const std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> RSFilterCacheManager::GeneratedCachedEffectData(
444 RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter,
445 const std::optional<Drawing::RectI>& srcRect, const std::optional<Drawing::RectI>& dstRect,
446 const std::tuple<bool, bool>& forceCacheFlags)
447 #endif
448 {
449 RS_OPTIONAL_TRACE_FUNC();
450 #ifndef USE_ROSEN_DRAWING
451 if (canvas.getDeviceClipBounds().isEmpty()) {
452 #else
453 if (canvas.GetDeviceClipBounds().IsEmpty()) {
454 #endif
455 return nullptr;
456 }
457 const auto& [src, dst] = ValidateParams(canvas, srcRect, dstRect, forceCacheFlags);
458 #ifndef USE_ROSEN_DRAWING
459 if (src.isEmpty() || dst.isEmpty()) {
460 #else
461 if (src.IsEmpty() || dst.IsEmpty()) {
462 #endif
463 return nullptr;
464 }
465 RS_TRACE_NAME_FMT("RSFilterCacheManager::GeneratedCachedEffectData status: %s", GetCacheState());
466 CheckCachedImages(canvas);
467 if (!IsCacheValid()) {
468 TakeSnapshot(canvas, filter, src);
469 } else {
470 --cacheUpdateInterval_;
471 }
472
473 bool shouldClearFilteredCache = false;
474 if (cachedFilteredSnapshot_ == nullptr || cachedFilteredSnapshot_->cachedImage_ == nullptr) {
475 auto previousFilterHash = cachedFilterHash_;
476 GenerateFilteredSnapshot(canvas, filter, dst);
477 // If 1. the filter hash matches, 2. the filter region is whole snapshot region, we can safely clear original
478 // snapshot, else we need to clear the filtered snapshot.
479 shouldClearFilteredCache = previousFilterHash != cachedFilterHash_ || !isEqualRect(dst, snapshotRegion_);
480 }
481 // Keep a reference to the cached image, since CompactCache may invalidate it.
482 auto cachedFilteredSnapshot = cachedFilteredSnapshot_;
483 // To reduce the memory consumption, we only keep either the cached snapshot or the filtered image.
484 if (std::get<0>(forceCacheFlags) || std::get<1>(forceCacheFlags)) {
485 shouldClearFilteredCache = false;
486 }
487 CompactCache(shouldClearFilteredCache);
488 return cachedFilteredSnapshot;
489 }
490
491 #ifndef USE_ROSEN_DRAWING
492 void RSFilterCacheManager::TakeSnapshot(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSSkiaFilter>& filter,
493 const SkIRect& srcRect, const bool needSnapshotOutset)
494 {
495 auto skSurface = canvas.GetSurface();
496 if (skSurface == nullptr) {
497 return;
498 }
499 RS_OPTIONAL_TRACE_FUNC();
500
501 // shrink the srcRect by 1px to avoid edge artifacts.
502 SkIRect snapshotIBounds;
503 if (needSnapshotOutset) {
504 snapshotIBounds = srcRect.makeOutset(-1, -1);
505 } else {
506 snapshotIBounds = srcRect;
507 }
508
509 // Take a screenshot.
510 auto snapshot = skSurface->makeImageSnapshot(snapshotIBounds);
511 if (snapshot == nullptr) {
512 ROSEN_LOGD("RSFilterCacheManager::TakeSnapshot failed to make an image snapshot.");
513 return;
514 }
515 if (RSSystemProperties::GetImageGpuResourceCacheEnable(snapshot->width(), snapshot->height())) {
516 ROSEN_LOGD("TakeSnapshot cache image resource(width:%{public}d, height:%{public}d).", snapshot->width(),
517 snapshot->height());
518 as_IB(snapshot)->hintCacheGpuResource();
519 }
520 filter->PreProcess(snapshot);
521
522 // Update the cache state.
523 snapshotRegion_ = RectI(srcRect.x(), srcRect.y(), srcRect.width(), srcRect.height());
524 cachedSnapshot_ = std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(snapshot), snapshotIBounds);
525
526 // If the cached image is larger than threshold, we will increase the cache update interval, which is configurable
527 // by `hdc shell param set persist.sys.graphic.filterCacheUpdateInterval <interval>`, the default value is 1.
528 // Update: we also considered the filter parameters, only enable skip-frame if the blur radius is large enough.
529 // Note: the cache will be invalidated immediately if the cached region cannot fully cover the filter region.
530 if (filter->GetFilterType() == RSFilter::AIBAR) {
531 // when dirty region change, delay 5 frames to update
532 cacheUpdateInterval_ = AIBAR_CACHE_UPDATE_INTERVAL;
533 } else {
534 bool isLargeArea = IsLargeArea(srcRect.width(), srcRect.height());
535 cacheUpdateInterval_ =
536 isLargeArea && filter->CanSkipFrame() ? RSSystemProperties::GetFilterCacheUpdateInterval() : 0;
537 }
538 cachedFilterHash_ = 0;
539 pendingPurge_ = false;
540 }
541 #else
542 void RSFilterCacheManager::TakeSnapshot(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter,
543 const Drawing::RectI& srcRect, const bool needSnapshotOutset)
544 {
545 auto drawingSurface = canvas.GetSurface();
546 if (drawingSurface == nullptr) {
547 return;
548 }
549 RS_OPTIONAL_TRACE_FUNC();
550
551 // shrink the srcRect by 1px to avoid edge artifacts.
552 Drawing::RectI snapshotIBounds;
553 snapshotIBounds = srcRect;
554 if (needSnapshotOutset) {
555 snapshotIBounds.MakeOutset(-1, -1);
556 }
557
558 // Take a screenshot.
559 auto snapshot = drawingSurface->GetImageSnapshot(snapshotIBounds);
560 if (snapshot == nullptr) {
561 ROSEN_LOGD("RSFilterCacheManager::TakeSnapshot failed to make an image snapshot.");
562 return;
563 }
564 if (RSSystemProperties::GetImageGpuResourceCacheEnable(snapshot->GetWidth(), snapshot->GetHeight())) {
565 ROSEN_LOGD("TakeSnapshot cache image resource(width:%{public}d, height:%{public}d).", snapshot->GetWidth(),
566 snapshot->GetHeight());
567 as_IB(snapshot->ExportSkImage().get())->hintCacheGpuResource();
568 }
569 filter->PreProcess(snapshot);
570
571 // Update the cache state.
572 snapshotRegion_ = RectI(srcRect.GetLeft(), srcRect.GetTop(), srcRect.GetWidth(), srcRect.GetHeight());
573 cachedSnapshot_ = std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(snapshot), snapshotIBounds);
574
575 // If the cached image is larger than threshold, we will increase the cache update interval, which is configurable
576 // by `hdc shell param set persist.sys.graphic.filterCacheUpdateInterval <interval>`, the default value is 1.
577 // Update: we also considered the filter parameters, only enable skip-frame if the blur radius is large enough.
578 // Note: the cache will be invalidated immediately if the cached region cannot fully cover the filter region.
579 if (filter->GetFilterType() == RSFilter::AIBAR) {
580 // when dirty region change, delay 5 frames to update
581 cacheUpdateInterval_ = AIBAR_CACHE_UPDATE_INTERVAL;
582 } else {
583 bool isLargeArea = IsLargeArea(srcRect.GetWidth(), srcRect.GetHeight());
584 cacheUpdateInterval_ =
585 isLargeArea && filter->CanSkipFrame() ? RSSystemProperties::GetFilterCacheUpdateInterval() : 0;
586 }
587 cachedFilterHash_ = 0;
588 pendingPurge_ = false;
589 }
590 #endif
591
592 #ifndef USE_ROSEN_DRAWING
593 void RSFilterCacheManager::FilterPartialRender(
594 RSPaintFilterCanvas& canvas, const std::shared_ptr<RSSkiaFilter>& filter, const SkIRect& dstRect)
595 #else
596 void RSFilterCacheManager::FilterPartialRender(
597 RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& dstRect)
598 #endif
599 {
600 RS_OPTIONAL_TRACE_FUNC();
601 #ifndef USE_ROSEN_DRAWING
602 auto filteredSnapshot = SkImage::MakeFromTexture(canvas.recordingContext(), task_->GetResultTexture(),
603 kBottomLeft_GrSurfaceOrigin, COLORTYPE_N32, kPremul_SkAlphaType, nullptr);
604 #else
605 auto filteredSnapshot = std::make_shared<Drawing::Image>();
606 Drawing::BitmapFormat bitmapFormat = { Drawing::ColorType::COLORTYPE_N32, Drawing::AlphaType::ALPHATYPE_PREMUL };
607 filteredSnapshot->BuildFromTexture(*canvas.GetGPUContext(), task_->GetResultTexture().GetTextureInfo(),
608 Drawing::TextureOrigin::BOTTOM_LEFT, bitmapFormat, nullptr);
609 #endif
610 if (filteredSnapshot == nullptr) {
611 GenerateFilteredSnapshot(canvas, filter, dstRect);
612 } else {
613 #ifndef USE_ROSEN_DRAWING
614 auto filteredRect = SkIRect::MakeWH(filteredSnapshot->width(), filteredSnapshot->height());
615 if (RSSystemProperties::GetImageGpuResourceCacheEnable(filteredSnapshot->width(), filteredSnapshot->height())) {
616 ROSEN_LOGD("GenerateFilteredSnapshot cache image resource(width:%{public}d, height:%{public}d).",
617 filteredSnapshot->width(), filteredSnapshot->height());
618 as_IB(filteredSnapshot)->hintCacheGpuResource();
619 }
620 #else
621 auto filteredRect = Drawing::RectI(0, 0, filteredSnapshot->GetWidth(), filteredSnapshot->GetHeight());
622 if (RSSystemProperties::GetImageGpuResourceCacheEnable(
623 filteredSnapshot->GetWidth(), filteredSnapshot->GetHeight())) {
624 ROSEN_LOGD("GenerateFilteredSnapshot cache image resource(width:%{public}d, height:%{public}d).",
625 filteredSnapshot->GetWidth(), filteredSnapshot->GetHeight());
626 as_IB(filteredSnapshot->ExportSkImage().get())->hintCacheGpuResource();
627 }
628 #endif
629 cachedFilteredSnapshot_.reset();
630 cachedFilteredSnapshot_ =
631 std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(filteredSnapshot), task_->GetDstRect());
632 cachedFilterHash_ = filter->Hash();
633 }
634 }
635
636 #ifndef USE_ROSEN_DRAWING
637 void RSFilterCacheManager::GenerateFilteredSnapshot(
638 RSPaintFilterCanvas& canvas, const std::shared_ptr<RSSkiaFilter>& filter, const SkIRect& dstRect)
639 {
640 auto surface = canvas.GetSurface();
641 if (surface == nullptr || cachedSnapshot_ == nullptr || cachedSnapshot_->cachedImage_ == nullptr) {
642 return;
643 }
644 // The cache type has been validated, so filterRegion_ and cachedImage_ should be valid. There is no need to check
645 // them again.
646 RS_OPTIONAL_TRACE_FUNC();
647
648 // Create an offscreen canvas with the same size as the filter region.
649 auto offscreenRect = dstRect;
650 auto offscreenSurface = surface->makeSurface(offscreenRect.width(), offscreenRect.height());
651 RSPaintFilterCanvas offscreenCanvas(offscreenSurface.get());
652
653 // Src rect and dst rect, with origin at (0, 0).
654 auto src = SkRect::MakeSize(SkSize::Make(cachedSnapshot_->cachedRect_.size()));
655 auto dst = SkRect::MakeSize(SkSize::Make(offscreenRect.size()));
656
657 // Draw the cached snapshot on the offscreen canvas, apply the filter, and post-process.
658 filter->DrawImageRect(offscreenCanvas, cachedSnapshot_->cachedImage_, src, dst);
659 filter->PostProcess(offscreenCanvas);
660
661 // Update the cache state with the filtered snapshot.
662 auto filteredSnapshot = offscreenSurface->makeImageSnapshot();
663 if (RSSystemProperties::GetImageGpuResourceCacheEnable(filteredSnapshot->width(), filteredSnapshot->height())) {
664 ROSEN_LOGD("GenerateFilteredSnapshot cache image resource(width:%{public}d, height:%{public}d).",
665 filteredSnapshot->width(), filteredSnapshot->height());
666 as_IB(filteredSnapshot)->hintCacheGpuResource();
667 }
668 if (RSSystemProperties::GetRecordingEnabled()) {
669 if (filteredSnapshot->isTextureBacked()) {
670 RS_LOGI("RSFilterCacheManager::GenerateFilteredSnapshot cachedImage from texture to raster image");
671 filteredSnapshot = filteredSnapshot->makeRasterImage();
672 }
673 }
674 cachedFilteredSnapshot_ =
675 std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(filteredSnapshot), offscreenRect);
676 cachedFilterHash_ = filter->Hash();
677 }
678 #else
679 void RSFilterCacheManager::GenerateFilteredSnapshot(
680 RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& dstRect)
681 {
682 auto surface = canvas.GetSurface();
683 if (surface == nullptr || cachedSnapshot_ == nullptr || cachedSnapshot_->cachedImage_ == nullptr) {
684 return;
685 }
686 // The cache type has been validated, so filterRegion_ and cachedImage_ should be valid. There is no need to check
687 // them again.
688 RS_OPTIONAL_TRACE_FUNC();
689
690 // Create an offscreen canvas with the same size as the filter region.
691 auto offscreenRect = dstRect;
692 auto offscreenSurface = surface->MakeSurface(offscreenRect.GetWidth(), offscreenRect.GetHeight());
693 RSPaintFilterCanvas offscreenCanvas(offscreenSurface.get());
694
695 // Src rect and dst rect, with origin at (0, 0).
696 auto src = Drawing::Rect(0, 0, cachedSnapshot_->cachedRect_.GetWidth(), cachedSnapshot_->cachedRect_.GetHeight());
697 auto dst = Drawing::Rect(0, 0, offscreenRect.GetWidth(), offscreenRect.GetHeight());
698
699 // Draw the cached snapshot on the offscreen canvas, apply the filter, and post-process.
700 filter->DrawImageRect(offscreenCanvas, cachedSnapshot_->cachedImage_, src, dst);
701 filter->PostProcess(offscreenCanvas);
702
703 // Update the cache state with the filtered snapshot.
704 auto filteredSnapshot = offscreenSurface->GetImageSnapshot();
705 if (RSSystemProperties::GetImageGpuResourceCacheEnable(
706 filteredSnapshot->GetWidth(), filteredSnapshot->GetHeight())) {
707 ROSEN_LOGD("GenerateFilteredSnapshot cache image resource(width:%{public}d, height:%{public}d).",
708 filteredSnapshot->GetWidth(), filteredSnapshot->GetHeight());
709 as_IB(filteredSnapshot->ExportSkImage().get())->hintCacheGpuResource();
710 }
711 if (RSSystemProperties::GetRecordingEnabled()) {
712 if (filteredSnapshot->IsTextureBacked()) {
713 RS_LOGI("RSFilterCacheManager::GenerateFilteredSnapshot cachedImage from texture to raster image");
714 filteredSnapshot = filteredSnapshot->MakeRasterImage();
715 }
716 }
717 cachedFilteredSnapshot_ =
718 std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(filteredSnapshot), offscreenRect);
719 cachedFilterHash_ = filter->Hash();
720 }
721 #endif
722
723 #ifndef USE_ROSEN_DRAWING
724 void RSFilterCacheManager::DrawCachedFilteredSnapshot(RSPaintFilterCanvas& canvas, const SkIRect& dstRect) const
725 {
726 if (cachedFilteredSnapshot_ == nullptr || cachedFilteredSnapshot_->cachedImage_ == nullptr) {
727 return;
728 }
729 RS_OPTIONAL_TRACE_FUNC();
730
731 // Draw in device coordinates.
732 SkAutoCanvasRestore autoRestore(&canvas, true);
733 canvas.resetMatrix();
734
735 // Only draw within the visible rect.
736 ClipVisibleRect(canvas);
737
738 // The cache type and parameters has been validated, dstRect must be subset of cachedFilteredSnapshot_->cachedRect_.
739 SkRect dst = SkRect::Make(dstRect);
740 SkRect src;
741 if (newCache_) {
742 src = SkRect::MakeSize(SkSize::Make(cachedFilteredSnapshot_->cachedImage_->dimensions()));
743 } else {
744 src = SkRect::Make(dstRect.makeOffset(-cachedFilteredSnapshot_->cachedRect_.topLeft()));
745 src.intersect(SkRect::Make(cachedFilteredSnapshot_->cachedImage_->bounds()));
746 }
747
748 SkPaint paint;
749 paint.setAntiAlias(true);
750 canvas.drawImageRect(cachedFilteredSnapshot_->cachedImage_, src, dst, SkSamplingOptions(), &paint,
751 SkCanvas::kFast_SrcRectConstraint);
752 }
753 #else
754 void RSFilterCacheManager::DrawCachedFilteredSnapshot(RSPaintFilterCanvas& canvas, const Drawing::RectI& dstRect) const
755 {
756 if (cachedFilteredSnapshot_ == nullptr || cachedFilteredSnapshot_->cachedImage_ == nullptr) {
757 return;
758 }
759 RS_OPTIONAL_TRACE_FUNC();
760
761 // Draw in device coordinates.
762 Drawing::AutoCanvasRestore autoRestore(canvas, true);
763 canvas.ResetMatrix();
764
765 // Only draw within the visible rect.
766 ClipVisibleRect(canvas);
767
768 // The cache type and parameters has been validated, dstRect must be subset of cachedFilteredSnapshot_->cachedRect_.
769 Drawing::Rect dst(dstRect.GetLeft(), dstRect.GetTop(), dstRect.GetRight(), dstRect.GetBottom());
770 Drawing::Rect src;
771 if (newCache_) {
772 src = { 0, 0, cachedFilteredSnapshot_->cachedImage_->GetWidth(),
773 cachedFilteredSnapshot_->cachedImage_->GetHeight() };
774 } else {
775 src = { dstRect.GetLeft(), dstRect.GetTop(), dstRect.GetRight(), dstRect.GetBottom() };
776 src.Offset(-cachedFilteredSnapshot_->cachedRect_.GetLeft(), -cachedFilteredSnapshot_->cachedRect_.GetTop());
777 src.Intersect(Drawing::Rect(0, 0, cachedFilteredSnapshot_->cachedImage_->GetWidth(),
778 cachedFilteredSnapshot_->cachedImage_->GetHeight()));
779 }
780
781 Drawing::Brush brush;
782 brush.SetAntiAlias(true);
783 canvas.AttachBrush(brush);
784 canvas.DrawImageRect(*cachedFilteredSnapshot_->cachedImage_, src, dst, Drawing::SamplingOptions(),
785 Drawing::SrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
786 canvas.DetachBrush();
787 }
788 #endif
789
790 void RSFilterCacheManager::InvalidateCache(CacheType cacheType)
791 {
792 // bitwise test
793 if (cacheType & CacheType::CACHE_TYPE_SNAPSHOT) {
794 cachedSnapshot_.reset();
795 }
796 if (cacheType & CacheType::CACHE_TYPE_FILTERED_SNAPSHOT) {
797 cachedFilteredSnapshot_.reset();
798 }
799 }
800
801 void RSFilterCacheManager::ReleaseCacheOffTree()
802 {
803 RS_OPTIONAL_TRACE_FUNC();
804 ROSEN_LOGD("RSFilterCacheManager::ReleaseCacheOffTree task_:%{public}p", task_.get());
805 std::unique_lock<std::mutex> lock(task_->grBackendTextureMutex_);
806 cachedSnapshot_.reset();
807 cachedFilteredSnapshot_.reset();
808 newCache_ = false;
809 task_->isTaskRelease_.store(true);
810 task_->cachedFirstFilter_ = nullptr;
811 task_->ResetInTask();
812 task_->SetCompleted(false);
813 task_->isFirstInit_ = true;
814 task_->SetStatus(CacheProcessStatus::WAITING);
815 task_->Reset();
816 if (task_->GetHandler() != nullptr) {
817 auto task_tmp = task_;
818 task_->GetHandler()->PostTask(
819 [task_tmp]() { task_tmp->ResetGrContext(); }, AppExecFwk::EventQueue::Priority::IMMEDIATE);
820 }
821 }
822
823 #ifndef USE_ROSEN_DRAWING
824 inline void RSFilterCacheManager::ClipVisibleRect(RSPaintFilterCanvas& canvas)
825 {
826 auto visibleIRect = canvas.GetVisibleRect().round();
827 auto deviceClipRect = canvas.getDeviceClipBounds();
828 if (!visibleIRect.isEmpty() && deviceClipRect.intersect(visibleIRect)) {
829 canvas.clipIRect(visibleIRect);
830 }
831 }
832 #else
833 inline void RSFilterCacheManager::ClipVisibleRect(RSPaintFilterCanvas& canvas)
834 {
835 auto visibleRectF = canvas.GetVisibleRect();
836 visibleRectF.Round();
837 Drawing::RectI visibleIRect = { (int)visibleRectF.GetLeft(), (int)visibleRectF.GetTop(),
838 (int)visibleRectF.GetRight(), (int)visibleRectF.GetBottom() };
839 auto deviceClipRect = canvas.GetDeviceClipBounds();
840 if (!visibleIRect.IsEmpty() && deviceClipRect.Intersect(visibleIRect)) {
841 canvas.ClipIRect(visibleIRect, Drawing::ClipOp::INTERSECT);
842 }
843 }
844 #endif
845
846 const RectI& RSFilterCacheManager::GetCachedImageRegion() const
847 {
848 static const auto emptyRect = RectI();
849 return IsCacheValid() ? snapshotRegion_ : emptyRect;
850 }
851
852 inline static bool IsCacheInvalid(const RSPaintFilterCanvas::CachedEffectData& cache, RSPaintFilterCanvas& canvas)
853 {
854 #ifndef USE_ROSEN_DRAWING
855 return cache.cachedImage_ == nullptr || !cache.cachedImage_->isValid(canvas.recordingContext());
856 #else
857 return cache.cachedImage_ == nullptr || !cache.cachedImage_->IsValid(canvas.GetGPUContext().get());
858 #endif
859 }
860
861 void RSFilterCacheManager::CheckCachedImages(RSPaintFilterCanvas& canvas)
862 {
863 if (cachedSnapshot_ != nullptr && IsCacheInvalid(*cachedSnapshot_, canvas)) {
864 ROSEN_LOGE("RSFilterCacheManager::CheckCachedImages cachedSnapshot_ is invalid");
865 cachedSnapshot_.reset();
866 }
867 if (cachedFilteredSnapshot_ != nullptr && IsCacheInvalid(*cachedFilteredSnapshot_, canvas)) {
868 ROSEN_LOGE("RSFilterCacheManager::CheckCachedImages cachedFilteredSnapshot_ is invalid");
869 cachedFilteredSnapshot_.reset();
870 }
871 }
872
873 #ifndef USE_ROSEN_DRAWING
874 std::tuple<SkIRect, SkIRect> RSFilterCacheManager::ValidateParams(
875 RSPaintFilterCanvas& canvas, const std::optional<SkIRect>& srcRect,
876 const std::optional<SkIRect>& dstRect, const std::tuple<bool, bool>& forceCacheFlags)
877 {
878 SkIRect src;
879 SkIRect dst;
880 auto deviceRect = SkIRect::MakeWH(canvas.imageInfo().width(), canvas.imageInfo().height());
881 if (!srcRect.has_value()) {
882 src = canvas.getDeviceClipBounds();
883 } else {
884 src = srcRect.value();
885 src.intersect(deviceRect);
886 }
887 if (!dstRect.has_value()) {
888 dst = src;
889 } else {
890 dst = dstRect.value();
891 dst.intersect(deviceRect);
892 }
893 if (snapshotRegion_.GetLeft() > dst.x() || snapshotRegion_.GetRight() < dst.right() ||
894 snapshotRegion_.GetTop() > dst.y() || snapshotRegion_.GetBottom() < dst.bottom()) {
895 // dst region is out of snapshot region, cache is invalid.
896 // It should already be checked by UpdateCacheStateWithFilterRegion in prepare phase, we should never be here.
897 ROSEN_LOGE("RSFilterCacheManager::ValidateParams Cache expired. Reason: dst region is out of snapshot region.");
898 }
899 return { src, dst };
900 }
901 #else
902 std::tuple<Drawing::RectI, Drawing::RectI> RSFilterCacheManager::ValidateParams(RSPaintFilterCanvas& canvas,
903 const std::optional<Drawing::RectI>& srcRect, const std::optional<Drawing::RectI>& dstRect,
904 const std::tuple<bool, bool>& forceCacheFlags)
905 {
906 Drawing::RectI src;
907 Drawing::RectI dst;
908 auto deviceRect = Drawing::RectI(0, 0, canvas.GetImageInfo().GetWidth(), canvas.GetImageInfo().GetHeight());
909 if (!srcRect.has_value()) {
910 src = canvas.GetDeviceClipBounds();
911 } else {
912 src = srcRect.value();
913 src.Intersect(deviceRect);
914 }
915 if (!dstRect.has_value()) {
916 dst = src;
917 } else {
918 dst = dstRect.value();
919 dst.Intersect(deviceRect);
920 }
921 if (snapshotRegion_.GetLeft() > dst.GetLeft() || snapshotRegion_.GetRight() < dst.GetRight() ||
922 snapshotRegion_.GetTop() > dst.GetTop() || snapshotRegion_.GetBottom() < dst.GetBottom()) {
923 // dst region is out of snapshot region, cache is invalid.
924 // It should already be checked by UpdateCacheStateWithFilterRegion in prepare phase, we should never be here.
925 ROSEN_LOGD("RSFilterCacheManager::ValidateParams Cache expired. Reason: dst region is out of snapshot region.");
926 if (!std::get<0>(forceCacheFlags) || !std::get<1>(forceCacheFlags)) {
927 InvalidateCache();
928 }
929 }
930 return { src, dst };
931 }
932 #endif
933
934 inline void RSFilterCacheManager::CompactCache(bool shouldClearFilteredCache)
935 {
936 if (pendingPurge_ && cacheUpdateInterval_ == 0) {
937 InvalidateCache();
938 return;
939 }
940 InvalidateCache(
941 shouldClearFilteredCache ? CacheType::CACHE_TYPE_FILTERED_SNAPSHOT : CacheType::CACHE_TYPE_SNAPSHOT);
942 }
943 } // namespace Rosen
944 } // namespace OHOS
945 #endif
946