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