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