• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_blur_node.h"
17 
18 #include <base/math/mathf.h>
19 #include <core/property/property_handle_util.h>
20 #include <core/property/property_types.h>
21 #include <core/property_tools/property_api_impl.inl>
22 #include <render/device/intf_gpu_resource_manager.h>
23 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
24 #include <render/nodecontext/intf_node_context_pso_manager.h>
25 #include <render/nodecontext/intf_render_command_list.h>
26 #include <render/nodecontext/intf_render_node_context_manager.h>
27 #include <render/nodecontext/intf_render_node_parser_util.h>
28 #include <render/nodecontext/intf_render_node_util.h>
29 #include <render/property/property_types.h>
30 
31 #include "default_engine_constants.h"
32 #include "device/gpu_resource_handle_util.h"
33 #include "render/shaders/common/render_post_process_structs_common.h"
34 #include "render_post_process_blur.h"
35 #include "util/log.h"
36 
37 using namespace BASE_NS;
38 using namespace CORE_NS;
39 using namespace RENDER_NS;
40 
41 CORE_BEGIN_NAMESPACE()
42 DATA_TYPE_METADATA(RenderPostProcessBlurNode::NodeInputs, MEMBER_PROPERTY(input, "input", 0))
43 DATA_TYPE_METADATA(RenderPostProcessBlurNode::NodeOutputs, MEMBER_PROPERTY(output, "output", 0))
44 CORE_END_NAMESPACE()
45 
46 RENDER_BEGIN_NAMESPACE()
47 namespace {
48 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
49 
50 constexpr string_view SHADER_NAME { "rendershaders://shader/fullscreen_blur.shader" };
51 constexpr uint32_t MAX_MIP_COUNT { 16U };
52 constexpr uint32_t MAX_PASS_PER_LEVEL_COUNT { 3U };
53 constexpr uint32_t MAX_BINDER_COUNT = MAX_MIP_COUNT * MAX_PASS_PER_LEVEL_COUNT;
54 
GetImageRenderArea(const IRenderNodeGpuResourceManager & gpuResourceMgr,const RenderHandle handle)55 RenderPassDesc::RenderArea GetImageRenderArea(
56     const IRenderNodeGpuResourceManager& gpuResourceMgr, const RenderHandle handle)
57 {
58     const GpuImageDesc desc = gpuResourceMgr.GetImageDescriptor(handle);
59     return { 0U, 0U, desc.width, desc.height };
60 }
61 } // namespace
62 
RenderPostProcessBlurNode()63 RenderPostProcessBlurNode::RenderPostProcessBlurNode()
64     : inputProperties_(
65           &nodeInputsData, array_view(PropertyType::DataType<RenderPostProcessBlurNode::NodeInputs>::properties)),
66       outputProperties_(
67           &nodeOutputsData, array_view(PropertyType::DataType<RenderPostProcessBlurNode::NodeOutputs>::properties))
68 
69 {}
70 
GetRenderInputProperties()71 IPropertyHandle* RenderPostProcessBlurNode::GetRenderInputProperties()
72 {
73     return inputProperties_.GetData();
74 }
75 
GetRenderOutputProperties()76 IPropertyHandle* RenderPostProcessBlurNode::GetRenderOutputProperties()
77 {
78     return outputProperties_.GetData();
79 }
80 
GetRenderDescriptorCounts() const81 DescriptorCounts RenderPostProcessBlurNode::GetRenderDescriptorCounts() const
82 {
83     return descriptorCounts_;
84 }
85 
SetRenderAreaRequest(const RenderAreaRequest & renderAreaRequest)86 void RenderPostProcessBlurNode::SetRenderAreaRequest(const RenderAreaRequest& renderAreaRequest)
87 {
88     useRequestedRenderArea_ = true;
89     renderAreaRequest_ = renderAreaRequest;
90 }
91 
Init(const IRenderPostProcess::Ptr & postProcess,IRenderNodeContextManager & renderNodeContextMgr)92 void RenderPostProcessBlurNode::Init(
93     const IRenderPostProcess::Ptr& postProcess, IRenderNodeContextManager& renderNodeContextMgr)
94 {
95     // clear
96     pipelineData_ = {};
97     binders_.clear();
98 
99     renderNodeContextMgr_ = &renderNodeContextMgr;
100     postProcess_ = postProcess;
101 
102     // default inputs
103     IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
104     defaultInput_.handle = gpuResourceMgr.GetImageHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_GPU_IMAGE);
105     defaultInput_.samplerHandle =
106         gpuResourceMgr.GetSamplerHandle(DefaultEngineGpuResourceConstants::CORE_DEFAULT_SAMPLER_LINEAR_CLAMP);
107 
108     // load shaders
109     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
110     pipelineData_.gsd = shaderMgr.GetGraphicsShaderDataByShaderHandle(shaderMgr.GetShaderHandle(SHADER_NAME));
111 
112     // get needed descriptor set counts
113     const IRenderNodeUtil& renderNodeUtil = renderNodeContextMgr_->GetRenderNodeUtil();
114     descriptorCounts_ = renderNodeUtil.GetDescriptorCounts(pipelineData_.gsd.pipelineLayoutData);
115     for (auto& ref : descriptorCounts_.counts) {
116         ref.count *= MAX_BINDER_COUNT;
117     }
118 
119     valid_ = true;
120 }
121 
PreExecute()122 void RenderPostProcessBlurNode::PreExecute()
123 {
124     if (valid_ && postProcess_) {
125         const array_view<const uint8_t> propertyView = postProcess_->GetData();
126         // this node is directly dependant
127         PLUGIN_ASSERT(propertyView.size_bytes() == sizeof(RenderPostProcessBlurNode::EffectProperties));
128         if (propertyView.size_bytes() == sizeof(RenderPostProcessBlurNode::EffectProperties)) {
129             effectProperties_ = (const RenderPostProcessBlurNode::EffectProperties&)(*propertyView.data());
130         }
131     } else {
132         effectProperties_.enabled = false;
133     }
134 
135     if (effectProperties_.enabled) {
136         // check input and output
137         const bool valid = EvaluateInOut();
138         if (valid) {
139             EvaluateTemporaryTargets();
140             mipsBlur = (nodeInputsData.input.handle == nodeOutputsData.output.handle) ||
141                        ((effectProperties_.blurConfiguration.maxMipLevel != 0U) &&
142                            (effectProperties_.blurConfiguration.filterSize == 1.0f));
143         }
144         valid_ = valid && effectProperties_.enabled;
145     }
146 }
147 
GetExecuteFlags() const148 IRenderNode::ExecuteFlags RenderPostProcessBlurNode::GetExecuteFlags() const
149 {
150     if (effectProperties_.enabled) {
151         return 0;
152     } else {
153         return IRenderNode::ExecuteFlagBits::EXECUTE_FLAG_BITS_DO_NOT_EXECUTE;
154     }
155 }
156 
Execute(IRenderCommandList & cmdList)157 void RenderPostProcessBlurNode::Execute(IRenderCommandList& cmdList)
158 {
159     PLUGIN_ASSERT(effectProperties_.enabled);
160     if (!valid_) {
161         return;
162     }
163 
164     CheckDescriptorSetNeed();
165 
166     RENDER_DEBUG_MARKER_COL_SCOPE(cmdList, "RenderBlur", DefaultDebugConstants::CORE_DEFAULT_DEBUG_COLOR);
167 
168     if (binders_.empty()) {
169         return;
170     }
171 
172     BindableImage currOutput = nodeOutputsData.output;
173     if (!RenderHandleUtil::IsValid(currOutput.handle)) {
174         return;
175     }
176     // get the property values
177 
178     // update the output
179     nodeOutputsData.output = currOutput;
180 
181     const IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
182     const RenderPassDesc::RenderArea imageArea = GetImageRenderArea(gpuResourceMgr, currOutput.handle);
183     const RenderPassDesc::RenderArea renderArea = useRequestedRenderArea_ ? renderAreaRequest_.area : imageArea;
184     if ((renderArea.extentWidth == 0) || (renderArea.extentHeight == 0)) {
185         return;
186     }
187 
188     RenderPass renderPass;
189     renderPass.renderPassDesc.attachmentCount = 1;
190     renderPass.renderPassDesc.renderArea = { 0, 0, imageArea.extentWidth, imageArea.extentHeight };
191     renderPass.renderPassDesc.subpassCount = 1;
192     renderPass.renderPassDesc.attachments[0].loadOp = CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
193     renderPass.renderPassDesc.attachments[0].storeOp = CORE_ATTACHMENT_STORE_OP_STORE;
194     renderPass.renderPassDesc.attachmentHandles[0] = currOutput.handle;
195     renderPass.subpassStartIndex = 0;
196     auto& subpass = renderPass.subpassDesc;
197     subpass.colorAttachmentCount = 1;
198     subpass.colorAttachmentIndices[0] = 0;
199 
200     if (!RenderHandleUtil::IsValid(pipelineData_.psoScale)) {
201         const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
202         auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
203         const ShaderSpecializationConstantView sscv = shaderMgr.GetReflectionSpecialization(pipelineData_.gsd.shader);
204         {
205             const uint32_t specializationFlags[] = { effectProperties_.blurShaderScaleType };
206             const ShaderSpecializationConstantDataView specDataView { sscv.constants, specializationFlags };
207             pipelineData_.psoScale = psoMgr.GetGraphicsPsoHandle(
208                 pipelineData_.gsd, specDataView, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
209         }
210         {
211             const uint32_t specializationFlags[] = { effectProperties_.blurShaderType };
212             const ShaderSpecializationConstantDataView specDataView { sscv.constants, specializationFlags };
213             pipelineData_.psoBlur = psoMgr.GetGraphicsPsoHandle(
214                 pipelineData_.gsd, specDataView, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
215         }
216     }
217     if (mipsBlur) {
218         if (effectProperties_.blurConfiguration.blurType == BlurConfiguration::BlurType::TYPE_NORMAL) {
219             RenderGaussian(cmdList, renderPass);
220         } else {
221             RenderDirectionalBlur(cmdList, renderPass);
222         }
223     } else {
224         RenderData(cmdList, renderPass);
225     }
226 }
227 
228 // constants for RenderBlur::RenderData
229 namespace {
230 constexpr bool USE_CUSTOM_BARRIERS = true;
231 
232 constexpr ImageResourceBarrier SRC_UNDEFINED { 0, CORE_PIPELINE_STAGE_TOP_OF_PIPE_BIT, CORE_IMAGE_LAYOUT_UNDEFINED };
233 constexpr ImageResourceBarrier COL_ATTACHMENT { CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
234     CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
235 constexpr ImageResourceBarrier SHDR_READ { CORE_ACCESS_SHADER_READ_BIT, CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
236     CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
237 // transition the final mip level to read only as well
238 constexpr ImageResourceBarrier FINAL_SRC { CORE_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
239     CORE_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | CORE_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
240     CORE_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
241 constexpr ImageResourceBarrier FINAL_DST { CORE_ACCESS_SHADER_READ_BIT,
242     CORE_PIPELINE_STAGE_VERTEX_SHADER_BIT, // first possible shader read stage
243     CORE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
244 } // namespace
245 
246 namespace {
DownscaleBarrier(IRenderCommandList & cmdList,const RenderHandle image,const uint32_t mipLevel)247 void DownscaleBarrier(IRenderCommandList& cmdList, const RenderHandle image, const uint32_t mipLevel)
248 {
249     ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
250         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
251     imgRange.baseMipLevel = mipLevel;
252     cmdList.CustomImageBarrier(image, SRC_UNDEFINED, COL_ATTACHMENT, imgRange);
253     const uint32_t inputMipLevel = mipLevel - 1u;
254     imgRange.baseMipLevel = inputMipLevel;
255     if (inputMipLevel == 0) {
256         cmdList.CustomImageBarrier(image, SHDR_READ, imgRange);
257     } else {
258         cmdList.CustomImageBarrier(image, COL_ATTACHMENT, SHDR_READ, imgRange);
259     }
260     cmdList.AddCustomBarrierPoint();
261 }
262 
BlurHorizontalBarrier(IRenderCommandList & cmdList,const RenderHandle realImage,const uint32_t mipLevel,const RenderHandle tmpImage)263 void BlurHorizontalBarrier(
264     IRenderCommandList& cmdList, const RenderHandle realImage, const uint32_t mipLevel, const RenderHandle tmpImage)
265 {
266     ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
267         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
268     imgRange.baseMipLevel = mipLevel;
269     cmdList.CustomImageBarrier(realImage, COL_ATTACHMENT, SHDR_READ, imgRange);
270     imgRange.baseMipLevel = mipLevel - 1;
271     cmdList.CustomImageBarrier(tmpImage, SRC_UNDEFINED, COL_ATTACHMENT, imgRange);
272     cmdList.AddCustomBarrierPoint();
273 }
274 
BlurVerticalBarrier(IRenderCommandList & cmdList,const RenderHandle realImage,const uint32_t mipLevel,const RenderHandle tmpImage)275 void BlurVerticalBarrier(
276     IRenderCommandList& cmdList, const RenderHandle realImage, const uint32_t mipLevel, const RenderHandle tmpImage)
277 {
278     ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
279         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
280     imgRange.baseMipLevel = mipLevel;
281     cmdList.CustomImageBarrier(realImage, SHDR_READ, COL_ATTACHMENT, imgRange);
282     imgRange.baseMipLevel = mipLevel - 1;
283     cmdList.CustomImageBarrier(tmpImage, COL_ATTACHMENT, SHDR_READ, imgRange);
284     cmdList.AddCustomBarrierPoint();
285 }
286 
287 struct ConstDrawInput {
288     IRenderCommandList& cmdList;
289     const RenderPass& renderPass;
290     const PushConstant& pushConstant;
291     const LocalPostProcessPushConstantStruct& pc;
292     RenderHandle sampler;
293 };
BlurPass(const ConstDrawInput & di,IDescriptorSetBinder & binder,const RenderHandle psoHandle,const RenderHandle image,const uint32_t inputMipLevel)294 void BlurPass(const ConstDrawInput& di, IDescriptorSetBinder& binder, const RenderHandle psoHandle,
295     const RenderHandle image, const uint32_t inputMipLevel)
296 {
297     di.cmdList.BeginRenderPass(
298         di.renderPass.renderPassDesc, di.renderPass.subpassStartIndex, di.renderPass.subpassDesc);
299     di.cmdList.BindPipeline(psoHandle);
300 
301     binder.ClearBindings();
302     binder.BindSampler(0, di.sampler);
303     binder.BindImage(1u, { image, inputMipLevel });
304     di.cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
305     di.cmdList.BindDescriptorSet(0, binder.GetDescriptorSetHandle());
306 
307     di.cmdList.PushConstant(di.pushConstant, reinterpret_cast<const uint8_t*>(&di.pc));
308     di.cmdList.Draw(3u, 1u, 0u, 0u);
309     di.cmdList.EndRenderPass();
310 }
311 } // namespace
312 
RenderDirectionalBlur(IRenderCommandList & cmdList,const RenderPass & renderPassBase)313 void RenderPostProcessBlurNode::RenderDirectionalBlur(IRenderCommandList& cmdList, const RenderPass& renderPassBase)
314 {
315     RenderPass renderPass = renderPassBase;
316     if constexpr (USE_CUSTOM_BARRIERS) {
317         cmdList.BeginDisableAutomaticBarrierPoints();
318     }
319     const vec4 factor = (effectProperties_.blurConfiguration.blurType == BlurConfiguration::BlurType::TYPE_HORIZONTAL)
320                             ? vec4 { 1.0f, 0.0f, 0.0f, 0.0f }
321                             : vec4 { 0.0f, 1.0f, 0.0f, 0.0f };
322 
323     // with every mip, first we do a downscale
324     // then a single horizontal/vertical blur
325     LocalPostProcessPushConstantStruct pc { { 1.0f, 0.0f, 0.0f, 0.0f }, factor };
326     uint32_t descIdx = 0U;
327     const uint32_t blurCount = Math::min(effectProperties_.blurConfiguration.maxMipLevel, inputImgData_.mipCount);
328     const ConstDrawInput di { cmdList, renderPass, pipelineData_.gsd.pipelineLayoutData.pushConstant, pc,
329         defaultInput_.samplerHandle };
330     ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0,
331         PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
332 
333     const RenderHandle handle0 = inputImgData_.rawHandle;
334     const RenderHandle handle1 = tmpImgTargets_.rawHandle;
335     for (uint32_t idx = 1U; idx < blurCount; ++idx) {
336         const uint32_t mip = idx;
337 
338         const Math::UVec2 size = { Math::max(1u, inputImgData_.size.x >> mip),
339             Math::max(1u, inputImgData_.size.y >> mip) };
340         const Math::Vec2 fSize = { static_cast<float>(size.x), static_cast<float>(size.y) };
341         const Math::Vec4 texSizeInvTexSize { fSize.x * 1.0f, fSize.y * 1.0f, 1.0f / fSize.x, 1.0f / fSize.y };
342         pc = { texSizeInvTexSize, factor };
343 
344         renderPass.renderPassDesc.renderArea = { 0, 0, size.x, size.y };
345         renderPass.renderPassDesc.attachmentHandles[0] = handle0;
346         renderPass.renderPassDesc.attachments[0].mipLevel = mip;
347 
348         cmdList.SetDynamicStateViewport({ 0.0f, 0.0f, fSize.x, fSize.y, 0.0f, 1.0f });
349         cmdList.SetDynamicStateScissor({ 0, 0, size.x, size.y });
350 
351         // downscale
352         if constexpr (USE_CUSTOM_BARRIERS) {
353             DownscaleBarrier(cmdList, handle0, mip);
354         }
355         BlurPass(di, *binders_[descIdx++], pipelineData_.psoScale, handle0, mip - 1u);
356 
357         if constexpr (USE_CUSTOM_BARRIERS) {
358             BlurHorizontalBarrier(cmdList, handle0, mip, handle1);
359         }
360 
361         // Apply horizontal/vertical blur on main image and store in temp
362         renderPass.renderPassDesc.attachmentHandles[0] = handle1;
363         renderPass.renderPassDesc.attachments[0].mipLevel = mip - 1u;
364         BlurPass(di, *binders_[descIdx++], pipelineData_.psoBlur, handle0, mip);
365 
366         if constexpr (USE_CUSTOM_BARRIERS) {
367             BlurVerticalBarrier(cmdList, handle0, mip, handle1);
368         }
369 
370         // copy temp (mip-1) to main (mip)
371         renderPass.renderPassDesc.attachmentHandles[0] = handle0;
372         renderPass.renderPassDesc.attachments[0].mipLevel = mip;
373         BlurPass(di, *binders_[descIdx++], pipelineData_.psoScale, handle1, mip - 1u);
374     }
375 
376     if constexpr (USE_CUSTOM_BARRIERS) {
377         if (inputImgData_.mipCount > 1U) {
378             // transition the final used mip level
379             if (blurCount > 0) {
380                 imgRange.baseMipLevel = blurCount - 1;
381                 imgRange.levelCount = 1;
382                 cmdList.CustomImageBarrier(handle0, FINAL_SRC, FINAL_DST, imgRange);
383             }
384             if (blurCount < inputImgData_.mipCount) {
385                 // transition the final levels which might be in undefined state
386                 imgRange.baseMipLevel = blurCount;
387                 imgRange.levelCount = inputImgData_.mipCount - blurCount;
388                 cmdList.CustomImageBarrier(handle0, SRC_UNDEFINED, FINAL_DST, imgRange);
389             }
390         }
391         cmdList.AddCustomBarrierPoint();
392         cmdList.EndDisableAutomaticBarrierPoints();
393     }
394 }
395 
RenderGaussian(IRenderCommandList & cmdList,const RenderPass & renderPassBase)396 void RenderPostProcessBlurNode::RenderGaussian(IRenderCommandList& cmdList, const RenderPass& renderPassBase)
397 {
398     RenderPass renderPass = renderPassBase;
399     if constexpr (USE_CUSTOM_BARRIERS) {
400         cmdList.BeginDisableAutomaticBarrierPoints();
401     }
402 
403     // with every mip, first we do a downscale
404     // then a single horizontal and a single vertical blur
405     LocalPostProcessPushConstantStruct pc { { 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.0f } };
406     uint32_t descIdx = 0U;
407     const uint32_t blurCount = Math::min(effectProperties_.blurConfiguration.maxMipLevel, inputImgData_.mipCount);
408     const ConstDrawInput di { cmdList, renderPass, pipelineData_.gsd.pipelineLayoutData.pushConstant, pc,
409         defaultInput_.samplerHandle };
410     const RenderHandle handle0 = inputImgData_.rawHandle;
411     const RenderHandle handle1 = tmpImgTargets_.rawHandle;
412     for (uint32_t idx = 1U; idx < blurCount; ++idx) {
413         const uint32_t mip = idx;
414 
415         const Math::UVec2 size = { Math::max(1u, inputImgData_.size.x >> mip),
416             Math::max(1u, inputImgData_.size.y >> mip) };
417         const Math::Vec2 fSize = { static_cast<float>(size.x), static_cast<float>(size.y) };
418         const Math::Vec4 texSizeInvTexSize { fSize.x * 1.0f, fSize.y * 1.0f, 1.0f / fSize.x, 1.0f / fSize.y };
419         pc = { texSizeInvTexSize, { 1.0f, 0.0f, 0.0f, 0.0f } };
420 
421         renderPass.renderPassDesc.renderArea = { 0, 0, size.x, size.y };
422         renderPass.renderPassDesc.attachmentHandles[0] = handle0;
423         renderPass.renderPassDesc.attachments[0].mipLevel = mip;
424 
425         cmdList.SetDynamicStateViewport({ 0.0f, 0.0f, fSize.x, fSize.y, 0.0f, 1.0f });
426         cmdList.SetDynamicStateScissor({ 0, 0, size.x, size.y });
427 
428         // downscale
429         if constexpr (USE_CUSTOM_BARRIERS) {
430             DownscaleBarrier(cmdList, handle0, mip);
431         }
432         BlurPass(di, *binders_[descIdx++], pipelineData_.psoScale, handle0, mip - 1u);
433 
434         // horizontal (from real image to temp)
435         if constexpr (USE_CUSTOM_BARRIERS) {
436             BlurHorizontalBarrier(cmdList, handle0, mip, handle1);
437         }
438 
439         renderPass.renderPassDesc.attachmentHandles[0] = handle1;
440         renderPass.renderPassDesc.attachments[0].mipLevel = mip - 1u;
441         BlurPass(di, *binders_[descIdx++], pipelineData_.psoBlur, handle0, mip);
442 
443         // vertical
444         if constexpr (USE_CUSTOM_BARRIERS) {
445             BlurVerticalBarrier(cmdList, handle0, mip, handle1);
446         }
447 
448         renderPass.renderPassDesc.attachmentHandles[0] = handle0;
449         renderPass.renderPassDesc.attachments[0].mipLevel = mip;
450         pc.factor = { 0.0f, 1.0f, 0.0f, 0.0f };
451         BlurPass(di, *binders_[descIdx++], pipelineData_.psoBlur, handle1, mip - 1);
452     }
453 
454     if constexpr (USE_CUSTOM_BARRIERS) {
455         if (inputImgData_.mipCount > 1u) {
456             // transition the final used mip level
457             if (blurCount > 0) {
458                 const ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, blurCount - 1, 1, 0,
459                     PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
460                 cmdList.CustomImageBarrier(handle0, FINAL_SRC, FINAL_DST, imgRange);
461             }
462             if (blurCount < inputImgData_.mipCount) {
463                 // transition the final levels which might be in undefined state
464                 const ImageSubresourceRange imgRange { CORE_IMAGE_ASPECT_COLOR_BIT, blurCount,
465                     inputImgData_.mipCount - blurCount, 0, PipelineStateConstants::GPU_IMAGE_ALL_LAYERS };
466                 cmdList.CustomImageBarrier(handle0, SRC_UNDEFINED, FINAL_DST, imgRange);
467             }
468         }
469         cmdList.AddCustomBarrierPoint();
470         cmdList.EndDisableAutomaticBarrierPoints();
471     }
472 }
473 
RenderData(IRenderCommandList & cmdList,const RenderPass & renderPassBase)474 void RenderPostProcessBlurNode::RenderData(IRenderCommandList& cmdList, const RenderPass& renderPassBase)
475 {
476     if ((!RenderHandleUtil::IsValid(tmpImgTargets_.rawHandle)) ||
477         (!RenderHandleUtil::IsValid(tmpImgTargets_.rawHandleExt))) {
478         return;
479     }
480 
481     RenderPass renderPass = renderPassBase;
482 
483     // with every mip, first we do a downscale
484     // then a single horizontal and a single vertical blur
485     LocalPostProcessPushConstantStruct pc { { 1.0f, 0.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f, 0.0f } };
486     uint32_t descIdx = 0U;
487     const uint32_t blurCount =
488         Math::min(static_cast<uint32_t>(effectProperties_.blurConfiguration.filterSize), MAX_MIP_COUNT);
489     const ConstDrawInput di { cmdList, renderPass, pipelineData_.gsd.pipelineLayoutData.pushConstant, pc,
490         defaultInput_.samplerHandle };
491     const RenderHandle inputHandle = inputImgData_.rawHandle;
492     const RenderHandle handle0 = tmpImgTargets_.rawHandle;
493     const RenderHandle handle1 = tmpImgTargets_.rawHandleExt;
494     // first downscale -> then ping pong
495     {
496         const Math::UVec2 size = { inputImgData_.size.x / 2U, inputImgData_.size.y / 2U };
497         const Math::Vec2 fSize = { static_cast<float>(size.x), static_cast<float>(size.y) };
498         const Math::Vec4 texSizeInvTexSize { fSize.x * 1.0f, fSize.y * 1.0f, 1.0f / fSize.x, 1.0f / fSize.y };
499         pc = { texSizeInvTexSize, { 1.0f, 0.0f, 0.0f, 0.0f } };
500 
501         renderPass.renderPassDesc.renderArea = { 0, 0, size.x, size.y };
502 
503         cmdList.SetDynamicStateViewport({ 0.0f, 0.0f, fSize.x, fSize.y, 0.0f, 1.0f });
504         cmdList.SetDynamicStateScissor({ 0, 0, size.x, size.y });
505 
506         renderPass.renderPassDesc.attachmentHandles[0] = handle0;
507         BlurPass(di, *binders_[descIdx++], pipelineData_.psoScale, inputHandle, 0U);
508     }
509 
510     // output will be handle0
511     const Math::UVec2 size = { inputImgData_.size.x / 2U, inputImgData_.size.y / 2U };
512     const Math::Vec2 fSize = { static_cast<float>(size.x), static_cast<float>(size.y) };
513     const Math::Vec4 texSizeInvTexSize { fSize.x * 1.0f, fSize.y * 1.0f, 1.0f / fSize.x, 1.0f / fSize.y };
514     pc = { texSizeInvTexSize, { 1.0f, 0.0f, 0.0f, 0.0f } };
515     renderPass.renderPassDesc.renderArea = { 0, 0, size.x, size.y };
516 
517     cmdList.SetDynamicStateViewport({ 0.0f, 0.0f, fSize.x, fSize.y, 0.0f, 1.0f });
518     cmdList.SetDynamicStateScissor({ 0, 0, size.x, size.y });
519 
520     for (uint32_t idx = 0U; idx < blurCount; ++idx) {
521         // horizontal (from real image to temp)
522         pc.factor = { 1.0f, 0.0f, 0.0f, 0.0f };
523         renderPass.renderPassDesc.attachmentHandles[0] = handle1;
524         BlurPass(di, *binders_[descIdx++], pipelineData_.psoBlur, handle0, 0U);
525 
526         // vertical
527         renderPass.renderPassDesc.attachmentHandles[0] = handle0;
528         pc.factor = { 0.0f, 1.0f, 0.0f, 0.0f };
529         BlurPass(di, *binders_[descIdx++], pipelineData_.psoBlur, handle1, 0U);
530     }
531 
532     // update output
533     nodeOutputsData.output.handle = handle0;
534 }
535 
EvaluateInOut()536 bool RenderPostProcessBlurNode::EvaluateInOut()
537 {
538     inputImgData_.rawHandle = nodeInputsData.input.handle;
539     if (RenderHandleUtil::IsValid(nodeInputsData.input.handle)) {
540         nodeOutputsData.output.handle = RenderHandleUtil::IsValid(nodeOutputsData.output.handle)
541                                             ? nodeOutputsData.output.handle
542                                             : nodeInputsData.input.handle;
543         return true;
544     }
545 #if (RENDER_VALIDATION_ENABLED == 1)
546     CORE_LOG_ONCE_W(renderNodeContextMgr_->GetName() + "_inout_issue",
547         "RENDER_VALIDATION: render post process input / output issue");
548 #endif
549     return false;
550 }
551 
CheckDescriptorSetNeed()552 void RenderPostProcessBlurNode::CheckDescriptorSetNeed()
553 {
554     if (binders_.empty()) {
555         constexpr uint32_t set { 0U };
556         binders_.clear();
557         binders_.resize(MAX_BINDER_COUNT);
558 
559         INodeContextDescriptorSetManager& descriptorSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
560         const auto& bindings = pipelineData_.gsd.pipelineLayoutData.descriptorSetLayouts[set].bindings;
561         for (uint32_t idx = 0; idx < MAX_BINDER_COUNT; ++idx) {
562             const RenderHandle descHandle = descriptorSetMgr.CreateDescriptorSet(bindings);
563             binders_[idx] = descriptorSetMgr.CreateDescriptorSetBinder(descHandle, bindings);
564         }
565     }
566 }
567 
EvaluateTemporaryTargets()568 void RenderPostProcessBlurNode::EvaluateTemporaryTargets()
569 {
570     IRenderNodeGpuResourceManager& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
571     const GpuImageDesc inDesc = gpuResourceMgr.GetImageDescriptor(nodeInputsData.input.handle);
572     inputImgData_.size = { inDesc.width, inDesc.height };
573     inputImgData_.mipCount = inDesc.mipCount;
574     Math::UVec2 texSize = inputImgData_.size / 2U;
575     texSize.x = Math::max(1u, texSize.x);
576     texSize.y = Math::max(1u, texSize.y);
577     if (texSize.x != tmpImgTargets_.size.x || texSize.y != tmpImgTargets_.size.y) {
578         const bool needsTwoTargets =
579             ((inDesc.usageFlags & ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0);
580         tmpImgTargets_.size = texSize;
581         constexpr ImageUsageFlags usageFlags = ImageUsageFlagBits::CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
582                                                ImageUsageFlagBits::CORE_IMAGE_USAGE_SAMPLED_BIT |
583                                                ImageUsageFlagBits::CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
584         const GpuImageDesc desc {
585             ImageType::CORE_IMAGE_TYPE_2D,
586             ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,
587             inDesc.format,
588             ImageTiling::CORE_IMAGE_TILING_OPTIMAL,
589             usageFlags,
590             MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
591             0U,
592             EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS,
593             texSize.x,
594             texSize.y,
595             1U,
596             Math::max(1U, (inDesc.mipCount - 1U)),
597             1u,
598             SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,
599             {},
600         };
601 #if (RENDER_VALIDATION_ENABLED == 1)
602         const auto additionalName =
603             BASE_NS::to_string(reinterpret_cast<uintptr_t>(reinterpret_cast<void*>(postProcess_.get())));
604         tmpImgTargets_.handle =
605             gpuResourceMgr.Create(renderNodeContextMgr_->GetName() + "_BLUR0_" + additionalName, desc);
606         if (needsTwoTargets) {
607             tmpImgTargets_.handleExt =
608                 gpuResourceMgr.Create(renderNodeContextMgr_->GetName() + "_BLUR1" + additionalName, desc);
609         }
610 #else
611         tmpImgTargets_.handle = renderNodeContextMgr_->GetGpuResourceManager().Create(tmpImgTargets_.handle, desc);
612         if (needsTwoTargets) {
613             tmpImgTargets_.handleExt =
614                 renderNodeContextMgr_->GetGpuResourceManager().Create(tmpImgTargets_.handleExt, desc);
615         }
616 #endif
617         if (!needsTwoTargets) {
618             tmpImgTargets_.handleExt = {};
619         }
620         tmpImgTargets_.rawHandle = tmpImgTargets_.handle.GetHandle();
621         tmpImgTargets_.rawHandleExt = tmpImgTargets_.handleExt.GetHandle();
622         tmpImgTargets_.mipCount = desc.mipCount;
623     }
624 }
625 RENDER_END_NAMESPACE()
626