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