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