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 "render_node_default_shadows_blur.h"
17
18 #include <algorithm>
19
20 #include <3d/render/intf_render_data_store_default_light.h>
21 #include <core/log.h>
22 #include <core/namespace.h>
23 #include <render/datastore/intf_render_data_store_manager.h>
24 #include <render/device/intf_gpu_resource_manager.h>
25 #include <render/device/intf_shader_manager.h>
26 #include <render/device/pipeline_layout_desc.h>
27 #include <render/device/pipeline_state_desc.h>
28 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
29 #include <render/nodecontext/intf_node_context_pso_manager.h>
30 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
31 #include <render/nodecontext/intf_render_command_list.h>
32 #include <render/nodecontext/intf_render_node_context_manager.h>
33 #include <render/render_data_structures.h>
34 #include <render/resource_handle.h>
35
36 // shaders
37 #include <render/shaders/common/render_blur_common.h>
38 #include <render/shaders/common/render_post_process_structs_common.h>
39
40 CORE3D_BEGIN_NAMESPACE()
41 using namespace BASE_NS;
42 using namespace RENDER_NS;
43 namespace {
44 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
45 constexpr uint32_t MAX_LOOP_COUNT { 2u };
46 } // namespace
47
InitNode(IRenderNodeContextManager & renderNodeContextMgr)48 void RenderNodeDefaultShadowsBlur::InitNode(IRenderNodeContextManager& renderNodeContextMgr)
49 {
50 renderNodeContextMgr_ = &renderNodeContextMgr;
51
52 const auto& renderNodeGraphData = renderNodeContextMgr_->GetRenderNodeGraphData();
53 stores_ = RenderNodeSceneUtil::GetSceneRenderDataStores(
54 renderNodeContextMgr, renderNodeGraphData.renderNodeGraphDataStoreName);
55
56 const auto& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
57 shadowColorBufferHandle_ = gpuResourceMgr.GetImageHandle(
58 stores_.dataStoreNameScene + DefaultMaterialLightingConstants::SHADOW_VSM_COLOR_BUFFER_NAME);
59 samplerHandle_ = gpuResourceMgr.GetSamplerHandle("CORE_DEFAULT_SAMPLER_LINEAR_CLAMP");
60 bufferHandle_ = gpuResourceMgr.GetBufferHandle("CORE_DEFAULT_GPU_BUFFER");
61
62 const auto& shaderMgr = renderNodeContextMgr.GetShaderManager();
63 shaderData_ = {};
64 {
65 shaderData_.shaderHandle = shaderMgr.GetShaderHandle("rendershaders://shader/fullscreen_blur.shader");
66 const auto& reflPipelineLayout = shaderMgr.GetReflectionPipelineLayout(shaderData_.shaderHandle);
67 shaderData_.pushConstant = reflPipelineLayout.pushConstant;
68 }
69
70 CreateDescriptorSets();
71 }
72
PreExecuteFrame()73 void RenderNodeDefaultShadowsBlur::PreExecuteFrame()
74 {
75 shadowCount_ = 0U;
76
77 const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
78 const auto* dataStoreLight =
79 static_cast<IRenderDataStoreDefaultLight*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameLight));
80 if (dataStoreLight) {
81 const auto lightCounts = dataStoreLight->GetLightCounts();
82 shadowTypes_ = dataStoreLight->GetShadowTypes();
83 if (shadowTypes_.shadowType == IRenderDataStoreDefaultLight::ShadowType::VSM) {
84 if ((lightCounts.dirShadow > 0) || (lightCounts.spotShadow > 0)) {
85 // only run with VSM
86 shadowCount_ = lightCounts.dirShadow + lightCounts.spotShadow;
87
88 auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
89 GpuImageDesc shadowImageDesc = gpuResourceMgr.GetImageDescriptor(shadowColorBufferHandle_);
90 if ((shadowImageDesc.width != temporaryImage_.width) ||
91 (shadowImageDesc.height != temporaryImage_.height) ||
92 (shadowImageDesc.format != temporaryImage_.format) ||
93 (shadowImageDesc.sampleCountFlags != temporaryImage_.sampleCountFlags)) {
94 shadowImageDesc.imageViewType = CORE_IMAGE_VIEW_TYPE_2D;
95 shadowImageDesc.layerCount = 1u;
96 #if (CORE3D_VALIDATION_ENABLED == 1)
97 const string name = renderNodeContextMgr_->GetName() + "_ShadowTemporaryImage";
98 temporaryImage_.imageHandle = gpuResourceMgr.Create(name, shadowImageDesc);
99 #else
100 temporaryImage_.imageHandle = gpuResourceMgr.Create(temporaryImage_.imageHandle, shadowImageDesc);
101 #endif
102 temporaryImage_.width = shadowImageDesc.width;
103 temporaryImage_.height = shadowImageDesc.height;
104 temporaryImage_.format = shadowImageDesc.format;
105 temporaryImage_.sampleCountFlags = shadowImageDesc.sampleCountFlags;
106 }
107 }
108 }
109 }
110 }
111
GetExecuteFlags() const112 IRenderNode::ExecuteFlags RenderNodeDefaultShadowsBlur::GetExecuteFlags() const
113 {
114 // this node does only blurring for VSM and can be left out easily
115 if (shadowCount_ > 0U) {
116 return 0U;
117 } else {
118 return IRenderNode::ExecuteFlagBits::EXECUTE_FLAG_BITS_DO_NOT_EXECUTE;
119 }
120 }
121
ExecuteFrame(IRenderCommandList & cmdList)122 void RenderNodeDefaultShadowsBlur::ExecuteFrame(IRenderCommandList& cmdList)
123 {
124 const auto& renderDataStoreMgr = renderNodeContextMgr_->GetRenderDataStoreManager();
125 const auto* dataStoreLight =
126 static_cast<IRenderDataStoreDefaultLight*>(renderDataStoreMgr.GetRenderDataStore(stores_.dataStoreNameLight));
127 if (dataStoreLight) {
128 if (shadowTypes_.shadowType != IRenderDataStoreDefaultLight::ShadowType::VSM) {
129 return; // early out
130 }
131 // NOTE: try separating/overlapping different shadows
132 // first horizontal for all then vertical for all (-> less syncs)
133 const IRenderDataStoreDefaultLight::LightCounts lightCounts = dataStoreLight->GetLightCounts();
134 if ((lightCounts.dirShadow > 0) || (lightCounts.spotShadow > 0)) {
135 ExplicitInputBarrier(cmdList, shadowColorBufferHandle_);
136 }
137 if (lightCounts.dirShadow > 0) {
138 ProcessSingleShadow(cmdList, 0u, shadowColorBufferHandle_, temporaryImage_);
139 }
140 if (lightCounts.spotShadow > 0) {
141 ProcessSingleShadow(cmdList, 1u, shadowColorBufferHandle_, temporaryImage_);
142 }
143 }
144 }
145
ProcessSingleShadow(IRenderCommandList & cmdList,const uint32_t drawIdx,const RenderHandle imageHandle,const TemporaryImage & tempImage)146 void RenderNodeDefaultShadowsBlur::ProcessSingleShadow(IRenderCommandList& cmdList, const uint32_t drawIdx,
147 const RenderHandle imageHandle, const TemporaryImage& tempImage)
148 {
149 auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
150 if (gpuResourceMgr.IsGpuImage(imageHandle) && gpuResourceMgr.IsGpuImage(tempImage.imageHandle.GetHandle())) {
151 RenderPass renderPass;
152 renderPass.renderPassDesc.attachmentCount = 1u;
153 renderPass.renderPassDesc.renderArea = { 0, 0, tempImage.width, tempImage.height };
154 renderPass.renderPassDesc.subpassCount = 1u;
155 renderPass.renderPassDesc.attachments[0].layer = drawIdx;
156 renderPass.subpassStartIndex = 0;
157 auto& subpass = renderPass.subpassDesc;
158 subpass.colorAttachmentCount = 1u;
159 subpass.colorAttachmentIndices[0] = 0;
160
161 renderPass.renderPassDesc.attachments[0] = { 0, 0, AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_DONT_CARE,
162 AttachmentStoreOp::CORE_ATTACHMENT_STORE_OP_STORE, AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_DONT_CARE,
163 AttachmentStoreOp::CORE_ATTACHMENT_STORE_OP_DONT_CARE, ClearValue { ClearColorValue {} } };
164
165 if (!RenderHandleUtil::IsValid(shaderData_.psoHandle)) {
166 const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
167 const RenderHandle graphicsStateHandle =
168 shaderMgr.GetGraphicsStateHandleByShaderHandle(shaderData_.shaderHandle);
169 const auto& reflPipelineLayout = shaderMgr.GetReflectionPipelineLayout(shaderData_.shaderHandle);
170 const ShaderSpecializationConstantView sscv =
171 shaderMgr.GetReflectionSpecialization(shaderData_.shaderHandle);
172 const VertexInputDeclarationView vidv =
173 shaderMgr.GetReflectionVertexInputDeclaration(shaderData_.shaderHandle);
174 const uint32_t specializationFlags[] = { CORE_BLUR_TYPE_RG };
175 CORE_ASSERT(sscv.constants.size() == countof(specializationFlags));
176 const ShaderSpecializationConstantDataView specDataView { sscv.constants, specializationFlags };
177 auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
178 shaderData_.psoHandle = psoMgr.GetGraphicsPsoHandle(shaderData_.shaderHandle, graphicsStateHandle,
179 reflPipelineLayout, vidv, specDataView, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
180 }
181
182 const float fWidth = static_cast<float>(tempImage.width);
183 const float fHeight = static_cast<float>(tempImage.height);
184 const Math::Vec4 texSizeInvTexSize = { fWidth, fHeight, 1.0f / fWidth, 1.0f / fHeight };
185
186 const ViewportDesc viewport { 0.0f, 0.0f, fWidth, fHeight, 0.0f, 1.0f };
187 const ScissorDesc scissor { 0, 0, tempImage.width, tempImage.height };
188
189 RenderData(cmdList, renderPass, viewport, scissor, imageHandle, tempImage.imageHandle.GetHandle(), drawIdx,
190 texSizeInvTexSize);
191 }
192 }
193
RenderData(IRenderCommandList & cmdList,const RenderPass & renderPassBase,const ViewportDesc & viewport,const ScissorDesc & scissor,const RenderHandle inputHandle,const RenderHandle outputHandle,const uint32_t drawIdx,const Math::Vec4 texSizeInvTexSize)194 void RenderNodeDefaultShadowsBlur::RenderData(IRenderCommandList& cmdList, const RenderPass& renderPassBase,
195 const ViewportDesc& viewport, const ScissorDesc& scissor, const RenderHandle inputHandle,
196 const RenderHandle outputHandle, const uint32_t drawIdx, const Math::Vec4 texSizeInvTexSize)
197 {
198 RenderPass renderPass = renderPassBase;
199 uint32_t loopCount = 0;
200 if (shadowTypes_.shadowSmoothness == IRenderDataStoreDefaultLight::ShadowSmoothness::NORMAL) {
201 loopCount = 1U;
202 } else if (shadowTypes_.shadowSmoothness == IRenderDataStoreDefaultLight::ShadowSmoothness::SOFT) {
203 loopCount = 2U;
204 }
205
206 RenderHandle sets[2u] {};
207 {
208 auto& binder = *allDescriptorSets_.globalSet;
209 sets[0u] = binder.GetDescriptorSetHandle();
210 binder.ClearBindings();
211 uint32_t binding = 0u;
212 binder.BindBuffer(binding++, bufferHandle_, 0u);
213 binder.BindBuffer(binding++, bufferHandle_, 0u);
214 cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
215 }
216
217 for (uint32_t idx = 0; idx < loopCount; ++idx) {
218 const uint32_t descriptorSetIndex = (drawIdx * loopCount) + idx;
219 // horizontal
220 renderPass.renderPassDesc.attachmentHandles[0] = outputHandle;
221 RenderBlur(cmdList, renderPass, viewport, scissor, allDescriptorSets_.set1Horizontal[descriptorSetIndex],
222 texSizeInvTexSize, { 1.0f, 0.0f, 0.0f, 0.0f }, inputHandle);
223 ExplicitOutputBarrier(cmdList, inputHandle);
224 // vertical
225 renderPass.renderPassDesc.attachmentHandles[0] = inputHandle;
226 RenderBlur(cmdList, renderPass, viewport, scissor, allDescriptorSets_.set1Vertical[descriptorSetIndex],
227 texSizeInvTexSize, { 0.0f, 1.0f, 0.0f, 0.0f }, outputHandle);
228 }
229 }
230
RenderBlur(IRenderCommandList & cmdList,const RenderPass & renderPass,const ViewportDesc & viewport,const ScissorDesc & scissor,const IDescriptorSetBinder::Ptr & binder,const Math::Vec4 & texSizeInvTexSize,const Math::Vec4 & dir,const RenderHandle imageHandle)231 void RenderNodeDefaultShadowsBlur::RenderBlur(IRenderCommandList& cmdList, const RenderPass& renderPass,
232 const ViewportDesc& viewport, const ScissorDesc& scissor, const IDescriptorSetBinder::Ptr& binder,
233 const Math::Vec4& texSizeInvTexSize, const Math::Vec4& dir, const RenderHandle imageHandle)
234 {
235 RenderHandle sets[2u] {};
236 sets[0u] = allDescriptorSets_.globalSet->GetDescriptorSetHandle();
237
238 cmdList.BeginRenderPass(renderPass.renderPassDesc, renderPass.subpassStartIndex, renderPass.subpassDesc);
239 cmdList.SetDynamicStateViewport(viewport);
240 cmdList.SetDynamicStateScissor(scissor);
241 cmdList.BindPipeline(shaderData_.psoHandle);
242
243 {
244 auto& bind = *binder;
245 sets[1u] = bind.GetDescriptorSetHandle();
246 bind.ClearBindings();
247 bind.BindSampler(0, samplerHandle_);
248 bind.BindImage(1, imageHandle);
249
250 cmdList.UpdateDescriptorSet(bind.GetDescriptorSetHandle(), bind.GetDescriptorSetLayoutBindingResources());
251 }
252 cmdList.BindDescriptorSets(0u, sets);
253
254 const LocalPostProcessPushConstantStruct pc { texSizeInvTexSize, dir };
255 cmdList.PushConstant(shaderData_.pushConstant, reinterpret_cast<const uint8_t*>(&pc));
256
257 cmdList.Draw(3u, 1u, 0u, 0u);
258 cmdList.EndRenderPass();
259 }
260
ExplicitInputBarrier(IRenderCommandList & cmdList,const RenderHandle handle)261 void RenderNodeDefaultShadowsBlur::ExplicitInputBarrier(IRenderCommandList& cmdList, const RenderHandle handle)
262 {
263 const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
264 PipelineStageFlagBits::CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
265 ImageLayout::CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
266 const ImageSubresourceRange range { CORE_IMAGE_ASPECT_COLOR_BIT, 0,
267 PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
268 cmdList.CustomImageBarrier(handle, dst, range);
269
270 cmdList.AddCustomBarrierPoint();
271 }
272
ExplicitOutputBarrier(IRenderCommandList & cmdList,const RenderHandle handle)273 void RenderNodeDefaultShadowsBlur::ExplicitOutputBarrier(IRenderCommandList& cmdList, const RenderHandle handle)
274 {
275 const ImageResourceBarrier dst { AccessFlagBits::CORE_ACCESS_SHADER_READ_BIT,
276 PipelineStageFlagBits::CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
277 ImageLayout::CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
278 const ImageSubresourceRange range { CORE_IMAGE_ASPECT_COLOR_BIT, 0,
279 PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
280 cmdList.CustomImageBarrier(handle, dst, range);
281
282 cmdList.AddCustomBarrierPoint();
283 }
284
CreateDescriptorSets()285 void RenderNodeDefaultShadowsBlur::CreateDescriptorSets()
286 {
287 auto& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
288 const uint32_t descriptorSetCount = DefaultMaterialLightingConstants::MAX_SHADOW_COUNT * MAX_LOOP_COUNT;
289 {
290 const DescriptorCounts dc { {
291 { CORE_DESCRIPTOR_TYPE_SAMPLER, descriptorSetCount },
292 { CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, descriptorSetCount },
293 { CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2u }, // global set with two ubos
294 } };
295 descriptorSetMgr.ResetAndReserve(dc);
296 }
297
298 const auto& reflPipelineLayout =
299 renderNodeContextMgr_->GetShaderManager().GetReflectionPipelineLayout(shaderData_.shaderHandle);
300 const uint32_t descSetCount = descriptorSetCount / 2u;
301 allDescriptorSets_.set1Horizontal.resize(descSetCount);
302 allDescriptorSets_.set1Vertical.resize(descSetCount);
303 constexpr uint32_t globalSet = 0u;
304 constexpr uint32_t localSet = 1u;
305 {
306 const RenderHandle descriptorSetHandle = descriptorSetMgr.CreateDescriptorSet(globalSet, reflPipelineLayout);
307 allDescriptorSets_.globalSet = descriptorSetMgr.CreateDescriptorSetBinder(
308 descriptorSetHandle, reflPipelineLayout.descriptorSetLayouts[globalSet].bindings);
309 }
310 for (uint32_t idx = 0; idx < descSetCount; ++idx) {
311 {
312 const RenderHandle descriptorSetHandle = descriptorSetMgr.CreateDescriptorSet(localSet, reflPipelineLayout);
313 allDescriptorSets_.set1Horizontal[idx] = descriptorSetMgr.CreateDescriptorSetBinder(
314 descriptorSetHandle, reflPipelineLayout.descriptorSetLayouts[localSet].bindings);
315 }
316 {
317 const RenderHandle descriptorSetHandle = descriptorSetMgr.CreateDescriptorSet(localSet, reflPipelineLayout);
318 allDescriptorSets_.set1Vertical[idx] = descriptorSetMgr.CreateDescriptorSetBinder(
319 descriptorSetHandle, reflPipelineLayout.descriptorSetLayouts[localSet].bindings);
320 }
321 }
322 }
323
324 // for plugin / factory interface
Create()325 RENDER_NS::IRenderNode* RenderNodeDefaultShadowsBlur::Create()
326 {
327 return new RenderNodeDefaultShadowsBlur();
328 }
329
Destroy(IRenderNode * instance)330 void RenderNodeDefaultShadowsBlur::Destroy(IRenderNode* instance)
331 {
332 delete static_cast<RenderNodeDefaultShadowsBlur*>(instance);
333 }
334 CORE3D_END_NAMESPACE()
335