Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
SSAOPreRenderOperator.cpp
Go to the documentation of this file.
1
2
4
15
17
18namespace Divide {
19
20namespace
21{
22 constexpr U8 SSAO_NOISE_SIZE = 4;
24 constexpr U8 MAX_KERNEL_SIZE = 64;
25 constexpr U8 MIN_KERNEL_SIZE = 8;
27
28 [[nodiscard]] const vector<vec4<F32>>& ComputeKernel(const U8 sampleCount)
29 {
30 g_kernels.resize(sampleCount);
31 for (U16 i = 0; i < sampleCount; ++i) {
32 vec3<F32>& k = g_kernels[i].xyz;
33 k.set(Random(-1.f, 1.f),
34 Random(-1.f, 1.f),
35 Random( 0.f, 1.f)); // Kernel hemisphere points to positive Z-Axis.
36 k.normalize(); // Normalize, so included in the hemisphere.
37 k *= FastLerp(0.1f, 1.0f, SQUARED(to_F32(i) / to_F32(sampleCount))); // Create a scale value between [0;1].
38 }
39
40 return g_kernels;
41 }
42}
43
44//ref: http://john-chapman-graphics.blogspot.co.uk/2013/01/ssao-tutorial.html
47{
48 const auto& config = context.context().config().rendering.postFX.ssao;
49 _genHalfRes = config.UseHalfResolution;
50 _blurThreshold[0] = config.FullRes.BlurThreshold;
51 _blurThreshold[1] = config.HalfRes.BlurThreshold;
52 _blurSharpness[0] = config.FullRes.BlurSharpness;
53 _blurSharpness[1] = config.HalfRes.BlurSharpness;
54 _kernelSampleCount[0] = CLAMPED(config.FullRes.KernelSampleCount, MIN_KERNEL_SIZE, MAX_KERNEL_SIZE);
55 _kernelSampleCount[1] = CLAMPED(config.HalfRes.KernelSampleCount, MIN_KERNEL_SIZE, MAX_KERNEL_SIZE);
56 _blur[0] = config.FullRes.Blur;
57 _blur[1] = config.HalfRes.Blur;
58 _radius[0] = config.FullRes.Radius;
59 _radius[1] = config.HalfRes.Radius;
60 _power[0] = config.FullRes.Power;
61 _power[1] = config.HalfRes.Power;
62 _bias[0] = config.FullRes.Bias;
63 _bias[1] = config.HalfRes.Bias;
64 _maxRange[0] = config.FullRes.MaxRange;
65 _maxRange[1] = config.HalfRes.MaxRange;
66 _fadeStart[0] = config.FullRes.FadeDistance;
67 _fadeStart[1] = config.HalfRes.FadeDistance;
68
69 std::array<vec4<F32>, SQUARED(SSAO_NOISE_SIZE)> noiseData;
70
71 for (vec4<F32>& noise : noiseData)
72 {
73 noise.set(Random(-1.f, 1.f), Random(-1.f, 1.f), 0.f, 1.f);
74 noise.normalize();
75 }
76
77 SamplerDescriptor nearestSampler = {};
78 nearestSampler._wrapU = TextureWrap::CLAMP_TO_EDGE;
79 nearestSampler._wrapV = TextureWrap::CLAMP_TO_EDGE;
80 nearestSampler._wrapW = TextureWrap::CLAMP_TO_EDGE;
81 nearestSampler._minFilter = TextureFilter::NEAREST;
82 nearestSampler._magFilter = TextureFilter::NEAREST;
84 nearestSampler._anisotropyLevel = 0u;
85
86 SamplerDescriptor screenSampler = {};
87 screenSampler._wrapU = TextureWrap::CLAMP_TO_EDGE;
88 screenSampler._wrapV = TextureWrap::CLAMP_TO_EDGE;
89 screenSampler._wrapW = TextureWrap::CLAMP_TO_EDGE;
91 screenSampler._anisotropyLevel = 0u;
92
100
101 ResourceDescriptor<Texture> textureAttachment( "SSAOPreRenderOperator_NoiseTexture" );
102 TextureDescriptor& noiseDescriptor = textureAttachment._propertyDescriptor;
103
104 noiseDescriptor._dataType = GFXDataFormat::FLOAT_32;
105 noiseDescriptor._packing = GFXImagePacking::UNNORMALIZED;
106 noiseDescriptor._mipMappingState = MipMappingState::OFF;
107
108 _noiseTexture = CreateResource( textureAttachment);
109 Get(_noiseTexture)->createWithData((Byte*)noiseData.data(), noiseData.size() * sizeof(vec4<F32>), vec2<U16>(SSAO_NOISE_SIZE, SSAO_NOISE_SIZE), {});
110 {
111 TextureDescriptor outputDescriptor{};
112 outputDescriptor._dataType = GFXDataFormat::FLOAT_16;
113 outputDescriptor._baseFormat = GFXImageFormat::RED;
114 outputDescriptor._packing = GFXImagePacking::UNNORMALIZED;
115 outputDescriptor._mipMappingState = MipMappingState::OFF;
116 const vec2<U16> res = parent.screenRT()._rt->getResolution();
117
118 RenderTargetDescriptor desc = {};
119 desc._attachments =
120 {
122 };
123 desc._name = "SSAO_Out";
124 desc._resolution = res;
125
126 //Colour0 holds the AO texture
128
129 desc._name = "SSAO_Blur_Buffer";
131
132 desc._name = "SSAO_Out_HalfRes";
133 desc._resolution /= 2;
134
136 }
137 {
138 TextureDescriptor outputDescriptor{};
139 outputDescriptor._dataType = GFXDataFormat::FLOAT_32;
140 outputDescriptor._packing = GFXImagePacking::UNNORMALIZED;
141 outputDescriptor._mipMappingState = MipMappingState::OFF;
142
143 RenderTargetDescriptor desc = {};
144 desc._attachments =
145 {
147 };
148
149 desc._name = "HalfRes_Normals_Depth";
150 desc._resolution = parent.screenRT()._rt->getResolution() / 2;
151
153 }
154
155 const ShaderModuleDescriptor vertModule{ ShaderType::VERTEX, "baseVertexShaders.glsl", "FullScreenQuad" };
156
157 ShaderModuleDescriptor fragModule = {};
159 fragModule._sourceFile = "SSAOPass.glsl";
160
161 { //Calc Full
162 fragModule._variant = "SSAOCalc";
163 fragModule._defines.resize(0);
164 fragModule._defines.emplace_back(Util::StringFormat("SSAO_SAMPLE_COUNT {}", _kernelSampleCount[0]));
165
166 ShaderProgramDescriptor ssaoShaderDescriptor = {};
167 ssaoShaderDescriptor._modules.push_back(vertModule);
168 ssaoShaderDescriptor._modules.push_back(fragModule);
169
170 ResourceDescriptor<ShaderProgram> ssaoGenerate("SSAOCalc", ssaoShaderDescriptor );
171 ssaoGenerate.waitForReady(false);
172 _ssaoGenerateShader = CreateResource(ssaoGenerate);
173 }
174 { //Calc Half
175 fragModule._variant = "SSAOCalc";
176 fragModule._defines.resize(0);
177 fragModule._defines.emplace_back(Util::StringFormat("SSAO_SAMPLE_COUNT {}", _kernelSampleCount[1]));
178 fragModule._defines.emplace_back("COMPUTE_HALF_RES");
179
180 ShaderProgramDescriptor ssaoShaderDescriptor = {};
181 ssaoShaderDescriptor._modules.push_back(vertModule);
182 ssaoShaderDescriptor._modules.push_back(fragModule);
183
184 ResourceDescriptor<ShaderProgram> ssaoGenerateHalfRes( "SSAOCalcHalfRes", ssaoShaderDescriptor );
185 ssaoGenerateHalfRes.waitForReady(false);
186 _ssaoGenerateHalfResShader = CreateResource(ssaoGenerateHalfRes);
187 }
188
189 { //Blur
190 fragModule._variant = "SSAOBlur.Nvidia";
191 fragModule._defines.resize(0);
192 fragModule._defines.emplace_back(Util::StringFormat("BLUR_SIZE {}", SSAO_BLUR_SIZE));
193
194 ShaderProgramDescriptor ssaoShaderDescriptor = {};
195 ssaoShaderDescriptor._modules.push_back(vertModule);
196 ssaoShaderDescriptor._modules.push_back(fragModule);
197
198 ssaoShaderDescriptor._modules.back()._defines.emplace_back("HORIZONTAL");
199 ResourceDescriptor<ShaderProgram> ssaoBlurH( "SSAOBlur.Horizontal", ssaoShaderDescriptor );
200 ssaoBlurH.waitForReady(false);
202
203 ssaoShaderDescriptor._modules.back()._defines.back() = { "VERTICAL" };
204
205 ResourceDescriptor<ShaderProgram> ssaoBlurV( "SSAOBlur.Vertical", ssaoShaderDescriptor );
206 ssaoBlurV.waitForReady(false);
208 }
209 { //Pass-through
210 fragModule._variant = "SSAOPassThrough";
211 fragModule._defines.resize(0);
212
213 ShaderProgramDescriptor ssaoShaderDescriptor = {};
214 ssaoShaderDescriptor._modules.push_back(vertModule);
215 ssaoShaderDescriptor._modules.push_back(fragModule);
216
217 ResourceDescriptor<ShaderProgram> ssaoPassThrough( "SSAOPassThrough", ssaoShaderDescriptor );
218 ssaoPassThrough.waitForReady(false);
219
220 _ssaoPassThroughShader = CreateResource(ssaoPassThrough);
221 }
222 { //DownSample
223 fragModule._variant = "SSAODownsample";
224 fragModule._defines.resize(0);
225
226 ShaderProgramDescriptor ssaoShaderDescriptor = {};
227 ssaoShaderDescriptor._modules.push_back(vertModule);
228 ssaoShaderDescriptor._modules.push_back(fragModule);
229
230 ResourceDescriptor<ShaderProgram> ssaoDownSample( "SSAODownSample", ssaoShaderDescriptor );
231 ssaoDownSample.waitForReady(false);
232
233 _ssaoDownSampleShader = CreateResource(ssaoDownSample);
234 }
235 { //UpSample
236 fragModule._variant = "SSAOUpsample";
237 fragModule._defines.resize(0);
238
239 ShaderProgramDescriptor ssaoShaderDescriptor = {};
240 ssaoShaderDescriptor._modules.push_back(vertModule);
241 ssaoShaderDescriptor._modules.push_back(fragModule);
242
243 ResourceDescriptor<ShaderProgram> ssaoUpSample( "SSAOUpSample", ssaoShaderDescriptor );
244 ssaoUpSample.waitForReady(false);
245
246 _ssaoUpSampleShader = CreateResource(ssaoUpSample);
247 }
248
249 _ssaoGenerateConstants.set(_ID("sampleKernel"), PushConstantType::VEC4, ComputeKernel(sampleCount()));
253 _ssaoGenerateConstants.set(_ID("SSAO_NOISE_SCALE"), PushConstantType::VEC2, vec2<F32>((parent.screenRT()._rt->getResolution() * (_genHalfRes ? 0.5f : 1.f)) / SSAO_NOISE_SIZE));
256
260
262
263 PipelineDescriptor pipelineDescriptor = {};
265 pipelineDescriptor._stateBlock = _context.get2DStateBlock();
266 pipelineDescriptor._shaderProgramHandle = _ssaoDownSampleShader;
267
268 _downsamplePipeline = _context.newPipeline(pipelineDescriptor);
269
271 _generateHalfResPipeline = _context.newPipeline(pipelineDescriptor);
272
273 pipelineDescriptor._shaderProgramHandle = _ssaoUpSampleShader;
274 _upsamplePipeline = _context.newPipeline(pipelineDescriptor);
275
276 pipelineDescriptor._shaderProgramHandle = _ssaoGenerateShader;
277 _generateFullResPipeline = _context.newPipeline(pipelineDescriptor);
278
279 RenderStateBlock redChannelOnly = _context.get2DStateBlock();
280 redChannelOnly._colourWrite.b[0] = true;
281 redChannelOnly._colourWrite.b[1] = redChannelOnly._colourWrite.b[2] = redChannelOnly._colourWrite.b[3] = false;
282
283 pipelineDescriptor._stateBlock = redChannelOnly;
285 _blurHorizontalPipeline = _context.newPipeline(pipelineDescriptor);
286
288 _blurVerticalPipeline = _context.newPipeline(pipelineDescriptor);
289
290 pipelineDescriptor._shaderProgramHandle = _ssaoPassThroughShader;
291 _passThroughPipeline = _context.newPipeline(pipelineDescriptor);
292}
293
295{
300 {
302 }
303
312}
313
314bool SSAOPreRenderOperator::ready() const noexcept
315{
316 if (_ssaoBlurShaderHorizontal != INVALID_HANDLE<ShaderProgram> && Get(_ssaoBlurShaderHorizontal)->getState() == ResourceState::RES_LOADED &&
317 _ssaoBlurShaderVertical != INVALID_HANDLE<ShaderProgram> && Get(_ssaoBlurShaderVertical)->getState() == ResourceState::RES_LOADED &&
318 _ssaoGenerateShader != INVALID_HANDLE<ShaderProgram> && Get(_ssaoGenerateShader)->getState() == ResourceState::RES_LOADED &&
319 _ssaoGenerateHalfResShader != INVALID_HANDLE<ShaderProgram> && Get(_ssaoGenerateHalfResShader)->getState() == ResourceState::RES_LOADED &&
320 _ssaoDownSampleShader != INVALID_HANDLE<ShaderProgram> && Get(_ssaoDownSampleShader)->getState() == ResourceState::RES_LOADED &&
321 _ssaoPassThroughShader != INVALID_HANDLE<ShaderProgram> && Get(_ssaoPassThroughShader)->getState() == ResourceState::RES_LOADED &&
322 _ssaoUpSampleShader != INVALID_HANDLE<ShaderProgram> && Get(_ssaoUpSampleShader)->getState() == ResourceState::RES_LOADED)
323 {
325 }
326
327 return false;
328}
329
330void SSAOPreRenderOperator::reshape(const U16 width, const U16 height)
331{
332 PreRenderOperator::reshape(width, height);
333
334 _ssaoOutput._rt->resize(width, height);
335 _halfDepthAndNormals._rt->resize(width / 2, height / 2);
336
337 const vec2<F32> targetDim = vec2<F32>(width, height) * (_genHalfRes ? 0.5f : 1.f);
338
339 _ssaoGenerateConstants.set(_ID("SSAO_NOISE_SCALE"), PushConstantType::VEC2, targetDim / SSAO_NOISE_SIZE);
340}
341
343{
344 if (_genHalfRes != state)
345 {
346 _genHalfRes = state;
348 _context.context().config().changed(true);
349
350 const U16 width = state ? _halfDepthAndNormals._rt->getWidth() : _ssaoOutput._rt->getWidth();
351 const U16 height = state ? _halfDepthAndNormals._rt->getHeight() : _ssaoOutput._rt->getHeight();
352
353 _ssaoGenerateConstants.set(_ID("SSAO_NOISE_SCALE"), PushConstantType::VEC2, vec2<F32>(width, height) / SSAO_NOISE_SIZE);
354 _ssaoGenerateConstants.set(_ID("sampleKernel"), PushConstantType::VEC4, ComputeKernel(sampleCount()));
363 }
364}
365
367{
368 if (!COMPARE(radius(), val))
369 {
370 _radius[_genHalfRes ? 1 : 0] = val;
372 if (_genHalfRes)
373 {
375 }
376 else
377 {
379 }
380 _context.context().config().changed(true);
381 }
382}
383
385{
386 if (!COMPARE(power(), val))
387 {
388 _power[_genHalfRes ? 1 : 0] = val;
389 _ssaoGenerateConstants.set(_ID("SSAO_INTENSITY"), PushConstantType::FLOAT, val);
390 if (_genHalfRes)
391 {
393 }
394 else
395 {
397 }
398 _context.context().config().changed(true);
399 }
400}
401
403{
404 if (!COMPARE(bias(), val))
405 {
406 _bias[_genHalfRes ? 1 : 0] = val;
408 if (_genHalfRes)
409 {
411 }
412 else
413 {
415 }
416 _context.context().config().changed(true);
417 }
418}
419
420void SSAOPreRenderOperator::blurResults(const bool state) noexcept
421{
422 if (blurResults() != state)
423 {
424 _blur[_genHalfRes ? 1 : 0] = state;
425 if (_genHalfRes)
426 {
427 _context.context().config().rendering.postFX.ssao.HalfRes.Blur = state;
428 }
429 else
430 {
431 _context.context().config().rendering.postFX.ssao.FullRes.Blur = state;
432 }
433 _context.context().config().changed(true);
434 }
435}
436
438{
439 if (!COMPARE(blurThreshold(), val))
440 {
441 _blurThreshold[_genHalfRes ? 1 : 0] = val;
442 _ssaoBlurConstants.set(_ID("depthThreshold"), PushConstantType::FLOAT, val);
443 if (_genHalfRes)
444 {
446 }
447 else
448 {
450 }
451 _context.context().config().changed(true);
452 }
453}
454
456{
457 if (!COMPARE(blurSharpness(), val))
458 {
459 _blurSharpness[_genHalfRes ? 1 : 0] = val;
460 _ssaoBlurConstants.set(_ID("blurSharpness"), PushConstantType::FLOAT, val);
461 if (_genHalfRes)
462 {
464 }
465 else
466 {
468 }
469 _context.context().config().changed(true);
470 }
471}
472
474{
475 if (blurKernelSize() != val)
476 {
477 _kernelSize[_genHalfRes ? 1 : 0] = val;
478 _ssaoBlurConstants.set(_ID("blurKernelSize"), PushConstantType::INT, val);
479 if (_genHalfRes)
480 {
482 }
483 else
484 {
486 }
487 _context.context().config().changed(true);
488 }
489}
490
492{
493 val = std::max(0.01f, val);
494
495 if (!COMPARE(maxRange(), val))
496 {
497 _maxRange[_genHalfRes ? 1 : 0] = val;
499 if (_genHalfRes)
500 {
502 }
503 else
504 {
506 }
507 _context.context().config().changed(true);
508 }
509}
510
512{
513 val = std::max(0.01f, val);
514
515 if (!COMPARE(fadeStart(), val))
516 {
517 _fadeStart[_genHalfRes ? 1 : 0] = val;
519 if (_genHalfRes)
520 {
522 }
523 else
524 {
526 }
527 _context.context().config().changed(true);
528 }
529}
530
532{
533 return _kernelSampleCount[_genHalfRes ? 1 : 0];
534}
535
536void SSAOPreRenderOperator::prepare([[maybe_unused]] const PlayerIndex idx, GFX::CommandBuffer& bufferInOut)
537{
538 PreRenderOperator::prepare(idx, bufferInOut);
539
540 if (_stateChanged && !_enabled)
541 {
542 GFX::BeginRenderPassCommand* renderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>(bufferInOut);
543 renderPassCmd->_name = "DO_SSAO_CLEAR_TARGET";
548
549 GFX::EnqueueCommand<GFX::EndRenderPassCommand>(bufferInOut);
550 }
551
552 _stateChanged = false;
553}
554
555bool SSAOPreRenderOperator::execute([[maybe_unused]] const PlayerIndex idx, const CameraSnapshot& cameraSnapshot, [[maybe_unused]] const RenderTargetHandle& input, [[maybe_unused]] const RenderTargetHandle& output, GFX::CommandBuffer& bufferInOut)
556{
557 assert(_enabled);
558
559 _ssaoGenerateConstants.set(_ID("_zPlanes"), PushConstantType::VEC2, cameraSnapshot._zPlanes);
560
561 const auto& depthAtt = _parent.screenRT()._rt->getAttachment(RTAttachmentType::DEPTH);
563
564 if(genHalfRes())
565 {
566 { // DownSample depth and normals
567 GFX::BeginRenderPassCommand* renderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>(bufferInOut);
568 renderPassCmd->_name = "DO_SSAO_DOWNSAMPLE_NORMALS";
569 renderPassCmd->_target = _halfDepthAndNormals._targetID;
572
573 GFX::EnqueueCommand<GFX::BindPipelineCommand>(bufferInOut)->_pipeline = _downsamplePipeline;
574
575 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>(bufferInOut);
576 cmd->_usage = DescriptorSetUsage::PER_DRAW;
577 {
579 Set( binding._data, depthAtt->texture(), depthAtt->_descriptor._sampler );
580 }
581 {
583 Set( binding._data, normalsAtt->texture(), normalsAtt->_descriptor._sampler );
584 }
585
586 GFX::EnqueueCommand<GFX::DrawCommand>(bufferInOut)->_drawCommands.emplace_back();
587 GFX::EnqueueCommand<GFX::EndRenderPassCommand>(bufferInOut);
588 }
589 { // Generate Half Res AO
590 GFX::BeginRenderPassCommand* renderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>(bufferInOut);
591 renderPassCmd->_name = "DO_SSAO_HALF_RES_CALC";
592 renderPassCmd->_target = _ssaoHalfResOutput._targetID;
595
596 GFX::EnqueueCommand<GFX::BindPipelineCommand>(bufferInOut)->_pipeline = _generateHalfResPipeline;
597
598 GFX::SendPushConstantsCommand* sendPushConstantsCmd = GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut );
599 sendPushConstantsCmd->_uniformData = &_ssaoGenerateConstants;
600 sendPushConstantsCmd->_fastData.data[0] = cameraSnapshot._projectionMatrix;
601 sendPushConstantsCmd->_fastData.data[1] = cameraSnapshot._invProjectionMatrix;
602
604
605 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>(bufferInOut);
606 cmd->_usage = DescriptorSetUsage::PER_DRAW;
607 {
610 }
611 {
613 Set( binding._data, halfDepthAtt->texture(), halfDepthAtt->_descriptor._sampler );
614 }
615
616 GFX::EnqueueCommand<GFX::DrawCommand>(bufferInOut)->_drawCommands.emplace_back();
617 GFX::EnqueueCommand<GFX::EndRenderPassCommand>(bufferInOut);
618 }
619 { // UpSample AO
620 GFX::BeginRenderPassCommand* renderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>(bufferInOut);
621 renderPassCmd->_name = "DO_SSAO_UPSAMPLE_AO";
622 renderPassCmd->_target = _ssaoOutput._targetID;
625
626 GFX::EnqueueCommand<GFX::BindPipelineCommand>(bufferInOut)->_pipeline = _upsamplePipeline;
627
628 SamplerDescriptor linearSampler = {};
629 linearSampler._wrapU = TextureWrap::CLAMP_TO_EDGE;
630 linearSampler._wrapV = TextureWrap::CLAMP_TO_EDGE;
631 linearSampler._wrapW = TextureWrap::CLAMP_TO_EDGE;
633 linearSampler._anisotropyLevel = 0u;
634
635 const auto& halfResAOAtt = _ssaoHalfResOutput._rt->getAttachment(RTAttachmentType::COLOUR );
637
638 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>(bufferInOut);
639 cmd->_usage = DescriptorSetUsage::PER_DRAW;
640 {
642 Set( binding._data, halfResAOAtt->texture(), linearSampler );
643 }
644 {
646 Set( binding._data, depthAtt->texture(), depthAtt->_descriptor._sampler );
647 }
648 {
650 Set( binding._data, halfDepthAtt->texture(), halfDepthAtt->_descriptor._sampler );
651 }
652 {
654 Set( binding._data, halfResAOAtt->texture(), halfResAOAtt->_descriptor._sampler );
655 }
656 GFX::EnqueueCommand<GFX::DrawCommand>(bufferInOut)->_drawCommands.emplace_back();
657 GFX::EnqueueCommand<GFX::EndRenderPassCommand>(bufferInOut);
658 }
659 }
660 else
661 {
662 { // Generate Full Res AO
663 GFX::BeginRenderPassCommand* renderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>(bufferInOut);
664 renderPassCmd->_name = "DO_SSAO_CALC";
665 renderPassCmd->_target = _ssaoOutput._targetID;
668
669 GFX::EnqueueCommand<GFX::BindPipelineCommand>(bufferInOut)->_pipeline = _generateFullResPipeline;
670
671 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>(bufferInOut);
672 cmd->_usage = DescriptorSetUsage::PER_DRAW;
673 {
676 }
677 {
679 Set( binding._data, depthAtt->texture(), depthAtt->_descriptor._sampler );
680 }
681 {
683 Set( binding._data, normalsAtt->texture(), normalsAtt->_descriptor._sampler );
684 }
685
686 GFX::SendPushConstantsCommand* sendPushConstantsCmd = GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut );
687 sendPushConstantsCmd->_uniformData = &_ssaoGenerateConstants;
688 sendPushConstantsCmd->_fastData.data[0] = cameraSnapshot._projectionMatrix;
689 sendPushConstantsCmd->_fastData.data[1] = cameraSnapshot._invProjectionMatrix;
690
691 GFX::EnqueueCommand<GFX::DrawCommand>(bufferInOut)->_drawCommands.emplace_back();
692 GFX::EnqueueCommand<GFX::EndRenderPassCommand>(bufferInOut);
693 }
694 }
695 {
697
698 if (blurResults() && blurKernelSize() > 0)
699 {
700 _ssaoBlurConstants.set(_ID("_zPlanes"), PushConstantType::VEC2, cameraSnapshot._zPlanes);
701 _ssaoBlurConstants.set(_ID("texelSize"), PushConstantType::VEC2, vec2<F32>{ 1.f / Get(ssaoAtt->texture())->width(), 1.f / Get(ssaoAtt->texture())->height() });
702
703 // Blur AO
704 { //Horizontal
705 GFX::BeginRenderPassCommand* renderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>(bufferInOut);
706 renderPassCmd->_name = "DO_SSAO_BLUR_HORIZONTAL";
707 renderPassCmd->_target = _ssaoBlurBuffer._targetID;
710
711 GFX::EnqueueCommand<GFX::BindPipelineCommand>(bufferInOut)->_pipeline = _blurHorizontalPipeline;
712
713 GFX::SendPushConstantsCommand* sendPushConstantsCmd = GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut );
714 sendPushConstantsCmd->_uniformData = &_ssaoBlurConstants;
715 sendPushConstantsCmd->_fastData.data[0] = cameraSnapshot._invProjectionMatrix;
716
717 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>(bufferInOut);
718 cmd->_usage = DescriptorSetUsage::PER_DRAW;
719 {
721 Set( binding._data, ssaoAtt->texture(), ssaoAtt->_descriptor._sampler );
722 }
723 {
725 Set( binding._data, depthAtt->texture(), depthAtt->_descriptor._sampler );
726 }
727 {
729 Set( binding._data, normalsAtt->texture(), normalsAtt->_descriptor._sampler );
730 }
731
732 GFX::EnqueueCommand<GFX::DrawCommand>(bufferInOut)->_drawCommands.emplace_back();
733 GFX::EnqueueCommand<GFX::EndRenderPassCommand>(bufferInOut);
734 }
735 { //Vertical
736 GFX::BeginRenderPassCommand* renderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>(bufferInOut);
737 renderPassCmd->_name = "DO_SSAO_BLUR_VERTICAL";
741
742 GFX::EnqueueCommand<GFX::BindPipelineCommand>(bufferInOut)->_pipeline = _blurVerticalPipeline;
743
744 GFX::SendPushConstantsCommand* sendPushConstantsCmd = GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut );
745 sendPushConstantsCmd->_uniformData = &_ssaoBlurConstants;
746 sendPushConstantsCmd->_fastData.data[0] = cameraSnapshot._invProjectionMatrix;
747
749 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>(bufferInOut);
750 cmd->_usage = DescriptorSetUsage::PER_DRAW;
751 {
753 Set( binding._data, horizBlur->texture(), ssaoAtt->_descriptor._sampler );
754 }
755 {
757 Set( binding._data, depthAtt->texture(), depthAtt->_descriptor._sampler );
758 }
759 {
761 Set( binding._data, normalsAtt->texture(), normalsAtt->_descriptor._sampler );
762 }
763
764 GFX::EnqueueCommand<GFX::DrawCommand>(bufferInOut)->_drawCommands.emplace_back();
765 GFX::EnqueueCommand<GFX::EndRenderPassCommand>(bufferInOut);
766 }
767 }
768 else
769 {
770 GFX::BeginRenderPassCommand* renderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>(bufferInOut);
771 renderPassCmd->_name = "DO_SSAO_PASS_THROUGH";
775
776 GFX::EnqueueCommand<GFX::BindPipelineCommand>(bufferInOut)->_pipeline = _passThroughPipeline;
777
778 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>(bufferInOut);
779 cmd->_usage = DescriptorSetUsage::PER_DRAW;
780 {
782 Set( binding._data, ssaoAtt->texture(), ssaoAtt->_descriptor._sampler );
783 }
784 GFX::EnqueueCommand<GFX::DrawCommand>(bufferInOut)->_drawCommands.emplace_back();
785 GFX::EnqueueCommand<GFX::EndRenderPassCommand>(bufferInOut);
786 }
787 }
788
789 // No need to swap targets
790 return false;
791}
792}
#define WAIT_FOR_CONDITION(...)
#define DIVIDE_UNEXPECTED_CALL()
Rough around the edges Adapter pattern abstracting the actual rendering API and access to the GPU.
Definition: GFXDevice.h:215
GFXRTPool & renderTargetPool() noexcept
Definition: GFXDevice.inl:133
Pipeline * newPipeline(const PipelineDescriptor &descriptor)
Create and return a new graphics pipeline. This is only used for caching and doesn't use the object a...
Definition: GFXDevice.cpp:3074
const RenderStateBlock & get2DStateBlock() const noexcept
Definition: GFXDevice.inl:123
RenderTarget * getRenderTarget(const RenderTargetID target) const
Definition: GFXRTPool.cpp:50
RenderTargetHandle allocateRT(const RenderTargetDescriptor &descriptor)
Definition: GFXRTPool.cpp:17
bool deallocateRT(RenderTargetHandle &handle)
Definition: GFXRTPool.cpp:33
PlatformContext & context() noexcept
Configuration & config() noexcept
RenderTargetHandle screenRT() const noexcept
virtual void reshape(U16 width, U16 height)
virtual void prepare(PlayerIndex idx, GFX::CommandBuffer &bufferInOut)
virtual bool ready() const noexcept
RTAttachment * getAttachment(RTAttachmentType type, RTColourAttachmentSlot slot=RTColourAttachmentSlot::SLOT_0) const
bool resize(U16 width, U16 height)
Resize all attachments.
U16 getWidth() const noexcept
U16 getHeight() const noexcept
void prepare(PlayerIndex idx, GFX::CommandBuffer &bufferInOut) override
Handle< ShaderProgram > _ssaoUpSampleShader
Handle< ShaderProgram > _ssaoBlurShaderVertical
void reshape(U16 width, U16 height) override
Handle< ShaderProgram > _ssaoGenerateHalfResShader
Handle< ShaderProgram > _ssaoGenerateShader
bool ready() const noexcept override
Handle< ShaderProgram > _ssaoDownSampleShader
Handle< ShaderProgram > _ssaoPassThroughShader
Handle< ShaderProgram > _ssaoBlurShaderHorizontal
SSAOPreRenderOperator(GFXDevice &context, PreRenderBatch &parent)
bool execute(PlayerIndex idx, const CameraSnapshot &cameraSnapshot, const RenderTargetHandle &input, const RenderTargetHandle &output, GFX::CommandBuffer &bufferInOut) override
Return true if we rendered into "output".
vec3 & normalize() noexcept
transform the vector to unit length
void set(const T *v) noexcept
set the 3 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:707
Str StringFormat(const char *fmt, Args &&...args)
const vector< vec4< F32 > > & ComputeKernel(const U8 sampleCount)
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
std::byte Byte
FORCE_INLINE void DestroyResource(Handle< T > &handle, const bool immediate=false)
static constexpr U32 RT_DEPTH_ATTACHMENT_IDX
Definition: RTAttachment.h:71
constexpr T SQUARED(T input) noexcept
Definition: MathHelper.inl:156
int32_t I32
uint8_t U8
@ RES_LOADED
The resource is available for usage.
constexpr F32 to_F32(const T value)
T Random()
Definition: MathHelper.inl:95
eastl::vector< Type > vector
Definition: Vector.h:42
Project & parent
Definition: DefaultScene.h:41
uint16_t U16
void Set(DescriptorSetBindingData &dataInOut, ShaderBuffer *buffer, const BufferRange range) noexcept
constexpr U64 _ID(const char *const str, const U64 value=val_64_const) noexcept
DescriptorSetBinding & AddBinding(DescriptorSet &setInOut, U8 slot, U16 stageVisibilityMask)
FORCE_INLINE Handle< T > CreateResource(const ResourceDescriptor< T > &descriptor, bool &wasInCache, std::atomic_uint &taskCounter)
::value constexpr T CLAMPED(T n, T min, T max) noexcept
Definition: MathHelper.inl:126
RTClearEntry DEFAULT_CLEAR_ENTRY
T FastLerp(T v1, T v2, U t) noexcept
Definition: MathHelper.inl:246
bool COMPARE(T X, U Y) noexcept
FORCE_INLINE T * Get(const Handle< T > handle)
constexpr auto to_base(const Type value) -> Type
mat4< F32 > _projectionMatrix
mat4< F32 > _invProjectionMatrix
SSAOSettings FullRes
SSAOSettings HalfRes
bool UseHalfResolution
struct Divide::Configuration::Rendering::PostFX::SSAO ssao
struct Divide::Configuration::Rendering::PostFX postFX
struct Divide::Configuration::Rendering rendering
DescriptorSetBindingData _data
RTClearDescriptor _clearDescriptor
Definition: Commands.inl:97
PrimitiveTopology _primitiveTopology
Definition: Pipeline.h:48
Handle< ShaderProgram > _shaderProgramHandle
Definition: Pipeline.h:47
RenderStateBlock _stateBlock
Definition: Pipeline.h:46
vector< ShaderModuleDescriptor > _modules
InternalRTAttachmentDescriptors _attachments
Definition: RenderTarget.h:52
RenderTargetID _targetID
Definition: RenderTarget.h:47
static RenderTargetID NORMALS_RESOLVED
Definition: GFXDevice.h:199
static RenderTargetID SSAO_RESULT
Definition: GFXDevice.h:202
PropertyDescriptor< T > _propertyDescriptor
Definition: Resource.h:151
TextureFilter _minFilter
Texture filtering mode.
TextureWrap _wrapU
Texture wrap mode (Or S-R-T)
U8 _anisotropyLevel
The value must be in the range [0...255] and is automatically clamped by the max HW supported level.
TextureMipSampling _mipSampling
void set(U64 bindingHash, PushConstantType type, const T &value)