diff --git a/BoolkaCommon/SolutionHelpers.h b/BoolkaCommon/SolutionHelpers.h index e7c0775..4980567 100644 --- a/BoolkaCommon/SolutionHelpers.h +++ b/BoolkaCommon/SolutionHelpers.h @@ -143,6 +143,11 @@ for (auto& elem : arr) \ elem.Unload(); \ } +#define BLK_SAFE_UNLOAD_ARRAY(arr) \ + { \ + for (auto& elem : arr) \ + elem.SafeUnload(); \ + } #define BLK_FLOAT_PI 3.141592f diff --git a/D3D12Backend/APIWrappers/Device.cpp b/D3D12Backend/APIWrappers/Device.cpp index 8588487..9d6af9d 100644 --- a/D3D12Backend/APIWrappers/Device.cpp +++ b/D3D12Backend/APIWrappers/Device.cpp @@ -63,6 +63,11 @@ namespace Boolka return m_DStorageFactory; } + bool Device::SupportsRaytracing() const + { + return m_SupportsRaytracing; + } + bool Device::Initialize(Factory& factory) { BLK_ASSERT(m_Device == nullptr); @@ -71,6 +76,7 @@ namespace Boolka if (!SelectAndCreateDevice(factory)) return false; + InitializeFeatureSupport(); BLK_RENDER_PROFILING_ONLY(InitializeProfiling()); BLK_RENDER_DEBUG_ONLY(InitializeDebug()); @@ -99,10 +105,12 @@ namespace Boolka m_GraphicQueue.Unload(); m_DStorageFactory.Unload(); - BLK_RENDER_DEBUG_ONLY(ReportObjectLeaks()); + BLK_RENDER_DEBUG_ONLY(ReportDeviceObjectLeaks()); m_Device->Release(); m_Device = nullptr; + m_Adapter->Release(); + m_Adapter = nullptr; } void Device::Flush() @@ -174,19 +182,48 @@ namespace Boolka continue; } - m_Adapter = adapter; - m_Device = device; - return true; + if (FeatureSupportHelper::HasPreferredFeatures(device)) + { + BLK_SAFE_RELEASE(m_Adapter); + BLK_SAFE_RELEASE(m_Device); + m_Adapter = adapter; + m_Device = device; + return true; + } + + if (m_Adapter == nullptr) + { + m_Adapter = adapter; + m_Device = device; + } + else + { + adapter->Release(); + device->Release(); + } + + ++i; + continue; } + if (m_Adapter != nullptr) + { + return true; + } + ::MessageBoxW(0, L"No supported GPUs found.\nRequired features are:\nResource Binding Tier 3\n" - L"Shader Model 6.5\nRaytracing Tier 1.0\nMesh Shaders", + L"Shader Model 6.5\nRaytracing Tier 1.0\nMesh Shaders\n32 Wave width", L"GPU and/or driver unsupported", MB_OK | MB_ICONERROR); BLK_CRITICAL_DEBUG_BREAK(); return false; } + void Device::InitializeFeatureSupport() + { + m_SupportsRaytracing = FeatureSupportHelper::SupportRaytracing(m_Device); + } + #ifdef BLK_RENDER_PROFILING void Device::InitializeProfiling() { @@ -218,7 +255,7 @@ namespace Boolka debugInfoQueue->Release(); } - void Device::ReportObjectLeaks() + void Device::ReportDeviceObjectLeaks() { ID3D12DebugDevice2* debugDevice = nullptr; HRESULT hr = m_Device->QueryInterface(IID_PPV_ARGS(&debugDevice)); diff --git a/D3D12Backend/APIWrappers/Device.h b/D3D12Backend/APIWrappers/Device.h index 8ee37cc..63f7d57 100644 --- a/D3D12Backend/APIWrappers/Device.h +++ b/D3D12Backend/APIWrappers/Device.h @@ -28,6 +28,8 @@ namespace Boolka [[nodiscard]] DStorageFactory& GetDStorageFactory(); + [[nodiscard]] bool SupportsRaytracing() const; + bool Initialize(Factory& factory); void Unload(); @@ -42,13 +44,14 @@ namespace Boolka #endif private: bool SelectAndCreateDevice(Factory& factory); + void InitializeFeatureSupport(); #ifdef BLK_RENDER_PROFILING void InitializeProfiling(); #endif #ifdef BLK_RENDER_DEBUG void InitializeDebug(); void SetDebugBreakSeverity(D3D12_MESSAGE_SEVERITY severity); - void ReportObjectLeaks(); + void ReportDeviceObjectLeaks(); #endif IDXGIAdapter4* m_Adapter; @@ -60,6 +63,8 @@ namespace Boolka ComputeQueue m_ComputeQueue; CopyQueue m_CopyQueue; DStorageQueue m_DStorageQueue; + + bool m_SupportsRaytracing; }; } // namespace Boolka diff --git a/D3D12Backend/APIWrappers/PipelineState/StateObject.cpp b/D3D12Backend/APIWrappers/PipelineState/StateObject.cpp index abcdaa2..a38f63f 100644 --- a/D3D12Backend/APIWrappers/PipelineState/StateObject.cpp +++ b/D3D12Backend/APIWrappers/PipelineState/StateObject.cpp @@ -37,6 +37,11 @@ namespace Boolka m_StateObject = nullptr; } + void StateObject::SafeUnload() + { + BLK_SAFE_RELEASE(m_StateObject); + } + bool StateObject::InitializeInternal(Device& device, const wchar_t* name, const D3D12_STATE_OBJECT_DESC& desc) { diff --git a/D3D12Backend/APIWrappers/PipelineState/StateObject.h b/D3D12Backend/APIWrappers/PipelineState/StateObject.h index e6c5544..45856cb 100644 --- a/D3D12Backend/APIWrappers/PipelineState/StateObject.h +++ b/D3D12Backend/APIWrappers/PipelineState/StateObject.h @@ -30,6 +30,7 @@ namespace Boolka }; void Unload(); + void SafeUnload(); private: bool InitializeInternal(Device& device, const wchar_t* name, diff --git a/D3D12Backend/APIWrappers/Resources/Buffers/Buffer.cpp b/D3D12Backend/APIWrappers/Resources/Buffers/Buffer.cpp index 6bfee6c..a83a4f7 100644 --- a/D3D12Backend/APIWrappers/Resources/Buffers/Buffer.cpp +++ b/D3D12Backend/APIWrappers/Resources/Buffers/Buffer.cpp @@ -42,6 +42,11 @@ namespace Boolka return true; } + void Buffer::SafeUnload() + { + BLK_SAFE_RELEASE(m_Resource); + } + void Buffer::Unload() { BLK_ASSERT(m_Resource != nullptr); diff --git a/D3D12Backend/APIWrappers/Resources/Buffers/Buffer.h b/D3D12Backend/APIWrappers/Resources/Buffers/Buffer.h index 298b2d6..5d7b3d3 100644 --- a/D3D12Backend/APIWrappers/Resources/Buffers/Buffer.h +++ b/D3D12Backend/APIWrappers/Resources/Buffers/Buffer.h @@ -13,7 +13,9 @@ namespace Boolka ~Buffer() = default; bool Initialize(Device& device, UINT64 size, D3D12_HEAP_TYPE heapType, - D3D12_RESOURCE_FLAGS resourceFlags, D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON); + D3D12_RESOURCE_FLAGS resourceFlags, + D3D12_RESOURCE_STATES initialState = D3D12_RESOURCE_STATE_COMMON); + void SafeUnload(); void Unload(); }; diff --git a/D3D12Backend/Containers/PSOContainer.cpp b/D3D12Backend/Containers/PSOContainer.cpp index 51ec15b..6ccb362 100644 --- a/D3D12Backend/Containers/PSOContainer.cpp +++ b/D3D12Backend/Containers/PSOContainer.cpp @@ -41,6 +41,7 @@ namespace Boolka BLK_ASSERT_VAR(res); DebugFileReader::FreeMemory(PS); DebugFileReader::FreeMemory(VS); + emptyInputLayout.Unload(); PS = DebugFileReader::ReadFile("GBufferPassPixelShader.cso"); AS = DebugFileReader::ReadFile("AmplificationShader.cso"); @@ -121,48 +122,50 @@ namespace Boolka DebugFileReader::FreeMemory(CS); #endif - DebugProfileTimer rtpsoTimer; - rtpsoTimer.Start(); - - MemoryBlock shaderLib = DebugFileReader::ReadFile("RaytracePassLib.cso"); - const wchar_t* rayGenExport = L"RayGeneration"; - const wchar_t* missExport = L"MissShader"; - const wchar_t* closestHitExport = L"ClosestHit"; - const wchar_t* libExports[] = {rayGenExport, missExport, closestHitExport}; - const wchar_t* hitGroupExport = L"HitGroup"; - res = GetPSO(RTPSO::RaytracePass) - .Initialize(device, L"RTPSO::RaytracePass", - GlobalRootSignatureParam{defaultRootSig}, - DXILLibraryParam{shaderLib, libExports}, - HitGroupParam{hitGroupExport, closestHitExport}, - RaytracingShaderConfigParam{sizeof(HLSLShared::RaytracePayload), - sizeof(Vector2)}, - RaytracingPipelineConfigParam{BLK_RT_MAX_RECURSION_DEPTH}); - BLK_ASSERT_VAR(res); - DebugFileReader::FreeMemory(shaderLib); - - rtpsoTimer.Stop(L"RTPSO compile"); - - UINT64 shaderTableSize = ShaderTable::CalculateRequiredBufferSize(1, 1, 1); - - Buffer& shaderTableBuffer = - engineContext.GetResourceContainer().GetBuffer(ResourceContainer::Buf::RTShaderTable); - m_ShaderTablesUploadBuffer.Initialize(device, shaderTableSize); - void* uploadBuffer = m_ShaderTablesUploadBuffer.Map(); - GetShaderTable(RTShaderTable::Default) - .Build(shaderTableBuffer->GetGPUVirtualAddress(), uploadBuffer, - GetPSO(RTPSO::RaytracePass), 1, &rayGenExport, 1, &missExport, 1, - &hitGroupExport); - - GraphicCommandListImpl& initializationCommandList = - engineContext.GetInitializationCommandList(); - initializationCommandList->CopyResource(shaderTableBuffer.Get(), - m_ShaderTablesUploadBuffer.Get()); - - BLK_RENDER_DEBUG_ONLY(device.RemoveLastMessageFilter()); - emptyInputLayout.Unload(); - - timer.Stop(L"All PSOs compile"); + if (device.SupportsRaytracing()) + { + DebugProfileTimer rtpsoTimer; + rtpsoTimer.Start(); + + MemoryBlock shaderLib = DebugFileReader::ReadFile("RaytracePassLib.cso"); + const wchar_t* rayGenExport = L"RayGeneration"; + const wchar_t* missExport = L"MissShader"; + const wchar_t* closestHitExport = L"ClosestHit"; + const wchar_t* libExports[] = {rayGenExport, missExport, closestHitExport}; + const wchar_t* hitGroupExport = L"HitGroup"; + res = GetPSO(RTPSO::RaytracePass) + .Initialize(device, L"RTPSO::RaytracePass", + GlobalRootSignatureParam{defaultRootSig}, + DXILLibraryParam{shaderLib, libExports}, + HitGroupParam{hitGroupExport, closestHitExport}, + RaytracingShaderConfigParam{sizeof(HLSLShared::RaytracePayload), + sizeof(Vector2)}, + RaytracingPipelineConfigParam{BLK_RT_MAX_RECURSION_DEPTH}); + BLK_ASSERT_VAR(res); + DebugFileReader::FreeMemory(shaderLib); + + rtpsoTimer.Stop(L"RTPSO compile"); + + UINT64 shaderTableSize = ShaderTable::CalculateRequiredBufferSize(1, 1, 1); + + Buffer& shaderTableBuffer = engineContext.GetResourceContainer().GetBuffer( + ResourceContainer::Buf::RTShaderTable); + m_ShaderTablesUploadBuffer.Initialize(device, shaderTableSize); + void* uploadBuffer = m_ShaderTablesUploadBuffer.Map(); + GetShaderTable(RTShaderTable::Default) + .Build(shaderTableBuffer->GetGPUVirtualAddress(), uploadBuffer, + GetPSO(RTPSO::RaytracePass), 1, &rayGenExport, 1, &missExport, 1, + &hitGroupExport); + + GraphicCommandListImpl& initializationCommandList = + engineContext.GetInitializationCommandList(); + initializationCommandList->CopyResource(shaderTableBuffer.Get(), + m_ShaderTablesUploadBuffer.Get()); + + BLK_RENDER_DEBUG_ONLY(device.RemoveLastMessageFilter()); + + timer.Stop(L"All PSOs compile"); + } return true; } @@ -171,12 +174,15 @@ namespace Boolka { BLK_UNLOAD_ARRAY(m_GraphicPSOs); BLK_UNLOAD_ARRAY(m_ComputePSOs); - BLK_UNLOAD_ARRAY(m_RTPSOs); + BLK_SAFE_UNLOAD_ARRAY(m_RTPSOs); } - void PSOContainer::FinishInitialization() + void PSOContainer::FinishInitialization(Device& device) { - m_ShaderTablesUploadBuffer.Unload(); + if (device.SupportsRaytracing()) + { + m_ShaderTablesUploadBuffer.Unload(); + } } GraphicPipelineState& PSOContainer::GetPSO(GraphicPSO id) diff --git a/D3D12Backend/Containers/PSOContainer.h b/D3D12Backend/Containers/PSOContainer.h index fb72510..5942fd6 100644 --- a/D3D12Backend/Containers/PSOContainer.h +++ b/D3D12Backend/Containers/PSOContainer.h @@ -52,7 +52,7 @@ namespace Boolka bool Initialize(Device& device, RenderEngineContext& engineContext); void Unload(); - void FinishInitialization(); + void FinishInitialization(Device& device); [[nodiscard]] GraphicPipelineState& GetPSO(GraphicPSO id); [[nodiscard]] ComputePipelineState& GetPSO(ComputePSO id); diff --git a/D3D12Backend/Containers/RTASContainer.cpp b/D3D12Backend/Containers/RTASContainer.cpp index ecef0c5..3fb8464 100644 --- a/D3D12Backend/Containers/RTASContainer.cpp +++ b/D3D12Backend/Containers/RTASContainer.cpp @@ -50,6 +50,11 @@ namespace Boolka return true; } + void RTASContainer::SafeUnload() + { + m_ASBuffer.SafeUnload(); + } + void RTASContainer::Unload() { m_ASBuffer.Unload(); diff --git a/D3D12Backend/Containers/RTASContainer.h b/D3D12Backend/Containers/RTASContainer.h index ff3a4de..ff12d3f 100644 --- a/D3D12Backend/Containers/RTASContainer.h +++ b/D3D12Backend/Containers/RTASContainer.h @@ -18,6 +18,7 @@ namespace Boolka bool Initialize(Device& device, RenderEngineContext& engineContext, const SceneDataReader::HeaderWrapper& headerWrapper, Buffer& vertexBuffer, Buffer& indexBuffer); + void SafeUnload(); void Unload(); void FinishLoading(Device& device, RenderEngineContext& engineContext, diff --git a/D3D12Backend/Containers/Scene.cpp b/D3D12Backend/Containers/Scene.cpp index f4d9b06..f2821e6 100644 --- a/D3D12Backend/Containers/Scene.cpp +++ b/D3D12Backend/Containers/Scene.cpp @@ -68,14 +68,15 @@ namespace Boolka InitializeTextures(device, sceneHeader, headerWrapper, textureOffsets, mainSRVHeap, mainSRVHeapOffset); - MemoryBlock rtCacheheaderWrapper{}; - UINT64 sourceOffset = 0; UploadBuffers(device, sceneHeader, sourceOffset); - m_RTASContainer.Initialize(device, engineContext, headerWrapper, m_VertexBuffer1, - m_RTIndexBuffer); + if (device.SupportsRaytracing()) + { + m_RTASContainer.Initialize(device, engineContext, headerWrapper, m_VertexBuffer1, + m_RTIndexBuffer); + } UploadSkyBox(device, sceneHeader, sourceOffset); UploadTextures(device, sceneHeader, headerWrapper, sourceOffset); @@ -87,7 +88,7 @@ namespace Boolka { m_DataReader.CloseReader(); - m_RTASContainer.Unload(); + m_RTASContainer.SafeUnload(); BLK_UNLOAD_ARRAY(m_SceneTextures); m_SceneTextures.clear(); @@ -116,12 +117,18 @@ namespace Boolka { const SceneDataReader::HeaderWrapper headerWrapper = m_DataReader.GetHeaderWrapper(); - m_RTASContainer.FinishLoading(device, engineContext, headerWrapper); + if (device.SupportsRaytracing()) + { + m_RTASContainer.FinishLoading(device, engineContext, headerWrapper); + } } - void Scene::FinishInitialization() + void Scene::FinishInitialization(Device& device) { - m_RTASContainer.FinishInitialization(); + if (device.SupportsRaytracing()) + { + m_RTASContainer.FinishInitialization(); + } } UINT Scene::GetObjectCount() const diff --git a/D3D12Backend/Containers/Scene.h b/D3D12Backend/Containers/Scene.h index c63b732..229cddc 100644 --- a/D3D12Backend/Containers/Scene.h +++ b/D3D12Backend/Containers/Scene.h @@ -57,7 +57,7 @@ namespace Boolka void FinishLoading(Device& device, RenderEngineContext& engineContext); - void FinishInitialization(); + void FinishInitialization(Device& device); // All opaque objects placed before all transparent objects // So objects in range [0, m_OpaqueObjectCount) - are opaque diff --git a/D3D12Backend/Contexts/RenderEngineContext.cpp b/D3D12Backend/Contexts/RenderEngineContext.cpp index c5d232f..9b69827 100644 --- a/D3D12Backend/Contexts/RenderEngineContext.cpp +++ b/D3D12Backend/Contexts/RenderEngineContext.cpp @@ -105,10 +105,10 @@ namespace Boolka m_Scene.FinishLoading(device, *this); } - void RenderEngineContext::FinishInitialization() + void RenderEngineContext::FinishInitialization(Device& device) { - m_PSOContainer.FinishInitialization(); - m_Scene.FinishInitialization(); + m_PSOContainer.FinishInitialization(device); + m_Scene.FinishInitialization(device); } void RenderEngineContext::UnloadScene() diff --git a/D3D12Backend/Contexts/RenderEngineContext.h b/D3D12Backend/Contexts/RenderEngineContext.h index 91203e4..8b2c59a 100644 --- a/D3D12Backend/Contexts/RenderEngineContext.h +++ b/D3D12Backend/Contexts/RenderEngineContext.h @@ -33,7 +33,7 @@ namespace Boolka bool StartSceneLoading(Device& device, const wchar_t* folderPath); void FinishSceneLoading(Device& device, const wchar_t* folderPath); - void FinishInitialization(); + void FinishInitialization(Device& device); void UnloadScene(); void BuildPSOs(Device& device); diff --git a/D3D12Backend/FeatureSupportHelper.cpp b/D3D12Backend/FeatureSupportHelper.cpp index 1707266..5d2a52b 100644 --- a/D3D12Backend/FeatureSupportHelper.cpp +++ b/D3D12Backend/FeatureSupportHelper.cpp @@ -7,6 +7,16 @@ namespace Boolka { + bool FeatureSupportHelper::HasPreferredFeatures(ID3D12Device* device) + { + if (!SupportRaytracing(device)) + { + return false; + } + + return true; + } + bool FeatureSupportHelper::IsSupported(ID3D12Device* device) { D3D12_FEATURE_DATA_D3D12_OPTIONS options{}; @@ -25,20 +35,30 @@ namespace Boolka return false; } - D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5{}; - hr = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, sizeof(options5)); - if (FAILED(hr) || options5.RaytracingTier < D3D12_RAYTRACING_TIER_1_0) + D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7{}; + hr = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, sizeof(options7)); + if (FAILED(hr) || options7.MeshShaderTier < D3D12_MESH_SHADER_TIER_1) { return false; } - D3D12_FEATURE_DATA_D3D12_OPTIONS7 options7{}; - hr = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS7, &options7, sizeof(options7)); - if (FAILED(hr) || options7.MeshShaderTier < D3D12_MESH_SHADER_TIER_1) + D3D12_FEATURE_DATA_D3D12_OPTIONS1 options1{}; + hr = device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS1, &options1, sizeof(options1)); + if (FAILED(hr) || options1.WaveLaneCountMax < 32 || options1.WaveLaneCountMin > 32) { return false; } return true; } + + bool FeatureSupportHelper::SupportRaytracing(ID3D12Device* device) + { + D3D12_FEATURE_DATA_D3D12_OPTIONS5 options5{}; + HRESULT hr = + device->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS5, &options5, sizeof(options5)); + + return SUCCEEDED(hr) && options5.RaytracingTier >= D3D12_RAYTRACING_TIER_1_0; + } + } // namespace Boolka \ No newline at end of file diff --git a/D3D12Backend/FeatureSupportHelper.h b/D3D12Backend/FeatureSupportHelper.h index e8ab3a2..2f7c85e 100644 --- a/D3D12Backend/FeatureSupportHelper.h +++ b/D3D12Backend/FeatureSupportHelper.h @@ -8,7 +8,9 @@ namespace Boolka class FeatureSupportHelper { public: + [[nodiscard]] static bool HasPreferredFeatures(ID3D12Device* device); [[nodiscard]] static bool IsSupported(ID3D12Device* device); + [[nodiscard]] static bool SupportRaytracing(ID3D12Device* device); }; } // namespace Boolka diff --git a/D3D12Backend/RenderBackendImpl.cpp b/D3D12Backend/RenderBackendImpl.cpp index c4bc5e8..199be3f 100644 --- a/D3D12Backend/RenderBackendImpl.cpp +++ b/D3D12Backend/RenderBackendImpl.cpp @@ -60,6 +60,8 @@ namespace Boolka m_Factory.Unload(); m_Debug.Unload(); + BLK_RENDER_DEBUG_ONLY(ReportD3DObjectLeaks()); + m_FrameID = 0; } @@ -90,4 +92,18 @@ namespace Boolka m_Device.Flush(); } +#ifdef BLK_RENDER_DEBUG + void RenderBackendImpl::ReportD3DObjectLeaks() + { + IDXGIDebug1* dxgiDebug; + if (SUCCEEDED(DXGIGetDebugInterface1(0, IID_PPV_ARGS(&dxgiDebug)))) + { + dxgiDebug->ReportLiveObjects( + DXGI_DEBUG_ALL, + DXGI_DEBUG_RLO_FLAGS(DXGI_DEBUG_RLO_SUMMARY | DXGI_DEBUG_RLO_IGNORE_INTERNAL)); + dxgiDebug->Release(); + } + } +#endif + } // namespace Boolka diff --git a/D3D12Backend/RenderBackendImpl.h b/D3D12Backend/RenderBackendImpl.h index 82439b4..935b08c 100644 --- a/D3D12Backend/RenderBackendImpl.h +++ b/D3D12Backend/RenderBackendImpl.h @@ -30,6 +30,10 @@ namespace Boolka RenderSchedule m_RenderSchedule; Fence m_FrameFence; UINT64 m_FrameID; + +#ifdef BLK_RENDER_DEBUG + void ReportD3DObjectLeaks(); +#endif }; } // namespace Boolka diff --git a/D3D12Backend/RenderPasses/DebugOverlayPass.cpp b/D3D12Backend/RenderPasses/DebugOverlayPass.cpp index 0e7fbd4..a83f9bc 100644 --- a/D3D12Backend/RenderPasses/DebugOverlayPass.cpp +++ b/D3D12Backend/RenderPasses/DebugOverlayPass.cpp @@ -46,6 +46,8 @@ namespace Boolka m_ImguiDescriptorHeap.Get(), m_ImguiDescriptorHeap->GetCPUDescriptorHandleForHeapStart(), m_ImguiDescriptorHeap->GetGPUDescriptorHandleForHeapStart()); + + m_GPUSupportsRaytracing = device.SupportsRaytracing(); return true; } @@ -143,10 +145,34 @@ namespace Boolka { auto [engineContext, frameContext, threadContext] = renderContext.GetContexts(); - ImGui::Begin("Stats"); - const auto& debugStats = frameContext.GetFrameStats(); - const float fps = 1.0f / debugStats.frameTime; - const float fpsStable = 1.0f / debugStats.frameTimeStable; + ImguiStatsWindow(renderContext); + ImguiDebugWindow(renderContext); + ImguiHelpWindow(); + ImguiHardwareWindow(); + + ImGui::Render(); + } + + void DebugOverlayPass::ImguiHelpWindow() + { + ImGui::Begin("Help"); + if (ImGui::CollapsingHeader("Controls", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Text("WASD - Camera movement"); + ImGui::Text("Arrows - Camera rotation"); + ImGui::Text("T - Increase FOV"); + ImGui::Text("R - Decrease FOV"); + ImGui::Text("F1 - Hide/Show UI"); + ImGui::Text("O - Output camera position to clipboard"); + ImGui::Text("L - Load camera position from clipboard"); + ImGui::Text("Esc - Exit"); + } + ImGui::End(); + } + + void DebugOverlayPass::ImguiDebugWindow(const RenderContext& renderContext) + { + auto [engineContext, frameContext, threadContext] = renderContext.GetContexts(); const auto& cameraPos = frameContext.GetCameraPos(); const auto& viewMatrix = frameContext.GetViewMatrix(); const auto& projMatrix = frameContext.GetProjMatrix(); @@ -155,6 +181,29 @@ namespace Boolka // FOV along Y axis const float fov = BLK_RAD_TO_DEG(2.0f * std::atan(1.0f / projMatrix[1][1])); + ImGui::Begin("Debug"); + if (ImGui::CollapsingHeader("Camera", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Text("Pos X:%.2f Y:%.2f Z:%.2f", cameraPos.x(), cameraPos.y(), cameraPos.z()); + ImGui::Text("Dir X:%.2f Y:%.2f Z:%.2f", viewDir.x(), viewDir.y(), viewDir.z()); + ImGui::Text("FOV %.2f degrees", fov); + } + if (ImGui::CollapsingHeader("GPU Debug Markers", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImguiGPUDebugMarkers(renderContext); + } + ImGui::End(); + } + + void DebugOverlayPass::ImguiStatsWindow(const RenderContext& renderContext) + { + auto [engineContext, frameContext, threadContext] = renderContext.GetContexts(); + + ImGui::Begin("Stats"); + const auto& debugStats = frameContext.GetFrameStats(); + const float fps = 1.0f / debugStats.frameTime; + const float fpsStable = 1.0f / debugStats.frameTimeStable; + ImGui::Text("%5.1f FPS (avg %5.1f FPS)", fps, fpsStable); ImGui::Text("%5.2f ms (avg %5.2f ms)", debugStats.frameTime * 1000.0f, debugStats.frameTimeStable * 1000.0f); @@ -173,22 +222,15 @@ namespace Boolka ImguiGraphs(renderContext); } ImGui::End(); - ImGui::Begin("Debug"); - if (ImGui::CollapsingHeader("Camera", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::Text("Pos X:%.2f Y:%.2f Z:%.2f", cameraPos.x(), cameraPos.y(), cameraPos.z()); - ImGui::Text("Dir X:%.2f Y:%.2f Z:%.2f", viewDir.x(), viewDir.y(), viewDir.z()); - ImGui::Text("FOV %.2f degrees", fov); - } - if (ImGui::CollapsingHeader("GPU Debug Markers", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImguiGPUDebugMarkers(renderContext); - } - ImGui::End(); - ImGui::Begin("Help"); - ImguiHelpWindow(renderContext); + } + + void DebugOverlayPass::ImguiHardwareWindow() +{ + ImGui::Begin("Hardware"); + + ImGui::Text("GPU"); + ImGui::Text("Supports Raytracing - %s", m_GPUSupportsRaytracing ? "true" : "false"); ImGui::End(); - ImGui::Render(); } const char* GetMarkerName(size_t i) @@ -349,21 +391,6 @@ namespace Boolka m_GPUTime.PushValueAndRender(currentGPUTime, "GPU Time", graphWidth, graphHeight); } - void DebugOverlayPass::ImguiHelpWindow(const RenderContext& renderContext) - { - if (ImGui::CollapsingHeader("Controls", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::Text("WASD - Camera movement"); - ImGui::Text("Arrows - Camera rotation"); - ImGui::Text("T - Increase FOV"); - ImGui::Text("R - Decrease FOV"); - ImGui::Text("F1 - Hide/Show UI"); - ImGui::Text("O - Output camera position to clipboard"); - ImGui::Text("L - Load camera position from clipboard"); - ImGui::Text("Esc - Exit"); - } - } - template struct TupleSorter { diff --git a/D3D12Backend/RenderPasses/DebugOverlayPass.h b/D3D12Backend/RenderPasses/DebugOverlayPass.h index 0994e2f..501b9b8 100644 --- a/D3D12Backend/RenderPasses/DebugOverlayPass.h +++ b/D3D12Backend/RenderPasses/DebugOverlayPass.h @@ -24,17 +24,24 @@ namespace Boolka private: void ImguiFlipFrame(); void ImguiUIManagement(const RenderContext& renderContext); + + void ImguiHelpWindow(); + void ImguiDebugWindow(const RenderContext& renderContext); + void ImguiStatsWindow(const RenderContext& renderContext); + void ImguiHardwareWindow(); + void ImguiCullingTable(const RenderContext& renderContext); void ImguiGPUDebugMarkers(const RenderContext& renderContext); void ImguiUIGPUTimes(const RenderContext& renderContext); void ImguiGraphs(const RenderContext& renderContext); - void ImguiHelpWindow(const RenderContext& renderContext); DescriptorHeap m_ImguiDescriptorHeap; float m_ScaleFactor; bool m_IsEnabled; + bool m_GPUSupportsRaytracing; + ImguiGraphHelper m_FPSGraph; ImguiGraphHelper m_FrameTimeGraph; ImguiGraphHelper m_GPUTime; diff --git a/D3D12Backend/RenderPasses/RaytraceRenderPass.cpp b/D3D12Backend/RenderPasses/RaytraceRenderPass.cpp index 96c488b..fdc0818 100644 --- a/D3D12Backend/RenderPasses/RaytraceRenderPass.cpp +++ b/D3D12Backend/RenderPasses/RaytraceRenderPass.cpp @@ -24,8 +24,11 @@ namespace Boolka auto [engineContext, frameContext, threadContext] = renderContext.GetContexts(); auto& resourceContainer = engineContext.GetResourceContainer(); - - UINT frameIndex = frameContext.GetFrameIndex(); + + if (!m_Enabled) + { + return true; + } RootSignature& rootSig = resourceContainer.GetRootSignature(ResourceContainer::RootSig::Default); @@ -88,6 +91,7 @@ namespace Boolka bool RaytraceRenderPass::Initialize(Device& device, RenderContext& renderContext) { + m_Enabled = device.SupportsRaytracing(); return true; } diff --git a/D3D12Backend/RenderPasses/RaytraceRenderPass.h b/D3D12Backend/RenderPasses/RaytraceRenderPass.h index 4fe1be5..adb1b46 100644 --- a/D3D12Backend/RenderPasses/RaytraceRenderPass.h +++ b/D3D12Backend/RenderPasses/RaytraceRenderPass.h @@ -20,6 +20,7 @@ namespace Boolka bool PrepareRendering() final; private: + bool m_Enabled; }; } // namespace Boolka diff --git a/D3D12Backend/RenderSchedule/RenderSchedule.cpp b/D3D12Backend/RenderSchedule/RenderSchedule.cpp index dd478b0..9cfd6ff 100644 --- a/D3D12Backend/RenderSchedule/RenderSchedule.cpp +++ b/D3D12Backend/RenderSchedule/RenderSchedule.cpp @@ -33,7 +33,7 @@ namespace Boolka m_EngineContext.FinishSceneLoading(device, folderPath); m_EngineContext.FlushInitializationCommandList(device); device.GetDStorageQueue().SyncGPU(device.GetGraphicQueue()); - m_EngineContext.FinishInitialization(); + m_EngineContext.FinishInitialization(device); return true; } diff --git a/README.md b/README.md index e77de90..53bdfe1 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,8 @@ Features Requirements -------- * Windows 10 version 2004 or newer -* GPU with mesh shader and DXR 1.0 support (NVIDIA GTX 16xx or higher, AMD RX 6xxx or higher) +* GPU with mesh shader (NVIDIA GTX 16xx or higher, AMD RX 6xxx or higher) +* GPU with DXR 1.0 support recommended * SSD Recommended To build BoolkaEngine you'll also need: