Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
GFXDevice.cpp
Go to the documentation of this file.
1
2
3#include "config.h"
4
5#include "Headers/GFXDevice.h"
6#include "Headers/GFXRTPool.h"
8
10#include "Core/Headers/Kernel.h"
15
16#include "GUI/Headers/GUI.h"
18
21
25
28
30
37
41
43
44namespace Divide
45{
46
47 namespace TypeUtil
48 {
49 const char* GraphicResourceTypeToName( const GraphicsResource::Type type ) noexcept
50 {
51 return Names::resourceTypes[to_base( type )];
52 };
53
54 const char* RenderStageToString( const RenderStage stage ) noexcept
55 {
56 return Names::renderStage[to_base( stage )];
57 }
58
59 RenderStage StringToRenderStage( const char* stage ) noexcept
60 {
61 for ( U8 i = 0; i < to_U8( RenderStage::COUNT ); ++i )
62 {
63 if ( strcmp( stage, Names::renderStage[i] ) == 0 )
64 {
65 return static_cast<RenderStage>(i);
66 }
67 }
68
69 return RenderStage::COUNT;
70 }
71
72 const char* RenderPassTypeToString( const RenderPassType pass ) noexcept
73 {
74 return Names::renderPassType[to_base( pass )];
75 }
76
77 RenderPassType StringToRenderPassType( const char* pass ) noexcept
78 {
79 for ( U8 i = 0; i < to_U8( RenderPassType::COUNT ); ++i )
80 {
81 if ( strcmp( pass, Names::renderPassType[i] ) == 0 )
82 {
83 return static_cast<RenderPassType>(i);
84 }
85 }
86
88 }
89 };
90
91 namespace
92 {
94 constexpr size_t TargetBufferSizeCam = 1024u;
95
96 constexpr U32 GROUP_SIZE_AABB = 64u;
99
100 FORCE_INLINE U32 getGroupCount( const U32 threadCount, U32 const localSize )
101 {
102 return (threadCount + localSize - 1u) / localSize;
103 }
104
105 template<typename Data, size_t N>
107 {
108 LockGuard<Mutex> w_lock( container._dataLock );
109 for ( auto& entry : container._debugData )
110 {
111 if ( entry._frameLifeTime > 0u )
112 {
113 entry._frameLifeTime -= 1u;
114 }
115 }
116 }
117
118
120 {
121 std::thread _thread;
122 std::condition_variable _cv;
123 std::atomic_bool _running{false};
124 bool _hasWork{false};
127
128 eastl::queue<DisplayWindow*> _windows;
129 };
130
132 };
133
146 std::array<RenderTargetID, Config::MAX_REFLECTIVE_NODES_IN_VIEW> RenderTargetNames::REFLECTION_PLANAR = create_array<Config::MAX_REFLECTIVE_NODES_IN_VIEW, RenderTargetID>( INVALID_RENDER_TARGET_ID );
147 std::array<RenderTargetID, Config::MAX_REFRACTIVE_NODES_IN_VIEW> RenderTargetNames::REFRACTION_PLANAR = create_array<Config::MAX_REFRACTIVE_NODES_IN_VIEW, RenderTargetID>( INVALID_RENDER_TARGET_ID );
148
151
154
155
157 {
158 ShaderModuleDescriptor vertModule = {};
159 vertModule._moduleType = ShaderType::VERTEX;
160 vertModule._sourceFile = "ImmediateModeEmulation.glsl";
161
162 ShaderModuleDescriptor fragModule = {};
164 fragModule._sourceFile = "ImmediateModeEmulation.glsl";
165
166 ShaderProgramDescriptor shaderDescriptor = {};
167 shaderDescriptor._modules.push_back( vertModule );
168 shaderDescriptor._modules.push_back( fragModule );
169 {
170 ResourceDescriptor<ShaderProgram> immediateModeShader( "ImmediateModeEmulation", shaderDescriptor );
171 immediateModeShader.waitForReady( true );
172 _imShader = CreateResource( immediateModeShader );
173 }
174 {
175 shaderDescriptor._globalDefines.emplace_back( "NO_TEXTURE" );
176 ResourceDescriptor<ShaderProgram> immediateModeShader( "ImmediateModeEmulation-NoTexture", shaderDescriptor );
177 immediateModeShader.waitForReady( true );
178 _imShaderNoTexture = CreateResource( immediateModeShader );
179 }
180 {
181 efficient_clear( shaderDescriptor._globalDefines );
182 shaderDescriptor._modules.back()._defines.emplace_back( "WORLD_PASS" );
183 ResourceDescriptor<ShaderProgram> immediateModeShader( "ImmediateModeEmulation-World", shaderDescriptor );
184 immediateModeShader.waitForReady( true );
185 _imWorldShader = CreateResource( immediateModeShader );
186 }
187 {
188 shaderDescriptor._globalDefines.emplace_back( "NO_TEXTURE" );
189 ResourceDescriptor<ShaderProgram> immediateModeShader( "ImmediateModeEmulation-World-NoTexture", shaderDescriptor );
190 immediateModeShader.waitForReady( true );
191 _imWorldShaderNoTexture = CreateResource( immediateModeShader );
192 }
193
194
195 {
196 efficient_clear( shaderDescriptor._globalDefines );
197 shaderDescriptor._modules.back()._defines.emplace_back( "OIT_PASS" );
198 ResourceDescriptor<ShaderProgram> immediateModeShader( "ImmediateModeEmulation-OIT", shaderDescriptor );
199 immediateModeShader.waitForReady( true );
200 _imWorldOITShader = CreateResource( immediateModeShader );
201 }
202 {
203 shaderDescriptor._modules.back()._defines.emplace_back( "NO_TEXTURE" );
204 ResourceDescriptor<ShaderProgram> immediateModeShader( "ImmediateModeEmulation-OIT-NoTexture", shaderDescriptor );
205 immediateModeShader.waitForReady( true );
206 _imWorldOITShaderNoTexture = CreateResource( immediateModeShader );
207 }
208 }
209
211 {
212 DestroyResource( _imShader );
213 DestroyResource( _imShaderNoTexture );
214 DestroyResource( _imWorldShader );
215 DestroyResource( _imWorldShaderNoTexture );
216 DestroyResource( _imWorldOITShader );
217 DestroyResource( _imWorldOITShaderNoTexture );
218 }
219
220#pragma region Construction, destruction, initialization
221
223 {
240
247
262
273
274 _api->initDescriptorSets();
275
277 }
278
280 {
281 _impl._bindingCount = { 0u };
282 dirty( true );
283 }
284
286 {
287 for ( U8 i = 0u; i < newBindingData._bindingCount; ++i )
288 {
289 update( usage, newBindingData._bindings[i] );
290 }
291 }
292
294 {
295 for ( U8 i = 0u; i < _impl._bindingCount; ++i )
296 {
297 DescriptorSetBinding& bindingEntry = _impl._bindings[i];
298
299 if ( bindingEntry._slot == newBindingData._slot )
300 {
302 newBindingData._data._type != DescriptorSetBindingType::COUNT );
303
304 DIVIDE_ASSERT( usage == DescriptorSetUsage::PER_DRAW || bindingEntry._data._type == newBindingData._data._type );
305
306 if ( bindingEntry != newBindingData )
307 {
308 bindingEntry = newBindingData;
309 dirty( true );
310 }
311 return;
312 }
313 }
314
315 DIVIDE_ASSERT( _impl._bindingCount < MAX_BINDINGS_PER_DESCRIPTOR_SET - 1u);
316 _impl._bindings[_impl._bindingCount++] = newBindingData;
317 dirty( true );
318 }
319
322 , FrameListener( "GFXDevice", context.kernel().frameListenerMgr(), 1u)
323 {
325 }
326
328 {
330 }
331
333 {
334 assert( _api == nullptr && "GFXDevice error: initRenderingAPI called twice!" );
335
337 switch ( API )
338 {
340 {
341 _api = std::make_unique<GL_API>( *this );
342 } break;
344 {
345 _api = std::make_unique<VK_API>( *this );
346 } break;
347 case RenderAPI::None:
348 {
349 _api = std::make_unique<NONE_API>( *this );
350 } break;
351 default:
353 break;
354 };
355
356 DIVIDE_ASSERT( _api != nullptr, LOCALE_STR( "ERROR_GFX_DEVICE_API" ) );
357 renderAPI( API );
358
359 return err;
360 }
361
364 ErrorCode GFXDevice::initRenderingAPI( const I32 argc, char** argv, const RenderAPI API )
365 {
366 ErrorCode hardwareState = createAPIInstance( API );
367 Configuration& config = context().config();
368
369 if ( hardwareState == ErrorCode::NO_ERR )
370 {
371 // Initialize the rendering API
372 hardwareState = _api->initRenderingAPI( argc, argv, config );
373 }
374
375 if ( hardwareState != ErrorCode::NO_ERR )
376 {
377 // Validate initialization
378 return hardwareState;
379 }
380
382 {
383 Console::errorfn( LOCALE_STR( "ERROR_INSUFFICIENT_TEXTURE_UNITS" ) );
385 }
387 {
388 Console::errorfn( LOCALE_STR( "ERROR_INSUFFICIENT_ATTRIB_BINDS" ) );
390 }
391 DIVIDE_ASSERT( Config::MAX_CLIP_DISTANCES <= s_deviceInformation._maxClipDistances, "SDLWindowWrapper error: incorrect combination of clip and cull distance counts" );
392 DIVIDE_ASSERT( Config::MAX_CULL_DISTANCES <= s_deviceInformation._maxCullDistances, "SDLWindowWrapper error: incorrect combination of clip and cull distance counts" );
393 DIVIDE_ASSERT( Config::MAX_CULL_DISTANCES + Config::MAX_CLIP_DISTANCES <= s_deviceInformation._maxClipAndCullDistances, "SDLWindowWrapper error: incorrect combination of clip and cull distance counts" );
394
398
402
403 string refreshRates;
404
406 const auto printMode = [&prevMode, &refreshRates]()
407 {
408 Console::printfn( LOCALE_STR( "CURRENT_DISPLAY_MODE" ),
409 prevMode._resolution.width,
410 prevMode._resolution.height,
411 prevMode._bitsPerPixel,
412 prevMode._formatName.c_str(),
413 refreshRates.c_str() );
414 };
415
416 for ( size_t idx = 0; idx < DisplayManager::ActiveDisplayCount(); ++idx )
417 {
418 const auto& registeredModes = DisplayManager::GetDisplayModes( idx );
419 if ( !registeredModes.empty() )
420 {
421 Console::printfn( LOCALE_STR( "AVAILABLE_VIDEO_MODES" ), idx, registeredModes.size() );
422
423 prevMode = registeredModes.front();
424
425 for ( const auto& it : registeredModes )
426 {
427 if ( prevMode._resolution != it._resolution ||
428 prevMode._bitsPerPixel != it._bitsPerPixel ||
429 prevMode._formatName != it._formatName )
430 {
431 printMode();
432 refreshRates = "";
433 prevMode = it;
434 }
435
436 if ( refreshRates.empty() )
437 {
438 refreshRates = Util::to_string( to_U32( it._maxRefreshRate ) );
439 }
440 else
441 {
442 refreshRates.append( Util::StringFormat( ", {}", it._maxRefreshRate ) );
443 }
444 }
445 }
446 if ( !refreshRates.empty() )
447 {
448 printMode();
449 }
450 }
451
452 _rtPool = std::make_unique<GFXRTPool>( *this );
453
454 I32 numLightsPerCluster = config.rendering.numLightsPerCluster;
455 if ( numLightsPerCluster < 0 )
456 {
458 }
459 else
460 {
461 numLightsPerCluster = std::min( numLightsPerCluster, to_I32( Config::Lighting::ClusteredForward::MAX_LIGHTS_PER_CLUSTER ) );
462 }
463 if ( numLightsPerCluster != config.rendering.numLightsPerCluster )
464 {
465 config.rendering.numLightsPerCluster = numLightsPerCluster;
466 config.changed( true );
467 }
468 const U16 reflectionProbeRes = to_U16( nextPOW2( CLAMPED( to_U32( config.rendering.reflectionProbeResolution ), 16u, 4096u ) - 1u ) );
469 if ( reflectionProbeRes != config.rendering.reflectionProbeResolution )
470 {
471 config.rendering.reflectionProbeResolution = reflectionProbeRes;
472 config.changed( true );
473 }
474
475
476 hardwareState = ShaderProgram::OnStartup( context() );
477 if ( hardwareState == ErrorCode::NO_ERR )
478 {
479 hardwareState = initDescriptorSets();
480 }
481
482 if ( hardwareState == ErrorCode::NO_ERR)
483 {
484 s_renderThread._running = true;
485 s_renderThread._thread = std::thread( &GFXDevice::renderThread, this );
486 }
487
488 return hardwareState;
489 }
490
492 {
493 SetThreadName("Main render thread");
494 onThreadCreated( std::this_thread::get_id(), true );
495
496 while ( s_renderThread._running )
497 {
499 UniqueLock<Mutex> lock( s_renderThread._lock );
500 while( !s_renderThread._hasWork && s_renderThread._running )
501 {
502 s_renderThread._cv.wait( lock, []() { return s_renderThread._hasWork || !s_renderThread._running; } );
503 }
504
505 if ( s_renderThread._running )
506 {
507 s_renderThread._work();
508 }
509
510 s_renderThread._work = {};
511 s_renderThread._hasWork = false;
512 }
513 }
514
516 {
517 {
518 LockGuard<Mutex> lck( s_renderThread._lock );
519 s_renderThread._work = MOV(work);
520 s_renderThread._hasWork = true;
521 }
522 s_renderThread._cv.notify_one();
523 }
524
526 {
528
529 _sceneData->updateSceneDescriptorSet( bufferInOut, memCmdInOut );
530 }
531
532 void GFXDevice::resizeGPUBlocks( size_t targetSizeCam, size_t targetSizeCullCounter )
533 {
535
536 if ( targetSizeCam == 0u )
537 {
538 targetSizeCam = 1u;
539 }
540 if ( targetSizeCullCounter == 0u )
541 {
542 targetSizeCullCounter = 1u;
543 }
544
545 const bool resizeCamBuffer = _gfxBuffers.crtBuffers()._camDataBuffer == nullptr || _gfxBuffers.crtBuffers()._camDataBuffer->queueLength() != targetSizeCam;
546 const bool resizeCullCounter = _gfxBuffers.crtBuffers()._cullCounter == nullptr || _gfxBuffers.crtBuffers()._cullCounter->queueLength() != targetSizeCullCounter;
547
548 if ( !resizeCamBuffer && !resizeCullCounter )
549 {
550 return;
551 }
552
553 DIVIDE_ASSERT( ValidateGPUDataStructure(), "GFXDevice::resizeBlock: GPUBlock does not meet alignment requirements!");
554
555 _gfxBuffers.reset( resizeCamBuffer, resizeCullCounter );
556
557 if ( resizeCamBuffer )
558 {
559 ShaderBufferDescriptor bufferDescriptor = {};
560 bufferDescriptor._bufferParams._elementCount = 1;
564 bufferDescriptor._ringBufferLength = to_U16( targetSizeCam );
565 bufferDescriptor._bufferParams._elementSize = sizeof( GFXShaderData::CamData );
566 bufferDescriptor._initialData = { (Byte*)&_gpuBlock._camData, bufferDescriptor._bufferParams._elementSize };
567
568 for ( U8 i = 0u; i < GFXBuffers::PER_FRAME_BUFFER_COUNT; ++i )
569 {
570 Util::StringFormat( bufferDescriptor._name, "DVD_GPU_CAM_DATA_{}", i );
571 _gfxBuffers._perFrameBuffers[i]._camDataBuffer = newSB( bufferDescriptor );
573 }
574 }
575
576 if ( resizeCullCounter )
577 {
578 // Atomic counter for occlusion culling
579 ShaderBufferDescriptor bufferDescriptor = {};
580 bufferDescriptor._bufferParams._elementCount = 1;
581 bufferDescriptor._ringBufferLength = to_U16( targetSizeCullCounter );
582 bufferDescriptor._bufferParams._hostVisible = true;
583 bufferDescriptor._bufferParams._elementSize = 4 * sizeof( U32 );
587 bufferDescriptor._separateReadWrite = true;
588 bufferDescriptor._initialData = { (bufferPtr)&VECTOR4_ZERO._v[0], 4 * sizeof( U32 ) };
589 for ( U8 i = 0u; i < GFXBuffers::PER_FRAME_BUFFER_COUNT; ++i )
590 {
591 Util::StringFormat( bufferDescriptor._name, "CULL_COUNTER_{}", i );
592 _gfxBuffers._perFrameBuffers[i]._cullCounter = newSB( bufferDescriptor );
593 }
594 }
596 }
597
599 {
600 std::atomic_uint loadTasks = 0;
601 const Configuration& config = context().config();
602
605 Texture::OnStartup( *this );
607
608 resizeGPUBlocks( TargetBufferSizeCam, Config::MAX_FRAMES_IN_FLIGHT + 1u );
609
610 _shaderComputeQueue = std::make_unique<ShaderComputeQueue>();
611
612 // Create general purpose render state blocks
614
617
620
621 // We need to create all of our attachments for the default render targets
622 // Start with the screen render target: Try a half float, multisampled
623 // buffer (MSAA + HDR rendering if possible)
624
625 SamplerDescriptor defaultSampler = {};
626 defaultSampler._wrapU = TextureWrap::CLAMP_TO_EDGE;
627 defaultSampler._wrapV = TextureWrap::CLAMP_TO_EDGE;
628 defaultSampler._wrapW = TextureWrap::CLAMP_TO_EDGE;
629 defaultSampler._minFilter = TextureFilter::NEAREST;
630 defaultSampler._magFilter = TextureFilter::NEAREST;
631 defaultSampler._mipSampling = TextureMipSampling::NONE;
632 defaultSampler._anisotropyLevel = 0u;
633
634 SamplerDescriptor defaultSamplerMips = {};
635 defaultSamplerMips._wrapU = TextureWrap::CLAMP_TO_EDGE;
636 defaultSamplerMips._wrapV = TextureWrap::CLAMP_TO_EDGE;
637 defaultSamplerMips._wrapW = TextureWrap::CLAMP_TO_EDGE;
638 defaultSamplerMips._anisotropyLevel = 0u;
639
640 //PrePass
641 TextureDescriptor depthDescriptor{};
642 depthDescriptor._dataType = GFXDataFormat::FLOAT_32;
643 depthDescriptor._baseFormat = GFXImageFormat::RED;
644 depthDescriptor._packing = GFXImagePacking::DEPTH;
645 depthDescriptor._mipMappingState = MipMappingState::OFF;
646
647 TextureDescriptor velocityDescriptor{};
648 velocityDescriptor._dataType = GFXDataFormat::FLOAT_16;
649 velocityDescriptor._baseFormat = GFXImageFormat::RG;
650 velocityDescriptor._packing = GFXImagePacking::UNNORMALIZED;
651 velocityDescriptor._mipMappingState = MipMappingState::OFF;
652
653 //RG - packed normal, B - roughness, A - unused
654 TextureDescriptor normalsDescriptor{};
655 normalsDescriptor._dataType = GFXDataFormat::FLOAT_16;
656 normalsDescriptor._packing = GFXImagePacking::UNNORMALIZED;
657 normalsDescriptor._mipMappingState = MipMappingState::OFF;
658
659 //MainPass
660 TextureDescriptor screenDescriptor{};
661 screenDescriptor._dataType = GFXDataFormat::FLOAT_16;
662 screenDescriptor._packing = GFXImagePacking::UNNORMALIZED;
663 screenDescriptor._mipMappingState = MipMappingState::OFF;
664 AddImageUsageFlag( screenDescriptor, ImageUsage::SHADER_READ);
665
666 TextureDescriptor materialDescriptor{};
667 materialDescriptor._dataType = GFXDataFormat::FLOAT_16;
668 materialDescriptor._baseFormat = GFXImageFormat::RG;
669 materialDescriptor._packing = GFXImagePacking::UNNORMALIZED;
670 materialDescriptor._mipMappingState = MipMappingState::OFF;
671
672 // Normal, Previous and MSAA
673 {
675 {
678 InternalRTAttachmentDescriptor{ normalsDescriptor, defaultSampler, RTAttachmentType::COLOUR, ScreenTargets::NORMALS, false },
680 };
681
682 RenderTargetDescriptor screenDesc = {};
683 screenDesc._resolution = renderResolution;
684 screenDesc._attachments = attachments;
685 screenDesc._msaaSamples = config.rendering.MSAASamples;
686 screenDesc._name = "Screen";
687 RenderTargetNames::SCREEN = _rtPool->allocateRT( screenDesc )._targetID;
688
689 auto& screenAttachment = attachments[to_base( ScreenTargets::ALBEDO )];
690 screenAttachment._texDescriptor._mipMappingState = MipMappingState::MANUAL;
691 AddImageUsageFlag( screenAttachment._texDescriptor, ImageUsage::SHADER_READ);
692 screenAttachment._sampler = defaultSamplerMips;
693 screenDesc._msaaSamples = 0u;
694 screenDesc._name = "Screen Prev";
695 screenDesc._attachments = { screenAttachment };
696 RenderTargetNames::SCREEN_PREV = _rtPool->allocateRT( screenDesc )._targetID;
697
698 auto& normalAttachment = attachments[to_base( ScreenTargets::NORMALS )];
699 normalAttachment._slot = RTColourAttachmentSlot::SLOT_0;
700 normalAttachment._texDescriptor._mipMappingState = MipMappingState::OFF ;
701 AddImageUsageFlag( normalAttachment._texDescriptor, ImageUsage::SHADER_READ );
702 normalAttachment._sampler = defaultSamplerMips;
703 screenDesc._msaaSamples = 0u;
704 screenDesc._name = "Normals Resolved";
705 screenDesc._attachments = { normalAttachment };
706 RenderTargetNames::NORMALS_RESOLVED = _rtPool->allocateRT( screenDesc )._targetID;
707 }
708 {
709 SamplerDescriptor samplerBackBuffer = {};
710 samplerBackBuffer._wrapU = TextureWrap::CLAMP_TO_EDGE;
711 samplerBackBuffer._wrapV = TextureWrap::CLAMP_TO_EDGE;
712 samplerBackBuffer._wrapW = TextureWrap::CLAMP_TO_EDGE;
713 samplerBackBuffer._minFilter = TextureFilter::LINEAR;
714 samplerBackBuffer._magFilter = TextureFilter::LINEAR;
715 samplerBackBuffer._mipSampling = TextureMipSampling::NONE;
716 samplerBackBuffer._anisotropyLevel = 0u;
717
718 // This could've been RGB, but Vulkan doesn't seem to support VK_FORMAT_R8G8B8_UNORM in this situation, so ... well ... whatever.
719 // This will contained the final tonemaped image, so unless we desire HDR output, RGBA8 here is fine as anything else will require
720 // changes to the swapchain images!
721 TextureDescriptor backBufferDescriptor{};
722 backBufferDescriptor._mipMappingState = MipMappingState::OFF;
723 AddImageUsageFlag( backBufferDescriptor, ImageUsage::SHADER_READ );
725 {
726 InternalRTAttachmentDescriptor{ backBufferDescriptor, samplerBackBuffer, RTAttachmentType::COLOUR, ScreenTargets::ALBEDO },
727 };
728
729 RenderTargetDescriptor screenDesc = {};
730 screenDesc._resolution = renderResolution;
731 screenDesc._attachments = attachments;
732 screenDesc._msaaSamples = 0u;
733 screenDesc._name = "BackBuffer";
734 RenderTargetNames::BACK_BUFFER = _rtPool->allocateRT( screenDesc )._targetID;
735 }
736 {
737 TextureDescriptor ssaoDescriptor{};
738 ssaoDescriptor._dataType = GFXDataFormat::FLOAT_16;
739 ssaoDescriptor._baseFormat = GFXImageFormat::RED;
740 ssaoDescriptor._packing = GFXImagePacking::UNNORMALIZED;
741 ssaoDescriptor._mipMappingState = MipMappingState::OFF;
742
743 RenderTargetDescriptor ssaoDesc = {};
744 ssaoDesc._attachments =
745 {
747 };
748
749 ssaoDesc._name = "SSAO Result";
750 ssaoDesc._resolution = renderResolution;
751 ssaoDesc._msaaSamples = 0u;
752 RenderTargetNames::SSAO_RESULT = _rtPool->allocateRT( ssaoDesc )._targetID;
753 }
754 {
755 TextureDescriptor ssrDescriptor{};
756 ssrDescriptor._dataType = GFXDataFormat::FLOAT_16;
757 ssrDescriptor._packing = GFXImagePacking::UNNORMALIZED;
758 ssrDescriptor._mipMappingState = MipMappingState::OFF;
759
760 RenderTargetDescriptor ssrResultDesc = {};
761 ssrResultDesc._attachments =
762 {
764 };
765
766 ssrResultDesc._name = "SSR Result";
767 ssrResultDesc._resolution = renderResolution;
768 ssrResultDesc._msaaSamples = 0u;
769 RenderTargetNames::SSR_RESULT = _rtPool->allocateRT( ssrResultDesc )._targetID;
770
771 }
772 const U32 reflectRes = nextPOW2( CLAMPED( to_U32( config.rendering.reflectionPlaneResolution ), 16u, 4096u ) - 1u );
773
774 TextureDescriptor hiZDescriptor{};
775 hiZDescriptor._dataType = GFXDataFormat::FLOAT_32;
776 hiZDescriptor._baseFormat = GFXImageFormat::RED;
777 hiZDescriptor._packing = GFXImagePacking::UNNORMALIZED;
778 hiZDescriptor._mipMappingState = MipMappingState::MANUAL;
780
781 SamplerDescriptor hiZSampler = {};
785 hiZSampler._anisotropyLevel = 0u;
789
790 RenderTargetDescriptor hizRTDesc = {};
791 hizRTDesc._attachments =
792 {
794 };
795
796 {
797 hizRTDesc._name = "HiZ";
798 hizRTDesc._resolution = renderResolution;
799 RenderTargetNames::HI_Z = _rtPool->allocateRT( hizRTDesc )._targetID;
800
801 hizRTDesc._resolution.set( reflectRes, reflectRes );
802 hizRTDesc._name = "HiZ_Reflect";
803 RenderTargetNames::HI_Z_REFLECT = _rtPool->allocateRT( hizRTDesc )._targetID;
804 }
805
806 // Reflection Targets
807 SamplerDescriptor reflectionSampler = {};
808 reflectionSampler._wrapU = TextureWrap::CLAMP_TO_EDGE;
809 reflectionSampler._wrapV = TextureWrap::CLAMP_TO_EDGE;
810 reflectionSampler._wrapW = TextureWrap::CLAMP_TO_EDGE;
811 reflectionSampler._minFilter = TextureFilter::LINEAR;
812 reflectionSampler._magFilter = TextureFilter::LINEAR;
813 reflectionSampler._mipSampling = TextureMipSampling::NONE;
814
815 {
816 TextureDescriptor environmentDescriptorPlanar{};
817 environmentDescriptorPlanar._mipMappingState = MipMappingState::MANUAL;
818
819 TextureDescriptor depthDescriptorPlanar{};
820 depthDescriptorPlanar._dataType = GFXDataFormat::UNSIGNED_INT;
821 depthDescriptorPlanar._baseFormat = GFXImageFormat::RED;
822 depthDescriptorPlanar._packing = GFXImagePacking::DEPTH;
823 depthDescriptorPlanar._mipMappingState = MipMappingState::OFF;
824
825 {
826 RenderTargetDescriptor refDesc = {};
827 refDesc._attachments =
828 {
829 InternalRTAttachmentDescriptor{ environmentDescriptorPlanar, reflectionSampler, RTAttachmentType::COLOUR, RTColourAttachmentSlot::SLOT_0 },
831 };
832
833 refDesc._resolution = vec2<U16>( reflectRes );
834
835 for ( U32 i = 0; i < Config::MAX_REFLECTIVE_NODES_IN_VIEW; ++i )
836 {
837 Util::StringFormat( refDesc._name, "Reflection_Planar_{}", i );
838 RenderTargetNames::REFLECTION_PLANAR[i] = _rtPool->allocateRT( refDesc )._targetID;
839 }
840
841 for ( U32 i = 0; i < Config::MAX_REFRACTIVE_NODES_IN_VIEW; ++i )
842 {
843 Util::StringFormat( refDesc._name, "Refraction_Planar_{}", i );
844 RenderTargetNames::REFRACTION_PLANAR[i] = _rtPool->allocateRT( refDesc )._targetID;
845 }
846
847 environmentDescriptorPlanar._mipMappingState = MipMappingState::OFF;
848 refDesc._attachments =
849 {//skip depth
850 InternalRTAttachmentDescriptor{ environmentDescriptorPlanar, reflectionSampler, RTAttachmentType::COLOUR, RTColourAttachmentSlot::SLOT_0 }
851 };
852
853 refDesc._name = "Reflection_blur";
854 RenderTargetNames::REFLECTION_PLANAR_BLUR = _rtPool->allocateRT( refDesc )._targetID;
855 }
856 }
857 {
858 SamplerDescriptor accumulationSampler = {};
859 accumulationSampler._wrapU = TextureWrap::CLAMP_TO_EDGE;
860 accumulationSampler._wrapV = TextureWrap::CLAMP_TO_EDGE;
861 accumulationSampler._wrapW = TextureWrap::CLAMP_TO_EDGE;
862 accumulationSampler._minFilter = TextureFilter::NEAREST;
863 accumulationSampler._magFilter = TextureFilter::NEAREST;
864 accumulationSampler._mipSampling = TextureMipSampling::NONE;
865
866 TextureDescriptor accumulationDescriptor{};
867 accumulationDescriptor._dataType = GFXDataFormat::FLOAT_16;
868 accumulationDescriptor._packing = GFXImagePacking::UNNORMALIZED;
869 accumulationDescriptor._mipMappingState = MipMappingState::OFF;
870
871 //R = revealage
872 TextureDescriptor revealageDescriptor{};
873 revealageDescriptor._dataType = GFXDataFormat::FLOAT_16;
874 revealageDescriptor._baseFormat = GFXImageFormat::RED;
875 revealageDescriptor._packing = GFXImagePacking::UNNORMALIZED;
876 revealageDescriptor._mipMappingState = MipMappingState::OFF;
877
879 {
880 InternalRTAttachmentDescriptor{ accumulationDescriptor, accumulationSampler, RTAttachmentType::COLOUR, ScreenTargets::ACCUMULATION, false },
881 InternalRTAttachmentDescriptor{ revealageDescriptor, accumulationSampler, RTAttachmentType::COLOUR, ScreenTargets::REVEALAGE, false },
882 InternalRTAttachmentDescriptor{ normalsDescriptor, accumulationSampler, RTAttachmentType::COLOUR, ScreenTargets::NORMALS, false },
883 };
884 {
885 const RenderTarget* screenTarget = _rtPool->getRenderTarget( RenderTargetNames::SCREEN );
886 RTAttachment* screenAttachment = screenTarget->getAttachment( RTAttachmentType::COLOUR, ScreenTargets::ALBEDO );
887 RTAttachment* screenDepthAttachment = screenTarget->getAttachment( RTAttachmentType::DEPTH );
888
889 ExternalRTAttachmentDescriptors externalAttachments
890 {
893 };
894
895 RenderTargetDescriptor oitDesc = {};
896 oitDesc._name = "OIT";
897 oitDesc._resolution = renderResolution;
898 oitDesc._attachments = oitAttachments;
899 oitDesc._externalAttachments = externalAttachments;
900 oitDesc._msaaSamples = config.rendering.MSAASamples;
901 RenderTargetNames::OIT = _rtPool->allocateRT( oitDesc )._targetID;
902 }
903 {
904 for ( U16 i = 0u; i < Config::MAX_REFLECTIVE_NODES_IN_VIEW; ++i )
905 {
906 const RenderTarget* reflectTarget = _rtPool->getRenderTarget( RenderTargetNames::REFLECTION_PLANAR[i] );
907 RTAttachment* screenAttachment = reflectTarget->getAttachment( RTAttachmentType::COLOUR );
908 RTAttachment* depthAttachment = reflectTarget->getAttachment( RTAttachmentType::DEPTH );
909
910 RenderTargetDescriptor oitDesc = {};
911 oitDesc._attachments = oitAttachments;
912
913 ExternalRTAttachmentDescriptors externalAttachments{
916 };
917
918 Util::StringFormat( oitDesc._name, "OIT_REFLECT_RES_{}", i );
919 oitDesc._resolution = vec2<U16>( reflectRes );
920 oitDesc._externalAttachments = externalAttachments;
921 oitDesc._msaaSamples = 0;
922 RenderTargetNames::OIT_REFLECT = _rtPool->allocateRT( oitDesc )._targetID;
923 }
924 }
925 }
926 {
927 TextureDescriptor environmentDescriptorCube{};
928 environmentDescriptorCube._texType = TextureType::TEXTURE_CUBE_ARRAY;
929 environmentDescriptorCube._mipMappingState = MipMappingState::OFF;
930
931 TextureDescriptor depthDescriptorCube{};
932 depthDescriptorCube._texType = TextureType::TEXTURE_CUBE_ARRAY;
933 depthDescriptorCube._dataType = GFXDataFormat::UNSIGNED_INT;
934 depthDescriptorCube._baseFormat = GFXImageFormat::RED;
935 depthDescriptorCube._packing = GFXImagePacking::DEPTH;
936
937 depthDescriptorCube._mipMappingState = MipMappingState::OFF;
938
939 RenderTargetDescriptor refDesc = {};
940 refDesc._attachments =
941 {
942 InternalRTAttachmentDescriptor{ environmentDescriptorCube, reflectionSampler, RTAttachmentType::COLOUR, RTColourAttachmentSlot::SLOT_0 },
944 };
945
946 refDesc._resolution = vec2<U16>( reflectRes );
947
948 refDesc._name = "Reflection_Cube_Array";
949 RenderTargetNames::REFLECTION_CUBE = _rtPool->allocateRT( refDesc )._targetID;
950 }
951 {
952 ShaderModuleDescriptor compModule = {};
953 compModule._moduleType = ShaderType::COMPUTE;
954 compModule._defines.emplace_back( Util::StringFormat( "LOCAL_SIZE {}", DEPTH_REDUCE_LOCAL_SIZE ) );
955 compModule._defines.emplace_back( "imageSizeIn PushData0[0].xy");
956 compModule._defines.emplace_back( "imageSizeOut PushData0[0].zw");
957 compModule._defines.emplace_back( "wasEven (uint(PushData0[1].x) == 1u)");
958
959 compModule._sourceFile = "HiZConstruct.glsl";
960
961 ShaderProgramDescriptor shaderDescriptor = {};
962 shaderDescriptor._modules.push_back( compModule );
963
964 // Initialized our HierarchicalZ construction shader (takes a depth attachment and down-samples it for every mip level)
965 ResourceDescriptor<ShaderProgram> descriptor1( "HiZConstruct", shaderDescriptor );
966 descriptor1.waitForReady( false );
967 _hIZConstructProgram = CreateResource( descriptor1, loadTasks );
968
969 PipelineDescriptor pipelineDesc{};
971 pipelineDesc._primitiveTopology = PrimitiveTopology::COMPUTE;
972 pipelineDesc._stateBlock = getNoDepthTestBlock();
973 _hIZPipeline = newPipeline( pipelineDesc );
974 }
975 {
976 ShaderModuleDescriptor compModule = {};
977 compModule._moduleType = ShaderType::COMPUTE;
978 compModule._defines.emplace_back( Util::StringFormat( "WORK_GROUP_SIZE {}", GROUP_SIZE_AABB ) );
979 compModule._sourceFile = "HiZOcclusionCull.glsl";
980
981 ShaderProgramDescriptor shaderDescriptor = {};
982 shaderDescriptor._modules.push_back( compModule );
983
984 ResourceDescriptor<ShaderProgram> descriptor2( "HiZOcclusionCull", shaderDescriptor );
985 descriptor2.waitForReady( false );
986
987 _hIZCullProgram = CreateResource( descriptor2, loadTasks );
988
989 PipelineDescriptor pipelineDescriptor = {};
990 pipelineDescriptor._shaderProgramHandle = _hIZCullProgram;
992 _hIZCullPipeline = newPipeline( pipelineDescriptor );
993 }
994 {
995 ShaderModuleDescriptor vertModule = {};
996 vertModule._moduleType = ShaderType::VERTEX;
997 vertModule._sourceFile = "baseVertexShaders.glsl";
998 vertModule._variant = "FullScreenQuad";
999
1000 ShaderModuleDescriptor fragModule = {};
1001 fragModule._moduleType = ShaderType::FRAGMENT;
1002 fragModule._sourceFile = "fbPreview.glsl";
1003
1004 ShaderProgramDescriptor shaderDescriptor = {};
1005 shaderDescriptor._modules.push_back( vertModule );
1006 shaderDescriptor._modules.push_back( fragModule );
1007
1008 ResourceDescriptor<ShaderProgram> previewRTShader( "fbPreview", shaderDescriptor );
1009 previewRTShader.waitForReady( true );
1010
1011 _renderTargetDraw = CreateResource( previewRTShader, loadTasks );
1013 }
1014 {
1015 ShaderModuleDescriptor vertModule = {};
1016 vertModule._moduleType = ShaderType::VERTEX;
1017 vertModule._sourceFile = "baseVertexShaders.glsl";
1018 vertModule._variant = "FullScreenQuad";
1019
1020 ShaderModuleDescriptor fragModule = {};
1021 fragModule._moduleType = ShaderType::FRAGMENT;
1022 fragModule._sourceFile = "fbPreview.glsl";
1023 fragModule._variant = "LinearDepth.ScenePlanes";
1024
1025 ShaderProgramDescriptor shaderDescriptor = {};
1026 shaderDescriptor._modules.push_back( vertModule );
1027 shaderDescriptor._modules.push_back( fragModule );
1028
1029 ResourceDescriptor<ShaderProgram> previewReflectionRefractionDepth( "fbPreviewLinearDepthScenePlanes", shaderDescriptor );
1030 previewReflectionRefractionDepth.waitForReady( false );
1031 _previewRenderTargetDepth = CreateResource( previewReflectionRefractionDepth, loadTasks );
1032 }
1033 ShaderModuleDescriptor blurVertModule = {};
1034 blurVertModule._moduleType = ShaderType::VERTEX;
1035 blurVertModule._sourceFile = "baseVertexShaders.glsl";
1036 blurVertModule._variant = "FullScreenQuad";
1037 {
1038 ShaderModuleDescriptor fragModule = {};
1039 fragModule._moduleType = ShaderType::FRAGMENT;
1040 fragModule._sourceFile = "blur.glsl";
1041 fragModule._variant = "Generic";
1042 fragModule._defines.emplace_back("layer uint(PushData0[0].x)" );
1043 fragModule._defines.emplace_back("size PushData0[0].yz");
1044 fragModule._defines.emplace_back("kernelSize int(PushData0[0].w)");
1045 fragModule._defines.emplace_back("verticalBlur uint(PushData0[1].x)");
1046 {
1047 ShaderProgramDescriptor shaderDescriptorSingle = {};
1048 shaderDescriptorSingle._modules.push_back( blurVertModule );
1049 shaderDescriptorSingle._modules.push_back( fragModule );
1050
1051 ResourceDescriptor<ShaderProgram> blur( "BoxBlur_Single", shaderDescriptorSingle );
1052 _blurBoxShaderSingle = CreateResource( blur, loadTasks );
1053
1054 PipelineDescriptor pipelineDescriptor;
1055 pipelineDescriptor._stateBlock = get2DStateBlock();
1057 pipelineDescriptor._shaderProgramHandle = _blurBoxShaderSingle;
1058 _blurBoxPipelineSingleCmd._pipeline = newPipeline( pipelineDescriptor );
1059 }
1060 {
1061 ShaderProgramDescriptor shaderDescriptorLayered = {};
1062 shaderDescriptorLayered._modules.push_back( blurVertModule );
1063 shaderDescriptorLayered._modules.push_back( fragModule );
1064 shaderDescriptorLayered._modules.back()._variant += ".Layered";
1065 shaderDescriptorLayered._modules.back()._defines.emplace_back( "LAYERED" );
1066
1067 ResourceDescriptor<ShaderProgram> blur( "BoxBlur_Layered", shaderDescriptorLayered );
1068 _blurBoxShaderLayered = CreateResource( blur, loadTasks );
1069
1070 PipelineDescriptor pipelineDescriptor;
1071 pipelineDescriptor._stateBlock = get2DStateBlock();
1073 pipelineDescriptor._shaderProgramHandle = _blurBoxShaderLayered;
1074 _blurBoxPipelineLayeredCmd._pipeline = newPipeline( pipelineDescriptor );
1075 }
1076 }
1077 {
1078 {
1079 ShaderModuleDescriptor geomModule = {};
1080 geomModule._moduleType = ShaderType::GEOMETRY;
1081 geomModule._sourceFile = "blur.glsl";
1082 geomModule._variant = "GaussBlur";
1083
1084 geomModule._defines.emplace_back( "verticalBlur uint(PushData0[1].x)" );
1085 geomModule._defines.emplace_back( "layerCount int(PushData0[1].y)" );
1086 geomModule._defines.emplace_back( "layerOffsetRead int(PushData0[1].z)" );
1087 geomModule._defines.emplace_back( "layerOffsetWrite int(PushData0[1].w)" );
1088
1089 ShaderModuleDescriptor fragModule = {};
1090 fragModule._moduleType = ShaderType::FRAGMENT;
1091 fragModule._sourceFile = "blur.glsl";
1092 fragModule._variant = "GaussBlur";
1093
1094 {
1095 ShaderProgramDescriptor shaderDescriptorSingle = {};
1096 shaderDescriptorSingle._modules.push_back( blurVertModule );
1097 shaderDescriptorSingle._modules.push_back( geomModule );
1098 shaderDescriptorSingle._modules.push_back( fragModule );
1099 shaderDescriptorSingle._globalDefines.emplace_back( "GS_MAX_INVOCATIONS 1" );
1100
1101 ResourceDescriptor<ShaderProgram> blur( "GaussBlur_Single", shaderDescriptorSingle );
1102 _blurGaussianShaderSingle = CreateResource( blur, loadTasks );
1103
1104 PipelineDescriptor pipelineDescriptor;
1105 pipelineDescriptor._stateBlock = get2DStateBlock();
1107 pipelineDescriptor._primitiveTopology = PrimitiveTopology::POINTS;
1109 }
1110 {
1111 ShaderProgramDescriptor shaderDescriptorLayered = {};
1112 shaderDescriptorLayered._modules.push_back( blurVertModule );
1113 shaderDescriptorLayered._modules.push_back( geomModule );
1114 shaderDescriptorLayered._modules.push_back( fragModule );
1115 shaderDescriptorLayered._modules.back()._variant += ".Layered";
1116 shaderDescriptorLayered._modules.back()._defines.emplace_back( "LAYERED" );
1117 shaderDescriptorLayered._globalDefines.emplace_back( Util::StringFormat( "GS_MAX_INVOCATIONS {}", MAX_INVOCATIONS_BLUR_SHADER_LAYERED ) );
1118
1119 ResourceDescriptor<ShaderProgram> blur( "GaussBlur_Layered", shaderDescriptorLayered );
1120 _blurGaussianShaderLayered = CreateResource( blur, loadTasks );
1121
1122 PipelineDescriptor pipelineDescriptor;
1123 pipelineDescriptor._stateBlock = get2DStateBlock();
1125 pipelineDescriptor._primitiveTopology = PrimitiveTopology::POINTS;
1126
1128 }
1129 }
1130 // Create an immediate mode rendering shader that simulates the fixed function pipeline
1131 _imShaders = std::make_unique<ImShaders>();
1132 }
1133 {
1134 ShaderModuleDescriptor vertModule = {};
1135 vertModule._moduleType = ShaderType::VERTEX;
1136 vertModule._sourceFile = "baseVertexShaders.glsl";
1137 vertModule._variant = "FullScreenQuad";
1138
1139 ShaderModuleDescriptor fragModule = {};
1140 fragModule._moduleType = ShaderType::FRAGMENT;
1141 fragModule._sourceFile = "display.glsl";
1142 fragModule._defines.emplace_back( "convertToSRGB uint(PushData0[0].x)" );
1143
1144 ShaderProgramDescriptor shaderDescriptor = {};
1145 shaderDescriptor._modules.push_back( vertModule );
1146 shaderDescriptor._modules.push_back( fragModule );
1147
1148 {
1149 ResourceDescriptor<ShaderProgram> descriptor3( "display", shaderDescriptor );
1150 _displayShader = CreateResource( descriptor3, loadTasks );
1151
1152 PipelineDescriptor pipelineDescriptor = {};
1153 pipelineDescriptor._stateBlock = get2DStateBlock();
1154 pipelineDescriptor._shaderProgramHandle = _displayShader;
1156 _drawFSTexturePipelineCmd._pipeline = newPipeline( pipelineDescriptor );
1157
1158 BlendingSettings& blendState = pipelineDescriptor._blendStates._settings[0];
1159 blendState.enabled( true );
1160 blendState.blendSrc( BlendProperty::SRC_ALPHA );
1161 blendState.blendDest( BlendProperty::INV_SRC_ALPHA );
1162 blendState.blendOp( BlendOperation::ADD );
1164 }
1165 {
1166 shaderDescriptor._modules.back()._defines.emplace_back( "DEPTH_ONLY" );
1167 ResourceDescriptor<ShaderProgram> descriptor3( "display_depth", shaderDescriptor );
1168
1169 _depthShader = CreateResource( descriptor3, loadTasks );
1170 PipelineDescriptor pipelineDescriptor = {};
1171 pipelineDescriptor._stateBlock = _stateDepthOnlyRendering;
1173 pipelineDescriptor._shaderProgramHandle = _depthShader;
1174
1175 _drawFSDepthPipelineCmd._pipeline = newPipeline( pipelineDescriptor );
1176 }
1177 }
1178
1179 context().paramHandler().setParam<bool>( _ID( "rendering.previewDebugViews" ), false );
1180 {
1181 // Create general purpose render state blocks
1182 RenderStateBlock primitiveStateBlock{};
1183
1184 PipelineDescriptor pipelineDesc;
1186 pipelineDesc._shaderProgramHandle = _imShaders->imWorldShaderNoTexture();
1187 pipelineDesc._stateBlock = primitiveStateBlock;
1188
1189 _debugGizmoPipeline = pipelineDesc;
1190
1191 primitiveStateBlock._depthTestEnabled = false;
1192 pipelineDesc._stateBlock = primitiveStateBlock;
1193 _debugGizmoPipelineNoDepth = pipelineDesc;
1194
1195
1196 primitiveStateBlock._cullMode = CullMode::NONE;
1197 pipelineDesc._stateBlock = primitiveStateBlock;
1198 _debugGizmoPipelineNoCullNoDepth = pipelineDesc;
1199
1200
1201 primitiveStateBlock._depthTestEnabled = true;
1202 pipelineDesc._stateBlock = primitiveStateBlock;
1203 _debugGizmoPipelineNoCull = pipelineDesc;
1204 }
1205
1206 _renderer = std::make_unique<Renderer>( context() );
1207
1208 WAIT_FOR_CONDITION( loadTasks.load() == 0 );
1209 const DisplayWindow* mainWindow = context().app().windowManager().mainWindow();
1210
1211 SizeChangeParams params{};
1212 params.width = _rtPool->getRenderTarget( RenderTargetNames::SCREEN )->getWidth();
1213 params.height = _rtPool->getRenderTarget( RenderTargetNames::SCREEN )->getHeight();
1214 params.winGUID = mainWindow->getGUID();
1215 params.isMainWindow = true;
1216 if ( context().app().onResolutionChange( params ) )
1217 {
1218 NOP();
1219 }
1220
1221 _sceneData = std::make_unique<SceneShaderData>( *this );
1222
1223 // Everything is ready from the rendering point of view
1224 return ErrorCode::NO_ERR;
1225 }
1226
1229 {
1230 if ( _api == nullptr )
1231 {
1232 //closeRenderingAPI called without init!
1233 return;
1234 }
1235
1236 if ( s_renderThread._running )
1237 {
1238 {
1239 LockGuard<Mutex> lock( s_renderThread._lock );
1240 s_renderThread._hasWork = false;
1241 s_renderThread._running = false;
1242 }
1243 s_renderThread._cv.notify_one();
1244 s_renderThread._thread.join();
1245 }
1246
1247 _debugLines.reset();
1248 _debugBoxes.reset();
1249 _debugOBBs.reset();
1250 _debugFrustums.reset();
1251 _debugCones.reset();
1252 _debugSpheres.reset();
1253 _debugViews.clear();
1254
1255 // Delete the renderer implementation
1256 Console::printfn( LOCALE_STR( "CLOSING_RENDERER" ) );
1257 _renderer.reset( nullptr );
1258
1259 _rtPool.reset();
1260
1273
1274 _imShaders.reset();
1275 _gfxBuffers.reset( true, true );
1276 _sceneData.reset();
1277 // Close the shader manager
1278 _shaderComputeQueue.reset();
1280 {
1282 }
1283
1287 assert( ShaderProgram::ShaderProgramCount() == 0 );
1288 // Close the rendering API
1289 _api->closeRenderingAPI();
1290 _api.reset();
1291
1293 if ( !_graphicResources.empty() )
1294 {
1295 string list = " [ ";
1296 for ( const auto& [type, guid, nameHash] : _graphicResources )
1297 {
1298 list.append( Util::StringFormat("\n{}_{}_{},", TypeUtil::GraphicResourceTypeToName( type ), guid, nameHash) );
1299 }
1300 list.pop_back();
1301 list.append("\n ]");
1302
1303 Console::errorfn( LOCALE_STR( "ERROR_GFX_LEAKED_RESOURCES" ), _graphicResources.size() );
1304 Console::errorfn( list.c_str() );
1305 }
1306 _graphicResources.clear();
1307 }
1308
1309 void GFXDevice::onThreadCreated( const std::thread::id& threadID, const bool isMainRenderThread ) const
1310 {
1311 _api->onThreadCreated( threadID, isMainRenderThread );
1312 }
1313
1314#pragma endregion
1315
1316#pragma region Main frame loop
1318 void GFXDevice::idle( const bool fast, const U64 deltaTimeUSGame, [[maybe_unused]] const U64 deltaTimeUSApp )
1319 {
1321
1322 _api->idle( fast );
1323
1324 _shaderComputeQueue->idle();
1325 // Pass the idle call to the post processing system
1326 _renderer->idle( deltaTimeUSGame );
1327 // And to the shader manager
1328 ShaderProgram::Idle( context(), fast );
1329 }
1330
1331 void GFXDevice::update( const U64 deltaTimeUSFixed, const U64 deltaTimeUSApp )
1332 {
1333 getRenderer().postFX().update( deltaTimeUSFixed, deltaTimeUSApp );
1334 }
1335
1337 {
1339 if ( !_api->drawToWindow( window ) )
1340 {
1341 NOP();
1342 }
1343 }
1344
1346 {
1348
1349 _api->prepareFlushWindow( window );
1350 const vec2<U16> windowDimensions = window.getDrawableSize();
1351 setViewport( { 0, 0, windowDimensions.width, windowDimensions.height } );
1352 setScissor( { 0, 0, windowDimensions.width, windowDimensions.height } );
1353
1354 {
1358 {
1360 }
1361 ResetCommandBufferQueue(queue);
1362 }
1363 _api->flushWindow( window );
1364 }
1365
1366 bool GFXDevice::framePreRender( [[maybe_unused]] const FrameEvent& evt )
1367 {
1368 return true;
1369 }
1370
1371 bool GFXDevice::frameStarted( [[maybe_unused]] const FrameEvent& evt )
1372 {
1373 for ( GFXDescriptorSet& set : _descriptorSets )
1374 {
1375 set.clear();
1376 }
1377
1379 {
1382 }
1383 for ( U8 i = 0u; i < to_base( ShadowType::COUNT ); ++i )
1384 {
1386 {
1389 }
1390 }
1391
1393
1394 if ( _api->frameStarted() )
1395 {
1396 _context.app().windowManager().drawToWindow(context().mainWindow());
1397 return true;
1398 }
1399
1400 return false;
1401 }
1402
1403 bool GFXDevice::frameEnded( [[maybe_unused]] const FrameEvent& evt ) noexcept
1404 {
1406
1407 const bool editorRunning = Config::Build::ENABLE_EDITOR && context().editor().running();
1408 if ( !editorRunning )
1409 {
1410 PROFILE_SCOPE("Blit Backbuffer", Profiler::Category::Graphics);
1411
1412 Handle<GFX::CommandBuffer> bufferHandle = GFX::AllocateCommandBuffer("Blit Backbuffer");
1413 GFX::CommandBuffer* buffer = GFX::Get(bufferHandle);
1414
1415 GFX::BeginRenderPassCommand beginRenderPassCmd{};
1416 beginRenderPassCmd._target = SCREEN_TARGET_ID;
1417 beginRenderPassCmd._name = "Blit Backbuffer";
1418 beginRenderPassCmd._clearDescriptor[to_base( RTColourAttachmentSlot::SLOT_0 )] = { DefaultColours::BLACK, true };
1419 beginRenderPassCmd._descriptor._drawMask[to_base( RTColourAttachmentSlot::SLOT_0 )] = true;
1420 GFX::EnqueueCommand( *buffer, beginRenderPassCmd );
1421
1422 const auto& screenAtt = renderTargetPool().getRenderTarget( RenderTargetNames::BACK_BUFFER )->getAttachment( RTAttachmentType::COLOUR, GFXDevice::ScreenTargets::ALBEDO );
1423 const auto& texData = Get(screenAtt->texture())->getView();
1424
1425 drawTextureInViewport( texData, screenAtt->_descriptor._sampler, context().mainWindow().renderingViewport(), false, false, false, *buffer );
1426
1427 GFX::EnqueueCommand<GFX::EndRenderPassCommand>( *buffer );
1428 flushCommandBuffer( MOV(bufferHandle) );
1429 }
1430
1431 context().app().windowManager().flushWindow();
1432
1433
1434 /*while ( !s_renderThread._windows.empty() )
1435 {
1436 DisplayWindow* window = s_renderThread._windows.front();
1437
1438 _api->onRenderThreadLoopStart();
1439
1441 {
1442 _api->prepareFlushWindow( *window );
1443 {
1444 LockGuard<Mutex> w_lock( _queuedCommandbufferLock );
1445 GFX::CommandBufferQueue& queue = window->getCurrentCommandBufferQueue();
1446 for ( const GFX::CommandBufferQueue::Entry& entry : queue._commandBuffers )
1447 {
1448 flushCommandBufferInternal( *window, entry._buffer );
1449 }
1450 ResetCommandBufferQueue( queue );
1451 }
1452 _api->flushWindow( *window );
1453 }
1455
1456 s_renderThread._windows.pop();
1457 }*/
1458
1459 frameDrawCallsPrev( frameDrawCalls() );
1460 frameDrawCalls( 0u );
1461
1462 if ( _gfxBuffers._needsResizeCam )
1463 {
1464 PROFILE_SCOPE( "Resize GFX Blocks", Profiler::Category::Graphics );
1465
1466 const GFXBuffers::PerFrameBuffers& frameBuffers = _gfxBuffers.crtBuffers();
1467 const U32 currentSizeCam = frameBuffers._camDataBuffer->queueLength();
1468 const U32 currentSizeCullCounter = frameBuffers._cullCounter->queueLength();
1469 resizeGPUBlocks( _gfxBuffers._needsResizeCam ? currentSizeCam + TargetBufferSizeCam : currentSizeCam, currentSizeCullCounter );
1470 _gfxBuffers._needsResizeCam = false;
1471 }
1472
1473 _gfxBuffers.onEndFrame();
1475
1476 if (!_api->frameEnded())
1477 {
1479 }
1480 {
1481 PROFILE_SCOPE( "Lifetime updates", Profiler::Category::Graphics );
1482
1483 DecrementPrimitiveLifetime( _debugLines );
1484 DecrementPrimitiveLifetime( _debugBoxes );
1485 DecrementPrimitiveLifetime( _debugOBBs );
1486 DecrementPrimitiveLifetime( _debugFrustums );
1487 DecrementPrimitiveLifetime( _debugCones );
1488 DecrementPrimitiveLifetime( _debugSpheres );
1489
1490 _performanceMetrics._scratchBufferQueueUsage[0] = to_U32( _gfxBuffers.crtBuffers()._camWritesThisFrame );
1491 _performanceMetrics._scratchBufferQueueUsage[1] = to_U32( _gfxBuffers.crtBuffers()._renderWritesThisFrame );
1492 ++s_frameCount;
1493 }
1494
1495 return true;
1496 }
1497#pragma endregion
1498
1499#pragma region Utility functions
1502 const U16 arrayOffset,
1503 const vec3<F32>& pos,
1504 const vec2<F32> zPlanes,
1505 GFX::CommandBuffer& commandsInOut,
1506 GFX::MemoryBarrierCommand& memCmdInOut,
1507 mat4<F32>* viewProjectionOut)
1508 {
1510
1511 // Only the first colour attachment or the depth attachment is used for now and it must be a cube map texture
1512 RenderTarget* cubeMapTarget = _rtPool->getRenderTarget( params._target );
1513
1514 // Colour attachment takes precedent over depth attachment
1515 bool isValidFB = false;
1516 if ( cubeMapTarget->hasAttachment( RTAttachmentType::COLOUR ) )
1517 {
1518 // We only need the colour attachment
1519 isValidFB = IsCubeTexture( Get(cubeMapTarget->getAttachment( RTAttachmentType::COLOUR )->texture())->descriptor()._texType );
1520 }
1521 else if ( cubeMapTarget->hasAttachment( RTAttachmentType::DEPTH ) )
1522 {
1523 // We don't have a colour attachment, so we require a cube map depth attachment
1524 isValidFB = IsCubeTexture( Get(cubeMapTarget->getAttachment( RTAttachmentType::DEPTH )->texture())->descriptor()._texType );
1525 }
1526
1527 // Make sure we have a proper render target to draw to
1528 if ( !isValidFB )
1529 {
1530 // Future formats must be added later (e.g. cube map arrays)
1531 Console::errorfn( LOCALE_STR( "ERROR_GFX_DEVICE_INVALID_FB_CUBEMAP" ) );
1532 return;
1533 }
1534
1537 constexpr const char* PassNames[] = { "CUBEMAP_X+", "CUBEMAP_X-", "CUBEMAP_Y+", "CUBEMAP_Y-", "CUBEMAP_Z+", "CUBEMAP_Z-" };
1538
1539 DIVIDE_ASSERT( cubeMapTarget->getWidth() == cubeMapTarget->getHeight());
1540
1541 auto& passMgr = context().kernel().renderPassManager();
1542
1544
1545 // For each of the environment's faces (TOP, DOWN, NORTH, SOUTH, EAST, WEST)
1546 for ( U8 i = 0u; i < 6u; ++i )
1547 {
1548 params._passName = PassNames[i];
1549 params._stagePass._pass = static_cast<RenderStagePass::PassIndex>(i);
1550
1551 const DrawLayerEntry layer = { arrayOffset, i};
1552
1553 // Draw to the current cubemap face
1558
1559 // Set a 90 degree horizontal FoV perspective projection
1560 camera->setProjection( 1.f, Angle::to_VerticalFoV( Angle::DEGREES<F32>( 90.f ), 1.f ), zPlanes );
1561 // Point our camera to the correct face
1562 camera->lookAt( pos, pos + (CameraDirections[i] * zPlanes.max), CameraUpVectors[i] );
1563 // Pass our render function to the renderer
1564 passMgr->doCustomPass( camera, params, commandsInOut, memCmdInOut );
1565
1566 if ( viewProjectionOut != nullptr )
1567 {
1568 viewProjectionOut[i] = camera->viewProjectionMatrix();
1569 }
1570 }
1571 }
1572
1574 const U16 arrayOffset,
1575 const vec3<F32>& pos,
1576 const vec2<F32> zPlanes,
1577 GFX::CommandBuffer& bufferInOut,
1578 GFX::MemoryBarrierCommand& memCmdInOut,
1579 mat4<F32>* viewProjectionOut )
1580 {
1582
1583 RenderTarget* paraboloidTarget = _rtPool->getRenderTarget( params._target );
1584 // Colour attachment takes precedent over depth attachment
1585 const bool hasColour = paraboloidTarget->hasAttachment( RTAttachmentType::COLOUR );
1586 const bool hasDepth = paraboloidTarget->hasAttachment( RTAttachmentType::DEPTH );
1587 const vec2<U16> targetResolution = paraboloidTarget->getResolution();
1588
1589 bool isValidFB = false;
1590 if ( hasColour )
1591 {
1592 RTAttachment* colourAttachment = paraboloidTarget->getAttachment( RTAttachmentType::COLOUR );
1593 // We only need the colour attachment
1594 isValidFB = IsArrayTexture( Get(colourAttachment->texture())->descriptor()._texType );
1595 }
1596 else
1597 {
1598 RTAttachment* depthAttachment = paraboloidTarget->getAttachment( RTAttachmentType::DEPTH );
1599 // We don't have a colour attachment, so we require a cube map depth attachment
1600 isValidFB = hasDepth && IsArrayTexture( Get(depthAttachment->texture())->descriptor()._texType );
1601 }
1602 // Make sure we have a proper render target to draw to
1603 if ( !isValidFB )
1604 {
1605 // Future formats must be added later (e.g. cube map arrays)
1606 Console::errorfn( LOCALE_STR( "ERROR_GFX_DEVICE_INVALID_FB_DP" ) );
1607 return;
1608 }
1609
1610 params._passName = "DualParaboloid";
1611 const D64 aspect = to_D64( targetResolution.width ) / targetResolution.height;
1612 auto& passMgr = context().kernel().renderPassManager();
1613
1615
1616 for ( U8 i = 0u; i < 2u; ++i )
1617 {
1618 const U16 layer = arrayOffset + i;
1619
1624
1625 // Point our camera to the correct face
1626 camera->lookAt( pos, pos + (i == 0 ? WORLD_Z_NEG_AXIS : WORLD_Z_AXIS) * zPlanes.y );
1627 // Set a 180 degree vertical FoV perspective projection
1628 camera->setProjection( to_F32( aspect ), Angle::to_VerticalFoV( Angle::DEGREES<F32>( 180.0f ), aspect ), zPlanes );
1629 // And generated required matrices
1630 // Pass our render function to the renderer
1631 params._stagePass._pass = static_cast<RenderStagePass::PassIndex>(i);
1632
1633 passMgr->doCustomPass( camera, params, bufferInOut, memCmdInOut );
1634
1635 if ( viewProjectionOut != nullptr )
1636 {
1637 viewProjectionOut[i] = camera->viewProjectionMatrix();
1638 }
1639 }
1640 }
1641
1643 RenderTargetHandle& blurBuffer,
1644 const RenderTargetHandle& blurTarget,
1645 const RTAttachmentType att,
1646 const RTColourAttachmentSlot slot,
1647 const I32 kernelSize,
1648 const bool gaussian,
1649 const U8 layerCount,
1650 GFX::CommandBuffer& bufferInOut )
1651 {
1652 const auto& inputAttachment = blurSource._rt->getAttachment( att, slot );
1653 const auto& bufferAttachment = blurBuffer._rt->getAttachment( att, slot );
1654
1655 PushConstantsStruct pushData{};
1656 pushData.data[0]._vec[0].w = to_F32( kernelSize );
1657 pushData.data[0]._vec[1].y = to_F32( layerCount );
1658 pushData.data[0]._vec[1].z = 0.f;
1659 pushData.data[0]._vec[1].w = 0.f;
1660
1661 const U8 loopCount = gaussian ? 1u : layerCount;
1662
1663 {// Blur horizontally
1664 pushData.data[0]._vec[0].x = 0.f;
1665 pushData.data[0]._vec[1].x = 0.f;
1666 pushData.data[0]._vec[0].yz = vec2<F32>( blurBuffer._rt->getResolution() );
1667 pushData.data[0]._vec[2].xy.set( 1.f / blurBuffer._rt->getResolution().width, 1.f / blurBuffer._rt->getResolution().height );
1668
1669 GFX::BeginRenderPassCommand* renderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>( bufferInOut );
1670 renderPassCmd->_target = blurBuffer._targetID;
1671 renderPassCmd->_name = "BLUR_RENDER_TARGET_HORIZONTAL";
1675
1676 GFX::EnqueueCommand( bufferInOut, gaussian ? (layerCount > 1 ? _blurGaussianPipelineLayeredCmd : _blurGaussianPipelineSingleCmd)
1678
1679 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>( bufferInOut );
1680 cmd->_usage = DescriptorSetUsage::PER_DRAW;
1682 Set( binding._data, inputAttachment->texture(), inputAttachment->_descriptor._sampler );
1683
1684
1685 if ( !gaussian && layerCount > 1 )
1686 {
1687 pushData.data[0]._vec[0].x = 0.f;
1688 }
1689
1690 for ( U8 loop = 0u; loop < loopCount; ++loop )
1691 {
1692 if ( !gaussian && loop > 0u )
1693 {
1694 pushData.data[0]._vec[0].x = to_F32( loop );
1695 GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut)->_fastData = pushData;
1696 }
1697 GFX::EnqueueCommand<GFX::DrawCommand>( bufferInOut )->_drawCommands.emplace_back();
1698 }
1699
1701 }
1702 {// Blur vertically
1703 pushData.data[0]._vec[0].x = 0.f;
1704 pushData.data[0]._vec[1].x = 1.f;
1705 pushData.data[0]._vec[0].yz = vec2<F32>( blurTarget._rt->getResolution() );
1706 pushData.data[0]._vec[2].xy.set( 1.0f / blurTarget._rt->getResolution().width, 1.0f / blurTarget._rt->getResolution().height );
1707
1708 GFX::BeginRenderPassCommand* renderPassCmd = GFX::EnqueueCommand<GFX::BeginRenderPassCommand>( bufferInOut );
1709 renderPassCmd->_target = blurTarget._targetID;
1710 renderPassCmd->_name = "BLUR_RENDER_TARGET_VERTICAL";
1714
1715 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>( bufferInOut );
1716 cmd->_usage = DescriptorSetUsage::PER_DRAW;
1718 Set( binding._data, bufferAttachment->texture(), bufferAttachment->_descriptor._sampler );
1719
1720 GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut )->_fastData = pushData;
1721
1722 for ( U8 loop = 0u; loop < loopCount; ++loop )
1723 {
1724 if ( !gaussian && loop > 0u )
1725 {
1726 pushData.data[0]._vec[0].x = to_F32( loop );
1727 GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut )->_fastData = pushData;
1728 }
1729 GFX::EnqueueCommand<GFX::DrawCommand>( bufferInOut )->_drawCommands.emplace_back();
1730 }
1731
1733 }
1734 }
1735#pragma endregion
1736
1737#pragma region Resolution, viewport and window management
1738
1739 void GFXDevice::setScreenMSAASampleCount( const U8 sampleCount )
1740 {
1741 _queuedScreenSampleChange = sampleCount;
1742 }
1743
1744 void GFXDevice::setShadowMSAASampleCount( const ShadowType type, const U8 sampleCount )
1745 {
1746 _queuedShadowSampleChange[to_base( type )] = sampleCount;
1747 }
1748
1750 {
1751 CLAMP( sampleCount, U8_ZERO, DisplayManager::MaxMSAASamples() );
1752 if ( _context.config().rendering.MSAASamples != sampleCount )
1753 {
1754 _context.config().rendering.MSAASamples = sampleCount;
1755 _rtPool->getRenderTarget( RenderTargetNames::SCREEN )->updateSampleCount( sampleCount );
1756 _rtPool->getRenderTarget( RenderTargetNames::OIT )->updateSampleCount( sampleCount );
1758 }
1759 }
1760
1762 {
1763 CLAMP( sampleCount, U8_ZERO, DisplayManager::MaxMSAASamples() );
1764 ShadowMap::setMSAASampleCount( type, sampleCount );
1765 }
1766
1769 {
1770 if ( params.isMainWindow && !fitViewportInWindow( params.width, params.height ) )
1771 {
1772 NOP();
1773 }
1774 }
1775
1777 {
1778 if ( !params.isMainWindow )
1779 {
1780 return;
1781 }
1782
1783 const U16 w = params.width;
1784 const U16 h = params.height;
1785
1786 // Update resolution only if it's different from the current one.
1787 // Avoid resolution change on minimize so we don't thrash render targets
1788 if ( w < 1 || h < 1 || _renderingResolution == vec2<U16>( w, h ) )
1789 {
1790 return;
1791 }
1792
1793 Configuration& config = context().config();
1794
1795 const F32 aspectRatio = to_F32( w ) / h;
1796 const F32 vFoV = Angle::to_VerticalFoV( config.runtime.horizontalFOV, to_D64( aspectRatio ) );
1797 const vec2<F32> zPlanes( Camera::s_minNearZ, config.runtime.cameraViewDistance );
1798
1799 // Update the 2D camera so it matches our new rendering viewport
1800 if ( Camera::GetUtilityCamera( Camera::UtilityCamera::_2D )->setProjection( vec4<F32>( 0, to_F32( w ), 0, to_F32( h ) ), vec2<F32>( -1, 1 ) ) )
1801 {
1803 }
1804 if ( Camera::GetUtilityCamera( Camera::UtilityCamera::_2D_FLIP_Y )->setProjection( vec4<F32>( 0, to_F32( w ), to_F32( h ), 0 ), vec2<F32>( -1, 1 ) ) )
1805 {
1807 }
1808 if ( Camera::GetUtilityCamera( Camera::UtilityCamera::DEFAULT )->setProjection( aspectRatio, vFoV, zPlanes ) )
1809 {
1811 }
1812
1813 // Update render targets with the new resolution
1814 _rtPool->getRenderTarget( RenderTargetNames::BACK_BUFFER )->resize( w, h );
1815 _rtPool->getRenderTarget( RenderTargetNames::SCREEN )->resize( w, h );
1816 _rtPool->getRenderTarget( RenderTargetNames::SCREEN_PREV )->resize( w, h );
1817 _rtPool->getRenderTarget( RenderTargetNames::SSAO_RESULT )->resize( w, h );
1818 _rtPool->getRenderTarget( RenderTargetNames::SSR_RESULT )->resize( w, h );
1819 _rtPool->getRenderTarget( RenderTargetNames::HI_Z )->resize( w, h );
1820 _rtPool->getRenderTarget( RenderTargetNames::OIT )->resize( w, h );
1821
1822 // Update post-processing render targets and buffers
1823 _renderer->updateResolution( w, h );
1824 _renderingResolution.set( w, h );
1825
1826 if (!fitViewportInWindow( w, h ))
1827 {
1828 NOP();
1829 }
1830 }
1831
1832 bool GFXDevice::fitViewportInWindow( const U16 w, const U16 h )
1833 {
1834 const F32 currentAspectRatio = renderingAspectRatio();
1835
1836 I32 left = 0, bottom = 0;
1837 I32 newWidth = w;
1838 I32 newHeight = h;
1839
1840 const I32 tempWidth = to_I32( h * currentAspectRatio );
1841 const I32 tempHeight = to_I32( w / currentAspectRatio );
1842
1843 const F32 newAspectRatio = to_F32( tempWidth ) / tempHeight;
1844
1845 if ( newAspectRatio <= currentAspectRatio )
1846 {
1847 newWidth = tempWidth;
1848 left = to_I32( (w - newWidth) * 0.5f );
1849 }
1850 else
1851 {
1852 newHeight = tempHeight;
1853 bottom = to_I32( (h - newHeight) * 0.5f );
1854 }
1855
1856 context().mainWindow().renderingViewport( Rect<I32>( left, bottom, newWidth, newHeight ) );
1857
1858 return COMPARE(newAspectRatio, currentAspectRatio);
1859 }
1860#pragma endregion
1861
1862#pragma region GPU State
1863
1865 {
1867
1868 // Put the viewport update here as it is the most common source of gpu data invalidation and not always
1869 // needed for rendering (e.g. changed by RenderTarget::End())
1870
1871 const vec4<F32> tempViewport{ activeViewport() };
1872 if ( _gpuBlock._camData._viewPort != tempViewport )
1873 {
1874 _gpuBlock._camData._viewPort.set( tempViewport );
1875 const U32 clustersX = to_U32( std::ceil( to_F32( tempViewport.sizeX ) / Config::Lighting::ClusteredForward::CLUSTERS_X ) );
1876 const U32 clustersY = to_U32( std::ceil( to_F32( tempViewport.sizeY ) / Config::Lighting::ClusteredForward::CLUSTERS_Y ) );
1877 if ( clustersX != to_U32( _gpuBlock._camData._renderTargetInfo.z ) ||
1878 clustersY != to_U32( _gpuBlock._camData._renderTargetInfo.w ) )
1879 {
1882 }
1884 }
1885
1887 {
1889 _gpuBlock._camNeedsUpload = false;
1890 frameBuffers._camDataBuffer->incQueue();
1891 if ( ++frameBuffers._camWritesThisFrame >= frameBuffers._camDataBuffer->queueLength() )
1892 {
1893 //We've wrapped around this buffer inside of a single frame so sync performance will degrade unless we increase our buffer size
1895 //Because we are now overwriting existing data, we need to make sure that any fences that could possibly protect us have been flushed
1896 DIVIDE_ASSERT( frameBuffers._camBufferWriteRange._length == 0u );
1897 }
1898 const BufferRange writtenRange = frameBuffers._camDataBuffer->writeData( &_gpuBlock._camData )._range;
1899
1900 if ( frameBuffers._camBufferWriteRange._length == 0u )
1901 {
1902 frameBuffers._camBufferWriteRange = writtenRange;
1903 }
1904 else
1905 {
1906 Merge( frameBuffers._camBufferWriteRange, writtenRange );
1907 }
1908
1909 DescriptorSetBinding binding{};
1911 binding._slot = 1;
1912 Set( binding._data, _gfxBuffers.crtBuffers()._camDataBuffer.get(), { 0, 1 } );
1913
1915 return true;
1916 }
1917
1918 return false;
1919 }
1920
1923 {
1924 if ( clipPlanes != _clippingPlanes )
1925 {
1926 _clippingPlanes = clipPlanes;
1927
1928 auto& planes = _clippingPlanes.planes();
1929 auto& states = _clippingPlanes.planeState();
1930
1931 U8 count = 0u;
1932 for ( U8 i = 0u; i < to_U8( ClipPlaneIndex::COUNT ); ++i )
1933 {
1934 if ( states[i] )
1935 {
1936 _gpuBlock._camData._clipPlanes[count++].set( planes[i]._equation );
1937 if ( count == Config::MAX_CLIP_DISTANCES )
1938 {
1939 break;
1940 }
1941 }
1942 }
1943
1946 }
1947 }
1948
1949 void GFXDevice::setDepthRange( const vec2<F32> depthRange )
1950 {
1952 if ( data._renderTargetInfo.xy != depthRange )
1953 {
1954 data._renderTargetInfo.xy = depthRange;
1956 }
1957 }
1958
1959 void GFXDevice::renderFromCamera( const CameraSnapshot& cameraSnapshot )
1960 {
1962
1964
1965 bool projectionDirty = false, viewDirty = false;
1966
1967 if ( cameraSnapshot._projectionMatrix != data._projectionMatrix )
1968 {
1969 const F32 zNear = cameraSnapshot._zPlanes.min;
1970 const F32 zFar = cameraSnapshot._zPlanes.max;
1971
1972 data._projectionMatrix.set( cameraSnapshot._projectionMatrix );
1973 data._cameraProperties.xyz.set( zNear, zFar, cameraSnapshot._fov );
1974
1975 if ( cameraSnapshot._isOrthoCamera )
1976 {
1977 data._lightingTweakValues.x = 1.f; //scale
1978 data._lightingTweakValues.y = 0.f; //bias
1979 }
1980 else
1981 {
1982 //ref: http://www.aortiz.me/2018/12/21/CG.html
1984 const F32 zLogRatio = std::log( zFar / zNear );
1985
1986 data._lightingTweakValues.x = CLUSTERS_Z / zLogRatio; //scale
1987 data._lightingTweakValues.y = -(CLUSTERS_Z * std::log( zNear ) / zLogRatio); //bias
1988 }
1989 projectionDirty = true;
1990 }
1991
1992 if ( cameraSnapshot._viewMatrix != data._viewMatrix )
1993 {
1994 data._viewMatrix.set( cameraSnapshot._viewMatrix );
1995 data._invViewMatrix.set( cameraSnapshot._invViewMatrix );
1996 viewDirty = true;
1997 }
1998
1999 if ( projectionDirty || viewDirty )
2000 {
2002 _activeCameraSnapshot = cameraSnapshot;
2003 }
2004 }
2005
2006 void GFXDevice::shadowingSettings( const F32 lightBleedBias, const F32 minShadowVariance ) noexcept
2007 {
2008 GFXShaderData::CamData& data = _gpuBlock._camData;
2009
2010 if ( !COMPARE( data._lightingTweakValues.z, lightBleedBias ) ||
2011 !COMPARE( data._lightingTweakValues.w, minShadowVariance ) )
2012 {
2013 data._lightingTweakValues.zw = { lightBleedBias, minShadowVariance };
2014 _gpuBlock._camNeedsUpload = true;
2015 }
2016 }
2017
2018 void GFXDevice::worldAOViewProjectionMatrix( const mat4<F32>& vpMatrix ) noexcept
2019 {
2020 GFXShaderData::CamData& data = _gpuBlock._camData;
2021 data._worldAOVPMatrix = vpMatrix;
2022 _gpuBlock._camNeedsUpload = true;
2023 }
2024
2025 void GFXDevice::setPreviousViewProjectionMatrix( const PlayerIndex index, const mat4<F32>& prevViewMatrix, const mat4<F32> prevProjectionMatrix )
2026 {
2028
2029
2030 bool projectionDirty = false, viewDirty = false;
2031
2033
2034 if ( frameData._previousViewMatrix != prevViewMatrix )
2035 {
2036 frameData._previousViewMatrix = prevViewMatrix;
2037 viewDirty = true;
2038 }
2039 if ( frameData._previousProjectionMatrix != prevProjectionMatrix )
2040 {
2041 frameData._previousProjectionMatrix = prevProjectionMatrix;
2042 projectionDirty = true;
2043 }
2044
2045 if ( projectionDirty || viewDirty )
2046 {
2048 }
2049 }
2050
2051 bool GFXDevice::setViewport( const Rect<I32>& viewport )
2052 {
2053 _activeViewport.set( viewport );
2054 return _api->setViewportInternal( viewport );
2055 }
2056
2057 bool GFXDevice::setScissor( const Rect<I32>& scissor )
2058 {
2059 _activeScissor.set( scissor );
2060 return _api->setScissorInternal( scissor );
2061 }
2062
2063 void GFXDevice::setCameraSnapshot( const PlayerIndex index, const CameraSnapshot& snapshot ) noexcept
2064 {
2065 _cameraSnapshotHistory[index] = snapshot;
2066 }
2067
2069 {
2070 return _cameraSnapshotHistory[index];
2071 }
2072
2073 const CameraSnapshot& GFXDevice::getCameraSnapshot( const PlayerIndex index ) const noexcept
2074 {
2075 return _cameraSnapshotHistory[index];
2076 }
2077
2079 {
2080 return _gpuBlock._camData;
2081 }
2082
2084 {
2085 return _gpuBlock._prevFrameData[index];
2086 }
2087#pragma endregion
2088
2089#pragma region Command buffers, occlusion culling, etc
2091 {
2092 if (!uploadGPUBlock())
2093 {
2094 NOP();
2095 }
2096
2097 thread_local DescriptorSetEntries setEntries{};
2098
2099 constexpr DescriptorSetUsage prioritySorted[to_base( DescriptorSetUsage::COUNT )]
2100 {
2105 };
2106
2107 for ( const DescriptorSetUsage usage : prioritySorted )
2108 {
2109 GFXDescriptorSet& set = _descriptorSets[to_base( usage )];
2110 DescriptorSetEntry& entry = setEntries[to_base(usage)];
2111 entry._set = &set.impl();
2112 entry._usage = usage;
2113 entry._isDirty = set.dirty();
2114 set.dirty( false );
2115 }
2116
2117 _api->bindShaderResources( setEntries );
2118 }
2119
2121 {
2123
2126 AddCommandBufferToQueue( queue, MOV(commandBuffer) );
2127 }
2128
2130 {
2132
2133 const Rect<I32> initialViewport = activeViewport();
2134 const Rect<I32> initialScissor = activeScissor();
2135
2136 _api->preFlushCommandBuffer( commandBuffer );
2137
2138 const GFX::CommandBuffer::CommandList& commands = GFX::Get(commandBuffer)->commands();
2139 for ( GFX::CommandBase* cmd : commands )
2140 {
2141 if ( IsSubmitCommand( cmd->type() ) )
2142 {
2144 }
2145
2146 switch ( cmd->type() )
2147 {
2149 {
2150 PROFILE_SCOPE( "READ_BUFFER_DATA", Profiler::Category::Graphics );
2151
2153 crtCmd._buffer->readData( { crtCmd._offsetElementCount, crtCmd._elementCount }, crtCmd._target );
2154 } break;
2156 {
2157 PROFILE_SCOPE( "CLEAR_BUFFER_DATA", Profiler::Category::Graphics );
2158
2160 if ( crtCmd._buffer != nullptr )
2161 {
2163 memCmd._bufferLocks.push_back( crtCmd._buffer->clearData( { crtCmd._offsetElementCount, crtCmd._elementCount } ) );
2164 _api->flushCommand( &memCmd );
2165 }
2166 } break;
2168 {
2170
2172 } break;
2174 {
2175 PROFILE_SCOPE( "PUSH_VIEWPORT", Profiler::Category::Graphics );
2176
2178 _viewportStack.push( activeViewport() );
2179 setViewport( crtCmd->_viewport );
2180 } break;
2182 {
2184
2185 setViewport( _viewportStack.top() );
2186 _viewportStack.pop();
2187 } break;
2189 {
2192 } break;
2194 {
2196
2197 const GFX::SetCameraCommand* crtCmd = cmd->As<GFX::SetCameraCommand>();
2198 // Tell the Rendering API to draw from our desired PoV
2200 } break;
2202 {
2204
2205 const GFX::PushCameraCommand* crtCmd = cmd->As<GFX::PushCameraCommand>();
2206 DIVIDE_ASSERT( _cameraSnapshots.size() < MAX_CAMERA_SNAPSHOTS, "GFXDevice::flushCommandBuffer error: PUSH_CAMERA stack too deep!" );
2207
2210 } break;
2212 {
2214
2216 _cameraSnapshots.pop();
2217 } break;
2219 {
2220 PROFILE_SCOPE( "SET_CLIP_PLANES", Profiler::Category::Graphics );
2221
2223 } break;
2225 {
2226 PROFILE_SCOPE( "BIND_SHADER_RESOURCES", Profiler::Category::Graphics );
2227
2228 const auto resCmd = cmd->As<GFX::BindShaderResourcesCommand>();
2229 descriptorSet( resCmd->_usage ).update( resCmd->_usage, resCmd->_set );
2230
2231 } break;
2233 {
2234 DIVIDE_ASSERT(!cmd->As<GFX::DrawCommand>()->_drawCommands.empty());
2235 } break;
2236 default: break;
2237 }
2238
2239 _api->flushCommand( cmd );
2240 }
2241
2243 if ( frameBuffers._camBufferWriteRange._length > 0u )
2244 {
2245 GFX::MemoryBarrierCommand writeMemCmd{};
2246 BufferLock& lock = writeMemCmd._bufferLocks.emplace_back();
2247 lock._buffer = frameBuffers._camDataBuffer->getBufferImpl();
2248 lock._range = frameBuffers._camBufferWriteRange;
2250 _api->flushCommand( &writeMemCmd );
2251 frameBuffers._camBufferWriteRange = {};
2252 }
2253
2254 _api->postFlushCommandBuffer( commandBuffer );
2255
2256 setViewport( initialViewport );
2257 setScissor( initialScissor );
2258
2259 // Descriptor sets are only valid per command buffer they are submitted in. If we finish the command buffer submission,
2260 // we mark them as dirty so that the next command buffer can bind them again even if the data is the same
2261 // We always check the dirty flags before any draw/compute command by calling "validateAndUploadDescriptorSets" beforehand
2262 for ( auto& set : _descriptorSets )
2263 {
2264 set.dirty( true );
2265 }
2267 }
2268
2272 std::pair<Handle<Texture>, SamplerDescriptor> GFXDevice::constructHIZ( RenderTargetID depthBuffer, RenderTargetID HiZTarget, GFX::CommandBuffer& cmdBufferInOut )
2273 {
2275
2276 assert( depthBuffer != HiZTarget );
2277
2278 const RTAttachment* SrcAtt = _rtPool->getRenderTarget( depthBuffer )->getAttachment( RTAttachmentType::DEPTH );
2279 const RTAttachment* HiZAtt = _rtPool->getRenderTarget( HiZTarget )->getAttachment( RTAttachmentType::COLOUR );
2280 ResourcePtr<Texture> HiZTex = Get(HiZAtt->texture());
2281 DIVIDE_ASSERT( HiZTex->descriptor()._mipMappingState == MipMappingState::MANUAL );
2282
2283 GFX::EnqueueCommand<GFX::BeginDebugScopeCommand>( cmdBufferInOut )->_scopeName = "Construct Hi-Z";
2284 GFX::EnqueueCommand<GFX::BindPipelineCommand>( cmdBufferInOut )->_pipeline = _hIZPipeline;
2285
2286 U32 twidth = HiZTex->width();
2287 U32 theight = HiZTex->height();
2288 bool wasEven = false;
2289 U32 owidth = twidth;
2290 U32 oheight = theight;
2291
2292 for ( U16 i = 0u; i < HiZTex->mipCount(); ++i )
2293 {
2294 twidth = twidth < 1u ? 1u : twidth;
2295 theight = theight < 1u ? 1u : theight;
2296
2297 ImageView outImage = HiZTex->getView( { i, 1u } );
2298
2299 const ImageView inImage = i == 0u ? Get(SrcAtt->texture())->getView( )
2300 : HiZTex->getView( { to_U16(i - 1u), 1u }, { 0u, 1u });
2301
2302
2303 GFX::EnqueueCommand<GFX::MemoryBarrierCommand>( cmdBufferInOut )->_textureLayoutChanges.emplace_back(TextureLayoutChange
2304 {
2305 ._targetView = outImage,
2306 ._sourceLayout = ImageUsage::SHADER_READ,
2307 ._targetLayout = ImageUsage::SHADER_WRITE
2308 });
2309
2310 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>( cmdBufferInOut );
2311 cmd->_usage = DescriptorSetUsage::PER_DRAW;
2312 {
2314 Set(binding._data, outImage, ImageUsage::SHADER_WRITE);
2315 }
2316 {
2318 Set( binding._data, inImage, HiZAtt->_descriptor._sampler );
2319 }
2320
2321 PushConstantsStruct& pushConstants = GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( cmdBufferInOut )->_fastData;
2322 pushConstants.data[0]._vec[0].set( owidth, oheight, twidth, theight );
2323 pushConstants.data[0]._vec[1].x = wasEven ? 1.f : 0.f;
2324
2325 GFX::EnqueueCommand<GFX::DispatchComputeCommand>( cmdBufferInOut )->_computeGroupSize =
2326 {
2327 getGroupCount( twidth, DEPTH_REDUCE_LOCAL_SIZE ),
2328 getGroupCount( theight, DEPTH_REDUCE_LOCAL_SIZE ),
2329 1u
2330 };
2331
2332 wasEven = twidth % 2 == 0 && theight % 2 == 0;
2333 owidth = twidth;
2334 oheight = theight;
2335 twidth /= 2;
2336 theight /= 2;
2337
2338 GFX::EnqueueCommand<GFX::MemoryBarrierCommand>( cmdBufferInOut )->_textureLayoutChanges.emplace_back(TextureLayoutChange
2339 {
2340 ._targetView = outImage,
2341 ._sourceLayout = ImageUsage::SHADER_WRITE,
2342 ._targetLayout = ImageUsage::SHADER_READ
2343 });
2344 }
2345
2346 GFX::EnqueueCommand<GFX::EndDebugScopeCommand>( cmdBufferInOut );
2347
2348 return { HiZAtt->texture(), HiZAtt->_descriptor._sampler };
2349 }
2350
2352 const Handle<Texture> hizBuffer,
2353 const SamplerDescriptor sampler,
2354 const CameraSnapshot& cameraSnapshot,
2355 const bool countCulledNodes,
2356 GFX::CommandBuffer& bufferInOut )
2357 {
2359
2360 const U32 cmdCount = *passData._lastCommandCount;
2361 const U32 threadCount = getGroupCount( cmdCount, GROUP_SIZE_AABB );
2362
2363 if ( threadCount == 0u || !enableOcclusionCulling() )
2364 {
2365 GFX::EnqueueCommand<GFX::AddDebugMessageCommand>( bufferInOut )->_msg = "Occlusion Culling Skipped";
2366 return;
2367 }
2368
2369 ResourcePtr<Texture> hizTex = Get(hizBuffer);
2370
2371 ShaderBuffer* cullBuffer = _gfxBuffers.crtBuffers()._cullCounter.get();
2372 GFX::EnqueueCommand<GFX::BeginDebugScopeCommand>( bufferInOut )->_scopeName = "Occlusion Cull";
2373
2374 // Not worth the overhead for a handful of items and the Pre-Z pass should handle overdraw just fine
2375 GFX::EnqueueCommand<GFX::BindPipelineCommand>( bufferInOut )->_pipeline = _hIZCullPipeline;
2376 {
2377 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>( bufferInOut );
2378 cmd->_usage = DescriptorSetUsage::PER_DRAW;
2380 Set( binding._data, hizTex->getView(), sampler );
2381 }
2382 {
2383 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>( bufferInOut );
2384 cmd->_usage = DescriptorSetUsage::PER_PASS;
2386 Set( binding._data, cullBuffer, { 0u, 1u });
2387 }
2388
2389 passData._uniforms->set( _ID( "dvd_countCulledItems" ), PushConstantType::UINT, countCulledNodes ? 1u : 0u );
2390 passData._uniforms->set( _ID( "dvd_numEntities" ), PushConstantType::UINT, cmdCount );
2391 passData._uniforms->set( _ID( "dvd_viewSize" ), PushConstantType::VEC2, vec2<F32>( hizTex->width(), hizTex->height() ) );
2392 passData._uniforms->set( _ID( "dvd_frustumPlanes" ), PushConstantType::VEC4, cameraSnapshot._frustumPlanes );
2393
2394 auto pushConstantsCmd = GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut );
2395
2396 pushConstantsCmd->_uniformData = passData._uniforms;
2397
2398 PushConstantsStruct& fastConstants = pushConstantsCmd->_fastData;
2399 mat4<F32>::Multiply( cameraSnapshot._projectionMatrix, cameraSnapshot._viewMatrix, fastConstants.data[0] );
2400 fastConstants.data[1] = cameraSnapshot._viewMatrix;
2401
2402 GFX::EnqueueCommand<GFX::DispatchComputeCommand>( bufferInOut )->_computeGroupSize = { threadCount, 1, 1 };
2403
2404 // Occlusion culling barrier
2405 GFX::EnqueueCommand<GFX::MemoryBarrierCommand>( bufferInOut )->_bufferLocks.emplace_back(BufferLock
2406 {
2407 ._range = {0u, U32_MAX },
2409 ._buffer = cullBuffer->getBufferImpl()
2410 });
2411
2412 GFX::EnqueueCommand<GFX::EndDebugScopeCommand>( bufferInOut );
2413
2414 if ( queryPerformanceStats() && countCulledNodes )
2415 {
2416 GFX::ReadBufferDataCommand readAtomicCounter;
2417 readAtomicCounter._buffer = cullBuffer;
2418 readAtomicCounter._target = { &_lastCullCount, 4 * sizeof( U32 ) };
2419 readAtomicCounter._offsetElementCount = 0;
2420 readAtomicCounter._elementCount = 1;
2421 GFX::EnqueueCommand( bufferInOut, readAtomicCounter );
2422
2423 cullBuffer->incQueue();
2424
2425 GFX::ClearBufferDataCommand clearAtomicCounter{};
2426 clearAtomicCounter._buffer = cullBuffer;
2427 clearAtomicCounter._offsetElementCount = 0;
2428 clearAtomicCounter._elementCount = 1;
2429 GFX::EnqueueCommand( bufferInOut, clearAtomicCounter );
2430 }
2431 }
2432#pragma endregion
2433
2434#pragma region Drawing functions
2435 void GFXDevice::drawTextureInViewport( const ImageView& texture, const SamplerDescriptor sampler, const Rect<I32>& viewport, const bool convertToSrgb, const bool drawToDepthOnly, bool drawBlend, GFX::CommandBuffer& bufferInOut )
2436 {
2437 GFX::EnqueueCommand<GFX::BeginDebugScopeCommand>( bufferInOut )->_scopeName = "Draw Texture In Viewport";
2438 GFX::EnqueueCommand<GFX::PushCameraCommand>( bufferInOut )->_cameraSnapshot = Camera::GetUtilityCamera( Camera::UtilityCamera::_2D )->snapshot();
2440
2441 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>( bufferInOut );
2442 cmd->_usage = DescriptorSetUsage::PER_DRAW;
2444 Set( binding._data, texture, sampler );
2445
2446 GFX::EnqueueCommand<GFX::PushViewportCommand>( bufferInOut )->_viewport = viewport;
2447
2448 if ( !drawToDepthOnly )
2449 {
2450 GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut)->_fastData.data[0]._vec[0].x = convertToSrgb ? 1.f : 0.f;
2451 }
2452
2453 GFX::EnqueueCommand<GFX::DrawCommand>( bufferInOut )->_drawCommands.emplace_back();
2454 GFX::EnqueueCommand<GFX::PopViewportCommand>( bufferInOut );
2455 GFX::EnqueueCommand<GFX::PopCameraCommand>( bufferInOut );
2456 GFX::EnqueueCommand<GFX::EndDebugScopeCommand>( bufferInOut );
2457 }
2458#pragma endregion
2459
2460#pragma region Debug utilities
2461 void GFXDevice::renderDebugUI( const Rect<I32>& targetViewport, GFX::CommandBuffer& bufferInOut, GFX::MemoryBarrierCommand& memCmdInOut )
2462 {
2463 constexpr I32 padding = 5;
2464
2465 // Early out if we didn't request the preview
2466 if constexpr( Config::ENABLE_GPU_VALIDATION )
2467 {
2468 GFX::EnqueueCommand<GFX::BeginDebugScopeCommand>( bufferInOut )->_scopeName = "Render Debug Views";
2469
2471 Rect<I32>( targetViewport.x + padding,
2472 targetViewport.y + padding,
2473 targetViewport.z - padding,
2474 targetViewport.w - padding ),
2475 padding,
2476 bufferInOut,
2477 memCmdInOut);
2478
2479 GFX::EnqueueCommand<GFX::EndDebugScopeCommand>( bufferInOut );
2480 }
2481 }
2482
2484 {
2485 // Lazy-load preview shader
2486 if ( _previewDepthMapShader != INVALID_HANDLE<ShaderProgram>)
2487 {
2488 ShaderModuleDescriptor vertModule = {};
2489 vertModule._moduleType = ShaderType::VERTEX;
2490 vertModule._sourceFile = "baseVertexShaders.glsl";
2491 vertModule._variant = "FullScreenQuad";
2492
2493 ShaderModuleDescriptor fragModule = {};
2494 fragModule._moduleType = ShaderType::FRAGMENT;
2495 fragModule._sourceFile = "fbPreview.glsl";
2496 fragModule._variant = "LinearDepth";
2497
2498 ShaderProgramDescriptor shaderDescriptor = {};
2499 shaderDescriptor._modules.push_back( vertModule );
2500 shaderDescriptor._modules.push_back( fragModule );
2501
2502 // The LinearDepth variant converts the depth values to linear values between the 2 scene z-planes
2503 _previewDepthMapShader = CreateResource( ResourceDescriptor<ShaderProgram>( "fbPreviewLinearDepth", shaderDescriptor ) );
2504
2505 DebugView_ptr HiZ = std::make_shared<DebugView>();
2506 HiZ->_shader = _renderTargetDraw;
2509 HiZ->_name = "Hierarchical-Z";
2510 HiZ->_shaderData.set( _ID( "lodLevel" ), PushConstantType::FLOAT, 0.f );
2511 HiZ->_shaderData.set( _ID( "channelsArePacked" ), PushConstantType::BOOL, false );
2512 HiZ->_shaderData.set( _ID( "startChannel" ), PushConstantType::UINT, 0u );
2513 HiZ->_shaderData.set( _ID( "channelCount" ), PushConstantType::UINT, 1u );
2514 HiZ->_cycleMips = true;
2515
2516 DebugView_ptr DepthPreview = std::make_shared<DebugView>();
2517 DepthPreview->_shader = _previewDepthMapShader;
2520 DepthPreview->_name = "Depth Buffer";
2521 DepthPreview->_shaderData.set( _ID( "lodLevel" ), PushConstantType::FLOAT, 0.0f );
2522 DepthPreview->_shaderData.set( _ID( "_zPlanes" ), PushConstantType::VEC2, vec2<F32>( Camera::s_minNearZ, _context.config().runtime.cameraViewDistance ) );
2523
2524 DebugView_ptr NormalPreview = std::make_shared<DebugView>();
2525 NormalPreview->_shader = _renderTargetDraw;
2528 NormalPreview->_name = "Normals";
2529 NormalPreview->_shaderData.set( _ID( "lodLevel" ), PushConstantType::FLOAT, 0.0f );
2530 NormalPreview->_shaderData.set( _ID( "channelsArePacked" ), PushConstantType::BOOL, true );
2531 NormalPreview->_shaderData.set( _ID( "startChannel" ), PushConstantType::UINT, 0u );
2532 NormalPreview->_shaderData.set( _ID( "channelCount" ), PushConstantType::UINT, 2u );
2533 NormalPreview->_shaderData.set( _ID( "multiplier" ), PushConstantType::FLOAT, 1.0f );
2534
2535 DebugView_ptr VelocityPreview = std::make_shared<DebugView>();
2536 VelocityPreview->_shader = _renderTargetDraw;
2539 VelocityPreview->_name = "Velocity Map";
2540 VelocityPreview->_shaderData.set( _ID( "lodLevel" ), PushConstantType::FLOAT, 0.0f );
2541 VelocityPreview->_shaderData.set( _ID( "scaleAndBias" ), PushConstantType::BOOL, true );
2542 VelocityPreview->_shaderData.set( _ID( "normalizeOutput" ), PushConstantType::BOOL, true );
2543 VelocityPreview->_shaderData.set( _ID( "channelsArePacked" ), PushConstantType::BOOL, false );
2544 VelocityPreview->_shaderData.set( _ID( "startChannel" ), PushConstantType::UINT, 0u );
2545 VelocityPreview->_shaderData.set( _ID( "channelCount" ), PushConstantType::UINT, 2u );
2546 VelocityPreview->_shaderData.set( _ID( "multiplier" ), PushConstantType::FLOAT, 5.0f );
2547
2548 DebugView_ptr SSAOPreview = std::make_shared<DebugView>();
2549 SSAOPreview->_shader = _renderTargetDraw;
2552 SSAOPreview->_name = "SSAO Map";
2553 SSAOPreview->_shaderData.set( _ID( "lodLevel" ), PushConstantType::FLOAT, 0.0f );
2554 SSAOPreview->_shaderData.set( _ID( "channelsArePacked" ), PushConstantType::BOOL, false );
2555 SSAOPreview->_shaderData.set( _ID( "startChannel" ), PushConstantType::UINT, 0u );
2556 SSAOPreview->_shaderData.set( _ID( "channelCount" ), PushConstantType::UINT, 1u );
2557 SSAOPreview->_shaderData.set( _ID( "multiplier" ), PushConstantType::FLOAT, 1.0f );
2558
2559 DebugView_ptr AlphaAccumulationHigh = std::make_shared<DebugView>();
2560 AlphaAccumulationHigh->_shader = _renderTargetDraw;
2563 AlphaAccumulationHigh->_name = "Alpha Accumulation High";
2564 AlphaAccumulationHigh->_shaderData.set( _ID( "lodLevel" ), PushConstantType::FLOAT, 0.0f );
2565 AlphaAccumulationHigh->_shaderData.set( _ID( "channelsArePacked" ), PushConstantType::BOOL, false );
2566 AlphaAccumulationHigh->_shaderData.set( _ID( "startChannel" ), PushConstantType::UINT, 0u );
2567 AlphaAccumulationHigh->_shaderData.set( _ID( "channelCount" ), PushConstantType::UINT, 4u );
2568 AlphaAccumulationHigh->_shaderData.set( _ID( "multiplier" ), PushConstantType::FLOAT, 1.0f );
2569
2570 DebugView_ptr AlphaRevealageHigh = std::make_shared<DebugView>();
2571 AlphaRevealageHigh->_shader = _renderTargetDraw;
2574 AlphaRevealageHigh->_name = "Alpha Revealage High";
2575 AlphaRevealageHigh->_shaderData.set( _ID( "lodLevel" ), PushConstantType::FLOAT, 0.0f );
2576 AlphaRevealageHigh->_shaderData.set( _ID( "channelsArePacked" ), PushConstantType::BOOL, false );
2577 AlphaRevealageHigh->_shaderData.set( _ID( "startChannel" ), PushConstantType::UINT, 0u );
2578 AlphaRevealageHigh->_shaderData.set( _ID( "channelCount" ), PushConstantType::UINT, 1u );
2579 AlphaRevealageHigh->_shaderData.set( _ID( "multiplier" ), PushConstantType::FLOAT, 1.0f );
2580
2581 SamplerDescriptor lumaSampler = {};
2582 lumaSampler._wrapU = TextureWrap::CLAMP_TO_EDGE;
2583 lumaSampler._wrapV = TextureWrap::CLAMP_TO_EDGE;
2584 lumaSampler._wrapW = TextureWrap::CLAMP_TO_EDGE;
2585 lumaSampler._minFilter = TextureFilter::NEAREST;
2586 lumaSampler._magFilter = TextureFilter::NEAREST;
2588 lumaSampler._anisotropyLevel = 0u;
2589
2590 DebugView_ptr Luminance = std::make_shared<DebugView>();
2591 Luminance->_shader = _renderTargetDraw;
2592 Luminance->_texture = getRenderer().postFX().getFilterBatch().luminanceTex();
2593 Luminance->_sampler = lumaSampler;
2594 Luminance->_name = "Luminance";
2595 Luminance->_shaderData.set( _ID( "lodLevel" ), PushConstantType::FLOAT, 0.0f );
2596 Luminance->_shaderData.set( _ID( "channelsArePacked" ), PushConstantType::BOOL, false );
2597 Luminance->_shaderData.set( _ID( "startChannel" ), PushConstantType::UINT, 0u );
2598 Luminance->_shaderData.set( _ID( "channelCount" ), PushConstantType::UINT, 1u );
2599 Luminance->_shaderData.set( _ID( "multiplier" ), PushConstantType::FLOAT, 1.0f );
2600
2601 const RenderTargetHandle& edgeRTHandle = getRenderer().postFX().getFilterBatch().edgesRT();
2602
2603 DebugView_ptr Edges = std::make_shared<DebugView>();
2604 Edges->_shader = _renderTargetDraw;
2607 Edges->_name = "Edges";
2608 Edges->_shaderData.set( _ID( "lodLevel" ), PushConstantType::FLOAT, 0.0f );
2609 Edges->_shaderData.set( _ID( "channelsArePacked" ), PushConstantType::BOOL, false );
2610 Edges->_shaderData.set( _ID( "startChannel" ), PushConstantType::UINT, 0u );
2611 Edges->_shaderData.set( _ID( "channelCount" ), PushConstantType::UINT, 4u );
2612 Edges->_shaderData.set( _ID( "multiplier" ), PushConstantType::FLOAT, 1.0f );
2613
2614 addDebugView( HiZ );
2615 addDebugView( DepthPreview );
2616 addDebugView( NormalPreview );
2617 addDebugView( VelocityPreview );
2618 addDebugView( SSAOPreview );
2619 addDebugView( AlphaAccumulationHigh );
2620 addDebugView( AlphaRevealageHigh );
2621 addDebugView( Luminance );
2622 addDebugView( Edges );
2623
2625 }
2626 }
2627
2628 void GFXDevice::renderDebugViews( const Rect<I32> targetViewport, const I32 padding, GFX::CommandBuffer& bufferInOut, GFX::MemoryBarrierCommand& memCmdInOut )
2629 {
2630 static size_t labelStyleHash = TextLabelStyle( Font::DROID_SERIF_BOLD, UColour4( 196 ), 96 ).getHash();
2631
2632 thread_local vector<std::tuple<string, I32, Rect<I32>>> labelStack;
2633
2635
2636 constexpr I32 columnCount = 6u;
2637 I32 viewCount = to_I32( _debugViews.size() );
2638 for ( const auto& view : _debugViews )
2639 {
2640 if ( !view->_enabled )
2641 {
2642 --viewCount;
2643 }
2644 }
2645
2646 if ( viewCount == 0 )
2647 {
2648 return;
2649 }
2650
2651 labelStack.resize( 0 );
2652
2653 const I32 screenWidth = targetViewport.z - targetViewport.x;
2654 const I32 screenHeight = targetViewport.w - targetViewport.y;
2655 const F32 aspectRatio = to_F32( screenWidth ) / screenHeight;
2656
2657 const I32 viewportWidth = (screenWidth / columnCount) - (padding * (columnCount - 1u));
2658 const I32 viewportHeight = to_I32( viewportWidth / aspectRatio ) - padding;
2659 Rect<I32> viewport( targetViewport.z - viewportWidth, targetViewport.y, viewportWidth, viewportHeight );
2660
2661 const I32 initialOffsetX = viewport.x;
2662
2663 PipelineDescriptor pipelineDesc{};
2664 pipelineDesc._stateBlock = _state2DRendering;
2665 pipelineDesc._shaderProgramHandle = INVALID_HANDLE<ShaderProgram>;
2666 pipelineDesc._primitiveTopology = PrimitiveTopology::TRIANGLES;
2667
2668 const Rect<I32> previousViewport = activeViewport();
2669
2670 Pipeline* crtPipeline = nullptr;
2671 U16 idx = 0u;
2672 const I32 mipTimer = to_I32( std::ceil( Time::App::ElapsedMilliseconds() / 750.0f ) );
2673 for ( U16 i = 0; i < to_U16( _debugViews.size() ); ++i )
2674 {
2675 if ( !_debugViews[i]->_enabled )
2676 {
2677 continue;
2678 }
2679
2680 const DebugView_ptr& view = _debugViews[i];
2681
2682 if ( view->_cycleMips )
2683 {
2684 const F32 lodLevel = to_F32( mipTimer % Get(view->_texture)->mipCount() );
2685 view->_shaderData.set( _ID( "lodLevel" ), PushConstantType::FLOAT, lodLevel );
2686 labelStack.emplace_back( Util::StringFormat( "Mip level: {}", to_U8( lodLevel ) ), viewport.sizeY * 4, viewport );
2687 }
2688 const Handle<ShaderProgram> crtShader = pipelineDesc._shaderProgramHandle;
2689 const Handle<ShaderProgram> newShader = view->_shader;
2690
2691 if ( crtShader != newShader )
2692 {
2693 pipelineDesc._shaderProgramHandle = view->_shader;
2694 crtPipeline = newPipeline( pipelineDesc );
2695 }
2696
2697 GFX::EnqueueCommand<GFX::BindPipelineCommand>( bufferInOut )->_pipeline = crtPipeline;
2698 GFX::EnqueueCommand<GFX::SendPushConstantsCommand>( bufferInOut )->_uniformData = &view->_shaderData;
2699 GFX::EnqueueCommand<GFX::SetViewportCommand>( bufferInOut )->_viewport.set( viewport );
2700
2701 auto cmd = GFX::EnqueueCommand<GFX::BindShaderResourcesCommand>( bufferInOut );
2702 cmd->_usage = DescriptorSetUsage::PER_DRAW;
2703 DescriptorSetBinding& binding = AddBinding( cmd->_set, view->_textureBindSlot, ShaderStageVisibility::FRAGMENT );
2704 Set( binding._data, view->_texture, view->_sampler );
2705
2706 GFX::EnqueueCommand<GFX::DrawCommand>( bufferInOut )->_drawCommands.emplace_back();
2707
2708 if ( !view->_name.empty() )
2709 {
2710 labelStack.emplace_back( view->_name, viewport.sizeY, viewport );
2711 }
2712 if ( idx > 0 && idx % (columnCount - 1) == 0 )
2713 {
2714 viewport.y += viewportHeight + targetViewport.y;
2715 viewport.x = initialOffsetX;
2716 idx = 0u;
2717 }
2718 else
2719 {
2720 viewport.x -= viewportWidth + targetViewport.x;
2721 ++idx;
2722 }
2723 }
2724
2725 GFX::EnqueueCommand<GFX::PushCameraCommand>( bufferInOut )->_cameraSnapshot = Camera::GetUtilityCamera( Camera::UtilityCamera::_2D )->snapshot();
2726 // Draw labels at the end to reduce number of state changes
2727 TextElement text( labelStyleHash, RelativePosition2D{ ._x = RelativeValue{ ._scale = 0.1f, ._offset = 0.0f }, ._y = RelativeValue{ ._scale = 0.1f, ._offset = 0.0f } } );
2728 for ( const auto& [labelText, viewportOffsetY, viewportIn] : labelStack )
2729 {
2730 GFX::EnqueueCommand<GFX::SetViewportCommand>( bufferInOut )->_viewport.set( viewportIn );
2731
2732 text.position()._y._offset = to_F32( viewportOffsetY );
2733 text.text( labelText.c_str(), false );
2734 _context.gui().drawText( TextElementBatch{ text }, viewportIn, bufferInOut, memCmdInOut, false );
2735 }
2736 GFX::EnqueueCommand<GFX::PopCameraCommand>( bufferInOut );
2737 GFX::EnqueueCommand<GFX::SetViewportCommand>( bufferInOut )->_viewport.set( previousViewport );
2738 }
2739
2740 DebugView* GFXDevice::addDebugView( const std::shared_ptr<DebugView>& view )
2741 {
2743
2744 _debugViews.push_back( view );
2745
2746 if ( _debugViews.back()->_sortIndex == -1 )
2747 {
2748 _debugViews.back()->_sortIndex = to_I16( _debugViews.size() );
2749 }
2750
2751 eastl::sort( eastl::begin( _debugViews ),
2752 eastl::end( _debugViews ),
2753 []( const std::shared_ptr<DebugView>& a, const std::shared_ptr<DebugView>& b ) noexcept -> bool
2754 {
2755 if ( a->_groupID == b->_groupID )
2756 {
2757 return a->_sortIndex < b->_sortIndex;
2758 }
2759 if ( a->_sortIndex == b->_sortIndex )
2760 {
2761 return a->_groupID < b->_groupID;
2762 }
2763
2764 return a->_groupID < b->_groupID&& a->_sortIndex < b->_sortIndex;
2765 } );
2766
2767 return view.get();
2768 }
2769
2771 {
2772 return dvd_erase_if( _debugViews,
2773 [view]( const std::shared_ptr<DebugView>& entry ) noexcept
2774 {
2775 return view != nullptr && view->getGUID() == entry->getGUID();
2776 } );
2777 }
2778
2779 void GFXDevice::toggleDebugView( const I16 index, const bool state )
2780 {
2782 for ( auto& view : _debugViews )
2783 {
2784 if ( view->_sortIndex == index )
2785 {
2786 view->_enabled = state;
2787 break;
2788 }
2789 }
2790 }
2791
2792 void GFXDevice::toggleDebugGroup( I16 group, const bool state )
2793 {
2795 for ( auto& view : _debugViews )
2796 {
2797 if ( view->_groupID == group )
2798 {
2799 view->_enabled = state;
2800 }
2801 }
2802 }
2803
2805 {
2807 for ( const auto& view : _debugViews )
2808 {
2809 if ( view->_groupID == group )
2810 {
2811 if ( !view->_enabled )
2812 {
2813 return false;
2814 }
2815 }
2816 }
2817
2818 return true;
2819 }
2820
2821 void GFXDevice::getDebugViewNames( vector<std::tuple<string, I16, I16, bool>>& namesOut )
2822 {
2823 namesOut.resize( 0 );
2824
2826 for ( auto& view : _debugViews )
2827 {
2828 namesOut.emplace_back( view->_name, view->_groupID, view->_sortIndex, view->_enabled );
2829 }
2830 }
2831
2833 {
2834 if ( descriptor.noDepth )
2835 {
2836 return (descriptor.noCull ? _debugGizmoPipelineNoCullNoDepth : _debugGizmoPipelineNoDepth);
2837 }
2838 else if ( descriptor.noCull )
2839 {
2840 return _debugGizmoPipelineNoCull;
2841 }
2842
2843 return _debugGizmoPipeline;
2844 }
2845
2846 void GFXDevice::debugDrawLines( const I64 ID, const IM::LineDescriptor descriptor ) noexcept
2847 {
2848 _debugLines.add( ID, descriptor );
2849 }
2850
2852 {
2853 LockGuard<Mutex> r_lock( _debugLines._dataLock );
2854
2855 const size_t lineCount = _debugLines.size();
2856 for ( size_t f = 0u; f < lineCount; ++f )
2857 {
2858 auto& data = _debugLines._debugData[f];
2859 if ( data._frameLifeTime == 0u )
2860 {
2861 continue;
2862 }
2863
2864 IMPrimitive*& linePrimitive = _debugLines._debugPrimitives[f];
2865 if ( linePrimitive == nullptr )
2866 {
2867 linePrimitive = newIMP( Util::StringFormat( "DebugLine_{}", f ).c_str() );
2868 linePrimitive->setPipelineDescriptor( getDebugPipeline( data._descriptor ) );
2869 }
2870
2871 linePrimitive->forceWireframe( data._descriptor.wireframe ); //? Uhm, not gonna do much -Ionut
2872 linePrimitive->fromLines( data._descriptor );
2873 linePrimitive->getCommandBuffer( data._descriptor.worldMatrix, bufferInOut, memCmdInOut );
2874 }
2875 }
2876
2877 void GFXDevice::debugDrawBox( const I64 ID, const IM::BoxDescriptor descriptor ) noexcept
2878 {
2879 _debugBoxes.add( ID, descriptor );
2880 }
2881
2883 {
2884 LockGuard<Mutex> r_lock( _debugBoxes._dataLock );
2885 const size_t boxesCount = _debugBoxes.size();
2886 for ( U32 f = 0u; f < boxesCount; ++f )
2887 {
2888 auto& data = _debugBoxes._debugData[f];
2889 if ( data._frameLifeTime == 0u )
2890 {
2891 continue;
2892 }
2893
2894 IMPrimitive*& boxPrimitive = _debugBoxes._debugPrimitives[f];
2895 if ( boxPrimitive == nullptr )
2896 {
2897 boxPrimitive = newIMP( Util::StringFormat( "DebugBox_{}", f ).c_str() );
2898 boxPrimitive->setPipelineDescriptor( getDebugPipeline( data._descriptor ) );
2899 }
2900
2901 boxPrimitive->forceWireframe( data._descriptor.wireframe );
2902 boxPrimitive->fromBox( data._descriptor );
2903 boxPrimitive->getCommandBuffer( data._descriptor.worldMatrix, bufferInOut, memCmdInOut );
2904 }
2905 }
2906
2907 void GFXDevice::debugDrawOBB( const I64 ID, const IM::OBBDescriptor descriptor ) noexcept
2908 {
2909 _debugOBBs.add( ID, descriptor );
2910 }
2911
2913 {
2914 LockGuard<Mutex> r_lock( _debugOBBs._dataLock );
2915 const size_t boxesCount = _debugOBBs.size();
2916 for ( U32 f = 0u; f < boxesCount; ++f )
2917 {
2918 auto& data = _debugOBBs._debugData[f];
2919 if ( data._frameLifeTime == 0u )
2920 {
2921 continue;
2922 }
2923
2924 IMPrimitive*& boxPrimitive = _debugOBBs._debugPrimitives[f];
2925 if ( boxPrimitive == nullptr )
2926 {
2927 boxPrimitive = newIMP( Util::StringFormat( "DebugOBB_{}", f ).c_str() );
2928 boxPrimitive->setPipelineDescriptor( getDebugPipeline( data._descriptor ) );
2929 }
2930
2931 boxPrimitive->forceWireframe( data._descriptor.wireframe );
2932 boxPrimitive->fromOBB( data._descriptor );
2933 boxPrimitive->getCommandBuffer( data._descriptor.worldMatrix, bufferInOut, memCmdInOut );
2934 }
2935 }
2936 void GFXDevice::debugDrawSphere( const I64 ID, const IM::SphereDescriptor descriptor ) noexcept
2937 {
2938 _debugSpheres.add( ID, descriptor );
2939 }
2940
2942 {
2943 LockGuard<Mutex> r_lock( _debugSpheres._dataLock );
2944 const size_t spheresCount = _debugSpheres.size();
2945 for ( size_t f = 0u; f < spheresCount; ++f )
2946 {
2947 auto& data = _debugSpheres._debugData[f];
2948 if ( data._frameLifeTime == 0u )
2949 {
2950 continue;
2951 }
2952
2953 IMPrimitive*& spherePrimitive = _debugSpheres._debugPrimitives[f];
2954 if ( spherePrimitive == nullptr )
2955 {
2956 spherePrimitive = newIMP( Util::StringFormat( "DebugSphere_{}", f ).c_str() );
2957 spherePrimitive->setPipelineDescriptor( getDebugPipeline( data._descriptor ) );
2958 }
2959
2960 spherePrimitive->forceWireframe( data._descriptor.wireframe );
2961 spherePrimitive->fromSphere( data._descriptor );
2962 spherePrimitive->getCommandBuffer( data._descriptor.worldMatrix, bufferInOut, memCmdInOut );
2963 }
2964 }
2965
2966 void GFXDevice::debugDrawCone( const I64 ID, const IM::ConeDescriptor descriptor ) noexcept
2967 {
2968 _debugCones.add( ID, descriptor );
2969 }
2970
2972 {
2973 LockGuard<Mutex> r_lock( _debugCones._dataLock );
2974
2975 const size_t conesCount = _debugCones.size();
2976 for ( size_t f = 0u; f < conesCount; ++f )
2977 {
2978 auto& data = _debugCones._debugData[f];
2979 if ( data._frameLifeTime == 0u )
2980 {
2981 continue;
2982 }
2983
2984 IMPrimitive*& conePrimitive = _debugCones._debugPrimitives[f];
2985 if ( conePrimitive == nullptr )
2986 {
2987 conePrimitive = newIMP( Util::StringFormat( "DebugCone_{}", f ).c_str() );
2988 conePrimitive->setPipelineDescriptor( getDebugPipeline( data._descriptor ) );
2989 }
2990
2991 conePrimitive->forceWireframe( data._descriptor.wireframe );
2992 conePrimitive->fromCone( data._descriptor );
2993 conePrimitive->getCommandBuffer( data._descriptor.worldMatrix, bufferInOut, memCmdInOut );
2994 }
2995 }
2996
2997 void GFXDevice::debugDrawFrustum( const I64 ID, const IM::FrustumDescriptor descriptor ) noexcept
2998 {
2999 _debugFrustums.add( ID, descriptor );
3000 }
3001
3003 {
3004 LockGuard<Mutex> r_lock( _debugFrustums._dataLock );
3005
3006 const size_t frustumCount = _debugFrustums.size();
3007 for ( size_t f = 0u; f < frustumCount; ++f )
3008 {
3009 auto& data = _debugFrustums._debugData[f];
3010 if ( data._frameLifeTime == 0u )
3011 {
3012 continue;
3013 }
3014
3015 IMPrimitive*& frustumPrimitive = _debugFrustums._debugPrimitives[f];
3016 if ( frustumPrimitive == nullptr )
3017 {
3018 frustumPrimitive = newIMP( Util::StringFormat( "DebugFrustum_{}", f ).c_str() );
3019 frustumPrimitive->setPipelineDescriptor( getDebugPipeline( data._descriptor ) );
3020 }
3021
3022 frustumPrimitive->forceWireframe( data._descriptor.wireframe );
3023 frustumPrimitive->fromFrustum( data._descriptor );
3024 frustumPrimitive->getCommandBuffer( data._descriptor.worldMatrix, bufferInOut, memCmdInOut );
3025 }
3026 }
3027
3029 void GFXDevice::debugDraw( [[maybe_unused]] const SceneRenderState& sceneRenderState, GFX::CommandBuffer& bufferInOut, GFX::MemoryBarrierCommand& memCmdInOut )
3030 {
3031 debugDrawFrustums( bufferInOut, memCmdInOut );
3032 debugDrawLines( bufferInOut, memCmdInOut );
3033 debugDrawBoxes( bufferInOut, memCmdInOut );
3034 debugDrawOBBs( bufferInOut, memCmdInOut );
3035 debugDrawSpheres( bufferInOut, memCmdInOut );
3036 debugDrawCones( bufferInOut, memCmdInOut );
3037 }
3038#pragma endregion
3039
3040#pragma region GPU Object instantiation
3041 RenderTarget_uptr GFXDevice::newRT( const RenderTargetDescriptor& descriptor )
3042 {
3043 RenderTarget_uptr ret = _api->newRT(descriptor);
3044
3045 if ( ret != nullptr )
3046 {
3047 const bool valid = ret->create();
3048 DIVIDE_ASSERT( valid );
3049 return ret;
3050 }
3051
3052 return nullptr;
3053 }
3054
3055 IMPrimitive* GFXDevice::newIMP( const std::string_view name )
3056 {
3058 return s_IMPrimitivePool.newElement( *this, name );
3059 }
3060
3062 {
3063 if ( primitive != nullptr )
3064 {
3066 s_IMPrimitivePool.deleteElement( primitive );
3067 primitive = nullptr;
3068 return true;
3069 }
3070
3071 return false;
3072 }
3073
3075 {
3076 // Pipeline with no shader is no pipeline at all
3077 DIVIDE_ASSERT( descriptor._shaderProgramHandle != INVALID_HANDLE<ShaderProgram>, "Missing shader handle during pipeline creation!" );
3078 DIVIDE_ASSERT( descriptor._primitiveTopology != PrimitiveTopology::COUNT, "Missing primitive topology during pipeline creation!" );
3079
3080 const size_t hash = GetHash( descriptor );
3081
3083 const hashMap<size_t, Pipeline, NoHash<size_t>>::iterator it = _pipelineCache.find( hash );
3084 if ( it == std::cend( _pipelineCache ) )
3085 {
3086 return &insert( _pipelineCache, hash, Pipeline( descriptor ) ).first->second;
3087 }
3088
3089 return &it->second;
3090 }
3091
3092 void DestroyIMP(IMPrimitive*& primitive)
3093 {
3094 if (primitive != nullptr && !primitive->context().destroyIMP(primitive) )
3095 {
3096 DebugBreak();
3097 }
3098 primitive = nullptr;
3099 }
3100
3101 VertexBuffer_ptr GFXDevice::newVB( const VertexBuffer::Descriptor& descriptor )
3102 {
3103 return std::make_shared<VertexBuffer>( *this, descriptor );
3104 }
3105#pragma endregion
3106
3108 {
3109 assert( _shaderComputeQueue != nullptr );
3110 return *_shaderComputeQueue;
3111 }
3112
3114 {
3115 assert( _shaderComputeQueue != nullptr );
3116 return *_shaderComputeQueue;
3117 }
3118
3120 void GFXDevice::screenshot( const std::string_view fileName, GFX::CommandBuffer& bufferInOut ) const
3121 {
3122 const RenderTarget* screenRT = _rtPool->getRenderTarget( RenderTargetNames::BACK_BUFFER );
3123 auto readTextureCmd = GFX::EnqueueCommand<GFX::ReadTextureCommand>( bufferInOut );
3124 readTextureCmd->_texture = screenRT->getAttachment(RTAttachmentType::COLOUR, ScreenTargets::ALBEDO )->texture();
3125 readTextureCmd->_pixelPackAlignment._alignment = 1u;
3126 readTextureCmd->_callback = [fileName]( const ImageReadbackData& data )
3127 {
3128 if ( !data._data.empty() )
3129 {
3130 DIVIDE_ASSERT(data._bpp > 0u && data._numComponents > 0u);
3131 // Make sure we have a valid target directory
3132 if ( createDirectory( Paths::g_screenshotPath ) != FileError::NONE )
3133 {
3134 NOP();
3135 }
3136
3137 // Save to file
3138 if ( !ImageTools::SaveImage( ResourcePath( Util::StringFormat( "{}/{}_Date_{}.png", Paths::g_screenshotPath, fileName, CurrentDateTimeString().c_str() )),
3139 data._width,
3140 data._height,
3141 data._numComponents,
3142 data._bpp,
3143 data._sourceIsBGR,
3144 data._data.data(),
3146 {
3148 }
3149 }
3150 };
3151 }
3152};
#define WAIT_FOR_CONDITION(...)
#define LOCALE_STR(X)
Definition: Localization.h:91
#define MOV(...)
#define DIVIDE_ASSERT(...)
#define DIVIDE_UNEXPECTED_CALL()
#define NOP()
#define FORCE_INLINE
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
#define PROFILE_SCOPE(NAME, CATEGORY)
Definition: Profiler.h:86
char * argv[]
Definition: main.cpp:8
WindowManager & windowManager() noexcept
Definition: Application.inl:77
const mat4< F32 > & setProjection(vec2< F32 > zPlanes)
Definition: Camera.cpp:516
const mat4< F32 > & viewProjectionMatrix() const noexcept
Returns the most recent/up-to-date viewProjection matrix.
Definition: Camera.inl:186
static Camera * GetUtilityCamera(const UtilityCamera type)
Definition: Camera.cpp:120
const mat4< F32 > & lookAt(const mat4< F32 > &viewMatrix)
Sets the camera's view matrix to specify the specified value by extracting the eye position,...
Definition: Camera.cpp:354
const CameraSnapshot & snapshot() const noexcept
Returns the internal camera snapshot data (eye, orientation, etc)
Definition: Camera.inl:43
static constexpr F32 s_minNearZ
Definition: Camera.h:95
bool updateLookAt()
Return true if the cached camera state wasn't up-to-date.
Definition: Camera.cpp:384
vec2< U16 > getDrawableSize() const noexcept
GFX::CommandBufferQueue & getCurrentCommandBufferQueue()
const Rect< I32 > & renderingViewport() const noexcept
eastl::fixed_vector< CommandBase *, COMMAND_BUFFER_INIT_SIZE, true > CommandList
void drawTextureInViewport(const ImageView &texture, SamplerDescriptor sampler, const Rect< I32 > &viewport, bool convertToSrgb, bool drawToDepthOnly, bool drawBlend, GFX::CommandBuffer &bufferInOut)
Definition: GFXDevice.cpp:2435
Mutex _graphicsResourceMutex
Definition: GFXDevice.h:525
GFX::BindPipelineCommand _blurBoxPipelineLayeredCmd
Definition: GFXDevice.h:520
void occlusionCull(const RenderPass::PassData &passData, Handle< Texture > hizBuffer, SamplerDescriptor sampler, const CameraSnapshot &cameraSnapshot, bool countCulledNodes, GFX::CommandBuffer &bufferInOut)
Definition: GFXDevice.cpp:2351
void shadowingSettings(const F32 lightBleedBias, const F32 minShadowVariance) noexcept
Definition: GFXDevice.cpp:2006
GFXDescriptorSets _descriptorSets
Definition: GFXDevice.h:524
static constexpr U8 s_invalidQueueSampleCount
Definition: GFXDevice.h:484
std::array< U8, to_base(ShadowType::COUNT)> _queuedShadowSampleChange
Definition: GFXDevice.h:486
CameraSnapshot & getCameraSnapshot(PlayerIndex index) noexcept
Definition: GFXDevice.cpp:2068
void debugDrawCone(const I64 ID, IM::ConeDescriptor descriptor) noexcept
Definition: GFXDevice.cpp:2966
void debugDrawCones(GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: GFXDevice.cpp:2971
U8 _queuedScreenSampleChange
Definition: GFXDevice.h:485
Handle< ShaderProgram > _hIZCullProgram
Definition: GFXDevice.h:501
GFX::BindPipelineCommand _blurGaussianPipelineLayeredCmd
Definition: GFXDevice.h:522
void setDepthRange(vec2< F32 > depthRange)
Definition: GFXDevice.cpp:1949
void renderDebugViews(Rect< I32 > targetViewport, I32 padding, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: GFXDevice.cpp:2628
struct Divide::GFXDevice::GFXBuffers _gfxBuffers
bool setViewport(const Rect< I32 > &viewport)
Returns true if the viewport was changed.
Definition: GFXDevice.cpp:2051
RenderStateBlock _stateDepthOnlyRendering
Definition: GFXDevice.h:491
ShaderBuffer_uptr newSB(const ShaderBufferDescriptor &descriptor)
Definition: GFXDevice.inl:214
DebugPrimitiveHandler< IM::BoxDescriptor, 16u > _debugBoxes
Definition: GFXDevice.h:474
IMPrimitive * newIMP(std::string_view name)
Create and return a new immediate mode emulation primitive.
Definition: GFXDevice.cpp:3055
static IMPrimitivePool s_IMPrimitivePool
Definition: GFXDevice.h:575
void blurTarget(RenderTargetHandle &blurSource, RenderTargetHandle &blurBuffer, const RenderTargetHandle &blurTarget, RTAttachmentType att, RTColourAttachmentSlot slot, I32 kernelSize, bool gaussian, U8 layerCount, GFX::CommandBuffer &bufferInOut)
Definition: GFXDevice.cpp:1642
void onResolutionChange(const SizeChangeParams &params)
Definition: GFXDevice.cpp:1776
RenderStateBlock _defaultStateNoDepthTest
The default render state but with depth testing disabled.
Definition: GFXDevice.h:488
Pipeline * _hIZCullPipeline
Definition: GFXDevice.h:511
static DeviceInformation s_deviceInformation
Definition: GFXDevice.h:580
Handle< ShaderProgram > _depthShader
Definition: GFXDevice.h:503
static bool IsSubmitCommand(GFX::CommandType type) noexcept
Definition: GFXDevice.inl:168
Handle< ShaderProgram > _hIZConstructProgram
Definition: GFXDevice.h:500
void setCameraSnapshot(PlayerIndex index, const CameraSnapshot &snapshot) noexcept
Definition: GFXDevice.cpp:2063
void setClipPlanes(const FrustumClipPlanes &clipPlanes)
set a new list of clipping planes. The old one is discarded
Definition: GFXDevice.cpp:1922
Handle< ShaderProgram > _renderTargetDraw
Definition: GFXDevice.h:499
GFX::BindPipelineCommand _drawFSTexturePipelineBlendCmd
Definition: GFXDevice.h:517
static constexpr U8 MAX_CAMERA_SNAPSHOTS
Definition: GFXDevice.h:564
void debugDrawFrustums(GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: GFXDevice.cpp:3002
GFX::BindPipelineCommand _drawFSDepthPipelineCmd
Definition: GFXDevice.h:518
void setShadowMSAASampleCount(ShadowType type, U8 sampleCount)
Definition: GFXDevice.cpp:1744
void setShadowMSAASampleCountInternal(ShadowType type, U8 sampleCount)
Definition: GFXDevice.cpp:1761
void setScreenMSAASampleCountInternal(U8 sampleCount)
Definition: GFXDevice.cpp:1749
void generateCubeMap(RenderPassParams &params, U16 arrayOffset, const vec3< F32 > &pos, vec2< F32 > zPlanes, GFX::CommandBuffer &commandsInOut, GFX::MemoryBarrierCommand &memCmdInOut, mat4< F32 > *viewProjectionOut=nullptr)
Generate a cube texture and store it in the provided RenderTarget.
Definition: GFXDevice.cpp:1501
DebugPrimitiveHandler< IM::ConeDescriptor, 16u > _debugCones
Definition: GFXDevice.h:477
ShaderComputeQueue & shaderComputeQueue() noexcept
Definition: GFXDevice.cpp:3107
ErrorCode initRenderingAPI(I32 argc, char **argv, RenderAPI API)
Definition: GFXDevice.cpp:364
void update(U64 deltaTimeUSFixed, U64 deltaTimeUSApp)
Definition: GFXDevice.cpp:1331
GFX::BindPipelineCommand _blurBoxPipelineSingleCmd
Definition: GFXDevice.h:519
RenderTarget_uptr newRT(const RenderTargetDescriptor &descriptor)
Create and return a new framebuffer.
Definition: GFXDevice.cpp:3041
void worldAOViewProjectionMatrix(const mat4< F32 > &vpMatrix) noexcept
Definition: GFXDevice.cpp:2018
void setScreenMSAASampleCount(U8 sampleCount)
Definition: GFXDevice.cpp:1739
vector< DebugView_ptr > _debugViews
Definition: GFXDevice.h:532
PipelineDescriptor _debugGizmoPipelineNoCull
Definition: GFXDevice.h:514
PipelineDescriptor _debugGizmoPipeline
Definition: GFXDevice.h:512
PipelineDescriptor _debugGizmoPipelineNoCullNoDepth
Definition: GFXDevice.h:515
F32 renderingAspectRatio() const noexcept
Definition: GFXDevice.inl:179
void closeRenderingAPI()
Revert everything that was set up in initRenderingAPI()
Definition: GFXDevice.cpp:1228
GFXShaderData _gpuBlock
Definition: GFXDevice.h:529
DebugPrimitiveHandler< IM::FrustumDescriptor, 8u > _debugFrustums
Definition: GFXDevice.h:478
void onWindowSizeChange(const SizeChangeParams &params)
The main entry point for any resolution change request.
Definition: GFXDevice.cpp:1768
void generateDualParaboloidMap(RenderPassParams &params, U16 arrayOffset, const vec3< F32 > &pos, vec2< F32 > zPlanes, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut, mat4< F32 > *viewProjectionOut=nullptr)
Definition: GFXDevice.cpp:1573
RenderAPIWrapper_uptr _api
Definition: GFXDevice.h:468
MemoryPool< IMPrimitive, 1<< 15 > IMPrimitivePool
Definition: GFXDevice.h:574
Mutex _pipelineCacheLock
Definition: GFXDevice.h:561
RenderStateBlock _state2DRendering
Special render state for 2D rendering.
Definition: GFXDevice.h:490
GFXRTPool & renderTargetPool() noexcept
Definition: GFXDevice.inl:133
FrustumClipPlanes _clippingPlanes
The interpolation factor between the current and the last frame.
Definition: GFXDevice.h:493
std::unique_ptr< ShaderComputeQueue > _shaderComputeQueue
Definition: GFXDevice.h:471
bool uploadGPUBlock()
Upload draw related data to the GPU (view & projection matrices, viewport settings,...
Definition: GFXDevice.cpp:1864
std::stack< Rect< I32 > > _viewportStack
Definition: GFXDevice.h:569
GFX::BindPipelineCommand _blurGaussianPipelineSingleCmd
Definition: GFXDevice.h:521
Renderer_uptr _renderer
Definition: GFXDevice.h:469
Handle< ShaderProgram > _previewDepthMapShader
shader used to preview the depth buffer
Definition: GFXDevice.h:496
void renderFromCamera(const CameraSnapshot &cameraSnapshot)
Definition: GFXDevice.cpp:1959
Renderer & getRenderer() const
Definition: GFXDevice.inl:117
Mutex _queuedCommandbufferLock
Definition: GFXDevice.h:534
std::stack< CameraSnapshot, eastl::fixed_vector< CameraSnapshot, MAX_CAMERA_SNAPSHOTS, false > > _cameraSnapshots
Definition: GFXDevice.h:565
void idle(bool fast, U64 deltaTimeUSGame, U64 deltaTimeUSApp)
After a swap buffer call, the CPU may be idle waiting for the GPU to draw to the screen,...
Definition: GFXDevice.cpp:1318
ErrorCode initDescriptorSets()
Definition: GFXDevice.cpp:222
CameraSnapshot _activeCameraSnapshot
Definition: GFXDevice.h:480
DebugPrimitiveHandler< IM::SphereDescriptor, 16u > _debugSpheres
Definition: GFXDevice.h:476
bool frameEnded(const FrameEvent &evt) noexcept override
frameEnded is called after the buffers have been swapped
Definition: GFXDevice.cpp:1403
bool frameStarted(const FrameEvent &evt) override
Definition: GFXDevice.cpp:1371
const RenderStateBlock & getNoDepthTestBlock() const noexcept
returns the standard state block
Definition: GFXDevice.inl:128
void drawToWindow(DisplayWindow &window)
Definition: GFXDevice.cpp:1336
Handle< ShaderProgram > _previewRenderTargetColour
Definition: GFXDevice.h:497
PipelineDescriptor _debugGizmoPipelineNoDepth
Definition: GFXDevice.h:513
bool destroyIMP(IMPrimitive *&primitive)
Definition: GFXDevice.cpp:3061
Handle< ShaderProgram > _blurGaussianShaderLayered
Definition: GFXDevice.h:507
void debugDrawSphere(const I64 ID, IM::SphereDescriptor descriptor) noexcept
Definition: GFXDevice.cpp:2936
void renderDebugUI(const Rect< I32 > &targetViewport, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: GFXDevice.cpp:2461
Handle< ShaderProgram > _blurGaussianShaderSingle
Definition: GFXDevice.h:506
GFX::BindPipelineCommand _drawFSTexturePipelineCmd
Definition: GFXDevice.h:516
ErrorCode createAPIInstance(RenderAPI api)
Definition: GFXDevice.cpp:332
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
Handle< ShaderProgram > _blurBoxShaderSingle
Definition: GFXDevice.h:504
void debugDraw(const SceneRenderState &sceneRenderState, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Render all of our immediate mode primitives. This isn't very optimised and most are recreated per fra...
Definition: GFXDevice.cpp:3029
void debugDrawFrustum(const I64 ID, IM::FrustumDescriptor descriptor) noexcept
Definition: GFXDevice.cpp:2997
void flushWindow(DisplayWindow &window)
Definition: GFXDevice.cpp:1345
void getDebugViewNames(vector< std::tuple< string, I16, I16, bool > > &namesOut)
Definition: GFXDevice.cpp:2821
void debugDrawOBB(const I64 ID, IM::OBBDescriptor descriptor) noexcept
Definition: GFXDevice.cpp:2907
void validateAndUploadDescriptorSets()
Definition: GFXDevice.cpp:2090
Handle< ShaderProgram > _displayShader
Definition: GFXDevice.h:502
void setPreviousViewProjectionMatrix(PlayerIndex player, const mat4< F32 > &prevViewMatrix, const mat4< F32 > prevProjectionMatrix)
Definition: GFXDevice.cpp:2025
void debugDrawOBBs(GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: GFXDevice.cpp:2912
void screenshot(std::string_view fileName, GFX::CommandBuffer &bufferInOut) const
Save a screenshot in TGA format.
Definition: GFXDevice.cpp:3120
bool framePreRender(const FrameEvent &evt) override
framePreRenderStarted is called when we need to start processing the visual aspect of a scene
Definition: GFXDevice.cpp:1366
void debugDrawBox(const I64 ID, IM::BoxDescriptor descriptor) noexcept
Definition: GFXDevice.cpp:2877
static U64 s_frameCount
Definition: GFXDevice.h:578
Handle< ShaderProgram > _previewRenderTargetDepth
Definition: GFXDevice.h:498
Mutex _imprimitiveMutex
Definition: GFXDevice.h:570
bool removeDebugView(DebugView *view)
Definition: GFXDevice.cpp:2770
VertexBuffer_ptr newVB(const VertexBuffer::Descriptor &descriptor)
Create and return a new vertex array (VAO + VB + IB).
Definition: GFXDevice.cpp:3101
void onThreadCreated(const std::thread::id &threadID, bool isMainRenderThread) const
Definition: GFXDevice.cpp:1309
void flushCommandBufferInternal(Handle< GFX::CommandBuffer > commandBuffer)
Definition: GFXDevice.cpp:2129
void toggleDebugGroup(I16 groupID, bool state)
Definition: GFXDevice.cpp:2792
void debugDrawSpheres(GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: GFXDevice.cpp:2941
void debugDrawBoxes(GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
Definition: GFXDevice.cpp:2882
PipelineDescriptor & getDebugPipeline(const IM::BaseDescriptor &descriptor) noexcept
Definition: GFXDevice.cpp:2832
const RenderStateBlock & get2DStateBlock() const noexcept
Definition: GFXDevice.inl:123
const GFXShaderData::PrevFrameData & previousFrameData(PlayerIndex player) const noexcept
Definition: GFXDevice.cpp:2083
hashMap< size_t, Pipeline, NoHash< size_t > > _pipelineCache
Definition: GFXDevice.h:562
~GFXDevice() override
Definition: GFXDevice.cpp:327
GFXDescriptorSet & descriptorSet(DescriptorSetUsage usage) noexcept
Definition: GFXDevice.inl:204
bool getDebugGroupState(I16 groupID) const
Definition: GFXDevice.cpp:2804
ErrorCode postInitRenderingAPI(vec2< U16 > renderResolution)
Definition: GFXDevice.cpp:598
void debugDrawLines(const I64 ID, IM::LineDescriptor descriptor) noexcept
Definition: GFXDevice.cpp:2846
std::unique_ptr< GFXRTPool > _rtPool
Definition: GFXDevice.h:482
GFXDevice(PlatformContext &context)
Definition: GFXDevice.cpp:320
DebugPrimitiveHandler< IM::LineDescriptor, 16u > _debugLines
Definition: GFXDevice.h:473
bool fitViewportInWindow(U16 w, U16 h)
Definition: GFXDevice.cpp:1832
void updateSceneDescriptorSet(GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut) const
Definition: GFXDevice.cpp:525
void flushCommandBuffer(Handle< GFX::CommandBuffer > &&commandBuffer)
Definition: GFXDevice.cpp:2120
Mutex _debugViewLock
Definition: GFXDevice.h:531
std::pair< Handle< Texture >, SamplerDescriptor > constructHIZ(RenderTargetID depthBuffer, RenderTargetID HiZTarget, GFX::CommandBuffer &cmdBufferInOut)
Definition: GFXDevice.cpp:2272
void resizeGPUBlocks(size_t targetSizeCam, size_t targetSizeCullCounter)
Definition: GFXDevice.cpp:532
Pipeline * _hIZPipeline
Definition: GFXDevice.h:510
DebugPrimitiveHandler< IM::OBBDescriptor, 16u > _debugOBBs
Definition: GFXDevice.h:475
void toggleDebugView(I16 index, bool state)
Definition: GFXDevice.cpp:2779
DebugView * addDebugView(const std::shared_ptr< DebugView > &view)
Definition: GFXDevice.cpp:2740
void addRenderWork(DELEGATE< void > &&work)
Definition: GFXDevice.cpp:515
const GFXShaderData::CamData & cameraData() const noexcept
Definition: GFXDevice.cpp:2078
bool setScissor(const Rect< I32 > &scissor)
Definition: GFXDevice.cpp:2057
vector< std::tuple< GraphicsResource::Type, I64, U64 > > _graphicResources
Definition: GFXDevice.h:526
static D64 s_interpolationFactor
Definition: GFXDevice.h:577
Handle< ShaderProgram > _blurBoxShaderLayered
Definition: GFXDevice.h:505
vec2< U16 > _renderingResolution
Definition: GFXDevice.h:528
RenderTarget * getRenderTarget(const RenderTargetID target) const
Definition: GFXRTPool.cpp:50
FORCE_INLINE I64 getGUID() const noexcept
Definition: GUIDWrapper.h:51
void drawText(const TextElementBatch &batch, const Rect< I32 > &targetViewport, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut, bool pushCamera=true)
Text rendering is handled exclusively by Mikko Mononen's FontStash library (https://github....
Definition: GUI.cpp:180
IMPrimitive replaces immediate mode calls to VB based rendering.
Definition: IMPrimitive.h:58
void getCommandBuffer(GFX::CommandBuffer &commandBufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
void fromOBB(const IM::OBBDescriptor &box)
GFXDevice & context() noexcept
Definition: IMPrimitive.h:135
void setPipelineDescriptor(const PipelineDescriptor &descriptor)
void fromBox(const IM::BoxDescriptor &box)
void fromCone(const IM::ConeDescriptor &cone)
void fromLines(const IM::LineDescriptor &lines)
void fromFrustum(const IM::FrustumDescriptor &frustum)
static void InitStaticData()
Definition: IMPrimitive.cpp:55
void fromSphere(const IM::SphereDescriptor &sphere)
static void RecomputeShaders()
Definition: Material.cpp:131
void setParam(HashType nameID, T &&value)
PlatformContext & context() noexcept
DisplayWindow & mainWindow() noexcept
DisplayWindow & activeWindow() noexcept
Application & app() noexcept
Kernel & kernel() noexcept
ParamHandler & paramHandler() noexcept
Configuration & config() noexcept
void update(U64 deltaTimeUSFixed, U64 deltaTimeUSApp)
Definition: PostFX.cpp:252
PreRenderBatch & getFilterBatch() noexcept
Definition: PostFX.h:119
RenderTargetHandle edgesRT() const noexcept
Handle< Texture > luminanceTex() const noexcept
Handle< Texture > texture() const
RTAttachmentDescriptor _descriptor
Definition: RTAttachment.h:128
static void OnShutdown(const GFXDevice &gfx)
static void OnStartup(const GFXDevice &gfx)
RTAttachment * getAttachment(RTAttachmentType type, RTColourAttachmentSlot slot=RTColourAttachmentSlot::SLOT_0) const
U16 getWidth() const noexcept
bool hasAttachment(RTAttachmentType type, RTColourAttachmentSlot slot=RTColourAttachmentSlot::SLOT_0) const
vec2< U16 > getResolution() const noexcept
U16 getHeight() const noexcept
PostFX & postFX()
Definition: Renderer.h:61
virtual LockableBuffer * getBufferImpl()=0
void readData(BufferRange range, std::pair< bufferPtr, size_t > outData)
BufferLock clearData(BufferRange range)
static void OnEndFrame(GFXDevice &gfx)
static void OnBeginFrame(GFXDevice &gfx)
static void DestroyStaticData()
static void RegisterSetLayoutBinding(DescriptorSetUsage usage, U8 slot, DescriptorSetBindingType type, ShaderStageVisibility visibility)
static void Idle(PlatformContext &platformContext, bool fast)
static ErrorCode OnStartup(PlatformContext &context)
static void InitStaticData()
static ErrorCode SubmitSetLayouts(GFXDevice &gfx)
static I32 ShaderProgramCount() noexcept
static void setMSAASampleCount(ShadowType type, U8 sampleCount)
Definition: ShadowMap.cpp:514
size_t getHash() const override
Definition: TextLabel.cpp:34
static void OnShutdown() noexcept
Definition: Texture.cpp:78
static void OnStartup(GFXDevice &gfx)
Definition: Texture.cpp:41
void drawToWindow(DisplayWindow &window)
vec4< T > _vec[4]
Definition: MathMatrices.h:709
static mat4< T > Multiply(const mat4< T > &matrixA, const mat4< T > &matrixB) noexcept
ret = A * B
void set(std::initializer_list< T > matrix) noexcept
void set(const T *v) noexcept
set the 2 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:335
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
void set(const T *v) noexcept
set the 4 components of the vector manually using a source pointer to a (large enough) array
Definition: MathVectors.h:1241
vec2< T > xy
Definition: MathVectors.h:1366
vec3< T > xyz
Definition: MathVectors.h:1374
vec2< T > zw
Definition: MathVectors.h:1366
constexpr DEGREES< T > to_VerticalFoV(DEGREES< T > horizontalFoV, D64 aspectRatio) noexcept
Definition: MathHelper.inl:352
constexpr bool ENABLE_EDITOR
Definition: config.h:66
constexpr U8 CLUSTERS_X
Controls compute shader dispatch. e.g. Dispatch Z count = CLUSTERS_Z / CLUSTERS_Z_THREADS.
Definition: config.h:170
constexpr U16 MAX_LIGHTS_PER_CLUSTER
Upper limit of lights used in a cluster. The lower, the better performance at the cost of pop-in/glit...
Definition: config.h:167
constexpr bool ENABLE_GPU_VALIDATION
Error callbacks, validations, buffer checks, etc. are controlled by this flag. Heavy performance impa...
Definition: config.h:192
constexpr U8 MAX_CULL_DISTANCES
Definition: config.h:131
constexpr U8 MAX_REFLECTIVE_NODES_IN_VIEW
Definition: config.h:135
constexpr U8 MAX_REFRACTIVE_NODES_IN_VIEW
Similar to MAX_REFLECTIVE_NODES_IN_VIEW but for custom refraction passes (e.g. Water,...
Definition: config.h:138
constexpr U8 MAX_FRAMES_IN_FLIGHT
Maximum number of active frames until we start waiting on a fence/sync.
Definition: config.h:100
constexpr U8 MAX_CLIP_DISTANCES
Definition: config.h:127
constexpr const char * DROID_SERIF_BOLD
Definition: TextLabel.h:48
CommandBuffer * Get(Handle< CommandBuffer > handle)
FORCE_INLINE T * EnqueueCommand(CommandBuffer &buffer)
Handle< CommandBuffer > AllocateCommandBuffer(const char *name, const size_t reservedCmdCount)
bool SaveImage(const ResourcePath &filename, U16 width, U16 height, U8 numberOfComponents, U8 bytesPerPixel, const bool sourceIsBGR, const Byte *imageData, SaveImageFormat format)
Save an image to file of the desired format. Only R/RG/RGB/RGBA 8 bits per pixel data is supported as...
static const char * resourceTypes[]
static constexpr const char * renderStage[]
static constexpr const char * renderPassType[]
constexpr Optick::Category::Type Graphics
Definition: Profiler.h:60
D64 ElapsedMilliseconds() noexcept
const char * RenderPassTypeToString(const RenderPassType pass) noexcept
Definition: GFXDevice.cpp:72
RenderStage StringToRenderStage(const char *stage) noexcept
Definition: GFXDevice.cpp:59
const char * GraphicResourceTypeToName(const GraphicsResource::Type type) noexcept
Definition: GFXDevice.cpp:49
const char * RenderStageToString(const RenderStage stage) noexcept
Definition: GFXDevice.cpp:54
RenderPassType StringToRenderPassType(const char *pass) noexcept
Definition: GFXDevice.cpp:77
Str StringFormat(const char *fmt, Args &&...args)
string to_string(GET_PASS_TYPE< T > value)
void DecrementPrimitiveLifetime(DebugPrimitiveHandler< Data, N > &container)
Definition: GFXDevice.cpp:106
constexpr size_t TargetBufferSizeCam
How many writes we can basically issue per frame to our scratch buffers before we have to sync.
Definition: GFXDevice.cpp:94
FORCE_INLINE U32 getGroupCount(const U32 threadCount, U32 const localSize)
Definition: GFXDevice.cpp:100
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
std::array< DescriptorSetEntry, to_base(DescriptorSetUsage::COUNT)> DescriptorSetEntries
DELEGATE_STD< Ret, Args... > DELEGATE
std::lock_guard< mutex > LockGuard
Definition: SharedMutex.h:55
constexpr U32 nextPOW2(U32 n) noexcept
Definition: MathHelper.inl:207
std::byte Byte
eastl::fixed_vector< ExternalRTAttachmentDescriptor, RT_MAX_ATTACHMENT_COUNT, false > ExternalRTAttachmentDescriptors
Definition: RTAttachment.h:104
constexpr U32 to_U32(const T value)
FORCE_INLINE void DestroyResource(Handle< T > &handle, const bool immediate=false)
static constexpr U32 RT_DEPTH_ATTACHMENT_IDX
Definition: RTAttachment.h:71
void Merge(BufferRange &lhs, const BufferRange &rhs) noexcept
Definition: BufferRange.inl:49
void SetThreadName(std::string_view threadName) noexcept
void insert(eastl::vector< T, A1 > &target, const eastl::vector< T, A2 > &source)
Definition: Vector.h:97
static const vec3< F32 > WORLD_X_NEG_AXIS
Definition: MathVectors.h:1442
std::mutex Mutex
Definition: SharedMutex.h:40
static const vec3< F32 > WORLD_X_AXIS
Definition: MathVectors.h:1439
constexpr U16 to_U16(const T value)
constexpr RenderTargetID SCREEN_TARGET_ID
int32_t I32
T * ResourcePtr
Definition: Resource.h:112
uint8_t U8
constexpr U8 MAX_BINDINGS_PER_DESCRIPTOR_SET
bool DebugBreak(const bool condition) noexcept
@ RES_LOADED
The resource is available for usage.
static const vec3< F32 > WORLD_Y_NEG_AXIS
Definition: MathVectors.h:1443
static const vec3< F32 > WORLD_Z_AXIS
Definition: MathVectors.h:1441
std::string CurrentDateTimeString()
int16_t I16
constexpr F32 to_F32(const T value)
constexpr D64 to_D64(const T value)
bool IsCubeTexture(TextureType texType) noexcept
bool IsArrayTexture(TextureType texType) noexcept
RTAttachmentType
This enum is used when creating render targets to define the channel that the texture will attach to.
Definition: RTAttachment.h:47
size_t GetHash(const PropertyDescriptor< T > &descriptor) noexcept
Definition: Resource.inl:40
std::unique_lock< mutex > UniqueLock
Definition: SharedMutex.h:52
void AddImageUsageFlag(PropertyDescriptor< Texture > &descriptor, const ImageUsage usage) noexcept
FileError createDirectory(const ResourcePath &path)
eastl::vector< Type > vector
Definition: Vector.h:42
hashAlg::unordered_map< K, V, HashFun, Predicate > hashMap
Definition: HashMap.h:55
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)
eastl::fixed_vector< InternalRTAttachmentDescriptor, RT_MAX_ATTACHMENT_COUNT, false > InternalRTAttachmentDescriptors
Definition: RTAttachment.h:103
FORCE_INLINE Handle< T > CreateResource(const ResourceDescriptor< T > &descriptor, bool &wasInCache, std::atomic_uint &taskCounter)
constexpr RenderTargetID INVALID_RENDER_TARGET_ID
@ Vulkan
not supported yet
@ None
No rendering. Used for testing or server code.
RTColourAttachmentSlot
void efficient_clear(eastl::fixed_vector< T, nodeCount, bEnableOverflow, OverflowAllocator > &fixed_vector)
Definition: Vector.h:52
constexpr U8 to_U8(const T value)
::value constexpr T CLAMPED(T n, T min, T max) noexcept
Definition: MathHelper.inl:126
constexpr I16 to_I16(const T value)
static const vec3< F32 > WORLD_Z_NEG_AXIS
Definition: MathVectors.h:1444
constexpr U32 U32_MAX
double D64
ShadowType
Definition: ShadowMap.h:40
bool ValidateGPUDataStructure() noexcept
RTClearEntry DEFAULT_CLEAR_ENTRY
::value constexpr void CLAMP(T &n, T min, T max) noexcept
Clamps value n between min and max.
Definition: MathHelper.inl:114
bool COMPARE(T X, U Y) noexcept
vec4< U8 > UColour4
Definition: MathHelper.h:72
void DestroyIMP(IMPrimitive *&primitive)
Definition: GFXDevice.cpp:3092
constexpr I32 to_I32(const T value)
U32 RenderTargetID
DescriptorSetUsage
bool dvd_erase_if(eastl::vector< T, A > &vec, Predicate &&pred)
Definition: Vector.h:109
int64_t I64
FORCE_INLINE T * Get(const Handle< T > handle)
uint32_t U32
Project const SceneEntry & entry
Definition: DefaultScene.h:41
static const vec4< F32 > VECTOR4_ZERO
Definition: MathVectors.h:1435
void * bufferPtr
uint64_t U64
static const vec3< F32 > WORLD_Y_AXIS
Definition: MathVectors.h:1440
constexpr U8 U8_ZERO
constexpr auto to_base(const Type value) -> Type
BufferUpdateUsage _updateUsage
Definition: BufferParams.h:40
BufferUsageType _usageType
Definition: BufferParams.h:41
BufferUpdateFrequency _updateFrequency
Definition: BufferParams.h:39
BufferRange _range
Definition: BufferLocks.h:57
BufferSyncUsage _type
Definition: BufferLocks.h:58
LockableBuffer * _buffer
Definition: BufferLocks.h:60
size_t _elementSize
Buffer primitive size in bytes.
Definition: BufferParams.h:50
BufferFlags _flags
Definition: BufferParams.h:48
mat4< F32 > _invViewMatrix
mat4< F32 > _projectionMatrix
std::array< Plane< F32 >, 6 > _frustumPlanes
Angle::DEGREES< F32 > _fov
const std::array< bool, N > & planeState() const noexcept
Definition: ClipPlanes.h:76
const PlaneList< N > & planes() const noexcept
Definition: ClipPlanes.h:75
struct Divide::Configuration::Rendering rendering
struct Divide::Configuration::Runtime runtime
static NO_INLINE void errorfn(const char *format, T &&... args)
static NO_INLINE void printfn(const char *format, T &&... args)
eastl::fixed_vector< DataEntry, N, true > _debugData
Definition: GFXDevice.h:176
DescriptorSetBindingType _type
DescriptorSetBindingData _data
std::array< DescriptorSetBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET > _bindings
static U8 ActiveDisplayCount() noexcept
static U8 MaxMSAASamples() noexcept
static const OutputDisplayPropertiesContainer & GetDisplayModes(const size_t displayIndex) noexcept
U16 _layer
RTClearDescriptor _clearDescriptor
Definition: Commands.inl:97
FORCE_INLINE T * As()
Definition: Commands.h:60
Definition: CommandBuffer.h:97
eastl::fixed_vector< Entry, COMMAND_BUFFER_INIT_SIZE, true > _commandBuffers
GenericDrawCommandContainer _drawCommands
Definition: Commands.inl:81
CameraSnapshot _cameraSnapshot
Definition: Commands.inl:159
std::pair< bufferPtr, size_t > _target
Definition: Commands.inl:196
CameraSnapshot _cameraSnapshot
Definition: Commands.inl:155
FrustumClipPlanes _clippingPlanes
Definition: Commands.inl:165
static constexpr U8 PER_FRAME_BUFFER_COUNT
Definition: GFXDevice.h:538
void reset(const bool camBuffer, const bool cullBuffer) noexcept
Definition: GFXDevice.inl:234
PerFrameBuffers & crtBuffers() noexcept
Definition: GFXDevice.inl:224
struct Divide::GFXDevice::GFXBuffers::PerFrameBuffers _perFrameBuffers[PER_FRAME_BUFFER_COUNT]
void update(DescriptorSetUsage usage, const DescriptorSet &newBindingData)
Definition: GFXDevice.cpp:285
static constexpr RTColourAttachmentSlot ALBEDO
Definition: GFXDevice.h:228
static constexpr RTColourAttachmentSlot NORMALS
Definition: GFXDevice.h:230
static constexpr RTColourAttachmentSlot MODULATE
Definition: GFXDevice.h:231
static constexpr RTColourAttachmentSlot VELOCITY
Definition: GFXDevice.h:229
static constexpr RTColourAttachmentSlot ACCUMULATION
Definition: GFXDevice.h:232
static constexpr RTColourAttachmentSlot REVEALAGE
Definition: GFXDevice.h:233
vec4< F32 > _clipPlanes[Config::MAX_CLIP_DISTANCES]
Definition: GFXShaderData.h:56
struct Divide::GFXShaderData::CamData _camData
struct Divide::GFXShaderData::PrevFrameData _prevFrameData[Config::MAX_LOCAL_PLAYER_COUNT]
PrimitiveTopology _primitiveTopology
Definition: Pipeline.h:48
Handle< ShaderProgram > _shaderProgramHandle
Definition: Pipeline.h:47
RTBlendStates _blendStates
Definition: Pipeline.h:45
RenderStateBlock _stateBlock
Definition: Pipeline.h:46
vector< ShaderModuleDescriptor > _modules
SamplerDescriptor _sampler
Definition: RTAttachment.h:64
std::array< BlendingSettings, to_base(RTColourAttachmentSlot::COUNT)> _settings
DrawLayerEntry _writeLayers[RT_MAX_ATTACHMENT_COUNT]
RTDrawDescriptor _targetDescriptorPrePass
RTDrawDescriptor _targetDescriptorMainPass
ComparisonFunction _zFunc
ExternalRTAttachmentDescriptors _externalAttachments
Definition: RenderTarget.h:53
InternalRTAttachmentDescriptors _attachments
Definition: RenderTarget.h:52
RenderTargetID _targetID
Definition: RenderTarget.h:47
static RenderTargetID HI_Z
Definition: GFXDevice.h:204
static RenderTargetID REFLECTION_PLANAR_BLUR
Definition: GFXDevice.h:206
static RenderTargetID OIT
Definition: GFXDevice.h:200
static RenderTargetID BACK_BUFFER
Definition: GFXDevice.h:196
static RenderTargetID NORMALS_RESOLVED
Definition: GFXDevice.h:199
static RenderTargetID OIT_REFLECT
Definition: GFXDevice.h:201
static RenderTargetID HI_Z_REFLECT
Definition: GFXDevice.h:205
static RenderTargetID SSAO_RESULT
Definition: GFXDevice.h:202
static RenderTargetID SCREEN
Definition: GFXDevice.h:197
static RenderTargetID SSR_RESULT
Definition: GFXDevice.h:203
static RenderTargetID REFLECTION_CUBE
Definition: GFXDevice.h:207
static std::array< RenderTargetID, Config::MAX_REFRACTIVE_NODES_IN_VIEW > REFRACTION_PLANAR
Definition: GFXDevice.h:210
static std::array< RenderTargetID, Config::MAX_REFLECTIVE_NODES_IN_VIEW > REFLECTION_PLANAR
Definition: GFXDevice.h:209
static RenderTargetID SCREEN_PREV
Definition: GFXDevice.h:198
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
std::pair< bufferPtr, size_t > _initialData
Definition: ShaderBuffer.h:103
bool _separateReadWrite
Use a separate read/write index based on queue length.
Definition: ShaderBuffer.h:106
U16 width
The new width and height.
void set(U64 bindingHash, PushConstantType type, const T &value)