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 "pipeline/rs_effect_render_node.h"
17
18 #include "common/rs_obj_abs_geometry.h"
19 #include "common/rs_optional_trace.h"
20 #include "memory/rs_memory_track.h"
21 #include "params/rs_effect_render_params.h"
22 #include "platform/common/rs_log.h"
23 #include "platform/common/rs_system_properties.h"
24 #include "property/rs_properties_painter.h"
25 #include "visitor/rs_node_visitor.h"
26
27 namespace OHOS {
28 namespace Rosen {
29
RSEffectRenderNode(NodeId id,const std::weak_ptr<RSContext> & context,bool isTextureExportNode)30 RSEffectRenderNode::RSEffectRenderNode(NodeId id, const std::weak_ptr<RSContext>& context, bool isTextureExportNode)
31 : RSRenderNode(id, context, isTextureExportNode)
32 {
33 #ifndef ROSEN_ARKUI_X
34 MemoryInfo info = { sizeof(*this), ExtractPid(id), id, MEMORY_TYPE::MEM_RENDER_NODE };
35 MemoryTrack::Instance().AddNodeRecord(id, info);
36 #endif
37 }
38
~RSEffectRenderNode()39 RSEffectRenderNode::~RSEffectRenderNode()
40 {
41 #ifndef ROSEN_ARKUI_X
42 MemoryTrack::Instance().RemoveNodeRecord(GetId());
43 #endif
44 }
45
Prepare(const std::shared_ptr<RSNodeVisitor> & visitor)46 void RSEffectRenderNode::Prepare(const std::shared_ptr<RSNodeVisitor>& visitor)
47 {
48 if (!visitor) {
49 return;
50 }
51 ApplyModifiers();
52 visitor->PrepareEffectRenderNode(*this);
53 preStaticStatus_ = IsStaticCached();
54 }
55
QuickPrepare(const std::shared_ptr<RSNodeVisitor> & visitor)56 void RSEffectRenderNode::QuickPrepare(const std::shared_ptr<RSNodeVisitor>& visitor)
57 {
58 if (!visitor) {
59 return;
60 }
61 ApplyModifiers();
62 visitor->QuickPrepareEffectRenderNode(*this);
63 }
64
Process(const std::shared_ptr<RSNodeVisitor> & visitor)65 void RSEffectRenderNode::Process(const std::shared_ptr<RSNodeVisitor>& visitor)
66 {
67 if (!visitor) {
68 return;
69 }
70 RSRenderNode::RenderTraceDebug();
71 visitor->ProcessEffectRenderNode(*this);
72 }
73
ProcessRenderBeforeChildren(RSPaintFilterCanvas & canvas)74 void RSEffectRenderNode::ProcessRenderBeforeChildren(RSPaintFilterCanvas& canvas)
75 {
76 RSRenderNode::ProcessTransitionBeforeChildren(canvas);
77 auto& properties = GetRenderProperties();
78 // Disable effect region if either of the following conditions is met:
79 // 1. No child with useEffect(true) (needFilter_ == false)
80 // 2. Background filter is null
81 // 3. Canvas is offscreen
82 if (!properties.GetHaveEffectRegion() || properties.GetBackgroundFilter() == nullptr ||
83 !RSSystemProperties::GetEffectMergeEnabled() ||
84 canvas.GetCacheType() == RSPaintFilterCanvas::CacheType::OFFSCREEN) {
85 canvas.SetEffectData(nullptr);
86 return;
87 }
88
89 if (properties.GetBgImage() == nullptr) {
90 // EffectRenderNode w/o background image, use snapshot as underlay image
91 RSPropertiesPainter::DrawBackgroundEffect(properties, canvas);
92 } else {
93 // EffectRenderNode w/ background image, use bg image as underlay image
94 RSPropertiesPainter::DrawBackgroundImageAsEffect(properties, canvas);
95 }
96 }
97
GetFilterRect() const98 RectI RSEffectRenderNode::GetFilterRect() const
99 {
100 if (!ChildHasVisibleEffect()) {
101 return {};
102 }
103 return RSRenderNode::GetFilterRect();
104 }
105
SetEffectRegion(const std::optional<Drawing::RectI> & effectRegion)106 void RSEffectRenderNode::SetEffectRegion(const std::optional<Drawing::RectI>& effectRegion)
107 {
108 if (!effectRegion.has_value() || !effectRegion->IsValid()) {
109 ROSEN_LOGD("RSEffectRenderNode::SetEffectRegion: no effect region.");
110 GetMutableRenderProperties().SetHaveEffectRegion(false);
111 return;
112 }
113
114 const auto& properties = GetRenderProperties();
115 const auto& absRect = properties.GetBoundsGeometry()->GetAbsRect();
116 Drawing::RectI effectRect = effectRegion.value();
117 if (!effectRect.Intersect(
118 Drawing::RectI(absRect.GetLeft(), absRect.GetTop(), absRect.GetRight(), absRect.GetBottom()))) {
119 ROSEN_LOGD("RSEffectRenderNode::SetEffectRegion: no valid effect region.");
120 GetMutableRenderProperties().SetHaveEffectRegion(false);
121 return;
122 }
123 GetMutableRenderProperties().SetHaveEffectRegion(true);
124 }
125
CheckBlurFilterCacheNeedForceClearOrSave(bool rotationChanged,bool rotationStatusChanged)126 void RSEffectRenderNode::CheckBlurFilterCacheNeedForceClearOrSave(bool rotationChanged, bool rotationStatusChanged)
127 {
128 if (GetRenderProperties().GetBackgroundFilter() == nullptr) {
129 return;
130 }
131 auto filterDrawable = GetFilterDrawable(false);
132 if (filterDrawable == nullptr) {
133 return;
134 }
135 filterDrawable->MarkEffectNode();
136 RSRenderNode::CheckBlurFilterCacheNeedForceClearOrSave(rotationChanged, rotationStatusChanged);
137 if (IsForceClearOrUseFilterCache(filterDrawable)) {
138 return;
139 }
140 if (CheckFilterCacheNeedForceClear()) {
141 filterDrawable->MarkFilterForceClearCache();
142 } else if (CheckFilterCacheNeedForceSave()) {
143 filterDrawable->MarkFilterForceUseCache();
144 }
145 }
146
UpdateFilterCacheWithSelfDirty()147 void RSEffectRenderNode::UpdateFilterCacheWithSelfDirty()
148 {
149 if (!RSProperties::FilterCacheEnabled) {
150 ROSEN_LOGE("RSEffectRenderNode::UpdateFilterCacheManagerWithCacheRegion filter cache is disabled.");
151 return;
152 }
153 auto filterDrawable = GetFilterDrawable(false);
154 if (filterDrawable == nullptr || IsForceClearOrUseFilterCache(filterDrawable)) {
155 return;
156 }
157 RS_OPTIONAL_TRACE_NAME_FMT("RSEffectRenderNode[%llu]::UpdateFilterCacheWithSelfDirty lastRect:%s, currRegion:%s",
158 GetId(), GetFilterCachedRegion().ToString().c_str(), filterRegion_.ToString().c_str());
159 if (filterRegion_ == GetFilterCachedRegion()) {
160 return;
161 }
162 // effect render node only support background filter
163 MarkFilterStatusChanged(false, true);
164 }
165
MarkFilterCacheFlags(std::shared_ptr<DrawableV2::RSFilterDrawable> & filterDrawable,RSDirtyRegionManager & dirtyManager,bool needRequestNextVsync)166 void RSEffectRenderNode::MarkFilterCacheFlags(std::shared_ptr<DrawableV2::RSFilterDrawable>& filterDrawable,
167 RSDirtyRegionManager& dirtyManager, bool needRequestNextVsync)
168 {
169 preStaticStatus_ = IsStaticCached();
170 lastFrameHasVisibleEffect_ = ChildHasVisibleEffect();
171 if (filterDrawable == nullptr || IsForceClearOrUseFilterCache(filterDrawable)) {
172 return;
173 }
174 // use for skip-frame when screen rotation
175 if (isRotationChanged_) {
176 filterDrawable->MarkRotationChanged();
177 }
178 RSRenderNode::MarkFilterCacheFlags(filterDrawable, dirtyManager, needRequestNextVsync);
179 }
180
CheckFilterCacheNeedForceSave()181 bool RSEffectRenderNode::CheckFilterCacheNeedForceSave()
182 {
183 RS_OPTIONAL_TRACE_NAME_FMT("RSEffectRenderNode[%llu]::CheckFilterCacheNeedForceSave"
184 " isBackgroundImage:%d, isRotationChanged_:%d, IsStaticCached():%d,",
185 GetId(), GetRenderProperties().GetBgImage() != nullptr, isRotationChanged_, IsStaticCached());
186 return GetRenderProperties().GetBgImage() != nullptr || (IsStaticCached() && !isRotationChanged_);
187 }
188
CheckFilterCacheNeedForceClear()189 bool RSEffectRenderNode::CheckFilterCacheNeedForceClear()
190 {
191 RS_OPTIONAL_TRACE_NAME_FMT("RSEffectRenderNode[%llu]::CheckFilterCacheNeedForceClear foldStatusChanged_:%d,"
192 " preRotationStatus_:%d, isRotationChanged_:%d, preStaticStatus_:%d, isStaticCached:%d",
193 GetId(), foldStatusChanged_, preRotationStatus_, isRotationChanged_, preStaticStatus_, IsStaticCached());
194 // case 3: the state of freeze changed to false, and the last cache maybe wrong.
195 return foldStatusChanged_ || (preRotationStatus_ != isRotationChanged_) ||
196 (preStaticStatus_ != isStaticCached_ && isStaticCached_ == false);
197 }
198
SetRotationChanged(bool isRotationChanged)199 void RSEffectRenderNode::SetRotationChanged(bool isRotationChanged)
200 {
201 preRotationStatus_ = isRotationChanged_;
202 isRotationChanged_ = isRotationChanged;
203 }
204
GetRotationChanged() const205 bool RSEffectRenderNode::GetRotationChanged() const
206 {
207 return isRotationChanged_;
208 }
209
SetCurrentAttachedScreenId(uint64_t screenId)210 void RSEffectRenderNode::SetCurrentAttachedScreenId(uint64_t screenId)
211 {
212 currentAttachedScreenId_ = screenId;
213 }
214
GetCurrentAttachedScreenId() const215 uint64_t RSEffectRenderNode::GetCurrentAttachedScreenId() const
216 {
217 return currentAttachedScreenId_;
218 }
219
SetFoldStatusChanged(bool foldStatusChanged)220 void RSEffectRenderNode::SetFoldStatusChanged(bool foldStatusChanged)
221 {
222 foldStatusChanged_ = foldStatusChanged;
223 }
224
InitRenderParams()225 void RSEffectRenderNode::InitRenderParams()
226 {
227 stagingRenderParams_ = std::make_unique<RSEffectRenderParams>(GetId());
228 DrawableV2::RSRenderNodeDrawableAdapter::OnGenerate(shared_from_this());
229 if (renderDrawable_ == nullptr) {
230 RS_LOGE("RSEffectRenderNode::InitRenderParams failed");
231 return;
232 }
233 }
234
MarkFilterHasEffectChildren()235 void RSEffectRenderNode::MarkFilterHasEffectChildren()
236 {
237 if (GetRenderProperties().GetBackgroundFilter() == nullptr) {
238 return;
239 }
240 auto effectParams = static_cast<RSEffectRenderParams*>(stagingRenderParams_.get());
241 if (effectParams == nullptr) {
242 return;
243 }
244 effectParams->SetHasEffectChildren(ChildHasVisibleEffect());
245 if (!RSProperties::FilterCacheEnabled) {
246 UpdateDirtySlotsAndPendingNodes(RSDrawableSlot::BACKGROUND_FILTER);
247 }
248 }
249
OnFilterCacheStateChanged()250 void RSEffectRenderNode::OnFilterCacheStateChanged()
251 {
252 auto filterDrawable = GetFilterDrawable(false);
253 auto effectParams = static_cast<RSEffectRenderParams*>(stagingRenderParams_.get());
254 if (filterDrawable == nullptr || effectParams == nullptr) {
255 return;
256 }
257 effectParams->SetCacheValid(filterDrawable->IsFilterCacheValid());
258 }
259
EffectNodeShouldPaint() const260 bool RSEffectRenderNode::EffectNodeShouldPaint() const
261 {
262 return ChildHasVisibleEffect();
263 }
264
FirstFrameHasEffectChildren() const265 bool RSEffectRenderNode::FirstFrameHasEffectChildren() const
266 {
267 RS_OPTIONAL_TRACE_NAME_FMT("RSEffectRenderNode[%llu]::FirstFrameHasEffectChildren lastHasVisibleEffect:%d,"
268 "hasVisibleEffect:%d", GetId(), lastFrameHasVisibleEffect_, ChildHasVisibleEffect());
269 return GetRenderProperties().GetBackgroundFilter() != nullptr &&
270 !lastFrameHasVisibleEffect_ && ChildHasVisibleEffect();
271 }
272
FirstFrameHasNoEffectChildren() const273 bool RSEffectRenderNode::FirstFrameHasNoEffectChildren() const
274 {
275 return GetRenderProperties().GetBackgroundFilter() != nullptr &&
276 !ChildHasVisibleEffect() && lastFrameHasVisibleEffect_;
277 }
278
MarkClearFilterCacheIfEffectChildrenChanged()279 void RSEffectRenderNode::MarkClearFilterCacheIfEffectChildrenChanged()
280 {
281 // the first frame node has no effect child, it should not be painted and filter cache need to be cleared.
282 auto filterDrawable = GetFilterDrawable(false);
283 if (filterDrawable == nullptr || filterDrawable->IsForceClearFilterCache()) {
284 return;
285 }
286 if (!FirstFrameHasEffectChildren() && !FirstFrameHasNoEffectChildren()) {
287 return;
288 }
289 filterDrawable->MarkFilterForceClearCache();
290 // the first frame node has no effect child, force use cache should be cancled.
291 if (filterDrawable->IsForceUseFilterCache()) {
292 filterDrawable->MarkFilterForceUseCache(false);
293 }
294 }
295 } // namespace Rosen
296 } // namespace OHOS
297