• 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_bloom_node.h"
17 
18 #include <base/containers/fixed_string.h>
19 #include <base/containers/unordered_map.h>
20 #include <base/math/vector.h>
21 #include <core/property/property_types.h>
22 #include <core/property_tools/property_api_impl.inl>
23 #include <render/datastore/intf_render_data_store_manager.h>
24 #include <render/datastore/intf_render_data_store_pod.h>
25 #include <render/datastore/render_data_store_render_pods.h>
26 #include <render/device/intf_gpu_resource_manager.h>
27 #include <render/device/intf_shader_manager.h>
28 #include <render/namespace.h>
29 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
30 #include <render/nodecontext/intf_node_context_pso_manager.h>
31 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
32 #include <render/nodecontext/intf_render_command_list.h>
33 #include <render/nodecontext/intf_render_node_context_manager.h>
34 #include <render/nodecontext/intf_render_node_util.h>
35 #include <render/property/property_types.h>
36 
37 #include "datastore/render_data_store_pod.h"
38 #include "default_engine_constants.h"
39 #include "device/gpu_resource_handle_util.h"
40 #include "render_post_process_bloom.h"
41 #include "util/log.h"
42 
43 // shaders
44 #include <render/shaders/common/render_post_process_structs_common.h>
45 
46 using namespace BASE_NS;
47 using namespace CORE_NS;
48 using namespace RENDER_NS;
49 
50 CORE_BEGIN_NAMESPACE()
51 DATA_TYPE_METADATA(RenderPostProcessBloomNode::NodeInputs, MEMBER_PROPERTY(input, "input", 0))
52 DATA_TYPE_METADATA(RenderPostProcessBloomNode::NodeOutputs, MEMBER_PROPERTY(output, "output", 0))
53 CORE_END_NAMESPACE()
54 
55 RENDER_BEGIN_NAMESPACE()
56 namespace {
57 constexpr DynamicStateEnum DYNAMIC_STATES[] = { CORE_DYNAMIC_STATE_ENUM_VIEWPORT, CORE_DYNAMIC_STATE_ENUM_SCISSOR };
58 } // namespace
59 
RenderPostProcessBloomNode()60 RenderPostProcessBloomNode::RenderPostProcessBloomNode()
61     : inputProperties_(
62           &nodeInputsData, array_view(PropertyType::DataType<RenderPostProcessBloomNode::NodeInputs>::properties)),
63       outputProperties_(
64           &nodeOutputsData, array_view(PropertyType::DataType<RenderPostProcessBloomNode::NodeOutputs>::properties))
65 
66 {}
67 
GetRenderInputProperties()68 IPropertyHandle* RenderPostProcessBloomNode::GetRenderInputProperties()
69 {
70     return inputProperties_.GetData();
71 }
72 
GetRenderOutputProperties()73 IPropertyHandle* RenderPostProcessBloomNode::GetRenderOutputProperties()
74 {
75     return outputProperties_.GetData();
76 }
77 
SetRenderAreaRequest(const RenderAreaRequest & renderAreaRequest)78 void RenderPostProcessBloomNode::SetRenderAreaRequest(const RenderAreaRequest& renderAreaRequest)
79 {
80     useRequestedRenderArea_ = true;
81     renderAreaRequest_ = renderAreaRequest;
82 }
83 
Init(const IRenderPostProcess::Ptr & postProcess,IRenderNodeContextManager & renderNodeContextMgr)84 void RenderPostProcessBloomNode::Init(
85     const IRenderPostProcess::Ptr& postProcess, IRenderNodeContextManager& renderNodeContextMgr)
86 {
87     renderNodeContextMgr_ = &renderNodeContextMgr;
88     postProcess_ = postProcess;
89 
90     auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
91     samplerHandle_ = gpuResourceMgr.Create(samplerHandle_,
92         GpuSamplerDesc {
93             Filter::CORE_FILTER_LINEAR,                                  // magFilter
94             Filter::CORE_FILTER_LINEAR,                                  // minFilter
95             Filter::CORE_FILTER_LINEAR,                                  // mipMapMode
96             SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
97             SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeV
98             SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeW
99         });
100 
101     valid_ = true;
102 }
103 
PreExecute()104 void RenderPostProcessBloomNode::PreExecute()
105 {
106     if (valid_ && postProcess_) {
107         const array_view<const uint8_t> propertyView = postProcess_->GetData();
108         // this node is directly dependant
109         PLUGIN_ASSERT(propertyView.size_bytes() == sizeof(RenderPostProcessBloomNode::EffectProperties));
110         if (propertyView.size_bytes() == sizeof(RenderPostProcessBloomNode::EffectProperties)) {
111             effectProperties_ = (const RenderPostProcessBloomNode::EffectProperties&)(*propertyView.data());
112         }
113         const GpuImageDesc& imgDesc =
114             renderNodeContextMgr_->GetGpuResourceManager().GetImageDescriptor(nodeInputsData.input.handle);
115         uint32_t sizeDenom = 1u;
116         if (effectProperties_.bloomConfiguration.bloomQualityType == BloomConfiguration::QUALITY_TYPE_LOW) {
117             sizeDenom = 2u;
118         }
119         CreateTargets(Math::UVec2(imgDesc.width, imgDesc.height) / sizeDenom);
120     } else {
121         effectProperties_.enabled = false;
122     }
123 }
124 
Execute(IRenderCommandList & cmdList)125 void RenderPostProcessBloomNode::Execute(IRenderCommandList& cmdList)
126 {
127     // NOTE: need to be run even when not enabled when using render node
128     if (!valid_) {
129         return;
130     }
131 
132     // NOTE: target counts etc. should probably be resized based on configuration
133     CreatePsos();
134 
135     RENDER_DEBUG_MARKER_COL_SCOPE(cmdList, "RenderBloom", DefaultDebugConstants::CORE_DEFAULT_DEBUG_COLOR);
136 
137     const auto bloomQualityType = effectProperties_.bloomConfiguration.bloomQualityType;
138     PLUGIN_ASSERT(bloomQualityType < CORE_BLOOM_QUALITY_COUNT);
139     if (effectProperties_.bloomConfiguration.useCompute) {
140         psos_.downscale = psos_.downscaleHandlesCompute[bloomQualityType].regular;
141         psos_.downscaleAndThreshold = psos_.downscaleHandlesCompute[bloomQualityType].threshold;
142     } else {
143         psos_.downscale = psos_.downscaleHandles[bloomQualityType].regular;
144         psos_.downscaleAndThreshold = psos_.downscaleHandles[bloomQualityType].threshold;
145     }
146 
147     if (!effectProperties_.enabled) {
148         effectProperties_.bloomConfiguration.amountCoefficient = 0.0f;
149     }
150 
151     bloomParameters_ = Math::Vec4(
152         // .x = thresholdHard, luma values below this won't bloom
153         effectProperties_.bloomConfiguration.thresholdHard,
154         // .y = thresholdSoft, luma values from this value to hard threshold will reduce bloom input from 1.0 -> 0.0
155         // i.e. this creates softer threshold for bloom
156         effectProperties_.bloomConfiguration.thresholdSoft,
157         // .z = amountCoefficient, will multiply the colors from the bloom textures when combined with original color
158         // target
159         effectProperties_.bloomConfiguration.amountCoefficient,
160         // .w = scatter value (in .w dirt mask coefficient is used in combine)
161         effectProperties_.bloomConfiguration.scatter);
162     float scaleFactor = Math::min(1.0f, effectProperties_.bloomConfiguration.scaleFactor);
163 
164     scaleFactor = Math::max(0.01f, scaleFactor);
165     const auto fTexCount = static_cast<float>(targets_.tex1.size());
166     frameScaleMaxCount_ = static_cast<size_t>(Math::min(fTexCount, fTexCount * scaleFactor));
167     frameScaleMaxCount_ = Math::max(frameScaleMaxCount_, size_t(2)); // 2: frame count
168 
169     if (effectProperties_.bloomConfiguration.useCompute) {
170         ComputeBloom(cmdList);
171     } else {
172         GraphicsBloom(cmdList);
173     }
174 }
175 
GetExecuteFlags() const176 IRenderNode::ExecuteFlags RenderPostProcessBloomNode::GetExecuteFlags() const
177 {
178     if (effectProperties_.enabled) {
179         return 0;
180     } else {
181         return IRenderNode::ExecuteFlagBits::EXECUTE_FLAG_BITS_DO_NOT_EXECUTE;
182     }
183 }
184 
CreateTargets(const Math::UVec2 baseSize)185 void RenderPostProcessBloomNode::CreateTargets(const Math::UVec2 baseSize)
186 {
187     if (baseSize.x != baseSize_.x || baseSize.y != baseSize_.y) {
188         baseSize_ = baseSize;
189 
190         format_ = Format::BASE_FORMAT_B10G11R11_UFLOAT_PACK32;
191         ImageUsageFlags usageFlags = CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | CORE_IMAGE_USAGE_SAMPLED_BIT |
192                                      CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
193 
194         if (effectProperties_.bloomConfiguration.useCompute) {
195             format_ = Format::BASE_FORMAT_R16G16B16A16_SFLOAT; // used due to GLES
196             usageFlags = CORE_IMAGE_USAGE_STORAGE_BIT | CORE_IMAGE_USAGE_SAMPLED_BIT;
197         } else {
198             baseViewportDesc_ = { 0.0f, 0.0f, static_cast<float>(baseSize.x), static_cast<float>(baseSize.y), 0.0f,
199                 1.0f };
200             baseScissorDesc_ = { 0, 0, baseSize.x, baseSize.y };
201         }
202 
203         // create target image
204         const Math::UVec2 startTargetSize = baseSize_;
205         GpuImageDesc desc {
206             ImageType::CORE_IMAGE_TYPE_2D,
207             ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,
208             format_,
209             ImageTiling::CORE_IMAGE_TILING_OPTIMAL,
210             usageFlags,
211             MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
212             0,
213             EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS |
214                 EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_RESET_STATE_ON_FRAME_BORDERS,
215             startTargetSize.x,
216             startTargetSize.y,
217             1u,
218             1u,
219             1u,
220             SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,
221             {},
222         };
223 
224         auto& gpuResourceMgr = renderNodeContextMgr_->GetGpuResourceManager();
225 #if (RENDER_VALIDATION_ENABLED == 1)
226         const string_view nodeName = renderNodeContextMgr_->GetName();
227 #endif
228         for (size_t idx = 0; idx < targets_.tex1.size(); ++idx) {
229             // every bloom target is half the size of the original/ previous bloom target
230             desc.width /= 2u;
231             desc.height /= 2u;
232             desc.width = (desc.width >= 1u) ? desc.width : 1u;
233             desc.height = (desc.height >= 1u) ? desc.height : 1u;
234             targets_.tex1Size[idx] = Math::UVec2(desc.width, desc.height);
235 #if (RENDER_VALIDATION_ENABLED == 1)
236             const auto baseTargetName = nodeName + "_Bloom_" + to_string(idx);
237             targets_.tex1[idx] = gpuResourceMgr.Create(baseTargetName + "_A", desc);
238             if (!effectProperties_.bloomConfiguration.useCompute) {
239                 targets_.tex2[idx] = gpuResourceMgr.Create(baseTargetName + "_B", desc);
240             }
241 #else
242             targets_.tex1[idx] = gpuResourceMgr.Create(targets_.tex1[idx], desc);
243             if (!effectProperties_.bloomConfiguration.useCompute) {
244                 targets_.tex2[idx] = gpuResourceMgr.Create(targets_.tex2[idx], desc);
245             }
246 #endif
247         }
248     }
249 }
250 
GetRenderDescriptorCounts() const251 DescriptorCounts RenderPostProcessBloomNode::GetRenderDescriptorCounts() const
252 {
253     // NOTE: when added support for various bloom target counts, might need to be calculated for max
254     return DescriptorCounts { {
255         { CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 32u },
256         { CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 32u },
257         { CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE, 32u },
258         { CORE_DESCRIPTOR_TYPE_SAMPLER, 24u },
259     } };
260 }
261 
GetFinalTarget() const262 RenderHandle RenderPostProcessBloomNode::GetFinalTarget() const
263 {
264     if (RenderHandleUtil::IsValid(nodeOutputsData.output.handle)) {
265         return nodeOutputsData.output.handle;
266     } else {
267         // output tex1 on compute and tex2 on graphics
268         return effectProperties_.bloomConfiguration.useCompute ? (targets_.tex1[0u].GetHandle())
269                                                                : (targets_.tex2[0u].GetHandle());
270     }
271 }
272 
ComputeBloom(IRenderCommandList & cmdList)273 void RenderPostProcessBloomNode::ComputeBloom(IRenderCommandList& cmdList)
274 {
275     constexpr PushConstant pc { ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT,
276         sizeof(LocalPostProcessPushConstantStruct) };
277 
278     if (effectProperties_.enabled) {
279         ComputeDownscaleAndThreshold(pc, cmdList);
280         ComputeDownscale(pc, cmdList);
281         ComputeUpscale(pc, cmdList);
282     }
283     // needs to be done even when bloom is disabled if node is in use
284     if (RenderHandleUtil::IsValid(nodeOutputsData.output.handle)) {
285         ComputeCombine(pc, cmdList);
286     }
287 }
288 
ComputeDownscaleAndThreshold(const PushConstant & pc,IRenderCommandList & cmdList)289 void RenderPostProcessBloomNode::ComputeDownscaleAndThreshold(const PushConstant& pc, IRenderCommandList& cmdList)
290 {
291     cmdList.BindPipeline(psos_.downscaleAndThreshold);
292     const ShaderThreadGroup tgs = psos_.downscaleAndThresholdTGS;
293 
294     auto& binder = *binders_.downscaleAndThreshold;
295     binder.ClearBindings();
296     uint32_t binding = 0;
297     binder.BindImage(binding++, { targets_.tex1[0].GetHandle() });
298     binder.BindImage(binding++, { nodeInputsData.input });
299     binder.BindSampler(binding++, { samplerHandle_.GetHandle() });
300 
301     cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
302     cmdList.BindDescriptorSet(0U, binder.GetDescriptorSetHandle());
303 
304     const auto targetSize = targets_.tex1Size[0];
305 
306     LocalPostProcessPushConstantStruct uPc;
307     uPc.factor = bloomParameters_;
308     uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
309         1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
310 
311     cmdList.PushConstantData(pc, arrayviewU8(uPc));
312 
313     cmdList.Dispatch((targetSize.x + tgs.x - 1) / tgs.x, (targetSize.y + tgs.y - 1) / tgs.y, 1);
314 }
315 
ComputeDownscale(const PushConstant & pc,IRenderCommandList & cmdList)316 void RenderPostProcessBloomNode::ComputeDownscale(const PushConstant& pc, IRenderCommandList& cmdList)
317 {
318     cmdList.BindPipeline(psos_.downscale);
319     const ShaderThreadGroup tgs = psos_.downscaleTGS;
320 
321     for (size_t i = 1; i < frameScaleMaxCount_; ++i) {
322         {
323             auto& binder = *binders_.downscale[i];
324             const RenderHandle setHandle = binder.GetDescriptorSetHandle();
325             binder.ClearBindings();
326 
327             uint32_t binding = 0;
328             binder.BindImage(binding++, { targets_.tex1[i].GetHandle() });
329             binder.BindImage(binding++, { targets_.tex1[i - 1].GetHandle() });
330             binder.BindSampler(binding++, { samplerHandle_.GetHandle() });
331 
332             cmdList.UpdateDescriptorSet(
333                 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
334             cmdList.BindDescriptorSet(0U, setHandle);
335         }
336 
337         const auto targetSize = targets_.tex1Size[i];
338 
339         LocalPostProcessPushConstantStruct uPc;
340         uPc.factor = bloomParameters_;
341         // factor.x is the bloom type here
342         uPc.factor.x = static_cast<float>(effectProperties_.bloomConfiguration.bloomType);
343         uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
344             1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
345         cmdList.PushConstantData(pc, arrayviewU8(uPc));
346 
347         cmdList.Dispatch((targetSize.x + tgs.x - 1) / tgs.x, (targetSize.y + tgs.y - 1) / tgs.y, 1);
348     }
349 }
350 
ComputeUpscale(const PushConstant & pc,IRenderCommandList & cmdList)351 void RenderPostProcessBloomNode::ComputeUpscale(const PushConstant& pc, IRenderCommandList& cmdList)
352 {
353     cmdList.BindPipeline(psos_.upscale);
354     const ShaderThreadGroup tgs = psos_.upscaleTGS;
355 
356     for (size_t i = frameScaleMaxCount_ - 1; i != 0; --i) {
357         {
358             auto& binder = *binders_.upscale[i];
359             const RenderHandle setHandle = binder.GetDescriptorSetHandle();
360             binder.ClearBindings();
361 
362             binder.BindImage(0u, { targets_.tex1[i - 1].GetHandle() });
363             binder.BindImage(1u, { targets_.tex1[i].GetHandle() });
364             binder.BindSampler(2u, { samplerHandle_.GetHandle() });
365 
366             cmdList.UpdateDescriptorSet(
367                 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
368             cmdList.BindDescriptorSet(0U, setHandle);
369         }
370 
371         const auto targetSize = targets_.tex1Size[i - 1];
372 
373         LocalPostProcessPushConstantStruct uPc;
374         uPc.factor = bloomParameters_;
375         //  factor.x is the bloom type here
376         uPc.factor.x = static_cast<float>(effectProperties_.bloomConfiguration.bloomType);
377         uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
378             1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
379         cmdList.PushConstantData(pc, arrayviewU8(uPc));
380 
381         cmdList.Dispatch((targetSize.x + tgs.x - 1) / tgs.x, (targetSize.y + tgs.y - 1) / tgs.y, 1);
382     }
383 }
384 
ComputeCombine(const PushConstant & pc,IRenderCommandList & cmdList)385 void RenderPostProcessBloomNode::ComputeCombine(const PushConstant& pc, IRenderCommandList& cmdList)
386 {
387     cmdList.BindPipeline(psos_.combine);
388     const ShaderThreadGroup tgs = psos_.combineTGS;
389 
390     {
391         auto& binder = *binders_.combine;
392         const RenderHandle setHandle = binder.GetDescriptorSetHandle();
393         binder.ClearBindings();
394 
395         uint32_t binding = 0;
396         binder.BindImage(binding++, { nodeOutputsData.output });
397         binder.BindImage(binding++, { nodeInputsData.input });
398         binder.BindImage(binding++, { targets_.tex1[0].GetHandle() });
399         binder.BindSampler(binding++, { samplerHandle_.GetHandle() });
400 
401         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
402         cmdList.BindDescriptorSet(0U, setHandle);
403     }
404 
405     const auto targetSize = baseSize_;
406 
407     LocalPostProcessPushConstantStruct uPc;
408     uPc.factor = bloomParameters_;
409     uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
410         1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
411     cmdList.PushConstantData(pc, arrayviewU8(uPc));
412 
413     cmdList.Dispatch((targetSize.x + tgs.x - 1) / tgs.x, (targetSize.y + tgs.y - 1) / tgs.y, 1);
414 }
415 
GraphicsBloom(IRenderCommandList & cmdList)416 void RenderPostProcessBloomNode::GraphicsBloom(IRenderCommandList& cmdList)
417 {
418     RenderPass renderPass;
419     renderPass.renderPassDesc.attachmentCount = 1;
420     renderPass.renderPassDesc.subpassCount = 1;
421     renderPass.renderPassDesc.attachments[0].loadOp = AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
422     renderPass.renderPassDesc.attachments[0].storeOp = AttachmentStoreOp::CORE_ATTACHMENT_STORE_OP_STORE;
423 
424     RenderPassSubpassDesc& subpassDesc = renderPass.subpassDesc;
425     subpassDesc.colorAttachmentCount = 1;
426     subpassDesc.colorAttachmentIndices[0] = 0;
427 
428     constexpr PushConstant pc { ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT,
429         sizeof(LocalPostProcessPushConstantStruct) };
430 
431     if (effectProperties_.enabled) {
432         RenderDownscaleAndThreshold(renderPass, pc, cmdList);
433         RenderDownscale(renderPass, pc, cmdList);
434         RenderUpscale(renderPass, pc, cmdList);
435     }
436     // combine (needs to be done even when bloom is disabled if node is in use
437     if (RenderHandleUtil::IsValid(nodeOutputsData.output.handle)) {
438         RenderCombine(renderPass, pc, cmdList);
439     }
440 }
441 
RenderDownscaleAndThreshold(RenderPass & renderPass,const PushConstant & pc,IRenderCommandList & cmdList)442 void RenderPostProcessBloomNode::RenderDownscaleAndThreshold(
443     RenderPass& renderPass, const PushConstant& pc, IRenderCommandList& cmdList)
444 {
445     const auto targetSize = targets_.tex1Size[0];
446     const ViewportDesc viewportDesc { 0, 0, static_cast<float>(targetSize.x), static_cast<float>(targetSize.y) };
447     const ScissorDesc scissorDesc = { 0, 0, targetSize.x, targetSize.y };
448 
449     renderPass.renderPassDesc.attachmentHandles[0] = targets_.tex1[0].GetHandle();
450     renderPass.renderPassDesc.renderArea = { 0, 0, targetSize.x, targetSize.y };
451     cmdList.BeginRenderPass(renderPass.renderPassDesc, 0, renderPass.subpassDesc);
452 
453     cmdList.SetDynamicStateViewport(viewportDesc);
454     cmdList.SetDynamicStateScissor(scissorDesc);
455     cmdList.BindPipeline(psos_.downscaleAndThreshold);
456 
457     {
458         auto& binder = *binders_.downscaleAndThreshold;
459         const RenderHandle setHandle = binder.GetDescriptorSetHandle();
460         binder.ClearBindings();
461 
462         binder.BindImage(0U, { nodeInputsData.input });
463         binder.BindSampler(1U, { samplerHandle_.GetHandle() });
464         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
465         cmdList.BindDescriptorSet(0U, setHandle);
466     }
467 
468     LocalPostProcessPushConstantStruct uPc;
469     uPc.factor = bloomParameters_;
470     uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
471         1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
472 
473     cmdList.PushConstantData(pc, arrayviewU8(uPc));
474     cmdList.Draw(3u, 1u, 0u, 0u);
475     cmdList.EndRenderPass();
476 }
477 
RenderDownscale(RenderPass & renderPass,const PushConstant & pc,IRenderCommandList & cmdList)478 void RenderPostProcessBloomNode::RenderDownscale(
479     RenderPass& renderPass, const PushConstant& pc, IRenderCommandList& cmdList)
480 {
481     LocalPostProcessPushConstantStruct uPc;
482     uPc.factor = bloomParameters_;
483 
484     for (size_t idx = 1; idx < frameScaleMaxCount_; ++idx) {
485         const auto targetSize = targets_.tex1Size[idx];
486         const ViewportDesc viewportDesc { 0, 0, static_cast<float>(targetSize.x), static_cast<float>(targetSize.y) };
487         const ScissorDesc scissorDesc = { 0, 0, targetSize.x, targetSize.y };
488 
489         renderPass.renderPassDesc.attachmentHandles[0] = targets_.tex1[idx].GetHandle();
490         renderPass.renderPassDesc.renderArea = { 0, 0, targetSize.x, targetSize.y };
491         cmdList.BeginRenderPass(renderPass.renderPassDesc, 0, renderPass.subpassDesc);
492 
493         cmdList.SetDynamicStateViewport(viewportDesc);
494         cmdList.SetDynamicStateScissor(scissorDesc);
495 
496         cmdList.BindPipeline(psos_.downscale);
497 
498         {
499             auto& binder = *binders_.downscale[idx];
500             const RenderHandle setHandle = binder.GetDescriptorSetHandle();
501             binder.ClearBindings();
502             binder.BindImage(0u, { targets_.tex1[idx - 1].GetHandle() });
503             binder.BindSampler(1u, { samplerHandle_.GetHandle() });
504             cmdList.UpdateDescriptorSet(
505                 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
506             cmdList.BindDescriptorSet(0U, setHandle);
507         }
508         // factor.x is the bloom type here
509         uPc.factor.x = static_cast<float>(effectProperties_.bloomConfiguration.bloomType);
510         uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
511             1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
512 
513         cmdList.PushConstantData(pc, arrayviewU8(uPc));
514         cmdList.Draw(3u, 1u, 0u, 0u);
515         cmdList.EndRenderPass();
516     }
517 }
518 
RenderUpscale(RenderPass & renderPass,const PushConstant & pc,IRenderCommandList & cmdList)519 void RenderPostProcessBloomNode::RenderUpscale(
520     RenderPass& renderPass, const PushConstant& pc, IRenderCommandList& cmdList)
521 {
522     RenderPass renderPassUpscale = renderPass;
523     renderPassUpscale.renderPassDesc.attachments[0].loadOp = AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
524     renderPassUpscale.renderPassDesc.attachments[0].storeOp = AttachmentStoreOp::CORE_ATTACHMENT_STORE_OP_STORE;
525 
526     PLUGIN_ASSERT(targets_.tex1.size() == targets_.tex2.size());
527     RenderHandle input;
528     if (frameScaleMaxCount_ >= 1) {
529         input = targets_.tex1[frameScaleMaxCount_ - 1].GetHandle();
530     }
531     for (size_t idx = frameScaleMaxCount_ - 1; idx != 0; --idx) {
532         const auto targetSize = targets_.tex1Size[idx - 1];
533         const ViewportDesc viewportDesc { 0, 0, static_cast<float>(targetSize.x), static_cast<float>(targetSize.y) };
534         const ScissorDesc scissorDesc = { 0, 0, targetSize.x, targetSize.y };
535 
536         // tex2 as output
537         renderPassUpscale.renderPassDesc.attachmentHandles[0] = targets_.tex2[idx - 1].GetHandle();
538         renderPassUpscale.renderPassDesc.renderArea = { 0, 0, targetSize.x, targetSize.y };
539         cmdList.BeginRenderPass(renderPassUpscale.renderPassDesc, 0, renderPassUpscale.subpassDesc);
540 
541         cmdList.SetDynamicStateViewport(viewportDesc);
542         cmdList.SetDynamicStateScissor(scissorDesc);
543 
544         cmdList.BindPipeline(psos_.upscale);
545 
546         {
547             auto& binder = *binders_.upscale[idx];
548             const RenderHandle setHandle = binder.GetDescriptorSetHandle();
549             binder.ClearBindings();
550 
551             uint32_t binding = 0;
552             binder.BindImage(binding++, { input });
553             binder.BindImage(binding++, { targets_.tex1[idx - 1].GetHandle() });
554             binder.BindSampler(binding++, { samplerHandle_.GetHandle() });
555             cmdList.UpdateDescriptorSet(
556                 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
557             cmdList.BindDescriptorSet(0U, setHandle);
558         }
559         LocalPostProcessPushConstantStruct uPc;
560         uPc.factor = bloomParameters_;
561         // factor.x is the bloom type here
562         uPc.factor.x = static_cast<float>(effectProperties_.bloomConfiguration.bloomType);
563         uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
564             1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
565 
566         cmdList.PushConstantData(pc, arrayviewU8(uPc));
567         cmdList.Draw(3u, 1u, 0u, 0u);
568         cmdList.EndRenderPass();
569 
570         // next pass input
571         input = renderPassUpscale.renderPassDesc.attachmentHandles[0];
572     }
573 }
574 
RenderCombine(RenderPass & renderPass,const PushConstant & pc,IRenderCommandList & cmdList)575 void RenderPostProcessBloomNode::RenderCombine(
576     RenderPass& renderPass, const PushConstant& pc, IRenderCommandList& cmdList)
577 {
578     const auto targetSize = baseSize_;
579 
580     renderPass.renderPassDesc.attachmentHandles[0] = nodeOutputsData.output.handle;
581     renderPass.renderPassDesc.renderArea = { 0, 0, targetSize.x, targetSize.y };
582     cmdList.BeginRenderPass(renderPass.renderPassDesc, 0, renderPass.subpassDesc);
583 
584     cmdList.SetDynamicStateViewport(baseViewportDesc_);
585     cmdList.SetDynamicStateScissor(baseScissorDesc_);
586 
587     cmdList.BindPipeline(psos_.combine);
588 
589     {
590         auto& binder = *binders_.combine;
591         const RenderHandle setHandle = binder.GetDescriptorSetHandle();
592         binder.ClearBindings();
593 
594         uint32_t binding = 0;
595         binder.BindImage(binding++, { nodeInputsData.input });
596         // tex2 handle has the final result
597         binder.BindImage(binding++, { targets_.tex2[0].GetHandle() });
598         binder.BindSampler(binding++, { samplerHandle_.GetHandle() });
599 
600         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
601         cmdList.BindDescriptorSet(0U, setHandle);
602     }
603 
604     LocalPostProcessPushConstantStruct uPc;
605     uPc.factor = bloomParameters_;
606     uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
607         1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
608 
609     cmdList.PushConstantData(pc, arrayviewU8(uPc));
610     cmdList.Draw(3u, 1u, 0u, 0u);
611     cmdList.EndRenderPass();
612 }
613 
CreatePsos()614 void RenderPostProcessBloomNode::CreatePsos()
615 {
616     if (effectProperties_.bloomConfiguration.useCompute) {
617         CreateComputePsos();
618     } else {
619         CreateRenderPsos();
620     }
621 }
622 
CreateComputePsos()623 void RenderPostProcessBloomNode::CreateComputePsos()
624 {
625     if (binders_.combine) {
626         return;
627     }
628 
629     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
630     INodeContextPsoManager& psoMgr = renderNodeContextMgr_->GetPsoManager();
631     INodeContextDescriptorSetManager& dSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
632 
633     constexpr BASE_NS::pair<BloomConfiguration::BloomQualityType, uint32_t> configurations[] = {
634         { BloomConfiguration::BloomQualityType::QUALITY_TYPE_LOW, CORE_BLOOM_QUALITY_LOW },
635         { BloomConfiguration::BloomQualityType::QUALITY_TYPE_NORMAL, CORE_BLOOM_QUALITY_NORMAL },
636         { BloomConfiguration::BloomQualityType::QUALITY_TYPE_HIGH, CORE_BLOOM_QUALITY_HIGH }
637     };
638     for (const auto& configuration : configurations) {
639         {
640             auto shader = shaderMgr.GetShaderHandle("rendershaders://computeshader/bloom_downscale.shader");
641             const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shader);
642             ShaderSpecializationConstantView specializations = shaderMgr.GetReflectionSpecialization(shader);
643             const ShaderSpecializationConstantDataView specDataView {
644                 { specializations.constants.data(), specializations.constants.size() },
645                 { &configuration.second, 1u },
646             };
647 
648             psos_.downscaleHandlesCompute[configuration.first].regular =
649                 psoMgr.GetComputePsoHandle(shader, pl, specDataView);
650         }
651         {
652             auto shader = shaderMgr.GetShaderHandle("rendershaders://computeshader/bloom_downscale_threshold.shader");
653             const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shader);
654 
655             ShaderSpecializationConstantView specializations = shaderMgr.GetReflectionSpecialization(shader);
656             const ShaderSpecializationConstantDataView specDataView {
657                 { specializations.constants.data(), specializations.constants.size() },
658                 { &configuration.second, 1u },
659             };
660             psos_.downscaleHandlesCompute[configuration.first].threshold =
661                 psoMgr.GetComputePsoHandle(shader, pl, specDataView);
662         }
663     }
664 
665     constexpr uint32_t localSetIdx = 0U;
666     // the first one creates the global set as well
667     {
668         const RenderHandle shaderHandle =
669             shaderMgr.GetShaderHandle("rendershaders://computeshader/bloom_downscale_threshold.shader");
670         const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shaderHandle);
671         psos_.downscaleAndThreshold = psoMgr.GetComputePsoHandle(shaderHandle, pl, {});
672         psos_.downscaleAndThresholdTGS = shaderMgr.GetReflectionThreadGroupSize(shaderHandle);
673 
674         const auto& lBinds = pl.descriptorSetLayouts[localSetIdx].bindings;
675         binders_.downscaleAndThreshold = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(lBinds), lBinds);
676     }
677     {
678         const RenderHandle shaderHandle =
679             shaderMgr.GetShaderHandle("rendershaders://computeshader/bloom_downscale.shader");
680         const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shaderHandle);
681         psos_.downscale = psoMgr.GetComputePsoHandle(shaderHandle, pl, {});
682         psos_.downscaleTGS = shaderMgr.GetReflectionThreadGroupSize(shaderHandle);
683 
684         PLUGIN_ASSERT(binders_.downscale.size() >= TARGET_COUNT);
685         const auto& binds = pl.descriptorSetLayouts[localSetIdx].bindings;
686         for (uint32_t idx = 0; idx < TARGET_COUNT; ++idx) {
687             binders_.downscale[idx] = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
688         }
689     }
690     {
691         const RenderHandle shaderHandle =
692             shaderMgr.GetShaderHandle("rendershaders://computeshader/bloom_upscale.shader");
693         const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shaderHandle);
694         psos_.upscale = psoMgr.GetComputePsoHandle(shaderHandle, pl, {});
695         psos_.upscaleTGS = shaderMgr.GetReflectionThreadGroupSize(shaderHandle);
696 
697         PLUGIN_ASSERT(binders_.upscale.size() >= TARGET_COUNT);
698         const auto& binds = pl.descriptorSetLayouts[localSetIdx].bindings;
699         for (uint32_t idx = 0; idx < TARGET_COUNT; ++idx) {
700             binders_.upscale[idx] = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
701         }
702     }
703     {
704         const RenderHandle shaderHandle =
705             shaderMgr.GetShaderHandle("rendershaders://computeshader/bloom_combine.shader");
706         const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shaderHandle);
707         psos_.combine = psoMgr.GetComputePsoHandle(shaderHandle, pl, {});
708         psos_.combineTGS = shaderMgr.GetReflectionThreadGroupSize(shaderHandle);
709 
710         const auto& binds = pl.descriptorSetLayouts[localSetIdx].bindings;
711         binders_.combine = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
712     }
713 }
714 
CreateAndReflectRenderPso(const string_view shader)715 std::pair<RenderHandle, const PipelineLayout&> RenderPostProcessBloomNode::CreateAndReflectRenderPso(
716     const string_view shader)
717 {
718     const auto& shaderMgr = renderNodeContextMgr_->GetShaderManager();
719     const RenderHandle shaderHandle = shaderMgr.GetShaderHandle(shader.data());
720     const RenderHandle graphicsStateHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(shaderHandle);
721     const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shaderHandle);
722 
723     auto& psoMgr = renderNodeContextMgr_->GetPsoManager();
724     const RenderHandle pso = psoMgr.GetGraphicsPsoHandle(
725         shaderHandle, graphicsStateHandle, pl, {}, {}, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
726     return { pso, pl };
727 }
728 
CreateRenderPsos()729 void RenderPostProcessBloomNode::CreateRenderPsos()
730 {
731     if (binders_.combine) {
732         return;
733     }
734 
735     constexpr BASE_NS::pair<BloomConfiguration::BloomQualityType, uint32_t> configurations[] = {
736         { BloomConfiguration::BloomQualityType::QUALITY_TYPE_LOW, CORE_BLOOM_QUALITY_LOW },
737         { BloomConfiguration::BloomQualityType::QUALITY_TYPE_NORMAL, CORE_BLOOM_QUALITY_NORMAL },
738         { BloomConfiguration::BloomQualityType::QUALITY_TYPE_HIGH, CORE_BLOOM_QUALITY_HIGH }
739     };
740 
741     const IRenderNodeShaderManager& shaderMgr = renderNodeContextMgr_->GetShaderManager();
742     INodeContextPsoManager& psoMgr = renderNodeContextMgr_->GetPsoManager();
743 
744     for (const auto& configuration : configurations) {
745         {
746             auto shader = shaderMgr.GetShaderHandle("rendershaders://shader/bloom_downscale.shader");
747             const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shader);
748             ShaderSpecializationConstantView specializations = shaderMgr.GetReflectionSpecialization(shader);
749             const ShaderSpecializationConstantDataView specDataView {
750                 { specializations.constants.data(), specializations.constants.size() },
751                 { &configuration.second, 1u },
752             };
753             const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(shader);
754             psos_.downscaleHandles[configuration.first].regular = psoMgr.GetGraphicsPsoHandle(
755                 shader, graphicsState, pl, {}, specDataView, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
756         }
757 
758         {
759             auto shader = shaderMgr.GetShaderHandle("rendershaders://shader/bloom_downscale_threshold.shader");
760             const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shader);
761             ShaderSpecializationConstantView specializations = shaderMgr.GetReflectionSpecialization(shader);
762             const ShaderSpecializationConstantDataView specDataView {
763                 { specializations.constants.data(), specializations.constants.size() },
764                 { &configuration.second, 1u },
765             };
766             const RenderHandle graphicsState = shaderMgr.GetGraphicsStateHandleByShaderHandle(shader);
767             psos_.downscaleHandles[configuration.first].threshold = psoMgr.GetGraphicsPsoHandle(
768                 shader, graphicsState, pl, {}, specDataView, { DYNAMIC_STATES, countof(DYNAMIC_STATES) });
769         }
770     }
771 
772     INodeContextDescriptorSetManager& dSetMgr = renderNodeContextMgr_->GetDescriptorSetManager();
773     constexpr uint32_t localSet { 0U };
774     // the first one creates the global set as well
775     {
776         const auto [pso, pipelineLayout] =
777             CreateAndReflectRenderPso("rendershaders://shader/bloom_downscale_threshold.shader");
778         psos_.downscaleAndThreshold = pso;
779 
780         const auto& lBinds = pipelineLayout.descriptorSetLayouts[localSet].bindings;
781         binders_.downscaleAndThreshold = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(lBinds), lBinds);
782     }
783     {
784         const auto [pso, pipelineLayout] = CreateAndReflectRenderPso("rendershaders://shader/bloom_downscale.shader");
785         psos_.downscale = pso;
786         const auto& binds = pipelineLayout.descriptorSetLayouts[localSet].bindings;
787         for (uint32_t idx = 0; idx < TARGET_COUNT; ++idx) {
788             binders_.downscale[idx] = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
789         }
790     }
791     {
792         const auto [pso, pipelineLayout] = CreateAndReflectRenderPso("rendershaders://shader/bloom_upscale.shader");
793         psos_.upscale = pso;
794         const auto& binds = pipelineLayout.descriptorSetLayouts[localSet].bindings;
795         for (uint32_t idx = 0; idx < TARGET_COUNT; ++idx) {
796             binders_.upscale[idx] = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
797         }
798     }
799     {
800         const auto [pso, pipelineLayout] = CreateAndReflectRenderPso("rendershaders://shader/bloom_combine.shader");
801         psos_.combine = pso;
802         const auto& binds = pipelineLayout.descriptorSetLayouts[localSet].bindings;
803         binders_.combine = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
804     }
805 }
806 RENDER_END_NAMESPACE()
807