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