1 /*
2 * Copyright (c) 2022 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 "render_post_process_flare_node.h"
17
18 #include <base/containers/unique_ptr.h>
19 #include <base/math/matrix_util.h>
20 #include <core/log.h>
21 #include <core/property/property_handle_util.h>
22 #include <core/property_tools/property_api_impl.inl>
23 #include <render/device/intf_gpu_resource_manager.h>
24 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
25 #include <render/nodecontext/intf_node_context_pso_manager.h>
26 #include <render/nodecontext/intf_render_command_list.h>
27 #include <render/nodecontext/intf_render_node_context_manager.h>
28 #include <render/nodecontext/intf_render_node_parser_util.h>
29 #include <render/nodecontext/intf_render_node_util.h>
30 #include <render/property/property_types.h>
31
32 #include "default_engine_constants.h"
33 #include "postprocesses/render_post_process_flare.h"
34 #include "util/log.h"
35
36 using namespace BASE_NS;
37 using namespace CORE_NS;
38 using namespace RENDER_NS;
39
40 CORE_BEGIN_NAMESPACE()
41 DATA_TYPE_METADATA(RenderPostProcessFlareNode::NodeInputs, MEMBER_PROPERTY(input, "input", 0))
42 DATA_TYPE_METADATA(RenderPostProcessFlareNode::NodeOutputs, MEMBER_PROPERTY(output, "output", 0))
43 CORE_END_NAMESPACE()
44
45 RENDER_BEGIN_NAMESPACE()
46 namespace {
47 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
48
49 constexpr string_view SHADER_NAME { "rendershaders://shader/fullscreen_flare.shader" };
50
GetImageRenderArea(const IRenderNodeGpuResourceManager & gpuResourceMgr,const RenderHandle handle)51 RenderPassDesc::RenderArea GetImageRenderArea(
52 const IRenderNodeGpuResourceManager& gpuResourceMgr, const RenderHandle handle)
53 {
54 const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(handle);
55 return { 0U, 0U, desc.width, desc.height };
56 }
57 } // namespace
58
RenderPostProcessFlareNode()59 RenderPostProcessFlareNode::RenderPostProcessFlareNode()
60 : inputProperties_(
61 &nodeInputsData, array_view(PropertyType::DataType<RenderPostProcessFlareNode::NodeInputs>::properties)),
62 outputProperties_(
63 &nodeOutputsData, array_view(PropertyType::DataType<RenderPostProcessFlareNode::NodeOutputs>::properties))
64
65 {}
66
GetRenderInputProperties()67 IPropertyHandle* RenderPostProcessFlareNode::GetRenderInputProperties()
68 {
69 return inputProperties_.GetData();
70 }
71
GetRenderOutputProperties()72 IPropertyHandle* RenderPostProcessFlareNode::GetRenderOutputProperties()
73 {
74 return outputProperties_.GetData();
75 }
76
GetRenderDescriptorCounts() const77 DescriptorCounts RenderPostProcessFlareNode::GetRenderDescriptorCounts() const
78 {
79 return descriptorCounts_;
80 }
81
SetRenderAreaRequest(const RenderAreaRequest & renderAreaRequest)82 void RenderPostProcessFlareNode::SetRenderAreaRequest(const RenderAreaRequest& renderAreaRequest)
83 {
84 useRequestedRenderArea_ = true;
85 renderAreaRequest_ = renderAreaRequest;
86 }
87
Init(const IRenderPostProcess::Ptr & postProcess,IRenderNodeContextManager & renderNodeContextMgr)88 void RenderPostProcessFlareNode::Init(
89 const IRenderPostProcess::Ptr& postProcess, IRenderNodeContextManager& renderNodeContextMgr)
90 {
91 // clear
92 pipelineData_ = {};
93
94 renderNodeContextMgr_ = &renderNodeContextMgr;
95 postProcess_ = postProcess;
96
97 // default inputs
98 IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
99 defaultInput_.handle = gpuResourceMgr.GetImageHandle("CORE_DEFAULT_GPU_IMAGE");
100 defaultInput_.samplerHandle = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_CLAMP");
101
102 // load shaders
103 const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
104 pipelineData_.gsd = shaderMgr.GetGraphicsShaderDataByShaderHandle(shaderMgr.GetShaderHandle(SHADER_NAME));
105
106 // create psos
107 INodeContextPsoManager& psoMgr = renderNodeContextMgr_->GetPsoManager();
108 pipelineData_.pso = psoMgr.GetGraphicsPsoHandle(pipelineData_.gsd, {}, DYNAMIC_STATES);
109
110 // get needed descriptor set counts
111 const IRenderNodeUtil& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
112 descriptorCounts_ = renderNodeUtil.GetDescriptorCounts(pipelineData_.gsd.pipelineLayoutData);
113
114 valid_ = true;
115 }
116
PreExecute()117 void RenderPostProcessFlareNode::PreExecute()
118 {
119 if (valid_ && postProcess_) {
120 const array_view<const uint8_t> propertyView = postProcess_->GetData();
121 // this node is directly dependant
122 PLUGIN_ASSERT(propertyView.size_bytes() == sizeof(RenderPostProcessFlareNode::EffectProperties));
123 if (propertyView.size_bytes() == sizeof(RenderPostProcessFlareNode::EffectProperties)) {
124 effectProperties_ = (const RenderPostProcessFlareNode::EffectProperties&)(*propertyView.data());
125 }
126 } else {
127 effectProperties_.enabled = false;
128 }
129
130 if (effectProperties_.enabled) {
131 // check input and output
132 EvaluateOutput();
133 }
134 }
135
GetExecuteFlags() const136 IRenderNode::ExecuteFlags RenderPostProcessFlareNode::GetExecuteFlags() const
137 {
138 if (effectProperties_.enabled) {
139 return 0;
140 } else {
141 return IRenderNode::ExecuteFlagBits::EXECUTE_FLAG_BITS_DO_NOT_EXECUTE;
142 }
143 }
144
Execute(IRenderCommandList & cmdList)145 void RenderPostProcessFlareNode::Execute(IRenderCommandList& cmdList)
146 {
147 CORE_ASSERT(effectProperties_.enabled);
148
149 EvaluateOutput();
150
151 RENDER_DEBUG_MARKER_COL_SCOPE(cmdList, "RenderLensFlare", DefaultDebugConstants::CORE_DEFAULT_DEBUG_COLOR);
152
153 BindableImage currOutput = nodeOutputsData.output;
154 if (!RenderHandleUtil::IsValid(currOutput.handle)) {
155 return;
156 }
157 // update the output
158 nodeOutputsData.output = currOutput;
159
160 const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
161 const RenderPassDesc::RenderArea renderArea =
162 useRequestedRenderArea_ ? renderAreaRequest_.area : GetImageRenderArea(gpuResourceMgr, currOutput.handle);
163 if ((renderArea.extentWidth == 0) || (renderArea.extentHeight == 0)) {
164 return;
165 }
166
167 // render
168 RenderPass renderPass;
169 renderPass.renderPassDesc.attachmentCount = 1;
170 renderPass.renderPassDesc.renderArea = renderArea;
171 renderPass.renderPassDesc.subpassCount = 1;
172 renderPass.renderPassDesc.attachments[0].loadOp = CORE_ATTACHMENT_LOAD_OP_LOAD;
173 renderPass.renderPassDesc.attachments[0].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
174 renderPass.renderPassDesc.attachmentHandles[0] = { currOutput.handle };
175 renderPass.subpassStartIndex = 0;
176 auto& subpass = renderPass.subpassDesc;
177 subpass.colorAttachmentCount = 1;
178 subpass.colorAttachmentIndices[0] = 0;
179
180 cmdList.BeginRenderPass(renderPass.renderPassDesc, 0U, renderPass.subpassDesc);
181
182 // dynamic state
183 const auto& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
184 cmdList.SetDynamicStateViewport(renderNodeUtil.CreateDefaultViewport(renderPass));
185 cmdList.SetDynamicStateScissor(renderNodeUtil.CreateDefaultScissor(renderPass));
186
187 // bind pso
188 cmdList.BindPipeline(pipelineData_.pso);
189
190 if (pipelineData_.gsd.pipelineLayoutData.pushConstant.byteSize > 0U) {
191 const PushConstantStruct pc = GetPushDataStruct(renderArea.extentWidth, renderArea.extentHeight);
192 cmdList.PushConstantData(pipelineData_.gsd.pipelineLayoutData.pushConstant, arrayviewU8(pc));
193 }
194
195 // draw
196 cmdList.Draw(3U, 1U, 0U, 0U);
197
198 cmdList.EndRenderPass();
199 }
200
GetPushDataStruct(const uint32_t width,const uint32_t height) const201 RenderPostProcessFlareNode::PushConstantStruct RenderPostProcessFlareNode::GetPushDataStruct(
202 const uint32_t width, const uint32_t height) const
203 {
204 const Math::Vec3 flarePos = effectProperties_.flarePos;
205 float intensity = effectProperties_.intensity;
206 // NOTE: the shader is currently still run even though the intensity is zero
207 // signed culling for z
208 if ((flarePos.x < 0.0f) || (flarePos.x > 1.0f) || (flarePos.y < 0.0f) || (flarePos.y > 1.0f) ||
209 (flarePos.z < 0.0f)) {
210 intensity = 0.0f;
211 }
212
213 const float time = renderNodeContextMgr_->GetRenderNodeGraphData().renderingConfiguration.renderTimings.z;
214 PushConstantStruct pcV { { time, flarePos.x, flarePos.y, flarePos.z },
215 { static_cast<float>(width), static_cast<float>(height), intensity, 0.0f } };
216
217 return pcV;
218 }
219
EvaluateOutput()220 void RenderPostProcessFlareNode::EvaluateOutput()
221 {
222 if (RenderHandleUtil::IsValid(nodeInputsData.input.handle)) {
223 nodeOutputsData.output = nodeInputsData.input;
224 }
225 }
226 RENDER_END_NAMESPACE()
227