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