• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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_bloom.h"
17 
18 #include <base/containers/fixed_string.h>
19 #include <base/math/vector.h>
20 #include <render/datastore/intf_render_data_store_manager.h>
21 #include <render/datastore/intf_render_data_store_pod.h>
22 #include <render/datastore/render_data_store_render_pods.h>
23 #include <render/device/intf_gpu_resource_manager.h>
24 #include <render/device/intf_shader_manager.h>
25 #include <render/namespace.h>
26 #include <render/nodecontext/intf_node_context_descriptor_set_manager.h>
27 #include <render/nodecontext/intf_node_context_pso_manager.h>
28 #include <render/nodecontext/intf_pipeline_descriptor_set_binder.h>
29 #include <render/nodecontext/intf_render_command_list.h>
30 #include <render/nodecontext/intf_render_node_context_manager.h>
31 #include <render/nodecontext/intf_render_node_util.h>
32 
33 #include "util/log.h"
34 
35 // shaders
36 #include <render/shaders/common/render_post_process_structs_common.h>
37 
38 using namespace BASE_NS;
39 
RENDER_BEGIN_NAMESPACE()40 RENDER_BEGIN_NAMESPACE()
41 void RenderBloom::Init(IRenderNodeContextManager& renderNodeContextMgr, const BloomInfo& bloomInfo)
42 {
43     bloomInfo_ = bloomInfo;
44 
45     // NOTE: target counts etc. should probably be resized based on configuration
46     CreatePsos(renderNodeContextMgr);
47 
48     auto& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
49     samplerHandle_ = gpuResourceMgr.Create(samplerHandle_,
50         GpuSamplerDesc {
51             Filter::CORE_FILTER_LINEAR,                                  // magFilter
52             Filter::CORE_FILTER_LINEAR,                                  // minFilter
53             Filter::CORE_FILTER_LINEAR,                                  // mipMapMode
54             SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // addressModeU
55             SamplerAddressMode::CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE  // addressModeV
56         });
57 }
58 
PreExecute(IRenderNodeContextManager & renderNodeContextMgr,const BloomInfo & bloomInfo,const PostProcessConfiguration & ppConfig)59 void RenderBloom::PreExecute(IRenderNodeContextManager& renderNodeContextMgr, const BloomInfo& bloomInfo,
60     const PostProcessConfiguration& ppConfig)
61 {
62     bloomInfo_ = bloomInfo;
63 
64     const GpuImageDesc& imgDesc = renderNodeContextMgr.GetGpuResourceManager().GetImageDescriptor(bloomInfo_.input);
65     uint32_t sizeDenom = 1u;
66     if (ppConfig.bloomConfiguration.bloomQualityType == BloomConfiguration::QUALITY_TYPE_LOW) {
67         sizeDenom = 2u;
68     }
69     CreateTargets(renderNodeContextMgr, Math::UVec2(imgDesc.width, imgDesc.height) / sizeDenom);
70 }
71 
Execute(IRenderNodeContextManager & renderNodeContextMgr,IRenderCommandList & cmdList,const PostProcessConfiguration & ppConfig)72 void RenderBloom::Execute(IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList,
73     const PostProcessConfiguration& ppConfig)
74 {
75     bloomEnabled_ = false;
76     BloomConfiguration bloomConfiguration;
77     if (ppConfig.enableFlags & PostProcessConfiguration::ENABLE_BLOOM_BIT) {
78         bloomConfiguration.thresholdHard = ppConfig.bloomConfiguration.thresholdHard;
79         bloomConfiguration.thresholdSoft = ppConfig.bloomConfiguration.thresholdSoft;
80         bloomConfiguration.amountCoefficient = ppConfig.bloomConfiguration.amountCoefficient;
81         bloomConfiguration.dirtMaskCoefficient = ppConfig.bloomConfiguration.dirtMaskCoefficient;
82 
83         bloomEnabled_ = true;
84     }
85 
86     if (!bloomEnabled_) {
87         bloomConfiguration.amountCoefficient = 0.0f;
88     }
89 
90     bloomParameters_ = Math::Vec4(
91         // .x = thresholdHard, luma values below this won't bloom
92         bloomConfiguration.thresholdHard,
93         // .y = thresholdSoft, luma values from this value to hard threshold will reduce bloom input from 1.0 -> 0.0
94         // i.e. this creates softer threshold for bloom
95         bloomConfiguration.thresholdSoft,
96         // .z = amountCoefficient, will multiply the colors from the bloom textures when combined with original color
97         // target
98         bloomConfiguration.amountCoefficient,
99         // .w = -will multiply the dirt mask effect
100         bloomConfiguration.dirtMaskCoefficient);
101 
102     if (bloomInfo_.useCompute) {
103         ComputeBloom(renderNodeContextMgr, cmdList);
104     } else {
105         GraphicsBloom(renderNodeContextMgr, cmdList);
106     }
107 }
108 
GetDescriptorCounts() const109 DescriptorCounts RenderBloom::GetDescriptorCounts() const
110 {
111     // NOTE: when added support for various bloom target counts, might need to be calculated for max
112     return DescriptorCounts { {
113         { CORE_DESCRIPTOR_TYPE_INPUT_ATTACHMENT, 32u },
114         { CORE_DESCRIPTOR_TYPE_SAMPLED_IMAGE, 32u },
115         { CORE_DESCRIPTOR_TYPE_STORAGE_IMAGE, 32u },
116         { CORE_DESCRIPTOR_TYPE_SAMPLER, 24u },
117         { CORE_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 2u },
118     } };
119 }
120 
GetFinalTarget() const121 RenderHandle RenderBloom::GetFinalTarget() const
122 {
123     if (RenderHandleUtil::IsValid(bloomInfo_.output)) {
124         return bloomInfo_.output;
125     } else {
126         return targets_.tex1[0u].GetHandle();
127     }
128 }
129 
UpdateGlobalSet(IRenderCommandList & cmdList)130 void RenderBloom::UpdateGlobalSet(IRenderCommandList& cmdList)
131 {
132     auto& binder = *binders_.globalSet0;
133     binder.ClearBindings();
134     uint32_t binding = 0u;
135     binder.BindBuffer(binding++, bloomInfo_.globalUbo, 0);
136     binder.BindBuffer(binding++, bloomInfo_.globalUbo, 0);
137     cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
138 }
139 
ComputeBloom(IRenderNodeContextManager & renderNodeContextMgr,IRenderCommandList & cmdList)140 void RenderBloom::ComputeBloom(IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList)
141 {
142     constexpr PushConstant pc { ShaderStageFlagBits::CORE_SHADER_STAGE_COMPUTE_BIT,
143         sizeof(LocalPostProcessPushConstantStruct) };
144 
145     UpdateGlobalSet(cmdList);
146     if (bloomEnabled_) {
147         ComputeDownscaleAndThreshold(pc, cmdList);
148         ComputeDownscale(pc, cmdList);
149         ComputeUpscale(pc, cmdList);
150     }
151     // needs to be done even when bloom is disabled if node is in use
152     if (RenderHandleUtil::IsValid(bloomInfo_.output)) {
153         ComputeCombine(pc, cmdList);
154     }
155 }
156 
ComputeDownscaleAndThreshold(const PushConstant & pc,IRenderCommandList & cmdList)157 void RenderBloom::ComputeDownscaleAndThreshold(const PushConstant& pc, IRenderCommandList& cmdList)
158 {
159     RenderHandle sets[2u] {};
160     sets[0u] = binders_.globalSet0->GetDescriptorSetHandle();
161     {
162         auto& binder = *binders_.downscaleAndThreshold;
163         sets[1u] = binder.GetDescriptorSetHandle();
164         binder.ClearBindings();
165 
166         uint32_t binding = 0;
167         binder.BindImage(binding++, { targets_.tex1[0].GetHandle() });
168         binder.BindImage(binding++, { bloomInfo_.input });
169         binder.BindSampler(binding++, { samplerHandle_.GetHandle() });
170 
171         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
172     }
173 
174     cmdList.BindPipeline(psos_.downscaleAndThreshold);
175     const ShaderThreadGroup tgs = psos_.downscaleAndThresholdTGS;
176 
177     // bind all sets
178     cmdList.BindDescriptorSets(0, sets);
179 
180     const auto targetSize = targets_.tex1Size[0];
181 
182     LocalPostProcessPushConstantStruct uPc;
183     uPc.factor = bloomParameters_;
184     uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
185         1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
186 
187     cmdList.PushConstant(pc, reinterpret_cast<uint8_t*>(&uPc));
188 
189     cmdList.Dispatch((targetSize.x + tgs.x - 1) / tgs.x, (targetSize.y + tgs.y - 1) / tgs.y, 1);
190 }
191 
ComputeDownscale(const PushConstant & pc,IRenderCommandList & cmdList)192 void RenderBloom::ComputeDownscale(const PushConstant& pc, IRenderCommandList& cmdList)
193 {
194     cmdList.BindPipeline(psos_.downscale);
195     const ShaderThreadGroup tgs = psos_.downscaleTGS;
196 
197     cmdList.BindDescriptorSet(0u, binders_.globalSet0->GetDescriptorSetHandle());
198 
199     for (size_t i = 1; i < targets_.tex1.size(); ++i) {
200         auto& binder = *binders_.downscale[i];
201         binder.ClearBindings();
202 
203         uint32_t binding = 0;
204         binder.BindImage(binding++, { targets_.tex1[i].GetHandle() });
205         binder.BindImage(binding++, { targets_.tex1[i - 1].GetHandle() });
206         binder.BindSampler(binding++, { samplerHandle_.GetHandle() });
207 
208         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
209         cmdList.BindDescriptorSet(1u, binder.GetDescriptorSetHandle());
210 
211         const auto targetSize = targets_.tex1Size[i];
212 
213         LocalPostProcessPushConstantStruct uPc;
214         uPc.factor = bloomParameters_;
215         uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
216             1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
217         cmdList.PushConstant(pc, reinterpret_cast<uint8_t*>(&uPc));
218 
219         cmdList.Dispatch((targetSize.x + tgs.x - 1) / tgs.x, (targetSize.y + tgs.y - 1) / tgs.y, 1);
220     }
221 }
222 
ComputeUpscale(const PushConstant & pc,IRenderCommandList & cmdList)223 void RenderBloom::ComputeUpscale(const PushConstant& pc, IRenderCommandList& cmdList)
224 {
225     cmdList.BindPipeline(psos_.upscale);
226     const ShaderThreadGroup tgs = psos_.upscaleTGS;
227 
228     cmdList.BindDescriptorSet(0u, binders_.globalSet0->GetDescriptorSetHandle());
229 
230     for (size_t i = targets_.tex1.size() - 1; i != 0; --i) {
231         auto& binder = *binders_.upscale[i];
232         binder.ClearBindings();
233 
234         // NOTE: double binding
235         binder.BindImage(0u, { targets_.tex1[i].GetHandle() });
236         binder.BindImage(0u, { targets_.tex1[i].GetHandle() });
237         binder.BindImage(1u, { targets_.tex1[i - 1].GetHandle() });
238         binder.BindSampler(2u, { samplerHandle_.GetHandle() });
239 
240         // update the descriptor set bindings for set 1
241         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
242         cmdList.BindDescriptorSet(1u, binder.GetDescriptorSetHandle());
243 
244         const auto targetSize = targets_.tex1Size[i - 1];
245 
246         LocalPostProcessPushConstantStruct uPc;
247         uPc.factor = bloomParameters_;
248         uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
249             1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
250         cmdList.PushConstant(pc, reinterpret_cast<uint8_t*>(&uPc));
251 
252         cmdList.Dispatch((targetSize.x + tgs.x - 1) / tgs.x, (targetSize.y + tgs.y - 1) / tgs.y, 1);
253     }
254 }
255 
ComputeCombine(const PushConstant & pc,IRenderCommandList & cmdList)256 void RenderBloom::ComputeCombine(const PushConstant& pc, IRenderCommandList& cmdList)
257 {
258     cmdList.BindPipeline(psos_.combine);
259     const ShaderThreadGroup tgs = psos_.combineTGS;
260 
261     RenderHandle sets[2u] {};
262     sets[0u] = binders_.globalSet0->GetDescriptorSetHandle();
263     {
264         auto& binder = *binders_.combine;
265         sets[1u] = binder.GetDescriptorSetHandle();
266         binder.ClearBindings();
267         // bind resources to set 1
268         uint32_t binding = 0;
269         binder.BindImage(binding++, { bloomInfo_.output });
270         binder.BindImage(binding++, { bloomInfo_.input });
271         binder.BindImage(binding++, { targets_.tex1[0].GetHandle() });
272         binder.BindSampler(binding++, { samplerHandle_.GetHandle() });
273 
274         // update the descriptor set bindings for set 1
275         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
276     }
277 
278     cmdList.BindDescriptorSets(0u, sets);
279 
280     const auto targetSize = baseSize_;
281 
282     LocalPostProcessPushConstantStruct uPc;
283     uPc.factor = bloomParameters_;
284     uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
285         1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
286     cmdList.PushConstant(pc, reinterpret_cast<uint8_t*>(&uPc));
287 
288     cmdList.Dispatch((targetSize.x + tgs.x - 1) / tgs.x, (targetSize.y + tgs.y - 1) / tgs.y, 1);
289 }
290 
GraphicsBloom(IRenderNodeContextManager & renderNodeContextMgr,IRenderCommandList & cmdList)291 void RenderBloom::GraphicsBloom(IRenderNodeContextManager& renderNodeContextMgr, IRenderCommandList& cmdList)
292 {
293     RenderPass renderPass;
294     renderPass.renderPassDesc.attachmentCount = 1;
295     renderPass.renderPassDesc.subpassCount = 1;
296     renderPass.renderPassDesc.attachments[0].loadOp = AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
297     renderPass.renderPassDesc.attachments[0].storeOp = AttachmentStoreOp::CORE_ATTACHMENT_STORE_OP_STORE;
298 
299     RenderPassSubpassDesc& subpassDesc = renderPass.subpassDesc;
300     subpassDesc.colorAttachmentCount = 1;
301     subpassDesc.colorAttachmentIndices[0] = 0;
302 
303     constexpr PushConstant pc { ShaderStageFlagBits::CORE_SHADER_STAGE_FRAGMENT_BIT,
304         sizeof(LocalPostProcessPushConstantStruct) };
305 
306     UpdateGlobalSet(cmdList);
307     if (bloomEnabled_) {
308         RenderDownscaleAndThreshold(renderPass, pc, cmdList);
309         RenderDownscale(renderPass, pc, cmdList);
310         RenderUpscale(renderPass, pc, cmdList);
311     }
312     // combine (needs to be done even when bloom is disabled if node is in use
313     if (RenderHandleUtil::IsValid(bloomInfo_.output)) {
314         RenderCombine(renderPass, pc, cmdList);
315     }
316 }
317 
RenderDownscaleAndThreshold(RenderPass & renderPass,const PushConstant & pc,IRenderCommandList & cmdList)318 void RenderBloom::RenderDownscaleAndThreshold(
319     RenderPass& renderPass, const PushConstant& pc, IRenderCommandList& cmdList)
320 {
321     const auto targetSize = targets_.tex1Size[0];
322     const ViewportDesc viewportDesc { 0, 0, static_cast<float>(targetSize.x), static_cast<float>(targetSize.y) };
323     const ScissorDesc scissorDesc = { 0, 0, targetSize.x, targetSize.y };
324 
325     renderPass.renderPassDesc.attachmentHandles[0] = targets_.tex1[0].GetHandle();
326     renderPass.renderPassDesc.renderArea = { 0, 0, targetSize.x, targetSize.y };
327     cmdList.BeginRenderPass(renderPass.renderPassDesc, 0, renderPass.subpassDesc);
328 
329     cmdList.SetDynamicStateViewport(viewportDesc);
330     cmdList.SetDynamicStateScissor(scissorDesc);
331     cmdList.BindPipeline(psos_.downscaleAndThreshold);
332 
333     RenderHandle sets[2u] {};
334     sets[0u] = binders_.globalSet0->GetDescriptorSetHandle();
335     {
336         auto& binder = *binders_.downscaleAndThreshold;
337         sets[1u] = binder.GetDescriptorSetHandle();
338         binder.ClearBindings();
339 
340         binder.BindImage(0u, { bloomInfo_.input });
341         binder.BindSampler(1u, { samplerHandle_.GetHandle() });
342         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
343     }
344     cmdList.BindDescriptorSets(0u, sets);
345 
346     LocalPostProcessPushConstantStruct uPc;
347     uPc.factor = bloomParameters_;
348     uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
349         1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
350 
351     cmdList.PushConstant(pc, reinterpret_cast<uint8_t*>(&uPc));
352     cmdList.Draw(3u, 1u, 0u, 0u);
353     cmdList.EndRenderPass();
354 }
355 
RenderDownscale(RenderPass & renderPass,const PushConstant & pc,IRenderCommandList & cmdList)356 void RenderBloom::RenderDownscale(RenderPass& renderPass, const PushConstant& pc, IRenderCommandList& cmdList)
357 {
358     LocalPostProcessPushConstantStruct uPc;
359     uPc.factor = bloomParameters_;
360 
361     RenderHandle sets[2u] {};
362     sets[0u] = binders_.globalSet0->GetDescriptorSetHandle();
363     for (size_t idx = 1; idx < targets_.tex1.size(); ++idx) {
364         const auto targetSize = targets_.tex1Size[idx];
365         const ViewportDesc viewportDesc { 0, 0, static_cast<float>(targetSize.x), static_cast<float>(targetSize.y) };
366         const ScissorDesc scissorDesc = { 0, 0, targetSize.x, targetSize.y };
367 
368         renderPass.renderPassDesc.attachmentHandles[0] = targets_.tex1[idx].GetHandle();
369         renderPass.renderPassDesc.renderArea = { 0, 0, targetSize.x, targetSize.y };
370         cmdList.BeginRenderPass(renderPass.renderPassDesc, 0, renderPass.subpassDesc);
371 
372         cmdList.SetDynamicStateViewport(viewportDesc);
373         cmdList.SetDynamicStateScissor(scissorDesc);
374 
375         cmdList.BindPipeline(psos_.downscale);
376 
377         {
378             auto& binder = *binders_.downscale[idx];
379             sets[1u] = binder.GetDescriptorSetHandle();
380             binder.ClearBindings();
381             binder.BindImage(0u, { targets_.tex1[idx - 1].GetHandle() });
382             binder.BindSampler(1u, { samplerHandle_.GetHandle() });
383             cmdList.UpdateDescriptorSet(
384                 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
385         }
386         cmdList.BindDescriptorSets(0u, sets);
387 
388         uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
389             1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
390 
391         cmdList.PushConstant(pc, reinterpret_cast<uint8_t*>(&uPc));
392         cmdList.Draw(3u, 1u, 0u, 0u);
393         cmdList.EndRenderPass();
394     }
395 }
396 
RenderUpscale(RenderPass & renderPass,const PushConstant & pc,IRenderCommandList & cmdList)397 void RenderBloom::RenderUpscale(RenderPass& renderPass, const PushConstant& pc, IRenderCommandList& cmdList)
398 {
399     RenderPass renderPassUpscale = renderPass;
400     renderPassUpscale.subpassDesc.inputAttachmentCount = 1;
401     renderPassUpscale.subpassDesc.inputAttachmentIndices[0] = 0;
402     renderPassUpscale.renderPassDesc.attachments[0].loadOp = AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_LOAD;
403     renderPassUpscale.renderPassDesc.attachments[0].storeOp = AttachmentStoreOp::CORE_ATTACHMENT_STORE_OP_STORE;
404 
405     RenderHandle sets[2u] {};
406     sets[0u] = binders_.globalSet0->GetDescriptorSetHandle();
407     for (size_t idx = targets_.tex1.size() - 1; idx != 0; --idx) {
408         const auto targetSize = targets_.tex1Size[idx - 1];
409         const ViewportDesc viewportDesc { 0, 0, static_cast<float>(targetSize.x), static_cast<float>(targetSize.y) };
410         const ScissorDesc scissorDesc = { 0, 0, targetSize.x, targetSize.y };
411 
412         renderPassUpscale.renderPassDesc.attachmentHandles[0] = targets_.tex1[idx - 1].GetHandle();
413         renderPassUpscale.renderPassDesc.renderArea = { 0, 0, targetSize.x, targetSize.y };
414         cmdList.BeginRenderPass(renderPassUpscale.renderPassDesc, 0, renderPassUpscale.subpassDesc);
415 
416         cmdList.SetDynamicStateViewport(viewportDesc);
417         cmdList.SetDynamicStateScissor(scissorDesc);
418 
419         cmdList.BindPipeline(psos_.upscale);
420 
421         {
422             auto& binder = *binders_.upscale[idx];
423             sets[1u] = binder.GetDescriptorSetHandle();
424             binder.ClearBindings();
425 
426             uint32_t binding = 0;
427             binder.BindImage(binding++, { targets_.tex1[idx].GetHandle() });
428             binder.BindImage(
429                 binding++, { targets_.tex1[idx - 1].GetHandle(), PipelineStateConstants::GPU_IMAGE_ALL_MIP_LEVELS,
430                                PipelineStateConstants::GPU_IMAGE_ALL_LAYERS, ImageLayout::CORE_IMAGE_LAYOUT_GENERAL });
431             binder.BindSampler(binding++, { samplerHandle_.GetHandle() });
432             cmdList.UpdateDescriptorSet(
433                 binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
434         }
435         cmdList.BindDescriptorSets(0u, sets);
436         LocalPostProcessPushConstantStruct uPc;
437         uPc.factor = bloomParameters_;
438         uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
439             1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
440 
441         cmdList.PushConstant(pc, reinterpret_cast<uint8_t*>(&uPc));
442         cmdList.Draw(3u, 1u, 0u, 0u);
443         cmdList.EndRenderPass();
444     }
445 }
446 
RenderCombine(RenderPass & renderPass,const PushConstant & pc,IRenderCommandList & cmdList)447 void RenderBloom::RenderCombine(RenderPass& renderPass, const PushConstant& pc, IRenderCommandList& cmdList)
448 {
449     const auto targetSize = baseSize_;
450 
451     renderPass.renderPassDesc.attachmentHandles[0] = bloomInfo_.output;
452     renderPass.renderPassDesc.renderArea = { 0, 0, targetSize.x, targetSize.y };
453     cmdList.BeginRenderPass(renderPass.renderPassDesc, 0, renderPass.subpassDesc);
454 
455     cmdList.SetDynamicStateViewport(baseViewportDesc_);
456     cmdList.SetDynamicStateScissor(baseScissorDesc_);
457 
458     cmdList.BindPipeline(psos_.combine);
459 
460     RenderHandle sets[2u] {};
461     sets[0u] = binders_.globalSet0->GetDescriptorSetHandle();
462     {
463         auto& binder = *binders_.combine;
464         sets[1u] = binder.GetDescriptorSetHandle();
465         binder.ClearBindings();
466 
467         uint32_t binding = 0;
468         binder.BindImage(binding++, { bloomInfo_.input });
469         binder.BindImage(binding++, { targets_.tex1[0].GetHandle() });
470         binder.BindSampler(binding++, { samplerHandle_.GetHandle() });
471 
472         cmdList.UpdateDescriptorSet(binder.GetDescriptorSetHandle(), binder.GetDescriptorSetLayoutBindingResources());
473     }
474     cmdList.BindDescriptorSets(0u, sets);
475 
476     LocalPostProcessPushConstantStruct uPc;
477     uPc.factor = bloomParameters_;
478     uPc.viewportSizeInvSize = Math::Vec4(static_cast<float>(targetSize.x), static_cast<float>(targetSize.y),
479         1.0f / static_cast<float>(targetSize.x), 1.0f / static_cast<float>(targetSize.y));
480 
481     cmdList.PushConstant(pc, reinterpret_cast<uint8_t*>(&uPc));
482     cmdList.Draw(3u, 1u, 0u, 0u);
483     cmdList.EndRenderPass();
484 }
485 
CreateTargets(IRenderNodeContextManager & renderNodeContextMgr,const Math::UVec2 baseSize)486 void RenderBloom::CreateTargets(IRenderNodeContextManager& renderNodeContextMgr, const Math::UVec2 baseSize)
487 {
488     if (baseSize.x != baseSize_.x || baseSize.y != baseSize_.y) {
489         baseSize_ = baseSize;
490 
491         format_ = Format::BASE_FORMAT_B10G11R11_UFLOAT_PACK32;
492         ImageUsageFlags usageFlags = CORE_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | CORE_IMAGE_USAGE_SAMPLED_BIT |
493                                      CORE_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
494 
495         if (bloomInfo_.useCompute) {
496             format_ = Format::BASE_FORMAT_R16G16B16A16_SFLOAT; // used due to GLES
497             usageFlags = CORE_IMAGE_USAGE_STORAGE_BIT | CORE_IMAGE_USAGE_SAMPLED_BIT;
498         } else {
499             baseViewportDesc_ = { 0.0f, 0.0f, static_cast<float>(baseSize.x), static_cast<float>(baseSize.y), 0.0f,
500                 1.0f };
501             baseScissorDesc_ = { 0, 0, baseSize.x, baseSize.y };
502         }
503 
504         // create target image
505         const Math::UVec2 startTargetSize = baseSize_;
506         GpuImageDesc desc {
507             ImageType::CORE_IMAGE_TYPE_2D,
508             ImageViewType::CORE_IMAGE_VIEW_TYPE_2D,
509             format_,
510             ImageTiling::CORE_IMAGE_TILING_OPTIMAL,
511             usageFlags,
512             MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
513             0,
514             EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_DYNAMIC_BARRIERS,
515             startTargetSize.x,
516             startTargetSize.y,
517             1u,
518             1u,
519             1u,
520             SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,
521             {},
522         };
523 
524         auto& gpuResourceMgr = renderNodeContextMgr.GetGpuResourceManager();
525 #if (RENDER_VALIDATION_ENABLED == 1)
526         const string_view nodeName = renderNodeContextMgr.GetName();
527 #endif
528         for (size_t idx = 0; idx < targets_.tex1.size(); ++idx) {
529             // every bloom target is half the size of the original/ previous bloom target
530             desc.width /= 2u;
531             desc.height /= 2u;
532             desc.width = (desc.width >= 1u) ? desc.width : 1u;
533             desc.height = (desc.height >= 1u) ? desc.height : 1u;
534             targets_.tex1Size[idx] = Math::UVec2(desc.width, desc.height);
535 #if (RENDER_VALIDATION_ENABLED == 1)
536             const auto targetName = nodeName + "_Bloom_" + to_string(idx);
537             targets_.tex1[idx] = gpuResourceMgr.Create(targetName, desc);
538 #else
539             targets_.tex1[idx] = gpuResourceMgr.Create(targets_.tex1[idx], desc);
540 #endif
541         }
542     }
543 }
544 
CreatePsos(IRenderNodeContextManager & renderNodeContextMgr)545 void RenderBloom::CreatePsos(IRenderNodeContextManager& renderNodeContextMgr)
546 {
547     if (bloomInfo_.useCompute) {
548         CreateComputePsos(renderNodeContextMgr);
549     } else {
550         CreateRenderPsos(renderNodeContextMgr);
551     }
552 }
553 
CreateComputePsos(IRenderNodeContextManager & renderNodeContextMgr)554 void RenderBloom::CreateComputePsos(IRenderNodeContextManager& renderNodeContextMgr)
555 {
556     const auto& shaderMgr = renderNodeContextMgr.GetShaderManager();
557     INodeContextPsoManager& psoMgr = renderNodeContextMgr.GetPsoManager();
558     INodeContextDescriptorSetManager& dSetMgr = renderNodeContextMgr.GetDescriptorSetManager();
559 
560     constexpr uint32_t globalSet = 0u;
561     constexpr uint32_t localSetIdx = 1u;
562     // the first one creates the global set as well
563     {
564         const RenderHandle shaderHandle =
565             shaderMgr.GetShaderHandle("rendershaders://computeshader/bloom_downscale_threshold.shader");
566         const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shaderHandle);
567         psos_.downscaleAndThreshold = psoMgr.GetComputePsoHandle(shaderHandle, pl, {});
568         psos_.downscaleAndThresholdTGS = shaderMgr.GetReflectionThreadGroupSize(shaderHandle);
569 
570         const auto& gBinds = pl.descriptorSetLayouts[globalSet].bindings;
571         binders_.globalSet0 = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(gBinds), gBinds);
572 
573         const auto& lBinds = pl.descriptorSetLayouts[localSetIdx].bindings;
574         binders_.downscaleAndThreshold = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(lBinds), lBinds);
575     }
576     {
577         const RenderHandle shaderHandle =
578             shaderMgr.GetShaderHandle("rendershaders://computeshader/bloom_downscale.shader");
579         const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shaderHandle);
580         psos_.downscale = psoMgr.GetComputePsoHandle(shaderHandle, pl, {});
581         psos_.downscaleTGS = shaderMgr.GetReflectionThreadGroupSize(shaderHandle);
582 
583         PLUGIN_ASSERT(binders_.downscale.size() >= TARGET_COUNT);
584         const auto& binds = pl.descriptorSetLayouts[localSetIdx].bindings;
585         for (uint32_t idx = 0; idx < TARGET_COUNT; ++idx) {
586             binders_.downscale[idx] = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
587         }
588     }
589     {
590         const RenderHandle shaderHandle =
591             shaderMgr.GetShaderHandle("rendershaders://computeshader/bloom_upscale.shader");
592         const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shaderHandle);
593         psos_.upscale = psoMgr.GetComputePsoHandle(shaderHandle, pl, {});
594         psos_.upscaleTGS = shaderMgr.GetReflectionThreadGroupSize(shaderHandle);
595 
596         PLUGIN_ASSERT(binders_.upscale.size() >= TARGET_COUNT);
597         const auto& binds = pl.descriptorSetLayouts[localSetIdx].bindings;
598         for (uint32_t idx = 0; idx < TARGET_COUNT; ++idx) {
599             binders_.upscale[idx] = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
600         }
601     }
602     {
603         const RenderHandle shaderHandle =
604             shaderMgr.GetShaderHandle("rendershaders://computeshader/bloom_combine.shader");
605         const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shaderHandle);
606         psos_.combine = psoMgr.GetComputePsoHandle(shaderHandle, pl, {});
607         psos_.combineTGS = shaderMgr.GetReflectionThreadGroupSize(shaderHandle);
608 
609         const auto& binds = pl.descriptorSetLayouts[localSetIdx].bindings;
610         binders_.combine = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
611     }
612 }
613 
CreateAndReflectRenderPso(IRenderNodeContextManager & renderNodeContextMgr,const string_view shader,const RenderPass & renderPass,const DynamicStateFlags dynamicStateFlags)614 std::pair<RenderHandle, const PipelineLayout&> RenderBloom::CreateAndReflectRenderPso(
615     IRenderNodeContextManager& renderNodeContextMgr, const string_view shader, const RenderPass& renderPass,
616     const DynamicStateFlags dynamicStateFlags)
617 {
618     const auto& shaderMgr = renderNodeContextMgr.GetShaderManager();
619     const RenderHandle shaderHandle = shaderMgr.GetShaderHandle(shader.data());
620     const RenderHandle graphicsStateHandle = shaderMgr.GetGraphicsStateHandleByShaderHandle(shaderHandle);
621     const PipelineLayout& pl = shaderMgr.GetReflectionPipelineLayout(shaderHandle);
622 
623     auto& psoMgr = renderNodeContextMgr.GetPsoManager();
624     const RenderHandle pso =
625         psoMgr.GetGraphicsPsoHandle(shaderHandle, graphicsStateHandle, pl, {}, {}, dynamicStateFlags);
626     return { pso, pl };
627 }
628 
CreateRenderPsos(IRenderNodeContextManager & renderNodeContextMgr)629 void RenderBloom::CreateRenderPsos(IRenderNodeContextManager& renderNodeContextMgr)
630 {
631     RenderPass renderPass;
632     renderPass.renderPassDesc.attachmentCount = 1;
633     renderPass.renderPassDesc.attachmentHandles[0] = bloomInfo_.input;
634     renderPass.renderPassDesc.renderArea = { 0, 0, baseSize_.x, baseSize_.y };
635     renderPass.renderPassDesc.subpassCount = 1;
636     renderPass.renderPassDesc.attachments[0].loadOp = AttachmentLoadOp::CORE_ATTACHMENT_LOAD_OP_DONT_CARE;
637     renderPass.renderPassDesc.attachments[0].storeOp = AttachmentStoreOp::CORE_ATTACHMENT_STORE_OP_STORE;
638 
639     RenderPassSubpassDesc subpassDesc = renderPass.subpassDesc;
640     subpassDesc.colorAttachmentCount = 1;
641     subpassDesc.colorAttachmentIndices[0] = 0;
642 
643     constexpr DynamicStateFlags dynamicStateFlags = CORE_DYNAMIC_STATE_VIEWPORT | CORE_DYNAMIC_STATE_SCISSOR;
644 
645     INodeContextDescriptorSetManager& dSetMgr = renderNodeContextMgr.GetDescriptorSetManager();
646     constexpr uint32_t globalSet = 0u;
647     constexpr uint32_t localSet = 1u;
648     // the first one creates the global set as well
649     {
650         const auto [pso, pipelineLayout] = CreateAndReflectRenderPso(renderNodeContextMgr,
651             "rendershaders://shader/bloom_downscale_threshold.shader", renderPass, dynamicStateFlags);
652         psos_.downscaleAndThreshold = pso;
653 
654         const auto& gBinds = pipelineLayout.descriptorSetLayouts[globalSet].bindings;
655         binders_.globalSet0 = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(gBinds), gBinds);
656 
657         const auto& lBinds = pipelineLayout.descriptorSetLayouts[localSet].bindings;
658         binders_.downscaleAndThreshold = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(lBinds), lBinds);
659     }
660     {
661         const auto [pso, pipelineLayout] = CreateAndReflectRenderPso(
662             renderNodeContextMgr, "rendershaders://shader/bloom_downscale.shader", renderPass, dynamicStateFlags);
663         psos_.downscale = pso;
664         const auto& binds = pipelineLayout.descriptorSetLayouts[localSet].bindings;
665         for (uint32_t idx = 0; idx < TARGET_COUNT; ++idx) {
666             binders_.downscale[idx] = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
667         }
668     }
669     {
670         const auto [pso, pipelineLayout] = CreateAndReflectRenderPso(
671             renderNodeContextMgr, "rendershaders://shader/bloom_upscale.shader", renderPass, dynamicStateFlags);
672         psos_.upscale = pso;
673         const auto& binds = pipelineLayout.descriptorSetLayouts[localSet].bindings;
674         for (uint32_t idx = 0; idx < TARGET_COUNT; ++idx) {
675             binders_.upscale[idx] = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
676         }
677     }
678     {
679         const auto [pso, pipelineLayout] = CreateAndReflectRenderPso(
680             renderNodeContextMgr, "rendershaders://shader/bloom_combine.shader", renderPass, dynamicStateFlags);
681         psos_.combine = pso;
682         const auto& binds = pipelineLayout.descriptorSetLayouts[localSet].bindings;
683         binders_.combine = dSetMgr.CreateDescriptorSetBinder(dSetMgr.CreateDescriptorSet(binds), binds);
684     }
685 }
686 RENDER_END_NAMESPACE()
687