1 /*
2 * Copyright (c) 2024 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 "drawable/rs_effect_render_node_drawable.h"
17
18 #include "pipeline/render_thread/rs_uni_render_thread.h"
19 #include "platform/common/rs_log.h"
20 #ifdef SUBTREE_PARALLEL_ENABLE
21 #include "rs_parallel_manager.h"
22 #endif
23
24 namespace OHOS::Rosen::DrawableV2 {
25 RSEffectRenderNodeDrawable::Registrar RSEffectRenderNodeDrawable::instance_;
26
RSEffectRenderNodeDrawable(std::shared_ptr<const RSRenderNode> && node)27 RSEffectRenderNodeDrawable::RSEffectRenderNodeDrawable(std::shared_ptr<const RSRenderNode>&& node)
28 : RSRenderNodeDrawable(std::move(node))
29 {}
30
OnGenerate(std::shared_ptr<const RSRenderNode> node)31 RSRenderNodeDrawable::Ptr RSEffectRenderNodeDrawable::OnGenerate(std::shared_ptr<const RSRenderNode> node)
32 {
33 return new RSEffectRenderNodeDrawable(std::move(node));
34 }
35
OnDraw(Drawing::Canvas & canvas)36 void RSEffectRenderNodeDrawable::OnDraw(Drawing::Canvas& canvas)
37 {
38 #ifdef RS_ENABLE_GPU
39 if (RSUniRenderThread::GetCaptureParam().isSoloNodeUiCapture_) {
40 RS_LOGD("RSEffectRenderNodeDrawable::OnDraw node %{public}" PRIu64 " isSoloNodeUiCapture, skip", nodeId_);
41 return;
42 }
43 SetDrawSkipType(DrawSkipType::NONE);
44 if (!ShouldPaint()) {
45 SetDrawSkipType(DrawSkipType::SHOULD_NOT_PAINT);
46 return;
47 }
48
49 RS_LOGD("RSEffectRenderNodeDrawable::OnDraw node: %{public}" PRIu64, nodeId_);
50 auto effectParams = static_cast<RSEffectRenderParams*>(GetRenderParams().get());
51 if (!effectParams) {
52 SetDrawSkipType(DrawSkipType::RENDER_PARAMS_NULL);
53 RS_LOGE("RSSurfaceRenderNodeDrawable::OnDraw params is nullptr");
54 return;
55 }
56 Drawing::GPUResourceTag::SetCurrentNodeId(GetId());
57 auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(&canvas);
58 RSAutoCanvasRestore acr(paintFilterCanvas, RSPaintFilterCanvas::SaveType::kAll);
59
60 paintFilterCanvas->SetEffectIntersectWithDRM(effectParams->GetEffectIntersectWithDRM());
61 paintFilterCanvas->SetDarkColorMode(effectParams->GetDarkColorMode());
62
63 effectParams->ApplyAlphaAndMatrixToCanvas(*paintFilterCanvas);
64 auto& uniParam = RSUniRenderThread::Instance().GetRSRenderThreadParams();
65 SetOcclusionCullingEnabled((!uniParam || uniParam->IsOpDropped()) && GetOpDropped());
66 if (IsOcclusionCullingEnabled() && QuickReject(canvas, effectParams->GetLocalDrawRect())) {
67 SetDrawSkipType(DrawSkipType::OCCLUSION_SKIP);
68 return;
69 }
70
71 #ifdef SUBTREE_PARALLEL_ENABLE
72 if (paintFilterCanvas->IsQuickGetDrawState()) {
73 RSParallelManager::Singleton().OnQuickDraw(this, canvas, false);
74 return;
75 }
76 #endif
77
78 const Drawing::Rect& bounds = effectParams->GetFrameRect();
79
80 RSRenderNodeSingleDrawableLocker singleLocker(this);
81 if (UNLIKELY(!singleLocker.IsLocked())) {
82 singleLocker.DrawableOnDrawMultiAccessEventReport(__func__);
83 RS_LOGE("RSEffectRenderNodeDrawable::OnDraw node %{public}" PRIu64 " onDraw!!!", GetId());
84 if (RSSystemProperties::GetSingleDrawableLockerEnabled()) {
85 SetDrawSkipType(DrawSkipType::MULTI_ACCESS);
86 return;
87 }
88 }
89
90 if (!GenerateEffectDataOnDemand(effectParams, canvas, bounds, paintFilterCanvas)) {
91 SetDrawSkipType(DrawSkipType::GENERATE_EFFECT_DATA_ON_DEMAND_FAIL);
92 return;
93 }
94
95 RSRenderNodeDrawableAdapter::DrawImpl(canvas, bounds, drawCmdIndex_.childrenIndex_);
96 #endif
97 }
98
GenerateEffectDataOnDemand(RSEffectRenderParams * effectParams,Drawing::Canvas & canvas,const Drawing::Rect & bounds,RSPaintFilterCanvas * paintFilterCanvas)99 bool RSEffectRenderNodeDrawable::GenerateEffectDataOnDemand(RSEffectRenderParams* effectParams,
100 Drawing::Canvas& canvas, const Drawing::Rect& bounds, RSPaintFilterCanvas* paintFilterCanvas)
101 {
102 #ifdef RS_ENABLE_GPU
103 if (drawCmdIndex_.childrenIndex_ == -1) {
104 // case 0: No children, skip
105 return false;
106 } else if (drawCmdIndex_.backgroundFilterIndex_ == -1 ||
107 !(RSSystemProperties::GetEffectMergeEnabled() && RSFilterCacheManager::isCCMEffectMergeEnable_) ||
108 (!effectParams->GetHasEffectChildren() && !canvas.GetUICapture())) {
109 // case 1: no blur or no need to blur, do nothing
110 } else if (drawCmdIndex_.backgroundImageIndex_ == -1 || effectParams->GetCacheValid()) {
111 // case 2: dynamic blur, blur the underlay content
112 // case 3a: static blur with valid cache, reuse cache
113 Drawing::AutoCanvasRestore acr(canvas, true);
114 canvas.ClipIRect(Drawing::RectI(0, 0, bounds.GetWidth(), bounds.GetHeight()));
115 RSRenderNodeDrawableAdapter::DrawImpl(canvas, bounds, drawCmdIndex_.backgroundFilterIndex_);
116 } else {
117 // case 3b: static blur without valid cache, draw background image and blur
118 Drawing::AutoCanvasRestore acr(canvas, true);
119 canvas.ClipIRect(Drawing::RectI(0, 0, bounds.GetWidth(), bounds.GetHeight()));
120 auto surface = canvas.GetSurface();
121 if (!surface) {
122 ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundImageAsEffect surface is null");
123 return false;
124 }
125 // extract clip bounds
126 auto currentRect = canvas.GetDeviceClipBounds();
127 // create offscreen surface
128 auto offscreenSurface = surface->MakeSurface(currentRect.GetWidth(), currentRect.GetHeight());
129 if (!offscreenSurface) {
130 ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundImageAsEffect offscreenSurface is null");
131 return false;
132 }
133 auto offscreenCanvas = std::make_unique<RSPaintFilterCanvas>(offscreenSurface.get());
134 if (!offscreenCanvas || !paintFilterCanvas) {
135 return false;
136 }
137 // copy current matrix to offscreen canvas, while aligned with current rect
138 auto currentMatrix = canvas.GetTotalMatrix();
139 currentMatrix.PostTranslate(-currentRect.GetLeft(), -currentRect.GetTop());
140 offscreenCanvas->SetMatrix(currentMatrix);
141 // draw background image and blur
142 RSRenderNodeDrawableAdapter::DrawImpl(*offscreenCanvas, bounds, drawCmdIndex_.backgroundImageIndex_);
143 RSRenderNodeDrawableAdapter::DrawImpl(*offscreenCanvas, bounds, drawCmdIndex_.backgroundFilterIndex_);
144 // copy effect data from offscreen canvas to current canvas, aligned with current rect
145 if (auto effectData = offscreenCanvas->GetEffectData()) {
146 effectData->cachedRect_.Offset(currentRect.GetLeft(), currentRect.GetTop());
147 paintFilterCanvas->SetEffectData(effectData);
148 }
149 }
150 return true;
151 #else
152 return false;
153 #endif
154 }
155
OnCapture(Drawing::Canvas & canvas)156 void RSEffectRenderNodeDrawable::OnCapture(Drawing::Canvas& canvas)
157 {
158 auto& captureParam = RSUniRenderThread::GetCaptureParam();
159 bool stopDrawForRangeCapture = (canvas.GetUICapture() &&
160 captureParam.endNodeId_ == GetId() &&
161 captureParam.endNodeId_ != INVALID_NODEID);
162 if (stopDrawForRangeCapture) {
163 return;
164 }
165 if (RSRenderNodeDrawable::DealWithWhiteListNodes(canvas)) {
166 return;
167 }
168 RSEffectRenderNodeDrawable::OnDraw(canvas);
169 }
170 } // namespace OHOS::Rosen::DrawableV2
171