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