已合并
fix: check filter cache when occluded #31583
fix: check filter cache when occluded #31583
已合并
jieyunwyb1创建于 7月24日
共 5 个文件变更+290-20
@@ -59,6 +59,7 @@
59#include "pipeline/render_thread/rs_virtual_screen_parallel_manager.h"59#include "pipeline/render_thread/rs_virtual_screen_parallel_manager.h"
G
Ggaoweihua8月5日

ok

likedislike
60#include "pipeline/rs_base_render_node.h"60#include "pipeline/rs_base_render_node.h"
61#include "pipeline/rs_depth_render_node.h"61#include "pipeline/rs_depth_render_node.h"
62+#include "pipeline/rs_effect_utils.h"
62#include "pipeline/rs_screen_render_node.h"63#include "pipeline/rs_screen_render_node.h"
63#include "pipeline/rs_effect_render_node.h"64#include "pipeline/rs_effect_render_node.h"
64#include "pipeline/rs_logical_display_render_node.h"65#include "pipeline/rs_logical_display_render_node.h"
@@ -4038,17 +4039,22 @@ void RSUniRenderVisitor::UpdateVisibleEffectChildrenStatus(const RSRenderNode& r
4038void RSUniRenderVisitor::CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache(4039void RSUniRenderVisitor::CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache(
4039 const RSRenderNode& rootNode, RSDirtyRegionManager& dirtyManager)4040 const RSRenderNode& rootNode, RSDirtyRegionManager& dirtyManager)
4040{4041{
4042+ if (RSEffectUtils::ShouldSkipFilterNodeCheckInOccludedSubTree(curSurfaceNode_, rootNode, dirtyManager)) {
4043+ return;
4044+ }
4045+ 
4041 auto rotationStatus = GetRotationStatus();4046 auto rotationStatus = GetRotationStatus();
4042 const auto& nodeMap = RSMainThread::Instance()->GetContext().GetNodeMap();4047 const auto& nodeMap = RSMainThread::Instance()->GetContext().GetNodeMap();
4043 // calculate visibleEffectChild oldDirtyInSurface for effectNode4048 // calculate visibleEffectChild oldDirtyInSurface for effectNode
4044- for (auto& child : rootNode.GetVisibleEffectChild()) {4049+ if (dirtyFlag_) {
L
LLyBbq8月3日

为什么收缩了子树跳过后处理的条件?是否会有变严问题,其他场景需要处理,这个变严后不处理,上面的ShouldSkipFilterNodeCheckInOccludedSubTree也是

likedislike
saitoasuka_lh
saitoasuka_lh
8月3日 评论:
4045- auto& visibleEffectNode = nodeMap.GetRenderNode<RSRenderNode>(child);4050+ for (auto& child : rootNode.GetVisibleEffectChild()) {
4046- if (visibleEffectNode == nullptr) {4051+ auto& visibleEffectNode = nodeMap.GetRenderNode<RSRenderNode>(child);
4047- continue;4052+ if (visibleEffectNode) {
4053+ RectI filterRect;
4054+ visibleEffectNode->UpdateFilterRegionInSkippedSubTree(
4055+ dirtyManager, rootNode, filterRect, prepareClipRect_, prepareFilterClipRect_);
4056+ }
4048 }4057 }
4049- RectI filterRect;
4050- visibleEffectNode->UpdateFilterRegionInSkippedSubTree(dirtyManager, rootNode, filterRect,
4051- prepareClipRect_, prepareFilterClipRect_);
4052 }4058 }
4053 4059 
4054 for (auto& child : rootNode.GetVisibleFilterChild()) {4060 for (auto& child : rootNode.GetVisibleFilterChild()) {
@@ -4061,24 +4067,26 @@ void RSUniRenderVisitor::CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache(
4061 4067 
4062 // Check if HWC should be disabled for ColorPicker node4068 // Check if HWC should be disabled for ColorPicker node
4063 HandleColorPickerHwcDisable(*filterNode);4069 HandleColorPickerHwcDisable(*filterNode);
4064- // Skip nodes that only have ColorPickerDrawable without any real filter4070+ // Skip nodes that has no blur filter
4065- if (filterNode->IsColorPickerOnlyNode()) {4071+ if (!filterNode->HasBlurFilter()) {
chuchengcheng

这里为啥需要扩大下层遍历的范围?

likedislike
saitoasuka_lh
saitoasuka_lh
8月3日 评论:
4066 continue;4072 continue;
4067 }4073 }
4068 4074 
4075+ RS_OPTIONAL_TRACE_NAME_FMT("CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache node[" PRIu64 "]",
4076+ filterNode->GetId());
4069 auto effectNode = RSRenderNode::ReinterpretCast<RSEffectRenderNode>(filterNode);4077 auto effectNode = RSRenderNode::ReinterpretCast<RSEffectRenderNode>(filterNode);
4070- if (effectNode == nullptr) {4078+ if (effectNode != nullptr) {
4071- continue;4079+ effectNode->UpdateChildHasVisibleEffectWithoutEmptyRect();
4072 }4080 }
4073- effectNode->CheckBlurFilterCacheNeedForceClearOrSave(4081+ filterNode->CheckBlurFilterCacheNeedForceClearOrSave(
chuchengcheng

4075的effectNode没判空,下面直接使用

likedislike
saitoasuka_lh
saitoasuka_lh
8月3日 评论:
4074 rotationStatus.rotationChanged, rotationStatus.rotationStatusChanged);4082 rotationStatus.rotationChanged, rotationStatus.rotationStatusChanged);
4075- effectNode->UpdateChildHasVisibleEffectWithoutEmptyRect();4083+ filterNode->MarkClearFilterCacheIfEffectChildrenChanged();
chuchengcheng

这里MarkClearFilterCacheIfEffectChildrenChanged和Update之前的顺序颠倒,原因是啥

likedislike
saitoasuka_lh
saitoasuka_lh
8月3日 评论:
4076- effectNode->MarkClearFilterCacheIfEffectChildrenChanged();4084+ RSEffectUtils::UpdateFilterCacheWithBelowDirtyAndPendingPurge(*filterNode, dirtyManager);
4077- RectI filterRect;4085+ if (dirtyFlag_) {
4078- effectNode->UpdateFilterRegionInSkippedSubTree(dirtyManager, rootNode, filterRect,4086+ RectI filterRect;
4079- prepareClipRect_, prepareFilterClipRect_);4087+ UpdateFilterRenderContextForSkippedSubTree(dirtyManager, *filterNode, rootNode, filterRect);
4080- effectNode->FilterRectMergeDirtyRectInSkippedSubtree(dirtyManager, filterRect);4088+ }
4081- CollectFilterInfoAndUpdateDirty(*effectNode, dirtyManager);4089+ CollectFilterInfoAndUpdateDirty(*filterNode, dirtyManager);
4082 }4090 }
4083}4091}
4084 4092 
@@ -18,6 +18,7 @@
18 18 
19#include "effect/rs_render_effect_common_def.h"19#include "effect/rs_render_effect_common_def.h"
20#include "pipeline/rs_render_node.h"20#include "pipeline/rs_render_node.h"
21+#include "pipeline/rs_surface_render_node.h"
21 22 
22namespace OHOS {23namespace OHOS {
23 24 
@@ -29,6 +30,23 @@ public:
29 30 
30 // true:causes filter cache to be generated offscreen.31 // true:causes filter cache to be generated offscreen.
31 static bool IsOffscreenForFilterCache(RSRenderNode& node);32 static bool IsOffscreenForFilterCache(RSRenderNode& node);
33+ 
34+ // Check if filter node check can be skipped in occluded sub tree.
35+ // Returns true when:
36+ // 1. curSurfaceNode exists (current surface is being processed)
37+ // 2. curSurfaceNode is opaque, no need to consider dirty regions of surface nodes below it
38+ // 3. Current frame dirty region is empty (no content needs update)
39+ // In this case, the sub tree is fully occluded and clean, so filter check can be skipped.
40+ static bool ShouldSkipFilterNodeCheckInOccludedSubTree(
41+ const std::shared_ptr<RSSurfaceRenderNode>& curSurfaceNode, const RSRenderNode& rootNode,
42+ RSDirtyRegionManager& dirtyManager);
43+ 
44+ // Update filter cache with current frame dirty region and pending purge filter dirty rect.
45+ // This function processes both material filter and background filter:
46+ // 1. Updates filter cache with current frame dirty region
47+ // 2. Updates pending purge filter dirty rect for cache management
48+ static void UpdateFilterCacheWithBelowDirtyAndPendingPurge(RSRenderNode& node,
49+ RSDirtyRegionManager& dirtyManager);
32};50};
33} // namespace Rosen51} // namespace Rosen
34} // namespace OHOS52} // namespace OHOS
@@ -58,5 +58,29 @@ bool RSEffectUtils::IsOffscreenForFilterCache(RSRenderNode& node)
58 return (node.GetType() == RSRenderNodeType::CANVAS_NODE || node.GetType() == RSRenderNodeType::UNION_NODE) && (58 return (node.GetType() == RSRenderNodeType::CANVAS_NODE || node.GetType() == RSRenderNodeType::UNION_NODE) && (
59 node.GetDrawingCacheType() == RSDrawingCacheType::FOREGROUND_FILTER_CACHE || node.IsForegroundFilterEnable());59 node.GetDrawingCacheType() == RSDrawingCacheType::FOREGROUND_FILTER_CACHE || node.IsForegroundFilterEnable());
60}60}
61+ 
62+bool RSEffectUtils::ShouldSkipFilterNodeCheckInOccludedSubTree(
63+ const std::shared_ptr<RSSurfaceRenderNode>& curSurfaceNode, const RSRenderNode& rootNode,
64+ RSDirtyRegionManager& dirtyManager)
65+{
66+ return curSurfaceNode &&
67+ !curSurfaceNode->IsTransparent() &&
68+ dirtyManager.GetCurrentFrameDirtyRegion().IsEmpty();
69+}
70+ 
71+void RSEffectUtils::UpdateFilterCacheWithBelowDirtyAndPendingPurge(RSRenderNode& node,
72+ RSDirtyRegionManager& dirtyManager)
73+{
74+ if (node.GetRenderProperties().GetMaterialFilter()) {
chuchengcheng

两种模糊要处理两遍?

likedislike
saitoasuka_lh
saitoasuka_lh
8月3日 评论:
75+ node.UpdateFilterCacheWithBelowDirty(
76+ Occlusion::Rect(dirtyManager.GetCurrentFrameDirtyRegion()), RSDrawableSlot::MATERIAL_FILTER);
77+ node.UpdatePendingPurgeFilterDirtyRect(dirtyManager, RSDrawableSlot::MATERIAL_FILTER);
78+ }
79+ if (node.GetRenderProperties().GetBackgroundFilter()) {
80+ node.UpdateFilterCacheWithBelowDirty(
81+ Occlusion::Rect(dirtyManager.GetCurrentFrameDirtyRegion()));
82+ node.UpdatePendingPurgeFilterDirtyRect(dirtyManager, RSDrawableSlot::BACKGROUND_FILTER);
83+ }
84+}
61} // namespace Rosen85} // namespace Rosen
62-} // namespace OHOS86+} // namespace OHOS
@@ -7712,6 +7712,190 @@ HWTEST_F(RSUniRenderVisitorTest, CheckFilterNodeInOccludedSkippedSubTreeNeedClea
7712}7712}
7713 7713 
7714/**7714/**
7715+ * @tc.name: CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_ShouldSkip001
7716+ * @tc.desc: Test ShouldSkipFilterNodeCheckInOccludedSubTree returns true when conditions met
7717+ * @tc.type: FUNC
7718+ * @tc.require: issue25152
7719+ */
7720+HWTEST_F(RSUniRenderVisitorTest, CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_ShouldSkip001,
7721+ TestSize.Level2)
7722+{
7723+ auto rsContext = std::make_shared<RSContext>();
7724+ auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>();
7725+ ASSERT_NE(rsUniRenderVisitor, nullptr);
7726+ 
7727+ auto curSurfaceNode = std::make_shared<RSSurfaceRenderNode>(1000, rsContext->weak_from_this());
7728+ curSurfaceNode->InitRenderParams();
7729+ curSurfaceNode->SetAbilityBGAlpha(255);
7730+ curSurfaceNode->SetGlobalAlpha(1.0f);
7731+ EXPECT_FALSE(curSurfaceNode->IsTransparent());
7732+ 
7733+ auto rsRootRenderNode = std::make_shared<RSSurfaceRenderNode>(0, rsContext->weak_from_this());
7734+ rsRootRenderNode->InitRenderParams();
7735+ 
7736+ RSDirtyRegionManager dirtyManager;
7737+ 
7738+ rsUniRenderVisitor->curSurfaceNode_ = curSurfaceNode;
7739+ rsUniRenderVisitor->CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache(*rsRootRenderNode, dirtyManager);
7740+ 
7741+ EXPECT_TRUE(dirtyManager.GetFilterCollector().GetFilterDirtyRegionInfoList(false).empty());
7742+}
7743+ 
7744+/**
7745+ * @tc.name: CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_ParentTreeDirty001
7746+ * @tc.desc: Test rootNode.IsParentTreeDirty() true branch at line 4047 and 4078
7747+ * @tc.type: FUNC
7748+ * @tc.require: issue25152
7749+ */
7750+HWTEST_F(RSUniRenderVisitorTest, CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_ParentTreeDirty001,
7751+ TestSize.Level2)
7752+{
7753+ auto rsContext = std::make_shared<RSContext>();
7754+ auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>();
7755+ ASSERT_NE(rsUniRenderVisitor, nullptr);
7756+ rsUniRenderVisitor->dirtyFlag_ = true;
7757+ 
7758+ auto rsRootRenderNode = std::make_shared<RSSurfaceRenderNode>(0, rsContext->weak_from_this());
7759+ rsRootRenderNode->InitRenderParams();
7760+ rsRootRenderNode->SetDirty();
7761+ 
7762+ auto effectNode = std::make_shared<RSEffectRenderNode>(1);
7763+ RSMainThread::Instance()->GetContext().GetMutableNodeMap().RegisterRenderNode(effectNode);
7764+ effectNode->GetMutableRenderProperties().backgroundFilter_ = std::make_shared<RSFilter>();
7765+ effectNode->GetMutableRenderProperties().needFilter_ = true;
7766+ rsRootRenderNode->UpdateVisibleFilterChild(*effectNode);
7767+ rsRootRenderNode->UpdateVisibleEffectChild(*effectNode);
7768+ 
7769+ auto canvasNode = std::make_shared<RSCanvasRenderNode>(2);
7770+ RSMainThread::Instance()->GetContext().GetMutableNodeMap().RegisterRenderNode(canvasNode);
7771+ canvasNode->GetMutableRenderProperties().backgroundFilter_ = std::make_shared<RSFilter>();
7772+ canvasNode->GetMutableRenderProperties().needFilter_ = true;
7773+ rsRootRenderNode->UpdateVisibleFilterChild(*canvasNode);
7774+ 
7775+ RSDirtyRegionManager dirtyManager;
7776+ rsUniRenderVisitor->CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache(*rsRootRenderNode, dirtyManager);
7777+ 
7778+ RSMainThread::Instance()->GetContext().GetMutableNodeMap().UnregisterRenderNode(1);
7779+ RSMainThread::Instance()->GetContext().GetMutableNodeMap().UnregisterRenderNode(2);
7780+ EXPECT_TRUE(rsRootRenderNode->IsParentTreeDirty());
7781+}
7782+ 
7783+/**
7784+ * @tc.name: CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_VisibleEffectChild001
7785+ * @tc.desc: Test visibleEffectNode not null branch at line 4050
7786+ * @tc.type: FUNC
7787+ * @tc.require: issue25152
7788+ */
7789+HWTEST_F(RSUniRenderVisitorTest, CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_VisibleEffectChild001,
7790+ TestSize.Level2)
7791+{
7792+ auto rsContext = std::make_shared<RSContext>();
7793+ auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>();
7794+ ASSERT_NE(rsUniRenderVisitor, nullptr);
7795+ rsUniRenderVisitor->dirtyFlag_ = true;
7796+ 
7797+ auto rsRootRenderNode = std::make_shared<RSSurfaceRenderNode>(0, rsContext->weak_from_this());
7798+ rsRootRenderNode->InitRenderParams();
7799+ rsRootRenderNode->SetDirty();
7800+ 
7801+ auto visibleEffectChild = std::make_shared<RSEffectRenderNode>(100);
7802+ RSMainThread::Instance()->GetContext().GetMutableNodeMap().RegisterRenderNode(visibleEffectChild);
7803+ visibleEffectChild->GetMutableRenderProperties().needFilter_ = true;
7804+ rsRootRenderNode->visibleEffectChild_.insert(100);
7805+ 
7806+ RSDirtyRegionManager dirtyManager;
7807+ rsUniRenderVisitor->CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache(*rsRootRenderNode, dirtyManager);
7808+ 
7809+ RSMainThread::Instance()->GetContext().GetMutableNodeMap().UnregisterRenderNode(100);
7810+ EXPECT_TRUE(rsRootRenderNode->IsParentTreeDirty());
7811+}
7812+ 
7813+/**
7814+ * @tc.name: CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_VisibleEffectChildNull001
7815+ * @tc.desc: Test visibleEffectNode null branch at line 4050
7816+ * @tc.type: FUNC
7817+ * @tc.require: issue25152
7818+ */
7819+HWTEST_F(RSUniRenderVisitorTest, CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_VisibleEffectChildNull001,
7820+ TestSize.Level2)
7821+{
7822+ auto rsContext = std::make_shared<RSContext>();
7823+ auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>();
7824+ ASSERT_NE(rsUniRenderVisitor, nullptr);
7825+ rsUniRenderVisitor->dirtyFlag_ = true;
7826+ 
7827+ auto rsRootRenderNode = std::make_shared<RSSurfaceRenderNode>(0, rsContext->weak_from_this());
7828+ rsRootRenderNode->InitRenderParams();
7829+ rsRootRenderNode->SetDirty();
7830+ 
7831+ rsRootRenderNode->visibleEffectChild_.insert(200);
7832+ 
7833+ RSDirtyRegionManager dirtyManager;
7834+ rsUniRenderVisitor->CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache(*rsRootRenderNode, dirtyManager);
7835+ 
7836+ EXPECT_TRUE(rsRootRenderNode->IsParentTreeDirty());
7837+}
7838+ 
7839+/**
7840+ * @tc.name: CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_NoBlurFilter001
7841+ * @tc.desc: Test skipping nodes without blur filter at line 4063
7842+ * @tc.type: FUNC
7843+ * @tc.require: issue25152
7844+ */
7845+HWTEST_F(RSUniRenderVisitorTest, CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_NoBlurFilter001,
7846+ TestSize.Level2)
7847+{
7848+ auto rsContext = std::make_shared<RSContext>();
7849+ auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>();
7850+ ASSERT_NE(rsUniRenderVisitor, nullptr);
7851+ 
7852+ auto rsRootRenderNode = std::make_shared<RSSurfaceRenderNode>(0, rsContext->weak_from_this());
7853+ rsRootRenderNode->InitRenderParams();
7854+ 
7855+ auto canvasNode = std::make_shared<RSCanvasRenderNode>(1);
7856+ RSMainThread::Instance()->GetContext().GetMutableNodeMap().RegisterRenderNode(canvasNode);
7857+ canvasNode->GetMutableRenderProperties().needFilter_ = true;
7858+ rsRootRenderNode->UpdateVisibleFilterChild(*canvasNode);
7859+ 
7860+ RSDirtyRegionManager dirtyManager;
7861+ rsUniRenderVisitor->CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache(*rsRootRenderNode, dirtyManager);
7862+ 
7863+ RSMainThread::Instance()->GetContext().GetMutableNodeMap().UnregisterRenderNode(1);
7864+ EXPECT_TRUE(dirtyManager.GetFilterCollector().GetFilterDirtyRegionInfoList(false).empty());
7865+}
7866+ 
7867+/**
7868+ * @tc.name: CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_EffectNodeNotNull001
7869+ * @tc.desc: Test effectNode != nullptr branch at line 4070
7870+ * @tc.type: FUNC
7871+ * @tc.require: issue25152
7872+ */
7873+HWTEST_F(RSUniRenderVisitorTest, CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache_EffectNodeNotNull001,
7874+ TestSize.Level2)
7875+{
7876+ auto rsContext = std::make_shared<RSContext>();
7877+ auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>();
7878+ ASSERT_NE(rsUniRenderVisitor, nullptr);
7879+ rsUniRenderVisitor->dirtyFlag_ = true;
7880+ 
7881+ auto rsRootRenderNode = std::make_shared<RSSurfaceRenderNode>(0, rsContext->weak_from_this());
7882+ rsRootRenderNode->InitRenderParams();
7883+ rsRootRenderNode->SetDirty();
7884+ 
7885+ auto effectNode = std::make_shared<RSEffectRenderNode>(1);
7886+ RSMainThread::Instance()->GetContext().GetMutableNodeMap().RegisterRenderNode(effectNode);
7887+ effectNode->GetMutableRenderProperties().backgroundFilter_ = std::make_shared<RSFilter>();
7888+ effectNode->GetMutableRenderProperties().needFilter_ = true;
7889+ rsRootRenderNode->UpdateVisibleFilterChild(*effectNode);
7890+ 
7891+ RSDirtyRegionManager dirtyManager;
7892+ rsUniRenderVisitor->CheckFilterNodeInOccludedSkippedSubTreeNeedClearCache(*rsRootRenderNode, dirtyManager);
7893+ 
7894+ RSMainThread::Instance()->GetContext().GetMutableNodeMap().UnregisterRenderNode(1);
7895+ EXPECT_TRUE(rsRootRenderNode->IsParentTreeDirty());
7896+}
7897+ 
7898+/*
7715 * @tc.name: DelayNotifyUIBufferAvailableIfNeedTest0017899 * @tc.name: DelayNotifyUIBufferAvailableIfNeedTest001
7716 * @tc.desc: Cover branch: IsPendingUIBufferNotify=true, entry exists, all siblings ready, flush.7900 * @tc.desc: Cover branch: IsPendingUIBufferNotify=true, entry exists, all siblings ready, flush.
7717 * @tc.type: FUNC7901 * @tc.type: FUNC
@@ -130,5 +130,41 @@ HWTEST_F(RSEffectUtilsTest, AccumulateFilterRenderContext003, TestSize.Level1)
130 EXPECT_TRUE(result);130 EXPECT_TRUE(result);
131 EXPECT_EQ(filterContext.offscreenNodeId, canvasParent->GetId());131 EXPECT_EQ(filterContext.offscreenNodeId, canvasParent->GetId());
132}132}
133+ 
134+/**
135+ * @tc.name: UpdateFilterCacheWithBelowDirtyAndPendingPurge001
136+ * @tc.desc: test UpdateFilterCacheWithBelowDirtyAndPendingPurge with MaterialFilter
137+ * @tc.type: FUNC
138+ * @tc.require: issue25152
139+ */
140+HWTEST_F(RSEffectUtilsTest, UpdateFilterCacheWithBelowDirtyAndPendingPurge001, TestSize.Level2)
141+{
142+ auto node = std::make_shared<RSCanvasRenderNode>(id, context);
143+ node->GetMutableRenderProperties().GetEffect().materialFilter_ = std::make_shared<RSFilter>();
144+ 
145+ RSDirtyRegionManager dirtyManager;
146+ dirtyManager.MergeDirtyRect(RectI(0, 0, 100, 100));
147+ 
148+ RSEffectUtils::UpdateFilterCacheWithBelowDirtyAndPendingPurge(*node, dirtyManager);
149+ EXPECT_FALSE(dirtyManager.GetCurrentFrameDirtyRegion().IsEmpty());
150+}
151+ 
152+/**
153+ * @tc.name: UpdateFilterCacheWithBelowDirtyAndPendingPurge002
154+ * @tc.desc: test UpdateFilterCacheWithBelowDirtyAndPendingPurge with BackgroundFilter
155+ * @tc.type: FUNC
156+ * @tc.require: issue25152
157+ */
158+HWTEST_F(RSEffectUtilsTest, UpdateFilterCacheWithBelowDirtyAndPendingPurge002, TestSize.Level2)
159+{
160+ auto node = std::make_shared<RSCanvasRenderNode>(id, context);
161+ node->GetMutableRenderProperties().backgroundFilter_ = std::make_shared<RSFilter>();
162+ 
163+ RSDirtyRegionManager dirtyManager;
164+ dirtyManager.MergeDirtyRect(RectI(0, 0, 100, 100));
165+ 
166+ RSEffectUtils::UpdateFilterCacheWithBelowDirtyAndPendingPurge(*node, dirtyManager);
167+ EXPECT_FALSE(dirtyManager.GetCurrentFrameDirtyRegion().IsEmpty());
168+}
133} // namespace Rosen169} // namespace Rosen
134} // namespace OHOS170} // namespace OHOS