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/rs_uni_render_thread.h"
19 #include "platform/common/rs_log.h"
20
21 namespace OHOS::Rosen::DrawableV2 {
22 RSEffectRenderNodeDrawable::Registrar RSEffectRenderNodeDrawable::instance_;
23
RSEffectRenderNodeDrawable(std::shared_ptr<const RSRenderNode> && node)24 RSEffectRenderNodeDrawable::RSEffectRenderNodeDrawable(std::shared_ptr<const RSRenderNode>&& node)
25 : RSRenderNodeDrawable(std::move(node))
26 {}
27
OnGenerate(std::shared_ptr<const RSRenderNode> node)28 RSRenderNodeDrawable::Ptr RSEffectRenderNodeDrawable::OnGenerate(std::shared_ptr<const RSRenderNode> node)
29 {
30 return new RSEffectRenderNodeDrawable(std::move(node));
31 }
32
OnDraw(Drawing::Canvas & canvas)33 void RSEffectRenderNodeDrawable::OnDraw(Drawing::Canvas& canvas)
34 {
35 SetDrawSkipType(DrawSkipType::NONE);
36 if (!ShouldPaint()) {
37 SetDrawSkipType(DrawSkipType::SHOULD_NOT_PAINT);
38 return;
39 }
40
41 RS_LOGD("RSEffectRenderNodeDrawable::OnDraw node: %{public}" PRIu64, nodeId_);
42 auto effectParams = static_cast<RSEffectRenderParams*>(GetRenderParams().get());
43 if (!effectParams) {
44 SetDrawSkipType(DrawSkipType::RENDER_PARAMS_NULL);
45 RS_LOGE("RSSurfaceRenderNodeDrawable::OnDraw params is nullptr");
46 return;
47 }
48 auto paintFilterCanvas = static_cast<RSPaintFilterCanvas*>(&canvas);
49 RSAutoCanvasRestore acr(paintFilterCanvas, RSPaintFilterCanvas::SaveType::kAll);
50
51 effectParams->ApplyAlphaAndMatrixToCanvas(*paintFilterCanvas);
52 auto& uniParam = RSUniRenderThread::Instance().GetRSRenderThreadParams();
53 if ((UNLIKELY(!uniParam) || uniParam->IsOpDropped()) && GetOpDropped() &&
54 QuickReject(canvas, effectParams->GetLocalDrawRect())) {
55 SetDrawSkipType(DrawSkipType::OCCLUSION_SKIP);
56 return;
57 }
58 const Drawing::Rect& bounds = effectParams->GetFrameRect();
59
60 if (!GenerateEffectDataOnDemand(effectParams, canvas, bounds, paintFilterCanvas)) {
61 SetDrawSkipType(DrawSkipType::GENERATE_EFFECT_DATA_ON_DEMAND_FAIL);
62 return;
63 }
64
65 RSRenderNodeSingleDrawableLocker singleLocker(this);
66 if (UNLIKELY(!singleLocker.IsLocked())) {
67 SetDrawSkipType(DrawSkipType::MULTI_ACCESS);
68 singleLocker.DrawableOnDrawMultiAccessEventReport(__func__);
69 RS_LOGE("RSEffectRenderNodeDrawable::OnDraw node %{public}" PRIu64 " onDraw!!!", GetId());
70 return;
71 }
72 RSRenderNodeDrawableAdapter::DrawImpl(canvas, bounds, drawCmdIndex_.childrenIndex_);
73 }
74
GenerateEffectDataOnDemand(RSEffectRenderParams * effectParams,Drawing::Canvas & canvas,const Drawing::Rect & bounds,RSPaintFilterCanvas * paintFilterCanvas)75 bool RSEffectRenderNodeDrawable::GenerateEffectDataOnDemand(RSEffectRenderParams* effectParams,
76 Drawing::Canvas& canvas, const Drawing::Rect& bounds, RSPaintFilterCanvas* paintFilterCanvas)
77 {
78 if (drawCmdIndex_.childrenIndex_ == -1) {
79 // case 0: No children, skip
80 return false;
81 } else if (drawCmdIndex_.backgroundFilterIndex_ == -1 || !RSSystemProperties::GetEffectMergeEnabled() ||
82 !effectParams->GetHasEffectChildren()) {
83 // case 1: no blur or no need to blur, do nothing
84 } else if (drawCmdIndex_.backgroundImageIndex_ == -1 || effectParams->GetCacheValid()) {
85 // case 2: dynamic blur, blur the underlay content
86 // case 3a: static blur with valid cache, reuse cache
87 Drawing::AutoCanvasRestore acr(canvas, true);
88 canvas.ClipIRect(Drawing::RectI(0, 0, bounds.GetWidth(), bounds.GetHeight()));
89 RSRenderNodeDrawableAdapter::DrawImpl(canvas, bounds, drawCmdIndex_.backgroundFilterIndex_);
90 } else {
91 // case 3b: static blur without valid cache, draw background image and blur
92 Drawing::AutoCanvasRestore acr(canvas, true);
93 canvas.ClipIRect(Drawing::RectI(0, 0, bounds.GetWidth(), bounds.GetHeight()));
94 auto surface = canvas.GetSurface();
95 if (!surface) {
96 ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundImageAsEffect surface is null");
97 return false;
98 }
99 // extract clip bounds
100 auto currentRect = canvas.GetDeviceClipBounds();
101 // create offscreen surface
102 auto offscreenSurface = surface->MakeSurface(currentRect.GetWidth(), currentRect.GetHeight());
103 if (!offscreenSurface) {
104 ROSEN_LOGE("RSPropertiesPainter::DrawBackgroundImageAsEffect offscreenSurface is null");
105 return false;
106 }
107 auto offscreenCanvas = std::make_unique<RSPaintFilterCanvas>(offscreenSurface.get());
108 // copy current matrix to offscreen canvas, while aligned with current rect
109 auto currentMatrix = canvas.GetTotalMatrix();
110 currentMatrix.PostTranslate(-currentRect.GetLeft(), -currentRect.GetTop());
111 offscreenCanvas->SetMatrix(currentMatrix);
112 // draw background image and blur
113 RSRenderNodeDrawableAdapter::DrawImpl(*offscreenCanvas, bounds, drawCmdIndex_.backgroundImageIndex_);
114 RSRenderNodeDrawableAdapter::DrawImpl(*offscreenCanvas, bounds, drawCmdIndex_.backgroundFilterIndex_);
115 // copy effect data from offscreen canvas to current canvas, aligned with current rect
116 if (auto effectData = offscreenCanvas->GetEffectData()) {
117 effectData->cachedRect_.Offset(currentRect.GetLeft(), currentRect.GetTop());
118 paintFilterCanvas->SetEffectData(effectData);
119 }
120 }
121 return true;
122 }
123
OnCapture(Drawing::Canvas & canvas)124 void RSEffectRenderNodeDrawable::OnCapture(Drawing::Canvas& canvas)
125 {
126 RSEffectRenderNodeDrawable::OnDraw(canvas);
127 }
128 } // namespace OHOS::Rosen::DrawableV2
129