• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #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