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 "render/rs_filter_cache_manager.h"
17 #include "rs_trace.h"
18 #include "render/rs_filter.h"
19
20 #if (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_drawing_filter.h"
28 #include "render/rs_high_performance_visual_engine.h"
29 #include "render/rs_magnifier_shader_filter.h"
30 #include "render/rs_skia_filter.h"
31 #include "drawable/rs_property_drawable_utils.h"
32
33 namespace OHOS {
34 namespace Rosen {
35
36 constexpr int AIBAR_CACHE_UPDATE_INTERVAL = 5;
37 constexpr int ROTATION_CACHE_UPDATE_INTERVAL = 1;
38
39 bool RSFilterCacheManager::isCCMFilterCacheEnable_ = true;
40 bool RSFilterCacheManager::isCCMEffectMergeEnable_ = true;
41
GetCacheState() const42 const char* RSFilterCacheManager::GetCacheState() const
43 {
44 if (cachedFilteredSnapshot_ != nullptr) {
45 return "Filtered image found in cache. Reusing cached result.";
46 } else if (cachedSnapshot_ != nullptr) {
47 return "Snapshot found in cache. Generating filtered image using cached data.";
48 } else {
49 return "No valid cache found.";
50 }
51 }
52
UpdateCacheStateWithFilterHash(const std::shared_ptr<RSFilter> & filter)53 void RSFilterCacheManager::UpdateCacheStateWithFilterHash(const std::shared_ptr<RSFilter>& filter)
54 {
55 RS_OPTIONAL_TRACE_FUNC();
56 auto filterHash = filter->Hash();
57 if (cachedFilteredSnapshot_ == nullptr || cachedFilterHash_ == filterHash) {
58 return;
59 }
60 // filter changed, clear the filtered snapshot.
61 ROSEN_LOGD("RSFilterCacheManager::UpdateCacheStateWithFilterHash Cache expired. Reason: Cached filtered hash "
62 "%{public}X does not match new hash %{public}X.",
63 cachedFilterHash_, filterHash);
64 cachedFilteredSnapshot_.reset();
65 }
66
UpdateCacheStateWithFilterRegion()67 void RSFilterCacheManager::UpdateCacheStateWithFilterRegion()
68 {
69 if (!IsCacheValid()) {
70 return;
71 }
72 RS_OPTIONAL_TRACE_FUNC();
73
74 ROSEN_LOGD("RSFilterCacheManager::UpdateCacheStateWithFilterRegion Cache expired. Reason: Filter region is not "
75 "within the cached region.");
76 InvalidateFilterCache();
77 }
78
UpdateCacheStateWithDirtyRegion()79 void RSFilterCacheManager::UpdateCacheStateWithDirtyRegion()
80 {
81 if (!IsCacheValid()) {
82 return;
83 }
84 RS_OPTIONAL_TRACE_FUNC();
85 if (cacheUpdateInterval_ > 0) {
86 ROSEN_LOGD("RSFilterCacheManager::UpdateCacheStateWithDirtyRegion Delaying cache "
87 "invalidation for %{public}d frames.",
88 cacheUpdateInterval_);
89 pendingPurge_ = true;
90 } else {
91 InvalidateFilterCache();
92 }
93 }
94
UpdateCacheStateWithDirtyRegion(const RSDirtyRegionManager & dirtyManager)95 bool RSFilterCacheManager::UpdateCacheStateWithDirtyRegion(const RSDirtyRegionManager& dirtyManager)
96 {
97 if (!IsCacheValid()) {
98 return false;
99 }
100 RS_OPTIONAL_TRACE_FUNC();
101 auto& cachedImageRect = GetCachedImageRegion();
102 if (dirtyManager.currentFrameDirtyRegion_.Intersect(cachedImageRect) ||
103 std::any_of(dirtyManager.visitedDirtyRegions_.begin(), dirtyManager.visitedDirtyRegions_.end(),
104 [&cachedImageRect](const RectI& rect) { return rect.Intersect(cachedImageRect); })) {
105 // The underlying image is affected by the dirty region, determine if the cache should be invalidated by cache
106 // age. [PLANNING]: also take into account the filter radius / cache size / percentage of intersected area.
107 if (cacheUpdateInterval_ > 0) {
108 ROSEN_LOGD("RSFilterCacheManager::UpdateCacheStateWithDirtyRegion Delaying cache "
109 "invalidation for %{public}d frames.",
110 cacheUpdateInterval_);
111 pendingPurge_ = true;
112 } else {
113 InvalidateFilterCache();
114 }
115 return false;
116 }
117 if (pendingPurge_) {
118 ROSEN_LOGD("RSFilterCacheManager::UpdateCacheStateWithDirtyRegion MergeDirtyRect at %{public}d frames",
119 cacheUpdateInterval_);
120 InvalidateFilterCache();
121 return true;
122 } else {
123 return false;
124 }
125 }
126
CanDiscardCanvas(RSPaintFilterCanvas & canvas,const Drawing::RectI & dstRect) const127 bool RSFilterCacheManager::CanDiscardCanvas(RSPaintFilterCanvas& canvas, const Drawing::RectI& dstRect) const
128 {
129 /* Check that drawing will be in full canvas and no issues with clip */
130 return (RSSystemProperties::GetDiscardCanvasBeforeFilterEnabled() && canvas.IsClipRect() &&
131 canvas.GetDeviceClipBounds() == dstRect && canvas.GetWidth() == dstRect.GetWidth() &&
132 canvas.GetHeight() == dstRect.GetHeight() && dstRect.GetLeft() == 0 && dstRect.GetTop() == 0);
133 }
134
DrawFilterWithoutSnapshot(RSPaintFilterCanvas & canvas,const std::shared_ptr<RSDrawingFilter> & filter,const Drawing::RectI & src,const Drawing::RectI & dst,bool shouldClearFilteredCache)135 bool RSFilterCacheManager::DrawFilterWithoutSnapshot(RSPaintFilterCanvas& canvas,
136 const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& src, const Drawing::RectI& dst,
137 bool shouldClearFilteredCache)
138 {
139 if (!RSSystemProperties::GetDrawFilterWithoutSnapshotEnabled() || !shouldClearFilteredCache ||
140 cachedSnapshot_ == nullptr || cachedSnapshot_->cachedImage_ == nullptr) {
141 return false;
142 }
143 RS_OPTIONAL_TRACE_FUNC();
144 ROSEN_LOGD("RSFilterCacheManager::DrawFilterWithoutSnapshot");
145 /* Reuse code from RSPropertiesPainter::DrawFilter() when cache manager is not available */
146 auto clipIBounds = dst;
147 Drawing::AutoCanvasRestore acr(canvas, true);
148 canvas.ResetMatrix();
149 // Only draw within the visible rect.
150 ClipVisibleRect(canvas);
151 Drawing::Rect srcRect = Drawing::Rect(0, 0, cachedSnapshot_->cachedImage_->GetWidth(),
152 cachedSnapshot_->cachedImage_->GetHeight());
153 Drawing::Rect dstRect = clipIBounds;
154 bool discardCanvas = CanDiscardCanvas(canvas, dst);
155 filter->DrawImageRect(canvas, cachedSnapshot_->cachedImage_, srcRect, dstRect, { discardCanvas, false });
156 filter->PostProcess(canvas);
157 cachedFilterHash_ = filter->Hash();
158 return true;
159 }
160
DrawFilter(RSPaintFilterCanvas & canvas,const std::shared_ptr<RSDrawingFilter> & filter,bool manuallyHandleFilterCahe,bool shouldClearFilteredCache,const std::optional<Drawing::RectI> & srcRect,const std::optional<Drawing::RectI> & dstRect)161 void RSFilterCacheManager::DrawFilter(RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter,
162 bool manuallyHandleFilterCahe, bool shouldClearFilteredCache,
163 const std::optional<Drawing::RectI>& srcRect,
164 const std::optional<Drawing::RectI>& dstRect)
165 {
166 RS_OPTIONAL_TRACE_FUNC();
167 ROSEN_LOGD("RSFilterCacheManager::DrawFilter");
168 if (canvas.GetDeviceClipBounds().IsEmpty()) {
169 return;
170 }
171 const auto& [src, dst] = ValidateParams(canvas, srcRect, dstRect);
172 if (src.IsEmpty() || dst.IsEmpty()) {
173 return;
174 }
175 RS_TRACE_NAME_FMT("RSFilterCacheManager::DrawFilter status: %s", GetCacheState());
176 ROSEN_LOGD("RSFilterCacheManager::DrawFilter status: %{public}s", GetCacheState());
177 if (!IsCacheValid()) {
178 TakeSnapshot(canvas, filter, src);
179 }
180
181 if (cachedFilteredSnapshot_ == nullptr || cachedFilteredSnapshot_->cachedImage_ == nullptr) {
182 if (manuallyHandleFilterCahe ? DrawFilterWithoutSnapshot(canvas, filter, src, dst, shouldClearFilteredCache)
183 :DrawFilterWithoutSnapshot(canvas, filter, src, dst, renderClearFilteredCacheAfterDrawing_)) {
184 return;
185 } else {
186 GenerateFilteredSnapshot(canvas, filter, dst);
187 }
188 }
189 DrawCachedFilteredSnapshot(canvas, dst, filter);
190 }
191
GeneratedCachedEffectData(RSPaintFilterCanvas & canvas,const std::shared_ptr<RSDrawingFilter> & filter,const std::optional<Drawing::RectI> & srcRect,const std::optional<Drawing::RectI> & dstRect)192 const std::shared_ptr<RSPaintFilterCanvas::CachedEffectData> RSFilterCacheManager::GeneratedCachedEffectData(
193 RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter,
194 const std::optional<Drawing::RectI>& srcRect, const std::optional<Drawing::RectI>& dstRect)
195 {
196 RS_OPTIONAL_TRACE_FUNC();
197 ROSEN_LOGD("RSFilterCacheManager::GeneratedCachedEffectData");
198 if (canvas.GetDeviceClipBounds().IsEmpty()) {
199 return nullptr;
200 }
201 const auto& [src, dst] = ValidateParams(canvas, srcRect, dstRect);
202 if (src.IsEmpty() || dst.IsEmpty()) {
203 return nullptr;
204 }
205 RS_TRACE_NAME_FMT("RSFilterCacheManager::GeneratedCachedEffectData status: %s", GetCacheState());
206 ROSEN_LOGD("RSFilterCacheManager::GeneratedCachedEffectData status: %{public}s", GetCacheState());
207 if (!IsCacheValid()) {
208 TakeSnapshot(canvas, filter, src);
209 }
210
211 if (cachedFilteredSnapshot_ == nullptr || cachedFilteredSnapshot_->cachedImage_ == nullptr) {
212 GenerateFilteredSnapshot(canvas, filter, dst);
213 }
214 // Keep a reference to the cached image, since CompactCache may invalidate it.
215 auto cachedFilteredSnapshot = cachedFilteredSnapshot_;
216 return cachedFilteredSnapshot;
217 }
218
TakeSnapshot(RSPaintFilterCanvas & canvas,const std::shared_ptr<RSDrawingFilter> & filter,const Drawing::RectI & srcRect)219 void RSFilterCacheManager::TakeSnapshot(
220 RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& srcRect)
221 {
222 auto drawingSurface = canvas.GetSurface();
223 if (drawingSurface == nullptr) {
224 return;
225 }
226 RS_OPTIONAL_TRACE_FUNC();
227 RS_LOGD("RSFilterCacheManager::TakeSnapshot");
228 // shrink the srcRect by 1px to avoid edge artifacts.
229 Drawing::RectI snapshotIBounds = srcRect;
230
231 std::shared_ptr<RSShaderFilter> magnifierShaderFilter = filter->GetShaderFilterWithType(RSShaderFilter::MAGNIFIER);
232 if (magnifierShaderFilter != nullptr) {
233 auto tmpFilter = std::static_pointer_cast<RSMagnifierShaderFilter>(magnifierShaderFilter);
234 snapshotIBounds.Offset(tmpFilter->GetMagnifierOffsetX(), tmpFilter->GetMagnifierOffsetY());
235 }
236 std::shared_ptr<Drawing::Image> snapshot;
237 std::shared_ptr<RSShaderFilter> aibarShaderFilter = filter->GetShaderFilterWithType(RSShaderFilter::AIBAR);
238
239 if ((aibarShaderFilter != nullptr) && (HveFilter::GetHveFilter().GetSurfaceNodeSize() > 0)) {
240 snapshot = HveFilter::GetHveFilter().SampleLayer(canvas, srcRect);
241 } else {
242 // Take a screenshot
243 snapshot = drawingSurface->GetImageSnapshot(snapshotIBounds, false);
244 }
245
246 if (snapshot == nullptr) {
247 ROSEN_LOGD("RSFilterCacheManager::TakeSnapshot failed to make an image snapshot.");
248 return;
249 }
250 if (RSSystemProperties::GetImageGpuResourceCacheEnable(snapshot->GetWidth(), snapshot->GetHeight())) {
251 ROSEN_LOGD("TakeSnapshot cache image resource(width:%{public}d, height:%{public}d).", snapshot->GetWidth(),
252 snapshot->GetHeight());
253 snapshot->HintCacheGpuResource();
254 }
255 filter->PreProcess(snapshot);
256
257 // Update the cache state.
258 snapshotRegion_ = RectI(srcRect.GetLeft(), srcRect.GetTop(), srcRect.GetWidth(), srcRect.GetHeight());
259 cachedSnapshot_ = std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(snapshot), snapshotIBounds);
260 cachedFilterHash_ = 0;
261 }
262
GenerateFilteredSnapshot(RSPaintFilterCanvas & canvas,const std::shared_ptr<RSDrawingFilter> & filter,const Drawing::RectI & dstRect)263 void RSFilterCacheManager::GenerateFilteredSnapshot(
264 RSPaintFilterCanvas& canvas, const std::shared_ptr<RSDrawingFilter>& filter, const Drawing::RectI& dstRect)
265 {
266 auto surface = canvas.GetSurface();
267 if (surface == nullptr || cachedSnapshot_ == nullptr || cachedSnapshot_->cachedImage_ == nullptr) {
268 return;
269 }
270 // The cache type has been validated, so filterRegion_ and cachedImage_ should be valid. There is no need to check
271 // them again.
272 RS_OPTIONAL_TRACE_FUNC();
273 ROSEN_LOGD("RSFilterCacheManager::GenerateFilteredSnapshot");
274 // Create an offscreen canvas with the same size as the filter region.
275 auto offscreenRect = dstRect;
276 auto offscreenSurface = surface->MakeSurface(offscreenRect.GetWidth(), offscreenRect.GetHeight());
277 if (offscreenSurface == nullptr) {
278 RS_LOGD("RSFilterCacheManager::GenerateFilteredSnapshot offscreenSurface is nullptr");
279 return;
280 }
281 RSPaintFilterCanvas offscreenCanvas(offscreenSurface.get());
282
283 // Src rect and dst rect, with origin at (0, 0).
284 auto src = Drawing::Rect(0, 0, cachedSnapshot_->cachedRect_.GetWidth(), cachedSnapshot_->cachedRect_.GetHeight());
285 auto dst = Drawing::Rect(0, 0, offscreenRect.GetWidth(), offscreenRect.GetHeight());
286
287 // Draw the cached snapshot on the offscreen canvas, apply the filter, and post-process.
288 filter->DrawImageRect(offscreenCanvas, cachedSnapshot_->cachedImage_, src, dst, { false, true });
289 filter->PostProcess(offscreenCanvas);
290
291 // Update the cache state with the filtered snapshot.
292 auto filteredSnapshot = offscreenSurface->GetImageSnapshot();
293 if (filteredSnapshot == nullptr) {
294 ROSEN_LOGE("RSFilterCacheManager::GenerateFilteredSnapshot failed to get filteredSnapshot.");
295 return;
296 }
297 if (RSSystemProperties::GetImageGpuResourceCacheEnable(filteredSnapshot->GetWidth(),
298 filteredSnapshot->GetHeight())) {
299 ROSEN_LOGD("GenerateFilteredSnapshot cache image resource(width:%{public}d, height:%{public}d).",
300 filteredSnapshot->GetWidth(), filteredSnapshot->GetHeight());
301 filteredSnapshot->HintCacheGpuResource();
302 }
303 if (RSSystemProperties::GetRecordingEnabled()) {
304 if (filteredSnapshot->IsTextureBacked()) {
305 RS_LOGI("RSFilterCacheManager::GenerateFilteredSnapshot cachedImage from texture to raster image");
306 filteredSnapshot = filteredSnapshot->MakeRasterImage();
307 }
308 }
309 cachedFilteredSnapshot_ =
310 std::make_shared<RSPaintFilterCanvas::CachedEffectData>(std::move(filteredSnapshot), offscreenRect);
311 }
312
DrawCachedFilteredSnapshot(RSPaintFilterCanvas & canvas,const Drawing::RectI & dstRect,const std::shared_ptr<RSDrawingFilter> & filter) const313 void RSFilterCacheManager::DrawCachedFilteredSnapshot(RSPaintFilterCanvas& canvas, const Drawing::RectI& dstRect,
314 const std::shared_ptr<RSDrawingFilter>& filter) const
315 {
316 if (cachedFilteredSnapshot_ == nullptr || cachedFilteredSnapshot_->cachedImage_ == nullptr) {
317 return;
318 }
319 RS_OPTIONAL_TRACE_FUNC();
320 RS_LOGD("RSFilterCacheManager::DrawCachedFilteredSnapshot");
321 // Draw in device coordinates.
322 Drawing::AutoCanvasRestore autoRestore(canvas, true);
323 canvas.ResetMatrix();
324
325 // Only draw within the visible rect.
326 ClipVisibleRect(canvas);
327
328 // The cache type and parameters has been validated, dstRect must be subset of cachedFilteredSnapshot_->cachedRect_.
329 Drawing::Rect dst = {dstRect.GetLeft(), dstRect.GetTop(), dstRect.GetRight(), dstRect.GetBottom()};
330 Drawing::Rect src = {dstRect.GetLeft(), dstRect.GetTop(), dstRect.GetRight(), dstRect.GetBottom()};
331 src.Offset(-cachedFilteredSnapshot_->cachedRect_.GetLeft(), -cachedFilteredSnapshot_->cachedRect_.GetTop());
332 RS_OPTIONAL_TRACE_NAME_FMT("DrawCachedFilteredSnapshot cachedRect_:%s, src:%s, dst:%s",
333 cachedFilteredSnapshot_->cachedRect_.ToString().c_str(), src.ToString().c_str(), dst.ToString().c_str());
334 RS_LOGD("DrawCachedFilteredSnapshot cachedRect_:%{public}s, src:%{public}s, dst:%{public}s",
335 cachedFilteredSnapshot_->cachedRect_.ToString().c_str(), src.ToString().c_str(), dst.ToString().c_str());
336 Drawing::Brush brush;
337 brush.SetAntiAlias(true);
338 canvas.AttachBrush(brush);
339 if (CanDiscardCanvas(canvas, dstRect) && brush.GetColor().GetAlphaF() == 1.0 && filter &&
340 filter->GetFilterType() == RSFilter::MATERIAL) {
341 canvas.Discard();
342 }
343 canvas.DrawImageRect(*cachedFilteredSnapshot_->cachedImage_, src, dst, Drawing::SamplingOptions(),
344 Drawing::SrcRectConstraint::FAST_SRC_RECT_CONSTRAINT);
345 canvas.DetachBrush();
346 }
347
InvalidateFilterCache(FilterCacheType clearType)348 void RSFilterCacheManager::InvalidateFilterCache(FilterCacheType clearType)
349 {
350 if (clearType == FilterCacheType::BOTH) {
351 cachedSnapshot_.reset();
352 cachedFilteredSnapshot_.reset();
353 RS_OPTIONAL_TRACE_NAME_FMT("RSFilterCacheManager::InvalidateFilterCache BOTH");
354 ROSEN_LOGD("RSFilterCacheManager::InvalidateFilterCache BOTH");
355 return;
356 }
357 if (clearType == FilterCacheType::SNAPSHOT) {
358 cachedSnapshot_.reset();
359 RS_OPTIONAL_TRACE_NAME_FMT("RSFilterCacheManager::InvalidateFilterCache SNAPSHOT");
360 ROSEN_LOGD("RSFilterCacheManager::InvalidateFilterCache SNAPSHOT");
361 return;
362 }
363 if (clearType == FilterCacheType::FILTERED_SNAPSHOT) {
364 cachedFilteredSnapshot_.reset();
365 RS_OPTIONAL_TRACE_NAME_FMT("RSFilterCacheManager::InvalidateFilterCache FILTERED_SNAPSHOT");
366 ROSEN_LOGD("RSFilterCacheManager::InvalidateFilterCache FILTERED_SNAPSHOT");
367 }
368 }
369
GetFilterInvalid()370 bool RSFilterCacheManager::GetFilterInvalid()
371 {
372 return filterInvalid_;
373 }
374
SetFilterInvalid(bool invalidFilter)375 void RSFilterCacheManager::SetFilterInvalid(bool invalidFilter)
376 {
377 filterInvalid_ = invalidFilter;
378 }
379
IsForceUseFilterCache() const380 bool RSFilterCacheManager::IsForceUseFilterCache() const
381 {
382 return stagingForceUseCache_;
383 }
384
MarkFilterForceUseCache(bool forceUseCache)385 void RSFilterCacheManager::MarkFilterForceUseCache(bool forceUseCache)
386 {
387 stagingForceUseCache_ = forceUseCache;
388 }
389
IsForceClearFilterCache() const390 bool RSFilterCacheManager::IsForceClearFilterCache() const
391 {
392 return stagingForceClearCache_;
393 }
394
MarkFilterForceClearCache()395 void RSFilterCacheManager::MarkFilterForceClearCache()
396 {
397 stagingForceClearCache_ = true;
398 }
399
RecordFilterInfos(const std::shared_ptr<RSFilter> & rsFilter)400 void RSFilterCacheManager::RecordFilterInfos(const std::shared_ptr<RSFilter>& rsFilter)
401 {
402 auto filter = std::static_pointer_cast<RSDrawingFilter>(rsFilter);
403 if (filter == nullptr) {
404 return;
405 }
406 stagingFilterHashChanged_ = stagingCachedFilterHash_ != filter->Hash();
407 if (stagingFilterHashChanged_) {
408 stagingCachedFilterHash_ = filter->Hash();
409 }
410 filterType_ = filter->GetFilterType();
411 canSkipFrame_ = filter->CanSkipFrame();
412 }
413
MarkFilterRegionChanged()414 void RSFilterCacheManager::MarkFilterRegionChanged()
415 {
416 stagingFilterRegionChanged_ = true;
417 }
418
MarkFilterRegionInteractWithDirty()419 void RSFilterCacheManager::MarkFilterRegionInteractWithDirty()
420 {
421 stagingFilterInteractWithDirty_ = true;
422 }
423
MarkForceClearCacheWithLastFrame()424 void RSFilterCacheManager::MarkForceClearCacheWithLastFrame()
425 {
426 stagingForceClearCacheForLastFrame_ = true;
427 }
428
MarkFilterRegionIsLargeArea()429 void RSFilterCacheManager::MarkFilterRegionIsLargeArea()
430 {
431 stagingIsLargeArea_ = true;
432 }
433
UpdateFlags(FilterCacheType type,bool cacheValid)434 void RSFilterCacheManager::UpdateFlags(FilterCacheType type, bool cacheValid)
435 {
436 stagingClearType_ = type;
437 isFilterCacheValid_ = cacheValid;
438 if (!cacheValid) {
439 cacheUpdateInterval_ = stagingRotationChanged_ ? ROTATION_CACHE_UPDATE_INTERVAL :
440 (filterType_ == RSFilter::AIBAR ? AIBAR_CACHE_UPDATE_INTERVAL :
441 (stagingIsLargeArea_ && canSkipFrame_ ? RSSystemProperties::GetFilterCacheUpdateInterval() : 0));
442 pendingPurge_ = false;
443 return;
444 }
445 if (stagingIsAIBarInteractWithHWC_) {
446 if (cacheUpdateInterval_ > 0) {
447 cacheUpdateInterval_--;
448 pendingPurge_ = true;
449 }
450 } else {
451 if ((stagingFilterInteractWithDirty_ || stagingRotationChanged_) && cacheUpdateInterval_ > 0) {
452 cacheUpdateInterval_--;
453 pendingPurge_ = true;
454 }
455 }
456 stagingIsAIBarInteractWithHWC_ = false;
457 }
458
IsAIBarCacheValid()459 bool RSFilterCacheManager::IsAIBarCacheValid()
460 {
461 if (filterType_ != RSFilter::AIBAR) {
462 return false;
463 }
464 stagingIsAIBarInteractWithHWC_ = true;
465 RS_OPTIONAL_TRACE_NAME_FMT("RSFilterCacheManager::IsAIBarCacheValid \
466 cacheUpdateInterval_:%d forceClearCacheForLastFrame_:%d",
467 cacheUpdateInterval_, stagingForceClearCacheForLastFrame_);
468 if (cacheUpdateInterval_ == 0 || stagingForceClearCacheForLastFrame_) {
469 return false;
470 } else {
471 MarkFilterForceUseCache(true);
472 return true;
473 }
474 }
475
MarkEffectNode()476 void RSFilterCacheManager::MarkEffectNode()
477 {
478 stagingIsEffectNode_ = true;
479 }
480
SwapDataAndInitStagingFlags(std::unique_ptr<RSFilterCacheManager> & cacheManager)481 void RSFilterCacheManager::SwapDataAndInitStagingFlags(std::unique_ptr<RSFilterCacheManager>& cacheManager)
482 {
483 if (cacheManager == nullptr) {
484 return;
485 }
486 // stagingParams to renderParams
487 cacheManager->renderFilterHashChanged_ = stagingFilterHashChanged_;
488 cacheManager->renderForceClearCacheForLastFrame_ = stagingForceClearCacheForLastFrame_;
489 cacheManager->renderIsEffectNode_ = stagingIsEffectNode_;
490 cacheManager->renderIsSkipFrame_ = stagingIsSkipFrame_;
491 cacheManager->renderClearType_ = stagingClearType_;
492
493 cacheManager->stagingFilterRegionChanged_ = stagingFilterRegionChanged_;
494 cacheManager->filterType_ = filterType_;
495 cacheManager->stagingIsOccluded_ = stagingIsOccluded_;
496 cacheManager->ClearFilterCache();
497
498 // renderParams to stagingParams
499 lastCacheType_ = cacheManager->lastCacheType_;
500
501 // stagingParams init
502 stagingFilterHashChanged_ = false;
503 stagingForceClearCacheForLastFrame_ = false;
504 stagingIsEffectNode_ = false;
505 stagingIsSkipFrame_ = false;
506 stagingClearType_ = FilterCacheType::BOTH;
507
508 stagingFilterRegionChanged_ = false;
509 stagingFilterInteractWithDirty_ = false;
510 stagingRotationChanged_ = false;
511 stagingForceClearCache_ = false;
512 stagingForceUseCache_ = false;
513 stagingIsOccluded_ = false;
514
515 stagingIsLargeArea_ = false;
516 isFilterCacheValid_ = false;
517 }
518
MarkNeedClearFilterCache()519 void RSFilterCacheManager::MarkNeedClearFilterCache()
520 {
521 RS_TRACE_NAME_FMT("RSFilterCacheManager::MarkNeedClearFilterCache forceUseCache_:%d,"
522 "forceClearCache_:%d, hashChanged:%d, regionChanged_:%d, belowDirty_:%d,"
523 "lastCacheType:%d, cacheUpdateInterval_:%d, canSkip:%d, isLargeArea:%d, filterType_:%d, pendingPurge_:%d,"
524 "forceClearCacheWithLastFrame:%d, rotationChanged:%d",
525 stagingForceUseCache_, stagingForceClearCache_, stagingFilterHashChanged_,
526 stagingFilterRegionChanged_, stagingFilterInteractWithDirty_,
527 lastCacheType_, cacheUpdateInterval_, canSkipFrame_, stagingIsLargeArea_,
528 filterType_, pendingPurge_, stagingForceClearCacheForLastFrame_, stagingRotationChanged_);
529
530 ROSEN_LOGD("RSFilterDrawable::MarkNeedClearFilterCache, forceUseCache_:%{public}d,"
531 "forceClearCache_:%{public}d, hashChanged:%{public}d, regionChanged_:%{public}d, belowDirty_:%{public}d,"
532 "lastCacheType:%{public}hhu, cacheUpdateInterval_:%{public}d, canSkip:%{public}d, isLargeArea:%{public}d,"
533 "filterType_:%{public}d, pendingPurge_:%{public}d,"
534 "forceClearCacheWithLastFrame:%{public}d, rotationChanged:%{public}d",
535 stagingForceUseCache_, stagingForceClearCache_,
536 stagingFilterHashChanged_, stagingFilterRegionChanged_, stagingFilterInteractWithDirty_,
537 lastCacheType_, cacheUpdateInterval_, canSkipFrame_, stagingIsLargeArea_,
538 filterType_, pendingPurge_, stagingForceClearCacheForLastFrame_, stagingRotationChanged_);
539
540 // if do not request NextVsync, close skip
541 if (stagingForceClearCacheForLastFrame_) {
542 cacheUpdateInterval_ = 0;
543 }
544
545 stagingIsSkipFrame_ = stagingIsLargeArea_ && canSkipFrame_ && !stagingFilterRegionChanged_;
546
547 // no valid cache
548 if (lastCacheType_ == FilterCacheType::NONE) {
549 UpdateFlags(FilterCacheType::BOTH, false);
550 return;
551 }
552 // No need to invalidate cache if background image is not null or freezed
553 if (stagingForceUseCache_) {
554 UpdateFlags(FilterCacheType::NONE, true);
555 return;
556 }
557
558 // clear both two type cache: 1. force clear 2. filter region changed 3.skip-frame finished
559 // 4. background changed and effectNode rotated will enable skip-frame, the last frame need to update.
560 if (stagingForceClearCache_ || (stagingFilterRegionChanged_ && !stagingRotationChanged_) || NeedPendingPurge() ||
561 ((stagingFilterInteractWithDirty_ || stagingRotationChanged_) && cacheUpdateInterval_ <= 0)) {
562 UpdateFlags(FilterCacheType::BOTH, false);
563 return;
564 }
565
566 // clear snapshot cache last frame and clear filtered cache current frame
567 if (lastCacheType_ == FilterCacheType::FILTERED_SNAPSHOT && stagingFilterHashChanged_) {
568 UpdateFlags(FilterCacheType::FILTERED_SNAPSHOT, false);
569 return;
570 }
571
572 // when blur filter changes, we need to clear filtered cache if it valid.
573 UpdateFlags(stagingFilterHashChanged_ ?
574 FilterCacheType::FILTERED_SNAPSHOT : FilterCacheType::NONE, true);
575 }
576
NeedPendingPurge() const577 bool RSFilterCacheManager::NeedPendingPurge() const
578 {
579 return !stagingFilterInteractWithDirty_ && pendingPurge_;
580 }
581
ClearFilterCache()582 void RSFilterCacheManager::ClearFilterCache()
583 {
584 // 1. clear memory when region changed and is not the first time occured.
585 bool needClearMemoryForGpu = stagingFilterRegionChanged_ && GetCachedType() != FilterCacheType::NONE;
586 if (filterType_ == RSFilter::AIBAR && stagingIsOccluded_) {
587 InvalidateFilterCache(FilterCacheType::BOTH);
588 } else {
589 InvalidateFilterCache(renderClearType_);
590 }
591 // 2. clear memory when region changed without skip frame.
592 needClearMemoryForGpu = needClearMemoryForGpu && GetCachedType() == FilterCacheType::NONE;
593 if (needClearMemoryForGpu) {
594 SetFilterInvalid(true);
595 }
596
597 // whether to clear blur images. true: clear blur image, false: clear snapshot
598 bool isSaveSnapshot = renderFilterHashChanged_ || GetCachedType() == FilterCacheType::NONE;
599 bool isAIbarWithLastFrame = filterType_ == RSFilter::AIBAR && renderForceClearCacheForLastFrame_; // last vsync
600
601 if ((filterType_ != RSFilter::AIBAR || isAIbarWithLastFrame) && isSaveSnapshot) {
602 renderClearFilteredCacheAfterDrawing_ = true; // hold snapshot
603 } else {
604 renderClearFilteredCacheAfterDrawing_ = false; // hold blur image
605 }
606 if (renderIsEffectNode_ || renderIsSkipFrame_) { renderClearFilteredCacheAfterDrawing_ = renderFilterHashChanged_; }
607 lastCacheType_ = stagingIsOccluded_ ? GetCachedType() : (renderClearFilteredCacheAfterDrawing_ ?
608 FilterCacheType::SNAPSHOT : FilterCacheType::FILTERED_SNAPSHOT);
609 RS_TRACE_NAME_FMT("RSFilterCacheManager::ClearFilterCache, clearType:%d,"
610 " isOccluded_:%d, lastCacheType:%d needClearMemoryForGpu:%d ClearFilteredCacheAfterDrawing:%d",
611 renderClearType_, stagingIsOccluded_, lastCacheType_, needClearMemoryForGpu,
612 renderClearFilteredCacheAfterDrawing_);
613 }
614
IsSkippingFrame() const615 bool RSFilterCacheManager::IsSkippingFrame() const
616 {
617 return (stagingFilterInteractWithDirty_ || stagingRotationChanged_) && cacheUpdateInterval_ > 0;
618 }
619
MarkRotationChanged()620 void RSFilterCacheManager::MarkRotationChanged()
621 {
622 stagingRotationChanged_ = true;
623 }
624
625 // called after OnSync()
IsFilterCacheValidForOcclusion()626 bool RSFilterCacheManager::IsFilterCacheValidForOcclusion()
627 {
628 auto cacheType = GetCachedType();
629 RS_OPTIONAL_TRACE_NAME_FMT("RSFilterCacheManager::IsFilterCacheValidForOcclusion cacheType:%d renderClearType_:%d",
630 cacheType, renderClearType_);
631
632 return cacheType != FilterCacheType::NONE;
633 }
634
MarkNodeIsOccluded(bool isOccluded)635 void RSFilterCacheManager::MarkNodeIsOccluded(bool isOccluded)
636 {
637 stagingIsOccluded_ = isOccluded;
638 }
639
IsFilterCacheValid() const640 bool RSFilterCacheManager::IsFilterCacheValid() const
641 {
642 return isFilterCacheValid_;
643 }
644
WouldDrawLargeAreaBlur()645 bool RSFilterCacheManager::WouldDrawLargeAreaBlur()
646 {
647 RS_TRACE_NAME_FMT("wouldDrawLargeAreaBlur stagingIsLargeArea:%d canSkipFrame:%d"
648 " stagingUpdateInterval:%d stagingFilterInteractWithDirty:%d",
649 stagingIsLargeArea_, canSkipFrame_, cacheUpdateInterval_, stagingFilterInteractWithDirty_);
650 if (stagingIsLargeArea_) {
651 if (!canSkipFrame_) {
652 return true;
653 }
654 return cacheUpdateInterval_ == 1 && stagingFilterInteractWithDirty_;
655 }
656 return false;
657 }
658
WouldDrawLargeAreaBlurPrecisely()659 bool RSFilterCacheManager::WouldDrawLargeAreaBlurPrecisely()
660 {
661 RS_TRACE_NAME_FMT("wouldDrawLargeAreaBlurPrecisely stagingIsLargeArea:%d stagingForceClearCache:%d"
662 " canSkipFrame:%d stagingFilterHashChanged:%d stagingFilterInteractWithDirty:%d stagingFilterRegionChanged:%d"
663 " stagingUpdateInterval:%d stagingLastCacheType:%d", stagingIsLargeArea_,
664 stagingForceClearCache_, canSkipFrame_, stagingFilterHashChanged_, stagingFilterInteractWithDirty_,
665 stagingFilterRegionChanged_, cacheUpdateInterval_, lastCacheType_);
666 if (!stagingIsLargeArea_) {
667 return false;
668 }
669 if (stagingForceClearCache_) {
670 return true;
671 }
672 if (!canSkipFrame_ && !stagingFilterHashChanged_) {
673 return true;
674 }
675 if (!stagingFilterInteractWithDirty_ && !stagingFilterHashChanged_ && !stagingFilterRegionChanged_) {
676 return false;
677 }
678 if (cacheUpdateInterval_ == 0) {
679 return true;
680 }
681 if (lastCacheType_ == FilterCacheType::FILTERED_SNAPSHOT && stagingFilterHashChanged_) {
682 return true;
683 }
684 return false;
685 }
686
ReleaseCacheOffTree()687 void RSFilterCacheManager::ReleaseCacheOffTree()
688 {
689 RS_OPTIONAL_TRACE_FUNC();
690 cachedSnapshot_.reset();
691 cachedFilteredSnapshot_.reset();
692 }
693
GetCachedType() const694 FilterCacheType RSFilterCacheManager::GetCachedType() const
695 {
696 if (cachedSnapshot_ == nullptr && cachedFilteredSnapshot_ == nullptr) {
697 return FilterCacheType::NONE;
698 }
699 if (cachedSnapshot_ != nullptr) {
700 return FilterCacheType::SNAPSHOT;
701 }
702
703 if (cachedFilteredSnapshot_ != nullptr) {
704 return FilterCacheType::FILTERED_SNAPSHOT;
705 }
706 return FilterCacheType::BOTH;
707 }
708
ClipVisibleRect(RSPaintFilterCanvas & canvas)709 inline void RSFilterCacheManager::ClipVisibleRect(RSPaintFilterCanvas& canvas)
710 {
711 auto visibleRectF = canvas.GetVisibleRect();
712 visibleRectF.Round();
713 Drawing::RectI visibleIRect = {(int)visibleRectF.GetLeft(), (int)visibleRectF.GetTop(),
714 (int)visibleRectF.GetRight(), (int)visibleRectF.GetBottom()};
715 auto deviceClipRect = canvas.GetDeviceClipBounds();
716 if (!visibleIRect.IsEmpty() && deviceClipRect.Intersect(visibleIRect)) {
717 canvas.ClipIRect(visibleIRect, Drawing::ClipOp::INTERSECT);
718 }
719 }
720
GetCachedImageRegion() const721 const RectI& RSFilterCacheManager::GetCachedImageRegion() const
722 {
723 static const auto emptyRect = RectI();
724 return IsCacheValid() ? snapshotRegion_ : emptyRect;
725 }
726
IsCacheInvalid(const RSPaintFilterCanvas::CachedEffectData & cache,RSPaintFilterCanvas & canvas)727 inline static bool IsCacheInvalid(const RSPaintFilterCanvas::CachedEffectData& cache, RSPaintFilterCanvas& canvas)
728 {
729 return cache.cachedImage_ == nullptr || !cache.cachedImage_->IsValid(canvas.GetGPUContext().get());
730 }
731
CheckCachedImages(RSPaintFilterCanvas & canvas)732 void RSFilterCacheManager::CheckCachedImages(RSPaintFilterCanvas& canvas)
733 {
734 if (cachedSnapshot_ != nullptr && IsCacheInvalid(*cachedSnapshot_, canvas)) {
735 ROSEN_LOGE("RSFilterCacheManager::CheckCachedImages cachedSnapshot_ is invalid");
736 cachedSnapshot_.reset();
737 }
738
739 if (cachedFilteredSnapshot_ != nullptr && IsCacheInvalid(*cachedFilteredSnapshot_, canvas)) {
740 ROSEN_LOGE("RSFilterCacheManager::CheckCachedImages cachedFilteredSnapshot_ is invalid");
741 cachedFilteredSnapshot_.reset();
742 }
743 }
744
ValidateParams(RSPaintFilterCanvas & canvas,const std::optional<Drawing::RectI> & srcRect,const std::optional<Drawing::RectI> & dstRect)745 std::tuple<Drawing::RectI, Drawing::RectI> RSFilterCacheManager::ValidateParams(
746 RSPaintFilterCanvas& canvas, const std::optional<Drawing::RectI>& srcRect,
747 const std::optional<Drawing::RectI>& dstRect)
748 {
749 Drawing::RectI src;
750 Drawing::RectI dst;
751 auto deviceRect = Drawing::RectI(0, 0, canvas.GetImageInfo().GetWidth(), canvas.GetImageInfo().GetHeight());
752 if (!srcRect.has_value()) {
753 src = canvas.GetRoundInDeviceClipBounds();
754 } else {
755 src = srcRect.value();
756 src.Intersect(deviceRect);
757 }
758 if (!dstRect.has_value()) {
759 dst = src;
760 } else {
761 dst = dstRect.value();
762 dst.Intersect(deviceRect);
763 }
764 RS_OPTIONAL_TRACE_NAME_FMT("RSFilterCacheManager::ValidateParams src:%s, dst:%s",
765 src.ToString().c_str(), dst.ToString().c_str());
766 ROSEN_LOGD("RSFilterCacheManager::ValidateParams src:%{public}s, dst:%{public}s",
767 src.ToString().c_str(), dst.ToString().c_str());
768 return { src, dst };
769 }
770
CompactFilterCache()771 void RSFilterCacheManager::CompactFilterCache()
772 {
773 InvalidateFilterCache(renderClearFilteredCacheAfterDrawing_ ?
774 FilterCacheType::FILTERED_SNAPSHOT : FilterCacheType::SNAPSHOT);
775 }
776 } // namespace Rosen
777 } // namespace OHOS
778 #endif
779