From c233266e95931231961f35c842c78e7c4bdc50cf Mon Sep 17 00:00:00 2001 From: acmarrs-nvidia Date: Mon, 8 May 2023 12:05:38 -0400 Subject: [PATCH] v1.3.7 release --- ChangeLog.md | 16 + README.md | 2 +- rtxgi-sdk/include/rtxgi/Common.h | 4 +- rtxgi-sdk/shaders/ddgi/ProbeBlendingCS.hlsl | 39 +- rtxgi-sdk/shaders/ddgi/ReductionCS.hlsl | 2 +- samples/test-harness/config/cornell.ini | 7 + samples/test-harness/config/furnace.ini | 7 + samples/test-harness/config/multi-cornell.ini | 7 + samples/test-harness/config/sponza.ini | 9 +- samples/test-harness/config/tunnel.ini | 7 + samples/test-harness/config/two-rooms.ini | 11 +- samples/test-harness/include/Configs.h | 11 + samples/test-harness/include/Direct3D12.h | 17 +- samples/test-harness/include/Graphics.h | 6 +- .../test-harness/include/Instrumentation.h | 19 + samples/test-harness/include/Shaders.h | 3 +- samples/test-harness/include/Vulkan.h | 21 +- samples/test-harness/include/graphics/Types.h | 6 + .../test-harness/shaders/PathTraceRGS.hlsl | 22 +- .../shaders/include/Descriptors.hlsl | 3 + samples/test-harness/src/Configs.cpp | 24 + samples/test-harness/src/Direct3D12.cpp | 321 ++++++---- samples/test-harness/src/Shaders.cpp | 18 +- samples/test-harness/src/UI.cpp | 190 ++++-- samples/test-harness/src/Vulkan.cpp | 584 +++++++++--------- .../src/graphics/Composite_D3D12.cpp | 38 +- .../src/graphics/Composite_VK.cpp | 5 +- samples/test-harness/src/graphics/DDGI.cpp | 16 +- .../src/graphics/DDGIVisualizations_D3D12.cpp | 102 +-- .../src/graphics/DDGIVisualizations_VK.cpp | 29 +- .../test-harness/src/graphics/DDGI_D3D12.cpp | 86 +-- samples/test-harness/src/graphics/DDGI_VK.cpp | 31 +- .../src/graphics/GBuffer_D3D12.cpp | 36 +- .../test-harness/src/graphics/GBuffer_VK.cpp | 25 +- .../src/graphics/PathTracing_D3D12.cpp | 45 +- .../src/graphics/PathTracing_VK.cpp | 27 +- .../test-harness/src/graphics/RTAO_D3D12.cpp | 40 +- samples/test-harness/src/graphics/RTAO_VK.cpp | 26 +- .../test-harness/src/graphics/UI_D3D12.cpp | 14 +- samples/test-harness/src/graphics/UI_VK.cpp | 46 +- samples/test-harness/src/main.cpp | 195 +++--- 41 files changed, 1177 insertions(+), 940 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 5dd9cae..867515c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,21 @@ # RTXGI SDK Change Log +## 1.3.7 +### SDK +- **Bug Fixes** + - Fixes issue in ```ReductionCS.hlsl``` that caused a divide by zero when all probes in a volume are disabled. A reduction thread should not contribute to the variability calculation if ```threadFootprintWeightSum``` is zero. + - Fixes issue in ```ProbeBlendingCS.hlsl``` that prevented ```probeBrightnessThreshold``` from working as intended. Fixes GitHub Issue [#70](https://github.com/NVIDIAGameWorks/RTXGI/issues/70). + +### Test Harness +- **Improvements** + - Enhances shader compilation options and allows for the options to be specified in ```*.ini``` files. + - Enhancements to frame queueing/buffering. The CPU can now run ahead one frame, allowing CPU and GPU work to overlap. + - Adds a toggle to enable/disable progressive rendering in the path tracer. + - Increased the granularity of CPU timestamps and reworks the detailed performance UI. +- **Bug Fixes** + - Fixes minor issues with Vulkan timestamps. + + ## 1.3.6 ### SDK - **Improvements** diff --git a/README.md b/README.md index ee5f7d2..38479a3 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ The RTXGI SDK and sample application(s) require the following hardware and softw ### Hardware * Any DXR capable GPU. NVIDIA DXR enabled GPUs are: - * RTX 4090, 4080 + * RTX 4090, 4080, 4070 Ti, 4070 * RTX 3090 Ti, 3090, 3080 Ti, 3080, 3070 Ti, 3070, 3060 Ti, 3060, 3050 * Titan RTX * RTX 2080 Ti, 2080 SUPER, 2080, 2070 SUPER, 2070, 2060 SUPER, 2060 diff --git a/rtxgi-sdk/include/rtxgi/Common.h b/rtxgi-sdk/include/rtxgi/Common.h index bf1ac0e..d3464c7 100644 --- a/rtxgi-sdk/include/rtxgi/Common.h +++ b/rtxgi-sdk/include/rtxgi/Common.h @@ -30,11 +30,11 @@ namespace rtxgi { static const int major = 1; static const int minor = 3; - static const int revision = 6; + static const int revision = 7; inline static const char* getVersionString() { - return "1.3.6"; + return "1.3.7"; } }; diff --git a/rtxgi-sdk/shaders/ddgi/ProbeBlendingCS.hlsl b/rtxgi-sdk/shaders/ddgi/ProbeBlendingCS.hlsl index f70c40b..e3ce4f7 100644 --- a/rtxgi-sdk/shaders/ddgi/ProbeBlendingCS.hlsl +++ b/rtxgi-sdk/shaders/ddgi/ProbeBlendingCS.hlsl @@ -502,33 +502,34 @@ void DDGIProbeBlendingCS( result.rgb *= 1.f / (2.f * max(result.a, epsilon)); result.a = 1.f; - // Get the previous irradiance in the probe - float3 previous = Output[DispatchThreadID].rgb; + // Get the irradiance mean stored in the probe + float3 probeIrradianceMean = Output[DispatchThreadID].rgb; // Get the history weight (hysteresis) to use for the probe texel's previous value // If the probe was previously cleared to completely black, set the hysteresis to zero float hysteresis = volume.probeHysteresis; - if (dot(previous, previous) == 0) hysteresis = 0.f; + if (dot(probeIrradianceMean, probeIrradianceMean) == 0) hysteresis = 0.f; #if RTXGI_DDGI_BLEND_RADIANCE // Tone-mapping gamma adjustment result.rgb = pow(result.rgb, (1.f / volume.probeIrradianceEncodingGamma)); - float3 delta = (result.rgb - previous.rgb); + // Get the difference between the current irradiance and the irradiance mean stored in the probe + float3 delta = (result.rgb - probeIrradianceMean.rgb); - float3 previousIrradianceMean = previous.rgb; - float3 currentIrradianceSample = result.rgb; + // Store the current irradiance (before interpolation) for use in probe variability + float3 irradianceSample = result.rgb; - if (RTXGIMaxComponent(previous.rgb - result.rgb) > volume.probeIrradianceThreshold) + if (RTXGIMaxComponent(probeIrradianceMean.rgb - result.rgb) > volume.probeIrradianceThreshold) { // Lower the hysteresis when a large lighting change is detected hysteresis = max(0.f, hysteresis - 0.75f); } - if (length(delta) > volume.probeBrightnessThreshold) + if (RTXGILinearRGBToLuminance(delta) > volume.probeBrightnessThreshold) { - // Clamp the maximum change in irradiance when a large brightness change is detected - result.rgb = previous.rgb + (delta * 0.25f); + // Clamp the maximum per-update change in irradiance when a large brightness change is detected + delta *= 0.25f; } // Interpolate the new blended irradiance with the existing irradiance in the probe. @@ -542,26 +543,28 @@ void DDGIProbeBlendingCS( // dark convergence. static const float c_threshold = 1.f / 1024.f; float3 lerpDelta = (1.f - hysteresis) * delta; - if (RTXGIMaxComponent(result.rgb) < RTXGIMaxComponent(previous.rgb)) + if (RTXGIMaxComponent(result.rgb) < RTXGIMaxComponent(probeIrradianceMean.rgb)) { lerpDelta = min(max(c_threshold, abs(lerpDelta)), abs(delta)) * sign(lerpDelta); } - result = float4(previous.rgb + lerpDelta, 1.f); + result = float4(probeIrradianceMean.rgb + lerpDelta, 1.f); if (volume.probeVariabilityEnabled) { - float3 newIrradianceMean = result.rgb; - float3 newIrradianceSigma2 = (currentIrradianceSample - previousIrradianceMean) * (currentIrradianceSample - newIrradianceMean); - float newLuminanceSigma2 = RTXGILinearRGBToLuminance(newIrradianceSigma2); - float newLuminanceMean = RTXGILinearRGBToLuminance(newIrradianceMean); - float coefficientOfVariation = (newLuminanceMean <= c_threshold) ? 0.f : sqrt(newLuminanceSigma2) / newLuminanceMean; + // Compute the coefficient of variation + float3 irradianceMean = result.rgb; + float3 irradianceSigma2 = (irradianceSample - probeIrradianceMean) * (irradianceSample - irradianceMean); + float luminanceSigma2 = RTXGILinearRGBToLuminance(irradianceSigma2); + float luminanceMean = RTXGILinearRGBToLuminance(irradianceMean); + float coefficientOfVariation = (luminanceMean <= c_threshold) ? 0.f : sqrt(luminanceSigma2) / luminanceMean; + ProbeVariability[threadCoords].r = coefficientOfVariation; } #else // Interpolate the new filtered distance with the existing filtered distance in the probe. // A high hysteresis value emphasizes the existing probe filtered distance. - result = float4(lerp(result.rg, previous.rg, hysteresis), 0.f, 1.f); + result = float4(lerp(result.rg, probeIrradianceMean.rg, hysteresis), 0.f, 1.f); #endif Output[DispatchThreadID] = result; diff --git a/rtxgi-sdk/shaders/ddgi/ReductionCS.hlsl b/rtxgi-sdk/shaders/ddgi/ReductionCS.hlsl index dc73949..79e9f09 100644 --- a/rtxgi-sdk/shaders/ddgi/ReductionCS.hlsl +++ b/rtxgi-sdk/shaders/ddgi/ReductionCS.hlsl @@ -384,7 +384,7 @@ void DDGIExtraReductionCS(uint3 GroupID : SV_GroupID, uint3 GroupThreadID : SV_G } } } - float threadAverageValue = footprintInBounds ? threadFootprintValueSum / threadFootprintWeightSum : 0; + float threadAverageValue = (footprintInBounds && threadFootprintWeightSum > 0) ? threadFootprintValueSum / threadFootprintWeightSum : 0; // Per-thread weight will be 1.0 if thread sampled all 4x2 pixels, 0.125 if it only sampled one float ThreadTotalPossibleWeight = ThreadSampleFootprint.x * ThreadSampleFootprint.y; float threadWeight = threadFootprintWeightSum / ThreadTotalPossibleWeight; diff --git a/samples/test-harness/config/cornell.ini b/samples/test-harness/config/cornell.ini index ea311da..581f795 100644 --- a/samples/test-harness/config/cornell.ini +++ b/samples/test-harness/config/cornell.ini @@ -12,6 +12,13 @@ app.root=../../../samples/test-harness/ app.rtxgiSDK=../../../rtxgi-sdk/ app.title=RTXGI Test Harness +# shader compilation +shaders.warningsAsErrors=1 +shaders.disableOptimizations=0 +shaders.disableValidation=0 +shaders.shaderSymbols=1 +shaders.lifetimeMarkers=1 + # scene scene.name=Cornell-Box scene.path=data/gltf/cornell/ diff --git a/samples/test-harness/config/furnace.ini b/samples/test-harness/config/furnace.ini index 31e8f40..8e4ec00 100644 --- a/samples/test-harness/config/furnace.ini +++ b/samples/test-harness/config/furnace.ini @@ -12,6 +12,13 @@ app.root=../../../samples/test-harness/ app.rtxgiSDK=../../../rtxgi-sdk/ app.title=RTXGI Test Harness +# shader compilation +shaders.warningsAsErrors=1 +shaders.disableOptimizations=0 +shaders.disableValidation=0 +shaders.shaderSymbols=0 +shaders.lifetimeMarkers=0 + # scene scene.name=Furnace scene.path=data/gltf/furnace/ diff --git a/samples/test-harness/config/multi-cornell.ini b/samples/test-harness/config/multi-cornell.ini index c03561b..7c561bb 100644 --- a/samples/test-harness/config/multi-cornell.ini +++ b/samples/test-harness/config/multi-cornell.ini @@ -12,6 +12,13 @@ app.root=../../../samples/test-harness/ app.rtxgiSDK=../../../rtxgi-sdk/ app.title=RTXGI Test Harness +# shader compilation +shaders.warningsAsErrors=1 +shaders.disableOptimizations=0 +shaders.disableValidation=0 +shaders.shaderSymbols=0 +shaders.lifetimeMarkers=0 + # scene scene.name=Cornell-Boxes scene.path=data/gltf/multi-cornell/ diff --git a/samples/test-harness/config/sponza.ini b/samples/test-harness/config/sponza.ini index d1431f0..f1e0ca5 100644 --- a/samples/test-harness/config/sponza.ini +++ b/samples/test-harness/config/sponza.ini @@ -12,6 +12,13 @@ app.root=../../../samples/test-harness/ app.rtxgiSDK=../../../rtxgi-sdk/ app.title=RTXGI Test Harness +# shader compilation +shaders.warningsAsErrors=1 +shaders.disableOptimizations=0 +shaders.disableValidation=0 +shaders.shaderSymbols=1 +shaders.lifetimeMarkers=1 + # scene scene.name=Sponza scene.path=data/gltf/sponza/ @@ -78,7 +85,7 @@ ddgi.volume.0.probeNormalBias=0.1 ddgi.volume.0.probeViewBias=0.3 ddgi.volume.0.probeMaxRayDistance=10000 ddgi.volume.0.probeIrradianceThreshold=0.2 -ddgi.volume.0.probeBrightnessThreshold=2.0 +ddgi.volume.0.probeBrightnessThreshold=1.0 ddgi.volume.0.vis.probeVisType=1 ddgi.volume.0.vis.probeRadius=0.1 ddgi.volume.0.vis.probeDistanceDivisor=200 diff --git a/samples/test-harness/config/tunnel.ini b/samples/test-harness/config/tunnel.ini index dc71638..3e7cc71 100644 --- a/samples/test-harness/config/tunnel.ini +++ b/samples/test-harness/config/tunnel.ini @@ -12,6 +12,13 @@ app.root=../../../samples/test-harness/ app.rtxgiSDK=../../../rtxgi-sdk/ app.title=RTXGI Test Harness +# shader compilation +shaders.warningsAsErrors=1 +shaders.disableOptimizations=0 +shaders.disableValidation=0 +shaders.shaderSymbols=0 +shaders.lifetimeMarkers=0 + # scene scene.name=Tunnel scene.path=data/gltf/tunnel/ diff --git a/samples/test-harness/config/two-rooms.ini b/samples/test-harness/config/two-rooms.ini index 0a8cd52..9e513b5 100644 --- a/samples/test-harness/config/two-rooms.ini +++ b/samples/test-harness/config/two-rooms.ini @@ -12,6 +12,13 @@ app.root=../../../samples/test-harness/ app.rtxgiSDK=../../../rtxgi-sdk/ app.title=RTXGI Test Harness +# shader compilation +shaders.warningsAsErrors=1 +shaders.disableOptimizations=0 +shaders.disableValidation=0 +shaders.shaderSymbols=0 +shaders.lifetimeMarkers=0 + # scene scene.name=Two-Rooms scene.path=data/gltf/two-rooms/ @@ -67,7 +74,7 @@ ddgi.volume.0.probeRelocation.enabled=1 ddgi.volume.0.probeRelocation.minFrontfaceDistance=0.1 ddgi.volume.0.probeClassification.enabled=1 ddgi.volume.0.probeVariability.enabled=1 -ddgi.volume.0.probeVariability.threshold=0.035 +ddgi.volume.0.probeVariability.threshold=0.03 ddgi.volume.0.infiniteScrolling.enabled=1 ddgi.volume.0.textures.rayData.format=5 # EDDGIVolumeTextureFormat::F32x2 ddgi.volume.0.textures.irradiance.format=0 # EDDGIVolumeTextureFormat::U32 @@ -85,7 +92,7 @@ ddgi.volume.0.probeNormalBias=1.0 ddgi.volume.0.probeViewBias=6.0 ddgi.volume.0.probeMaxRayDistance=10000 ddgi.volume.0.probeIrradianceThreshold=0.2 -ddgi.volume.0.probeBrightnessThreshold=2.0 +ddgi.volume.0.probeBrightnessThreshold=0.22 ddgi.volume.0.vis.probeVisType=1 ddgi.volume.0.vis.probeRadius=2.0 ddgi.volume.0.vis.probeDistanceDivisor=30 diff --git a/samples/test-harness/include/Configs.h b/samples/test-harness/include/Configs.h index 45ea376..fdf9eef 100644 --- a/samples/test-harness/include/Configs.h +++ b/samples/test-harness/include/Configs.h @@ -144,6 +144,7 @@ namespace Configs { bool enabled = false; bool antialiasing = false; + bool progressive = true; bool shaderExecutionReordering = false; bool reload = false; float rayNormalBias = 0.001f; @@ -197,6 +198,15 @@ namespace Configs float rotationSpeed = 1.f; }; + struct Shaders + { + bool warningsAsErrors = true; // treat warnings as errors + bool disableOptimizations = false; // disable optimizations + bool disableValidation = false; // disable validation + bool shaderSymbols = false; // include symbols in shader blobs + bool lifetimeMarkers = false; // enable variable lifetime markers + }; + struct Application { int width = 1280; @@ -222,6 +232,7 @@ namespace Configs struct Config { Application app; + Shaders shaders; Input input; Scene scene; PathTrace pathTrace; diff --git a/samples/test-harness/include/Direct3D12.h b/samples/test-harness/include/Direct3D12.h index ce2dd07..6987fc4 100644 --- a/samples/test-harness/include/Direct3D12.h +++ b/samples/test-harness/include/Direct3D12.h @@ -31,8 +31,8 @@ namespace Graphics #define D3DCHECK(hr) if(!Check(hr, __FILE__, __LINE__)) { return false; } #ifdef GFX_PERF_INSTRUMENTATION - #define GPU_TIMESTAMP_BEGIN(x) d3d.cmdList->EndQuery(d3dResources.timestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, x); - #define GPU_TIMESTAMP_END(x) d3d.cmdList->EndQuery(d3dResources.timestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, x); + #define GPU_TIMESTAMP_BEGIN(x) d3d.cmdList[d3d.frameIndex]->EndQuery(d3dResources.timestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, x); + #define GPU_TIMESTAMP_END(x) d3d.cmdList[d3d.frameIndex]->EndQuery(d3dResources.timestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, x); #else #define GPU_TIMESTAMP_BEGIN(x) #define GPU_TIMESTAMP_END(x) @@ -99,15 +99,16 @@ namespace Graphics IDXGIFactory7* factory = nullptr; ID3D12Device6* device = nullptr; ID3D12CommandQueue* cmdQueue = nullptr; - ID3D12CommandAllocator* cmdAlloc[2] = { nullptr, nullptr }; - ID3D12GraphicsCommandList4* cmdList = nullptr; + ID3D12CommandAllocator* cmdAlloc[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; + ID3D12GraphicsCommandList4* cmdList[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; IDXGISwapChain4* swapChain = nullptr; - ID3D12Resource* backBuffer[2] = { nullptr, nullptr }; + ID3D12Resource* backBuffer[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; - ID3D12Fence* fence = nullptr; - UINT64 fenceValue = 0; - HANDLE fenceEvent; + ID3D12Fence* fence[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; + ID3D12Fence* immediateFence = nullptr; + HANDLE fenceEvent[MAX_FRAMES_IN_FLIGHT]; + HANDLE immediateFenceEvent; UINT frameIndex = 0; UINT frameNumber = 0; diff --git a/samples/test-harness/include/Graphics.h b/samples/test-harness/include/Graphics.h index 5ff2794..d0168bd 100644 --- a/samples/test-harness/include/Graphics.h +++ b/samples/test-harness/include/Graphics.h @@ -15,6 +15,7 @@ #include "Scenes.h" #include "Instrumentation.h" +const int MAX_FRAMES_IN_FLIGHT = 2; const int MAX_TLAS = 2; const int MAX_TEXTURES = 300; const int MAX_DDGIVOLUMES = 6; @@ -48,13 +49,16 @@ namespace Graphics { bool CreateDevice(Globals& gfx, Configs::Config& config); bool Initialize(const Configs::Config& config, Scenes::Scene& scene, Globals& gfx, GlobalResources& resources, std::ofstream& log); + bool PostInitialize(Globals& gfx, std::ofstream& log); void Update(Globals& gfx, GlobalResources& gfxResources, const Configs::Config& config, Scenes::Scene& scene); - bool Resize(Globals& gfx, GlobalResources& resources, int width, int height, std::ofstream& log); + bool ResizeBegin(Globals& gfx, GlobalResources& resources, int width, int height, std::ofstream& log); + bool ResizeEnd(Globals& gfx); bool ToggleFullscreen(Globals& gfx); bool ResetCmdList(Globals& gfx); bool SubmitCmdList(Globals& gfx); bool Present(Globals& gfx); bool WaitForGPU(Globals& gfx); + bool WaitForPrevGPUFrame(Globals& gfx); bool MoveToNextFrame(Globals& gfx); void Cleanup(Globals& gfx, GlobalResources& gfxResources); diff --git a/samples/test-harness/include/Instrumentation.h b/samples/test-harness/include/Instrumentation.h index d07ba47..ceb9bb1 100644 --- a/samples/test-harness/include/Instrumentation.h +++ b/samples/test-harness/include/Instrumentation.h @@ -18,6 +18,25 @@ namespace Instrumentation { + enum EStatIndex + { + FRAME = 0, + WAITFORGPU, + RESET, + TIMESTAMP_BEGIN, + INPUT, + UPDATE, + PT, + GBUFFER, + DDGI, + DDGI_VIS, + RTAO, + COMPOSITE, + UI, + TIMESTAMP_END, + SUBMIT, + PRESENT, + }; enum class EStatType { diff --git a/samples/test-harness/include/Shaders.h b/samples/test-harness/include/Shaders.h index 3b843ae..f96410a 100644 --- a/samples/test-harness/include/Shaders.h +++ b/samples/test-harness/include/Shaders.h @@ -29,6 +29,7 @@ namespace Shaders IDxcIncludeHandler* includes = nullptr; DxcCreateInstanceProc DxcCreateInstance = nullptr; + Configs::Shaders config = {}; std::string root = ""; std::string rtxgi = ""; @@ -118,6 +119,6 @@ namespace Shaders bool Initialize(const Configs::Config& config, ShaderCompiler& compiler); void AddDefine(ShaderProgram& shader, std::wstring name, std::wstring value); - bool Compile(ShaderCompiler& compiler, ShaderProgram& shader, bool warningsAsErrors = false, bool debugInfo = false); + bool Compile(ShaderCompiler& compiler, ShaderProgram& shader, bool warningsAsErrors = true); void Cleanup(ShaderCompiler& compiler); } diff --git a/samples/test-harness/include/Vulkan.h b/samples/test-harness/include/Vulkan.h index 9df473e..84d033d 100644 --- a/samples/test-harness/include/Vulkan.h +++ b/samples/test-harness/include/Vulkan.h @@ -212,24 +212,23 @@ namespace Graphics int queueFamilyIndex = -1; VkCommandPool commandPool = nullptr; - VkCommandBuffer cmdBuffer[2] = { nullptr, nullptr }; + VkCommandBuffer cmdBuffer[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; VkSurfaceKHR surface = nullptr; VkSwapchainKHR swapChain = nullptr; - VkImage swapChainImage[2] = { nullptr, nullptr }; - VkImageView swapChainImageView[2] = { nullptr, nullptr }; + VkImage swapChainImage[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; + VkImageView swapChainImageView[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; VkFormat swapChainFormat = VK_FORMAT_UNDEFINED; VkColorSpaceKHR swapChainColorSpace; VkRenderPass renderPass = nullptr; - VkFramebuffer frameBuffer[2] = { nullptr, nullptr }; + VkFramebuffer frameBuffer[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; - VkFence fences[2] = { nullptr, nullptr }; - uint32_t frameIndex = 0; - uint32_t frameNumber = 0; + VkFence immediateFence = nullptr; + VkFence fences[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; - VkSemaphore imageAcquiredSemaphore = nullptr; - VkSemaphore renderingCompleteSemaphore = nullptr; + VkSemaphore imageAcquiredSemaphore[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; + VkSemaphore presentSemaphore[MAX_FRAMES_IN_FLIGHT] = { nullptr, nullptr }; VkViewport viewport = {}; VkRect2D scissor = {}; @@ -247,6 +246,10 @@ namespace Graphics int windowWidth = 0; int windowHeight = 0; + uint32_t frameIndex = 0; + uint32_t frameNumber = 1; + uint32_t imageIndex = 0; + int width = 0; int height = 0; bool vsync = true; diff --git a/samples/test-harness/include/graphics/Types.h b/samples/test-harness/include/graphics/Types.h index 2eefe7b..88882d8 100644 --- a/samples/test-harness/include/graphics/Types.h +++ b/samples/test-harness/include/graphics/Types.h @@ -190,6 +190,12 @@ namespace Graphics return data; } + // Pack the progressive accumulation bool into the last bit of numBounces + void SetProgressive(bool value) + { + numBounces |= ((uint)value << 31); + } + // Pack the SER bool into the second-to-last bit of samplesPerPixel void SetShaderExecutionReordering(bool value) { diff --git a/samples/test-harness/shaders/PathTraceRGS.hlsl b/samples/test-harness/shaders/PathTraceRGS.hlsl index 58f138c..eb7ef09 100644 --- a/samples/test-harness/shaders/PathTraceRGS.hlsl +++ b/samples/test-harness/shaders/PathTraceRGS.hlsl @@ -26,7 +26,7 @@ float3 TracePath(RayDesc ray, uint seed) StructuredBuffer Lights = GetLights(); RaytracingAccelerationStructure SceneTLAS = GetAccelerationStructure(SCENE_TLAS_INDEX); - for (int bounceIndex = 0; bounceIndex < GetGlobalConst(pt, numBounces); bounceIndex++) + for (int bounceIndex = 0; bounceIndex < GetPTNumBounces(); bounceIndex++) { // Trace the ray PackedPayload packedPayload = (PackedPayload)0; @@ -168,18 +168,22 @@ void RayGen() // Progressive Accumulation float numPaths = (float)GetPTSamplesPerPixel(); + if (GetGlobalConst(app, frameNumber) > 1) { - // Read the previous color and number of paths - float3 previousColor = PTAccumulation[LaunchIndex.xy].xyz; - float numPreviousPaths = PTAccumulation[LaunchIndex.xy].w; + if (GetPTProgressive()) + { + // Read the previous color and number of paths + float3 previousColor = PTAccumulation[LaunchIndex.xy].xyz; + float numPreviousPaths = PTAccumulation[LaunchIndex.xy].w; - // Add in the new color and number of paths - color = (previousColor + color); - numPaths = (numPreviousPaths + numPaths); + // Add in the new color and number of paths + color = (previousColor + color); + numPaths = (numPreviousPaths + numPaths); - // Store to the accumulation buffer - PTAccumulation[LaunchIndex.xy] = float4(color, numPaths); + // Store to the accumulation buffer + PTAccumulation[LaunchIndex.xy] = float4(color, numPaths); + } } else { diff --git a/samples/test-harness/shaders/include/Descriptors.hlsl b/samples/test-harness/shaders/include/Descriptors.hlsl index 010796f..f0eae1a 100644 --- a/samples/test-harness/shaders/include/Descriptors.hlsl +++ b/samples/test-harness/shaders/include/Descriptors.hlsl @@ -38,6 +38,9 @@ VK_PUSH_CONST ConstantBuffer GlobalConst : register(b0, space0) #define GetGlobalConst(x, y) (GlobalConst.x##_##y) +uint GetPTNumBounces() { return (GetGlobalConst(pt, numBounces) & 0x7FFFFFFF); } +uint GetPTProgressive() { return (GetGlobalConst(pt, numBounces) & 0x80000000); } + uint GetPTSamplesPerPixel() { return (GetGlobalConst(pt, samplesPerPixel) & 0x3FFFFFFF); } uint GetPTAntialiasing() { return (GetGlobalConst(pt, samplesPerPixel) & 0x80000000); } uint GetPTShaderExecutionReordering() { return GetGlobalConst(pt, samplesPerPixel) & 0x40000000; } diff --git a/samples/test-harness/src/Configs.cpp b/samples/test-harness/src/Configs.cpp index c01723e..70bf4c5 100644 --- a/samples/test-harness/src/Configs.cpp +++ b/samples/test-harness/src/Configs.cpp @@ -502,6 +502,29 @@ namespace Configs return false; } + /** + * Parse a shaders configuration entry. + */ + bool ParseConfigShadersEntry(const std::vector& tokens, const std::string& rhs, Config& config, uint32_t lineNumber, std::ofstream& log) + { + // App config entries have exactly 2 tokens + PARSE_CHECK((tokens.size() == 2), lineNumber, log); + + // Extract the data from the rhs, stripping out unnecessary characters + std::string data; + PARSE_CHECK(Extract(rhs, data), lineNumber, log); + + if (tokens[1].compare("warningsAsErrors") == 0) { Store(data, config.shaders.warningsAsErrors); return true; } + if (tokens[1].compare("disableOptimizations") == 0) { Store(data, config.shaders.disableOptimizations); return true; } + if (tokens[1].compare("disableValidation") == 0) { Store(data, config.shaders.disableValidation); return true; } + if (tokens[1].compare("shaderSymbols") == 0) { Store(data, config.shaders.shaderSymbols); return true; } + if (tokens[1].compare("lifetimeMarkers") == 0) { Store(data, config.shaders.lifetimeMarkers); return true; } + + log << "\nUnsupported configuration value specified!"; + PARSE_CHECK(0, lineNumber, log); + return false; + } + /** * Parse an application configuration entry. */ @@ -576,6 +599,7 @@ namespace Configs std::vector tokens = Split(expression[0]); if (tokens[0].compare("app") == 0) { CHECK(ParseConfigAppEntry(tokens, expression[1], config, lineNumber, log), "parse config application entry!", log); continue; }; + if (tokens[0].compare("shaders") == 0) { CHECK(ParseConfigShadersEntry(tokens, expression[1], config, lineNumber, log), "parse config shaders entry!", log); continue; }; if (tokens[0].compare("scene") == 0) { CHECK(ParseConfigSceneEntry(tokens, expression[1], config, lineNumber, log), "parse config scene entry!", log); continue; }; if (tokens[0].compare("input") == 0) { CHECK(ParseConfigInputEntry(tokens, expression[1], config, lineNumber, log), "parse config input entry!", log); continue; }; if (tokens[0].compare("pt") == 0) { CHECK(ParseConfigPathTraceEntry(tokens, expression[1], config, lineNumber, log), "parse config path trace entry!", log); continue; }; diff --git a/samples/test-harness/src/Direct3D12.cpp b/samples/test-harness/src/Direct3D12.cpp index 339a71e..6001508 100644 --- a/samples/test-harness/src/Direct3D12.cpp +++ b/samples/test-harness/src/Direct3D12.cpp @@ -186,54 +186,72 @@ namespace Graphics } /** - * Create a command allocator for each frame. + * Create the command allocators. */ bool CreateCmdAllocators(Globals& d3d) { - for (UINT i = 0; i < 2; i++) + for (UINT index = 0; index < MAX_FRAMES_IN_FLIGHT; index++) { - D3DCHECK(d3d.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&d3d.cmdAlloc[i]))); + D3DCHECK(d3d.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&d3d.cmdAlloc[index]))); #ifdef GFX_NAME_OBJECTS - std::wstring name = L"Command Allocator " + std::to_wstring(i); - d3d.cmdAlloc[i]->SetName(name.c_str()); + std::wstring name = L"Command Allocator " + std::to_wstring(index); + d3d.cmdAlloc[index]->SetName(name.c_str()); #endif } return true; } /** - * Create the command list. + * Create the command lists. */ - bool CreateCmdList(Globals& d3d) + bool CreateCmdLists(Globals& d3d) { - D3DCHECK(d3d.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, d3d.cmdAlloc[d3d.frameIndex], nullptr, IID_PPV_ARGS(&d3d.cmdList))); - D3DCHECK(d3d.cmdList->Close()); - #ifdef GFX_NAME_OBJECTS - d3d.cmdList->SetName(L"Command List"); - #endif + for (UINT index = 0; index < MAX_FRAMES_IN_FLIGHT; index++) + { + D3DCHECK(d3d.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, d3d.cmdAlloc[index], nullptr, IID_PPV_ARGS(&d3d.cmdList[index]))); + D3DCHECK(d3d.cmdList[index]->Close()); + #ifdef GFX_NAME_OBJECTS + std::wstring name = L"Command List " + std::to_wstring(index); + d3d.cmdList[index]->SetName(name.c_str()); + #endif + } return true; } /** - * Create the fence and event handle. + * Create the fences and event handles. */ - bool CreateFence(Globals& d3d) + bool CreateFences(Globals& d3d) { - // Create the fence - D3DCHECK(d3d.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d.fence))); + // Create the frame fences and handles + for (UINT index = 0; index < MAX_FRAMES_IN_FLIGHT; index++) + { + D3DCHECK(d3d.device->CreateFence(1, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d.fence[index]))); + #ifdef GFX_NAME_OBJECTS + std::wstring name = L"Fence " + std::to_wstring(index); + d3d.fence[index]->SetName(name.c_str()); + #endif + + // Create the event handle to use for frame synchronization + d3d.fenceEvent[index] = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS); + if (d3d.fenceEvent[index] == nullptr) + { + if (FAILED(HRESULT_FROM_WIN32(GetLastError()))) return false; + } + } + + // Create the immediate fence and event handle + D3DCHECK(d3d.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&d3d.immediateFence))); #ifdef GFX_NAME_OBJECTS - d3d.fence->SetName(L"Fence"); + d3d.immediateFence->SetName(L"Immediate Fence"); #endif - // Initialize the fence - d3d.fence->Signal(d3d.fenceValue); - - // Create the event handle to use for frame synchronization - d3d.fenceEvent = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS); - if (d3d.fenceEvent == nullptr) + d3d.immediateFenceEvent = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS); + if (d3d.immediateFenceEvent == nullptr) { if (FAILED(HRESULT_FROM_WIN32(GetLastError()))) return false; } + return true; } @@ -244,7 +262,7 @@ namespace Graphics { // Describe the swap chain DXGI_SWAP_CHAIN_DESC1 desc = {}; - desc.BufferCount = 2; + desc.BufferCount = MAX_FRAMES_IN_FLIGHT; desc.Width = d3d.width; desc.Height = d3d.height; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; @@ -266,13 +284,34 @@ namespace Graphics // Get the swap chain interface D3DCHECK(swapChain->QueryInterface(__uuidof(IDXGISwapChain4), reinterpret_cast(&d3d.swapChain))); - SAFE_RELEASE(swapChain); + d3d.frameIndex = d3d.swapChain->GetCurrentBackBufferIndex(); return true; } + /** + * Create the back buffer and RTV. + */ + bool CreateBackBuffer(Globals& d3d, Resources& resources) + { + // Create a RTV for each back buffer + D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = resources.rtvDescHeapStart; + for (UINT bufferIndex = 0; bufferIndex < MAX_FRAMES_IN_FLIGHT; bufferIndex++) + { + D3DCHECK(d3d.swapChain->GetBuffer(bufferIndex, IID_PPV_ARGS(&d3d.backBuffer[bufferIndex]))); + #ifdef GFX_NAME_OBJECTS + std::wstring name = L"Back Buffer " + std::to_wstring(bufferIndex); + d3d.backBuffer[bufferIndex]->SetName(name.c_str()); + #endif + + d3d.device->CreateRenderTargetView(d3d.backBuffer[bufferIndex], nullptr, rtvHandle); + rtvHandle.ptr += resources.rtvDescHeapEntrySize; + } + return true; + } + /** * Create the RTV, Resource, and Sampler descriptor heaps. */ @@ -280,7 +319,7 @@ namespace Graphics { // Describe the RTV heap D3D12_DESCRIPTOR_HEAP_DESC rtvDesc = {}; - rtvDesc.NumDescriptors = 2; + rtvDesc.NumDescriptors = MAX_FRAMES_IN_FLIGHT; rtvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; rtvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; @@ -365,35 +404,6 @@ namespace Graphics return true; } - /** - * Create the back buffer and RTV. - */ - bool CreateBackBuffer(Globals& d3d, Resources& resources) - { - // Create a RTV for each back buffer - D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = resources.rtvDescHeapStart; - for (UINT bufferIndex = 0; bufferIndex < 2; bufferIndex++) - { - D3DCHECK(d3d.swapChain->GetBuffer(bufferIndex, IID_PPV_ARGS(&d3d.backBuffer[bufferIndex]))); - - d3d.device->CreateRenderTargetView(d3d.backBuffer[bufferIndex], nullptr, rtvHandle); - - #ifdef GFX_NAME_OBJECTS - if (bufferIndex == 0) - { - d3d.backBuffer[bufferIndex]->SetName(L"Back Buffer 0"); - } - else - { - d3d.backBuffer[bufferIndex]->SetName(L"Back Buffer 1"); - } - #endif - - rtvHandle.ptr += resources.rtvDescHeapEntrySize; - } - return true; - } - /** * Create the raster viewport. */ @@ -503,7 +513,7 @@ namespace Graphics (*upload)->Unmap(0, nullptr); // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(*device, 0, *upload, 0, sizeInBytes); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(*device, 0, *upload, 0, sizeInBytes); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -513,7 +523,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); return true; } @@ -555,7 +565,7 @@ namespace Graphics (*upload)->Unmap(0, nullptr); // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(*device, 0, *upload, 0, sizeInBytes); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(*device, 0, *upload, 0, sizeInBytes); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -565,7 +575,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); return true; } @@ -649,7 +659,7 @@ namespace Graphics buildDesc.ScratchAccelerationStructureData = resources.blas[mesh.index].scratch->GetGPUVirtualAddress(); buildDesc.DestAccelerationStructureData = resources.blas[mesh.index].as->GetGPUVirtualAddress(); - d3d.cmdList->BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr); + d3d.cmdList[d3d.frameIndex]->BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr); return true; } @@ -702,14 +712,14 @@ namespace Graphics buildDesc.ScratchAccelerationStructureData = resources.tlas.scratch->GetGPUVirtualAddress(); buildDesc.DestAccelerationStructureData = resources.tlas.as->GetGPUVirtualAddress(); - d3d.cmdList->BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr); + d3d.cmdList[d3d.frameIndex]->BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr); // Wait for the TLAS build to complete D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.UAV.pResource = resources.tlas.as; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); return true; } @@ -845,7 +855,7 @@ namespace Graphics destination.SubresourceIndex = mipIndex; // Copy the texture from the upload heap to the default heap - d3d.cmdList->CopyTextureRegion(&destination, 0, 0, 0, &source, NULL); + d3d.cmdList[d3d.frameIndex]->CopyTextureRegion(&destination, 0, 0, 0, &source, NULL); } // Transition the default heap texture resource to a shader resource @@ -856,7 +866,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); } return true; @@ -1247,17 +1257,21 @@ namespace Graphics // Leave fullscreen mode if necessary if (d3d.fullscreen) d3d.swapChain->SetFullscreenState(FALSE, nullptr); - CloseHandle(d3d.fenceEvent); Shaders::Cleanup(d3d.shaderCompiler); // Release core D3D12 objects - SAFE_RELEASE(d3d.backBuffer[0]); - SAFE_RELEASE(d3d.backBuffer[1]); + for (UINT index = 0; index < MAX_FRAMES_IN_FLIGHT; index++) + { + SAFE_RELEASE(d3d.backBuffer[index]); + SAFE_RELEASE(d3d.cmdList[index]); + SAFE_RELEASE(d3d.cmdAlloc[index]); + SAFE_RELEASE(d3d.fence[index]); + CloseHandle(d3d.fenceEvent[index]); + } + SAFE_RELEASE(d3d.immediateFence); + CloseHandle(d3d.immediateFenceEvent); + SAFE_RELEASE(d3d.swapChain); - SAFE_RELEASE(d3d.fence); - SAFE_RELEASE(d3d.cmdList); - SAFE_RELEASE(d3d.cmdAlloc[0]); - SAFE_RELEASE(d3d.cmdAlloc[1]); SAFE_RELEASE(d3d.cmdQueue); SAFE_RELEASE(d3d.device); SAFE_RELEASE(d3d.factory); @@ -1334,7 +1348,7 @@ namespace Graphics } // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(resources.lightsSTB, 0, resources.lightsSTBUpload, 0, size); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.lightsSTB, 0, resources.lightsSTBUpload, 0, size); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -1344,7 +1358,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); // Add the lights structured buffer SRV to the descriptor heap D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; @@ -1412,7 +1426,7 @@ namespace Graphics resources.materialsSTBUpload->Unmap(0, nullptr); // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(resources.materialsSTB, 0, resources.materialsSTBUpload, 0, size); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.materialsSTB, 0, resources.materialsSTBUpload, 0, size); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -1422,7 +1436,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); // Add the materials structured buffer SRV to the descriptor heap D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; @@ -1515,8 +1529,8 @@ namespace Graphics resources.geometryDataRBUpload->Unmap(0, nullptr); // Schedule a copy of the upload buffers to the device buffers - d3d.cmdList->CopyBufferRegion(resources.meshOffsetsRB, 0, resources.meshOffsetsRBUpload, 0, meshOffsetsSize); - d3d.cmdList->CopyBufferRegion(resources.geometryDataRB, 0, resources.geometryDataRBUpload, 0, geometryDataSize); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.meshOffsetsRB, 0, resources.meshOffsetsRBUpload, 0, meshOffsetsSize); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.geometryDataRB, 0, resources.geometryDataRBUpload, 0, geometryDataSize); // Transition the default heap resources to generic read after the copies are complete std::vector barriers; @@ -1532,7 +1546,7 @@ namespace Graphics barrier.Transition.pResource = resources.geometryDataRB; barriers.push_back(barrier); - d3d.cmdList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(static_cast(barriers.size()), barriers.data()); // Add the mesh offsets ByteAddressBuffer SRV to the descriptor heap D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; @@ -1582,7 +1596,7 @@ namespace Graphics resources.tlas.instancesUpload->Unmap(0, nullptr); // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(resources.tlas.instances, 0, resources.tlas.instancesUpload, 0, size); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.tlas.instances, 0, resources.tlas.instancesUpload, 0, size); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -1592,7 +1606,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); // Add the TLAS instances structured buffer SRV to the descriptor heap D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; @@ -1709,7 +1723,7 @@ namespace Graphics D3D12_RESOURCE_BARRIER uavBarrier = {}; uavBarrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; uavBarrier.UAV.pResource = nullptr; - d3d.cmdList->ResourceBarrier(1, &uavBarrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &uavBarrier); return true; } @@ -1865,21 +1879,21 @@ namespace Graphics ID3D12CommandAllocator* commandAlloc = nullptr; D3DCHECK(d3d.device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&commandAlloc))); #ifdef GFX_NAME_OBJECTS - d3d.cmdList->SetName(L"WriteResourceToDisk Command Allocator"); + commandAlloc->SetName(L"WriteResourceToDisk Command Allocator"); #endif // Create a command list ID3D12GraphicsCommandList* commandList = nullptr; D3DCHECK(d3d.device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, commandAlloc, nullptr, IID_PPV_ARGS(&commandList))); #ifdef GFX_NAME_OBJECTS - d3d.cmdList->SetName(L"WriteResourceToDisk Command List"); + commandList->SetName(L"WriteResourceToDisk Command List"); #endif // Create fence ID3D12Fence* fence = nullptr; D3DCHECK(d3d.device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&fence))); #ifdef GFX_NAME_OBJECTS - d3d.cmdList->SetName(L"WriteResourceToDisk Fence"); + fence->SetName(L"WriteResourceToDisk Fence"); #endif // Get the resource descriptor @@ -1979,8 +1993,7 @@ namespace Graphics D3DCHECK(d3d.cmdQueue->Signal(fence, 1)); // Block until the copy is complete - while (fence->GetCompletedValue() < 1) - SwitchToThread(); + while (fence->GetCompletedValue() < 1) SwitchToThread(); // Copy the staging resources and write them to disk bool result = true; @@ -2446,7 +2459,7 @@ namespace Graphics return true; } - /* + /** * Initialize D3D12. */ bool Initialize(const Configs::Config& config, Scenes::Scene& scene, Globals& d3d, Resources& resources, std::ofstream& log) @@ -2464,21 +2477,21 @@ namespace Graphics // Initialize the shader compiler CHECK(Shaders::Initialize(config, d3d.shaderCompiler), "initialize the shader compiler!", log); - // Create core D3D12 objects + // Create D3D12 device objects CHECK(CreateCmdQueue(d3d), "create command queue!", log); CHECK(CreateCmdAllocators(d3d), "create command allocators!", log); - CHECK(CreateFence(d3d), "create fence!", log); - CHECK(CreateSwapChain(d3d), " create swap chain!", log); - CHECK(CreateCmdList(d3d), "create command list!", log); - CHECK(ResetCmdList(d3d), " reset command list!", log); + CHECK(CreateFences(d3d), "create fence!", log); + CHECK(CreateCmdLists(d3d), "create command list!", log); CHECK(CreateDescriptorHeaps(d3d, resources, scene), "create descriptor heaps!", log); CHECK(CreateQueryHeaps(d3d, resources), "create query heaps!", log); CHECK(CreateGlobalRootSignature(d3d, resources), "create global root signature!", log); + CHECK(CreateSwapChain(d3d), " create swap chain!", log); CHECK(CreateBackBuffer(d3d, resources), "create back buffers!", log); CHECK(CreateRenderTargets(d3d, resources), "create render targets!", log); CHECK(CreateSamplers(d3d, resources), "create samplers!", log); CHECK(CreateViewport(d3d), "create viewport!", log); CHECK(CreateScissor(d3d), "create scissor!", log); + CHECK(ResetCmdList(d3d), " reset command list!", log); // Create default graphics resources CHECK(LoadAndCreateDefaultTextures(d3d, resources, config, log), "load and create default textures!", log); @@ -2495,7 +2508,11 @@ namespace Graphics CHECK(CreateSceneTextures(d3d, resources, scene, log), "create scene textures!", log); // Execute GPU work to finish initialization - SubmitCmdList(d3d); + // Close and submit the command list + D3DCHECK(d3d.cmdList[d3d.frameIndex]->Close()); + ID3D12CommandList* pGraphicsList = { d3d.cmdList[d3d.frameIndex] }; + d3d.cmdQueue->ExecuteCommandLists(1, &pGraphicsList); + WaitForGPU(d3d); ResetCmdList(d3d); @@ -2536,6 +2553,21 @@ namespace Graphics return true; } + /** + * Post initialization tasks. + */ + bool PostInitialize(Globals& d3d, std::ofstream& log) + { + // Close and submit the command list + D3DCHECK(d3d.cmdList[d3d.frameIndex]->Close()); + ID3D12CommandList* pGraphicsList = { d3d.cmdList[d3d.frameIndex] }; + d3d.cmdQueue->ExecuteCommandLists(1, &pGraphicsList); + + WaitForGPU(d3d); + + return true; + } + /** * Update constant buffers. */ @@ -2576,17 +2608,17 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); // Schedule a copy of the upload buffer to the device buffer UINT size = Scenes::Light::GetGPUDataSize() * lastDirtyLight; - d3d.cmdList->CopyBufferRegion(resources.lightsSTB, 0, resources.lightsSTBUpload, 0, size); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.lightsSTB, 0, resources.lightsSTBUpload, 0, size); // Transition the lights device buffer to generic read after the copy is complete barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); } } @@ -2603,9 +2635,15 @@ namespace Graphics d3d.scissor.right = d3d.width; d3d.scissor.bottom = d3d.height; - // Release back buffer and GBuffer - SAFE_RELEASE(d3d.backBuffer[0]); - SAFE_RELEASE(d3d.backBuffer[1]); + // Wait for GPU idle + WaitForGPU(d3d); + + // Release back buffer and GBuffer resources + for (UINT index = 0; index < MAX_FRAMES_IN_FLIGHT; index++) + { + d3d.fence[index]->Signal(1); // reset frame fences to initial state + SAFE_RELEASE(d3d.backBuffer[index]); + } SAFE_RELEASE(resources.rt.GBufferA); SAFE_RELEASE(resources.rt.GBufferB); SAFE_RELEASE(resources.rt.GBufferC); @@ -2616,11 +2654,11 @@ namespace Graphics d3d.swapChain->GetDesc(&desc); D3DCHECK(d3d.swapChain->ResizeBuffers(2, d3d.width, d3d.height, desc.BufferDesc.Format, desc.Flags)); - // Recreate the swapchain, back buffer, and GBuffer + // Recreate the back buffer and GBuffer resources if (!CreateBackBuffer(d3d, resources)) return false; if (!CreateRenderTargets(d3d, resources)) return false; - // Reset the frame index + // Reset the current frame index (always zero since it was just re-created) d3d.frameIndex = d3d.swapChain->GetCurrentBackBufferIndex(); // Reset the frame number @@ -2634,7 +2672,7 @@ namespace Graphics } /** - * Reset the command list. + * Reset the current frame's command list. */ bool ResetCmdList(Globals& d3d) { @@ -2642,23 +2680,26 @@ namespace Graphics D3DCHECK(d3d.cmdAlloc[d3d.frameIndex]->Reset()); // Reset the command list for the current frame - D3DCHECK(d3d.cmdList->Reset(d3d.cmdAlloc[d3d.frameIndex], nullptr)); + D3DCHECK(d3d.cmdList[d3d.frameIndex]->Reset(d3d.cmdAlloc[d3d.frameIndex], nullptr)); return true; } /** - * Submit the command list. + * Submit the current frame's command list. */ bool SubmitCmdList(Globals& d3d) { // Close the command list - D3DCHECK(d3d.cmdList->Close()); + D3DCHECK(d3d.cmdList[d3d.frameIndex]->Close()); // Submit the command list - ID3D12CommandList* pGraphicsList = { d3d.cmdList }; + ID3D12CommandList* pGraphicsList = { d3d.cmdList[d3d.frameIndex] }; d3d.cmdQueue->ExecuteCommandLists(1, &pGraphicsList); + // Schedule a fence update in the queue (from the GPU) + D3DCHECK(d3d.cmdQueue->Signal(d3d.fence[d3d.frameIndex], 1)); + return true; } @@ -2675,23 +2716,34 @@ namespace Graphics } /** - * Wait for pending GPU work to complete. + * Wait for the previous frame's executing GPU work to complete. */ - bool WaitForGPU(Globals& d3d) + bool WaitForPrevGPUFrame(Globals& d3d) { - // Increment the fence value - d3d.fenceValue++; + // Wait (on the CPU) until the previous frame's fence has been processed on the GPU + D3DCHECK(d3d.fence[d3d.frameIndex]->SetEventOnCompletion(1, d3d.fenceEvent[d3d.frameIndex])); + WaitForSingleObjectEx(d3d.fenceEvent[d3d.frameIndex], INFINITE, FALSE); + + // Reset the fence + d3d.fence[d3d.frameIndex]->Signal(0); + + return true; + } + /** + * Wait (right now) for GPU work to complete. + */ + bool WaitForGPU(Globals& d3d) + { // Schedule a fence update in the queue (from the GPU) - D3DCHECK(d3d.cmdQueue->Signal(d3d.fence, d3d.fenceValue)); + D3DCHECK(d3d.cmdQueue->Signal(d3d.immediateFence, 1)); // Wait (on the CPU) until the fence has been processed on the GPU - UINT64 fence = d3d.fence->GetCompletedValue(); - if (fence < d3d.fenceValue) - { - D3DCHECK(d3d.fence->SetEventOnCompletion(d3d.fenceValue, d3d.fenceEvent)); - WaitForSingleObjectEx(d3d.fenceEvent, INFINITE, FALSE); - } + D3DCHECK(d3d.immediateFence->SetEventOnCompletion(1, d3d.immediateFenceEvent)); + WaitForSingleObjectEx(d3d.immediateFenceEvent, INFINITE, FALSE); + + // Wait is complete, reset the immediate fence + d3d.immediateFence->Signal(0); return true; } @@ -2712,17 +2764,17 @@ namespace Graphics #ifdef GFX_PERF_INSTRUMENTATION void BeginFrame(Globals& d3d, GlobalResources& resources, Instrumentation::Performance& performance) { - d3d.cmdList->EndQuery(resources.timestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, performance.gpuTimes[0]->GetGPUQueryBeginIndex()); + d3d.cmdList[d3d.frameIndex]->EndQuery(resources.timestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, performance.gpuTimes[0]->GetGPUQueryBeginIndex()); } void EndFrame(Globals& d3d, GlobalResources& resources, Instrumentation::Performance& performance) { - d3d.cmdList->EndQuery(resources.timestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, performance.gpuTimes[0]->GetGPUQueryEndIndex()); + d3d.cmdList[d3d.frameIndex]->EndQuery(resources.timestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, performance.gpuTimes[0]->GetGPUQueryEndIndex()); } void ResolveTimestamps(Globals& d3d, GlobalResources& resources, Instrumentation::Performance& performance) { - d3d.cmdList->ResolveQueryData(resources.timestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, performance.GetNumActiveGPUQueries(), resources.timestamps, 0); + d3d.cmdList[d3d.frameIndex]->ResolveQueryData(resources.timestampHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, performance.GetNumActiveGPUQueries(), resources.timestamps, 0); } bool UpdateTimestamps(Globals& d3d, GlobalResources& resources, Instrumentation::Performance& performance) @@ -2795,6 +2847,14 @@ namespace Graphics return Graphics::D3D12::Initialize(config, scene, gfx, resources, log); } + /** + * Perform any remaining post-initialization tasks. + */ + bool PostInitialize(Globals& gfx, std::ofstream& log) + { + return Graphics::D3D12::PostInitialize(gfx, log); + } + /** * Update root constants and constant buffers. */ @@ -2806,11 +2866,16 @@ namespace Graphics /** * Resize the swapchain. */ - bool Resize(Globals& gfx, GlobalResources& gfxResources, int width, int height, std::ofstream& log) + bool ResizeBegin(Globals& gfx, GlobalResources& gfxResources, int width, int height, std::ofstream& log) { return Graphics::D3D12::Resize(gfx, gfxResources, width, height, log); } + bool ResizeEnd(Globals& gfx) + { + return true; // nothing to do here in D3D12 + } + /** * Toggle between windowed and fullscreen borderless modes. */ @@ -2820,7 +2885,7 @@ namespace Graphics } /** - * Reset the graphics command list. + * Reset the current frame's command list. */ bool ResetCmdList(Globals& gfx) { @@ -2828,7 +2893,7 @@ namespace Graphics } /** - * Submit the graphics command list. + * Submit the current frame's command list. */ bool SubmitCmdList(Globals& gfx) { @@ -2844,13 +2909,21 @@ namespace Graphics } /** - * Wait for the graphics device to idle. + * Wait (right now) for the graphics device to idle. */ bool WaitForGPU(Globals& gfx) { return Graphics::D3D12::WaitForGPU(gfx); } + /** + * Wait for the previous frame's graphics commands to complete on the GPU. + */ + bool WaitForPrevGPUFrame(Globals& gfx) + { + return Graphics::D3D12::WaitForPrevGPUFrame(gfx); + } + /** * Move to the next the next frame. */ diff --git a/samples/test-harness/src/Shaders.cpp b/samples/test-harness/src/Shaders.cpp index a291edc..0832fb8 100644 --- a/samples/test-harness/src/Shaders.cpp +++ b/samples/test-harness/src/Shaders.cpp @@ -87,6 +87,7 @@ namespace Shaders // Create the default include handler if(FAILED(dxc.utils->CreateDefaultIncludeHandler(&dxc.includes))) return false; + dxc.config = config.shaders; dxc.root = config.app.root; dxc.rtxgi = config.app.rtxgi; @@ -112,7 +113,7 @@ namespace Shaders /** * Compile a shader with the DirectX Shader Compiler (DXC). */ - bool Compile(ShaderCompiler& dxc, ShaderProgram& shader, bool warningsAsErrors, bool debugInfo) + bool Compile(ShaderCompiler& dxc, ShaderProgram& shader, bool warningsAsErrors) { uint32_t codePage = 0; IDxcBlobEncoding* pShaderSource = nullptr; @@ -133,13 +134,20 @@ namespace Shaders AddDefine(shader, L"HLSL", L"1"); // Treat warnings as errors - if(warningsAsErrors) shader.arguments.push_back(L"-WX"); + if(warningsAsErrors || dxc.config.warningsAsErrors) shader.arguments.push_back(L"-WX"); + + // Disable compilation optimizations + if(dxc.config.disableOptimizations) shader.arguments.push_back(L"-Od"); + + // Disable validation + if(dxc.config.disableValidation) shader.arguments.push_back(L"-Vd"); // Add with debug information to compiled shaders - if(debugInfo) + if(dxc.config.shaderSymbols) { - shader.arguments.push_back(L"-Zi"); - shader.arguments.push_back(L"-Qembed_debug"); + shader.arguments.push_back(L"-Zi"); // enable debug information (symbols) + shader.arguments.push_back(L"-Qembed_debug"); // embed shader pdb (symbols) in the shader + if(dxc.config.lifetimeMarkers) shader.arguments.push_back(L"-enable-lifetime-markers"); // enable variable lifetime markers } // Add include directories diff --git a/samples/test-harness/src/UI.cpp b/samples/test-harness/src/UI.cpp index d87d9f5..d8b731b 100644 --- a/samples/test-harness/src/UI.cpp +++ b/samples/test-harness/src/UI.cpp @@ -33,6 +33,7 @@ namespace Graphics static bool resChanged = false; static float debugWindowWidth = 500.f; static float perfWindowWidth = 300.f; + static float perfWindowHeight = 640.f; static float indent = 150.f; struct ResolutionOption { @@ -686,6 +687,9 @@ namespace Graphics ImGui::Checkbox("Antialiasing", &config.pathTrace.antialiasing); ImGui::SameLine(); AddQuestionMark("Enable or disable antialiasing"); + ImGui::Checkbox("Progressive Accumulation", &config.pathTrace.progressive); + ImGui::SameLine(); AddQuestionMark("Enable or disable progressive accumulation"); + if (gfx.supportsShaderExecutionReordering) { ImGui::Checkbox("Shader Execution Reordering", &config.pathTrace.shaderExecutionReordering); @@ -1205,7 +1209,7 @@ namespace Graphics SetupStyle(); // Size the debug window based on the application height - ImGui::SetNextWindowSize(ImVec2(perfWindowWidth, 550.f)); + ImGui::SetNextWindowSize(ImVec2(perfWindowWidth, perfWindowHeight)); ImGui::Begin("Detailed Performance", NULL, ImGuiWindowFlags_AlwaysAutoResize); ImVec4 colors[3] = @@ -1215,80 +1219,148 @@ namespace Graphics ImVec4(1.f, 0.f, 0.f, 1.f), }; - // GPU Performance - ImGui::TextColored(ImVec4(0.f, 0.71f, 0.071f, 1.f), "GPU"); - - // Display GPU times - uint32_t cIdx = GetPerfColor(performance.gpuTimes[0]->average); - ImGui::TextColored(colors[cIdx], "%s: %.3lf ms (avg, last %u frames)", performance.gpuTimes[0]->name.c_str(), performance.gpuTimes[0]->average, performance.gpuTimes[0]->sampleSize); - ImGui::Separator(); - - if (config.app.renderMode == ERenderMode::PATH_TRACE) - { - cIdx = GetPerfColor(performance.gpuTimes[1]->average); - ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", performance.gpuTimes[1]->name.c_str(), performance.gpuTimes[1]->average); - } - else if(config.app.renderMode == ERenderMode::DDGI) + // CPU Performance { - for (size_t index = 2; index < (performance.gpuTimes.size() - 1); index++) + ImGui::TextColored(ImVec4(0.259f, 0.529f, 0.961f, 1.f), "CPU"); + + // Get the stats + Instrumentation::Stat* frameStat = performance.cpuTimes[Instrumentation::EStatIndex::FRAME]; + Instrumentation::Stat* waitStat = performance.cpuTimes[Instrumentation::EStatIndex::WAITFORGPU]; + Instrumentation::Stat* resetStat = performance.cpuTimes[Instrumentation::EStatIndex::RESET]; + Instrumentation::Stat* timestampBeginStat = performance.cpuTimes[Instrumentation::EStatIndex::TIMESTAMP_BEGIN]; + Instrumentation::Stat* inputStat = performance.cpuTimes[Instrumentation::EStatIndex::INPUT]; + Instrumentation::Stat* updateStat = performance.cpuTimes[Instrumentation::EStatIndex::UPDATE]; + Instrumentation::Stat* renderStat = nullptr; + Instrumentation::Stat* uiStat = performance.cpuTimes[Instrumentation::EStatIndex::UI]; + Instrumentation::Stat* timestampEndStat = performance.cpuTimes[Instrumentation::EStatIndex::TIMESTAMP_END]; + Instrumentation::Stat* submitStat = performance.cpuTimes[Instrumentation::EStatIndex::SUBMIT]; + Instrumentation::Stat* presentStat = performance.cpuTimes[Instrumentation::EStatIndex::PRESENT]; + + // Compute the total render time + double renderTotal = resetStat->average; + if (config.app.renderMode == ERenderMode::PATH_TRACE) { - cIdx = GetPerfColor(performance.gpuTimes[index]->average); - ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", performance.gpuTimes[index]->name.c_str(), performance.gpuTimes[index]->average); + renderStat = performance.cpuTimes[Instrumentation::EStatIndex::PT]; + renderTotal += renderStat->average; + } + else if (config.app.renderMode == ERenderMode::DDGI) + { + for (size_t index = Instrumentation::EStatIndex::GBUFFER; index < Instrumentation::EStatIndex::UI; index++) + { + renderStat = performance.cpuTimes[index]; + renderTotal += renderStat->average; + } } - } - // UI - cIdx = GetPerfColor(performance.gpuTimes.back()->average); - ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", performance.gpuTimes.back()->name.c_str(), performance.gpuTimes.back()->average); + renderTotal += uiStat->average; + renderTotal += submitStat->average; + renderTotal += presentStat->average; - ImGui::Separator(); - ImGui::NewLine(); + // Frame + uint32_t cIdx = GetPerfColor(frameStat->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms (avg, last %u frames)", frameStat->name.c_str(), frameStat->average, frameStat->sampleSize); + ImGui::Separator(); - // CPU Performance - double gfxTotal = 0; - ImGui::TextColored(ImVec4(0.259f, 0.529f, 0.961f, 1.f), "CPU"); + ImGui::Indent(10.f); - cIdx = GetPerfColor(performance.cpuTimes[0]->average); - ImGui::TextColored(colors[cIdx], "%s: %.3lf ms (avg, last %u frames)", performance.cpuTimes[0]->name.c_str(), performance.cpuTimes[0]->average, performance.cpuTimes[0]->sampleSize); - ImGui::Separator(); - ImGui::Text("%s: %.3lf ms", performance.cpuTimes[1]->name.c_str(), performance.cpuTimes[1]->average); // input - ImGui::Text("%s: %.3lf ms", performance.cpuTimes[2]->name.c_str(), performance.cpuTimes[2]->average); // update + // Wait for GPU + cIdx = GetPerfColor(waitStat->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", waitStat->name.c_str(), waitStat->average); - ImGui::Separator(); + // Input, Update + ImGui::Text("%s: %.3lf ms", inputStat->name.c_str(), inputStat->average); + ImGui::Text("%s: %.3lf ms", updateStat->name.c_str(), updateStat->average); - if (config.app.renderMode == ERenderMode::PATH_TRACE) - { - gfxTotal += performance.cpuTimes[3]->average; - cIdx = GetPerfColor(performance.cpuTimes[3]->average); - ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", performance.cpuTimes[3]->name.c_str(), performance.cpuTimes[3]->average); - } - else if (config.app.renderMode == ERenderMode::DDGI) - { - for (size_t index = 4; index < performance.cpuTimes.size() - 2; index++) + // Timetamp + double timestampTotal = (timestampBeginStat->average + timestampEndStat->average); + ImGui::Text("%s: %.3lf ms", "Timestamps", timestampTotal); + + // Render + cIdx = GetPerfColor(renderTotal); + ImGui::TextColored(colors[cIdx], "Render: %.3lf ms", renderTotal); + + // Totals + double cpuTotal = (inputStat->average + updateStat->average + timestampTotal + renderTotal); + cIdx = GetPerfColor(cpuTotal); + ImGui::TextColored(colors[cIdx], "Total: %.3lf ms", inputStat->average + updateStat->average + timestampTotal + cpuTotal); + + ImGui::Separator(); + + // Idle + double idle = frameStat->average - (cpuTotal + waitStat->average); + ImGui::Text("Idle: %.3lf ms", idle); + + ImGui::Separator(); + + ImGui::Unindent(10.f); + ImGui::TextColored(ImVec4(0.259f, 0.529f, 0.961f, 1.f), "Render (CPU)"); + ImGui::Indent(10.f); + + // Reset + cIdx = GetPerfColor(resetStat->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", resetStat->name.c_str(), resetStat->average); + + if (config.app.renderMode == ERenderMode::PATH_TRACE) + { + renderStat = performance.cpuTimes[Instrumentation::EStatIndex::PT]; + cIdx = GetPerfColor(renderStat->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", renderStat->name.c_str(), renderStat->average); + } + else if (config.app.renderMode == ERenderMode::DDGI) { - gfxTotal += performance.cpuTimes[index]->average; - cIdx = GetPerfColor(performance.cpuTimes[index]->average); - ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", performance.cpuTimes[index]->name.c_str(), performance.cpuTimes[index]->average); + for (size_t index = Instrumentation::EStatIndex::GBUFFER; index < Instrumentation::EStatIndex::UI; index++) + { + renderStat = performance.cpuTimes[index]; + cIdx = GetPerfColor(renderStat->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", renderStat->name.c_str(), renderStat->average); + } } + + // UI + cIdx = GetPerfColor(uiStat->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", uiStat->name.c_str(), uiStat->average); + + // Submit + cIdx = GetPerfColor(submitStat->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", submitStat->name.c_str(), submitStat->average); + + // Present + cIdx = GetPerfColor(presentStat->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", presentStat->name.c_str(), presentStat->average); + + ImGui::Unindent(10.f); + ImGui::Separator(); } - // UI - gfxTotal += performance.cpuTimes[performance.cpuTimes.size() - 2]->average; - cIdx = GetPerfColor(performance.cpuTimes[performance.cpuTimes.size() - 2]->average); - ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", performance.cpuTimes[performance.cpuTimes.size() - 2]->name.c_str(), performance.cpuTimes[performance.cpuTimes.size() - 2]->average); + // GPU Performance + { + ImGui::TextColored(ImVec4(0.f, 0.71f, 0.071f, 1.f), "GPU"); - // Submit / Present - gfxTotal += performance.cpuTimes.back()->average; - cIdx = GetPerfColor(performance.cpuTimes.back()->average); - ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", performance.cpuTimes.back()->name.c_str(), performance.cpuTimes.back()->average); + // Display GPU times + uint32_t cIdx = GetPerfColor(performance.gpuTimes[0]->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms (avg, last %u frames)", performance.gpuTimes[0]->name.c_str(), performance.gpuTimes[0]->average, performance.gpuTimes[0]->sampleSize); + ImGui::Separator(); - // Idle - double idle = performance.cpuTimes[0]->average - (performance.cpuTimes[1]->average + performance.cpuTimes[2]->average + gfxTotal); - ImGui::Text("GFX Total: %.3lf ms", gfxTotal); - ImGui::Separator(); - ImGui::Text("Idle: %.3lf ms", idle); + if (config.app.renderMode == ERenderMode::PATH_TRACE) + { + cIdx = GetPerfColor(performance.gpuTimes[1]->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", performance.gpuTimes[1]->name.c_str(), performance.gpuTimes[1]->average); + } + else if (config.app.renderMode == ERenderMode::DDGI) + { + for (size_t index = 2; index < (performance.gpuTimes.size() - 1); index++) + { + cIdx = GetPerfColor(performance.gpuTimes[index]->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", performance.gpuTimes[index]->name.c_str(), performance.gpuTimes[index]->average); + } + } - ImGui::Separator(); + // UI + cIdx = GetPerfColor(performance.gpuTimes.back()->average); + ImGui::TextColored(colors[cIdx], "%s: %.3lf ms", performance.gpuTimes.back()->name.c_str(), performance.gpuTimes.back()->average); + + ImGui::Separator(); + } ImGui::SetWindowPos("Detailed Performance", ImVec2((gfx.width - ImGui::GetWindowWidth() - debugWindowWidth - 20.f), 20)); ImGui::End(); diff --git a/samples/test-harness/src/Vulkan.cpp b/samples/test-harness/src/Vulkan.cpp index 81403ba..ac5ca61 100644 --- a/samples/test-harness/src/Vulkan.cpp +++ b/samples/test-harness/src/Vulkan.cpp @@ -232,7 +232,7 @@ namespace Graphics // 3: VK_EXT_DEBUG_UTILS_EXTENSION_NAME std::vector extensionNames(glfwExtensions, glfwExtensions + glfwExtensionCount); extensionNames.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - #if _DEBUG + #if _DEBUG || GFX_NAME_OBJECTS extensionNames.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); #endif @@ -265,8 +265,8 @@ namespace Graphics VkApplicationInfo applicationInfo = {}; applicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; applicationInfo.apiVersion = VK_API_VERSION_1_2; - applicationInfo.applicationVersion = VK_MAKE_VERSION(1, 2, 0); - applicationInfo.engineVersion = VK_MAKE_VERSION(1, 2, 0); + applicationInfo.applicationVersion = VK_MAKE_VERSION(RTXGI_VERSION::major, RTXGI_VERSION::minor, RTXGI_VERSION::revision); + applicationInfo.engineVersion = VK_MAKE_VERSION(RTXGI_VERSION::major, RTXGI_VERSION::minor, RTXGI_VERSION::revision); applicationInfo.pApplicationName = "RTXGI Test Harness"; applicationInfo.pEngineName = "RTXGI Test Harness"; @@ -414,6 +414,7 @@ namespace Graphics #ifdef GFX_NAME_OBJECTS SetObjectName(vk.device, reinterpret_cast(vk.device), "VKDevice", VK_OBJECT_TYPE_DEVICE); SetObjectName(vk.device, reinterpret_cast(vk.queue), "VKQueue", VK_OBJECT_TYPE_QUEUE); + SetObjectName(vk.device, reinterpret_cast(vk.surface), "VKSurface", VK_OBJECT_TYPE_SURFACE_KHR); #endif // Get the properties of the device (include ray tracing properties) @@ -447,15 +448,21 @@ namespace Graphics { VkFenceCreateInfo fenceCreateInfo = {}; fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - for (uint32_t fenceIndex = 0; fenceIndex < 2; fenceIndex++) + for (uint32_t fenceIndex = 0; fenceIndex < MAX_FRAMES_IN_FLIGHT; fenceIndex++) { VKCHECK(vkCreateFence(vk.device, &fenceCreateInfo, nullptr, &vk.fences[fenceIndex])); + #ifdef GFX_NAME_OBJECTS + std::string fenceName = "Fence " + std::to_string(fenceIndex); + SetObjectName(vk.device, reinterpret_cast(vk.fences[fenceIndex]), fenceName.c_str(), VK_OBJECT_TYPE_FENCE); + #endif } + fenceCreateInfo.flags = 0; + VKCHECK(vkCreateFence(vk.device, &fenceCreateInfo, nullptr, &vk.immediateFence)); #ifdef GFX_NAME_OBJECTS - SetObjectName(vk.device, reinterpret_cast(vk.fences[0]), "Fence 0", VK_OBJECT_TYPE_FENCE); - SetObjectName(vk.device, reinterpret_cast(vk.fences[1]), "Fence 1", VK_OBJECT_TYPE_FENCE); + SetObjectName(vk.device, reinterpret_cast(vk.immediateFence), "Immediate Fence", VK_OBJECT_TYPE_FENCE); #endif return true; @@ -488,10 +495,10 @@ namespace Graphics swapchainSize = surfaceCapabilities.currentExtent; if (swapchainSize.width != vk.width) return false; if (swapchainSize.height != vk.height) return false; - if (surfaceCapabilities.minImageCount > 2) return false; + if (surfaceCapabilities.minImageCount > MAX_FRAMES_IN_FLIGHT) return false; // Note: maxImageCount of 0 means unlimited number of images - assert((surfaceCapabilities.maxImageCount != 0) && (surfaceCapabilities.maxImageCount > 2)); + assert((surfaceCapabilities.maxImageCount != 0) && (surfaceCapabilities.maxImageCount > MAX_FRAMES_IN_FLIGHT)); VkSurfaceTransformFlagBitsKHR surfaceTransformFlagBits = surfaceCapabilities.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ? VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR : surfaceCapabilities.currentTransform; @@ -504,7 +511,7 @@ namespace Graphics VkSwapchainCreateInfoKHR swapchainCreateInfo = {}; swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainCreateInfo.surface = vk.surface; - swapchainCreateInfo.minImageCount = 2; // double buffer + swapchainCreateInfo.minImageCount = MAX_FRAMES_IN_FLIGHT; swapchainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; swapchainCreateInfo.preTransform = surfaceTransformFlagBits; swapchainCreateInfo.imageColorSpace = vk.swapChainColorSpace; @@ -534,20 +541,19 @@ namespace Graphics // Create the swap chain VKCHECK(vkCreateSwapchainKHR(vk.device, &swapchainCreateInfo, nullptr, &vk.swapChain)); #ifdef GFX_NAME_OBJECTS - SetObjectName(vk.device, reinterpret_cast(vk.surface), "Surface", VK_OBJECT_TYPE_SURFACE_KHR); SetObjectName(vk.device, reinterpret_cast(vk.swapChain), "Swapchain", VK_OBJECT_TYPE_SWAPCHAIN_KHR); #endif // Get the swap chain image count uint32_t swapchainImageCount = 0; VKCHECK(vkGetSwapchainImagesKHR(vk.device, vk.swapChain, &swapchainImageCount, nullptr)); - if (swapchainImageCount != 2) return false; + if (swapchainImageCount != MAX_FRAMES_IN_FLIGHT) return false; // Get the swap chain images VKCHECK(vkGetSwapchainImagesKHR(vk.device, vk.swapChain, &swapchainImageCount, vk.swapChainImage)); // Create views for the swap chain images - for (uint32_t imageIndex = 0; imageIndex < 2; imageIndex++) + for (uint32_t imageIndex = 0; imageIndex < MAX_FRAMES_IN_FLIGHT; imageIndex++) { // Describe the image view VkImageViewCreateInfo imageViewCreateInfo = {}; @@ -561,16 +567,16 @@ namespace Graphics // Create the image view VKCHECK(vkCreateImageView(vk.device, &imageViewCreateInfo, nullptr, &vk.swapChainImageView[imageIndex])); - } - #ifdef GFX_NAME_OBJECTS - SetObjectName(vk.device, reinterpret_cast(vk.swapChainImage[0]), "Back Buffer Image 0", VK_OBJECT_TYPE_IMAGE); - SetObjectName(vk.device, reinterpret_cast(vk.swapChainImage[1]), "Back Buffer Image 1", VK_OBJECT_TYPE_IMAGE); - SetObjectName(vk.device, reinterpret_cast(vk.swapChainImageView[0]), "Back Buffer Image View 0", VK_OBJECT_TYPE_IMAGE_VIEW); - SetObjectName(vk.device, reinterpret_cast(vk.swapChainImageView[1]), "Back Buffer Image View 1", VK_OBJECT_TYPE_IMAGE_VIEW); - #endif + #ifdef GFX_NAME_OBJECTS + std::string imageName = "Back Buffer Image " + std::to_string(imageIndex); + SetObjectName(vk.device, reinterpret_cast(vk.swapChainImage[imageIndex]), imageName.c_str(), VK_OBJECT_TYPE_IMAGE); + + std::string viewName = "Back Buffer Image View " + std::to_string(imageIndex); + SetObjectName(vk.device, reinterpret_cast(vk.swapChainImageView[imageIndex]), viewName.c_str(), VK_OBJECT_TYPE_IMAGE_VIEW); + #endif + } - // Transition the back buffers to present ImageBarrierDesc barrier = { VK_IMAGE_LAYOUT_UNDEFINED, @@ -579,8 +585,12 @@ namespace Graphics VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } }; - SetImageLayoutBarrier(vk.cmdBuffer[vk.frameIndex], vk.swapChainImage[0], barrier); - SetImageLayoutBarrier(vk.cmdBuffer[vk.frameIndex], vk.swapChainImage[1], barrier); + + // Transition the back buffers to present + for (uint32_t imageIndex = 0; imageIndex < MAX_FRAMES_IN_FLIGHT; imageIndex++) + { + SetImageLayoutBarrier(vk.cmdBuffer[vk.frameIndex], vk.swapChainImage[imageIndex], barrier); + } return true; } @@ -592,14 +602,14 @@ namespace Graphics { // Describe the render pass VkAttachmentDescription attachmentDescriptions[1] = {}; - attachmentDescriptions[0].samples = VK_SAMPLE_COUNT_1_BIT; attachmentDescriptions[0].format = vk.swapChainFormat; + attachmentDescriptions[0].samples = VK_SAMPLE_COUNT_1_BIT; attachmentDescriptions[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachmentDescriptions[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachmentDescriptions[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachmentDescriptions[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; attachmentDescriptions[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; attachmentDescriptions[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + attachmentDescriptions[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + attachmentDescriptions[0].finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkAttachmentReference colorAttachmentReference = {}; colorAttachmentReference.attachment = 0; @@ -631,7 +641,7 @@ namespace Graphics */ bool CreateFrameBuffers(Globals& vk) { - for (uint32_t bufferIndex = 0; bufferIndex < 2; bufferIndex++) + for (uint32_t bufferIndex = 0; bufferIndex < MAX_FRAMES_IN_FLIGHT; bufferIndex++) { // Describe the frame buffer VkFramebufferCreateInfo framebufferCreateInfo = {}; @@ -646,7 +656,8 @@ namespace Graphics // Create the frame buffer VKCHECK(vkCreateFramebuffer(vk.device, &framebufferCreateInfo, nullptr, &vk.frameBuffer[bufferIndex])); #ifdef GFX_NAME_OBJECTS - SetObjectName(vk.device, reinterpret_cast(vk.frameBuffer[bufferIndex]), "Frame Buffer", VK_OBJECT_TYPE_FRAMEBUFFER); + std::string name = "Frame Buffer " + std::to_string(bufferIndex); + SetObjectName(vk.device, reinterpret_cast(vk.frameBuffer[bufferIndex]), name.c_str(), VK_OBJECT_TYPE_FRAMEBUFFER); #endif } @@ -677,25 +688,26 @@ namespace Graphics */ bool CreateCommandBuffers(Globals& vk) { - uint32_t numCommandBuffers = 2; - // Describe the command buffers VkCommandBufferAllocateInfo commandBufferAllocateInfo = {}; commandBufferAllocateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - commandBufferAllocateInfo.commandBufferCount = numCommandBuffers; + commandBufferAllocateInfo.commandBufferCount = MAX_FRAMES_IN_FLIGHT; commandBufferAllocateInfo.commandPool = vk.commandPool; commandBufferAllocateInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; // Allocate the command buffers from the command pool - std::vector commandBuffers{ numCommandBuffers }; + std::vector commandBuffers; + commandBuffers.resize(MAX_FRAMES_IN_FLIGHT); VKCHECK(vkAllocateCommandBuffers(vk.device, &commandBufferAllocateInfo, commandBuffers.data())); - vk.cmdBuffer[0] = commandBuffers[0]; - vk.cmdBuffer[1] = commandBuffers[1]; - #ifdef GFX_NAME_OBJECTS - SetObjectName(vk.device, reinterpret_cast(vk.cmdBuffer[0]), "Command Buffer 0", VK_OBJECT_TYPE_COMMAND_BUFFER); - SetObjectName(vk.device, reinterpret_cast(vk.cmdBuffer[1]), "Command Buffer 1", VK_OBJECT_TYPE_COMMAND_BUFFER); - #endif + for (uint32_t index = 0; index < MAX_FRAMES_IN_FLIGHT; index++) + { + vk.cmdBuffer[index] = commandBuffers[index]; + #ifdef GFX_NAME_OBJECTS + std::string name = "Command Buffer " + std::to_string(index); + SetObjectName(vk.device, reinterpret_cast(vk.cmdBuffer[0]), name.c_str(), VK_OBJECT_TYPE_COMMAND_BUFFER); + #endif + } return true; } @@ -707,13 +719,21 @@ namespace Graphics { VkSemaphoreCreateInfo semaphoreCreateInfo = {}; semaphoreCreateInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + semaphoreCreateInfo.flags = VK_SEMAPHORE_TYPE_BINARY; - VKCHECK(vkCreateSemaphore(vk.device, &semaphoreCreateInfo, nullptr, &vk.imageAcquiredSemaphore)); - VKCHECK(vkCreateSemaphore(vk.device, &semaphoreCreateInfo, nullptr, &vk.renderingCompleteSemaphore)); - #ifdef GFX_NAME_OBJECTS - SetObjectName(vk.device, reinterpret_cast(vk.imageAcquiredSemaphore), "Image Acquired Semaphore", VK_OBJECT_TYPE_SEMAPHORE); - SetObjectName(vk.device, reinterpret_cast(vk.renderingCompleteSemaphore), "Rendering Complete Semaphore", VK_OBJECT_TYPE_SEMAPHORE); - #endif + for (uint32_t semaphoreIndex = 0; semaphoreIndex < MAX_FRAMES_IN_FLIGHT; semaphoreIndex++) + { + VKCHECK(vkCreateSemaphore(vk.device, &semaphoreCreateInfo, nullptr, &vk.imageAcquiredSemaphore[semaphoreIndex])); + VKCHECK(vkCreateSemaphore(vk.device, &semaphoreCreateInfo, nullptr, &vk.presentSemaphore[semaphoreIndex])); + + #ifdef GFX_NAME_OBJECTS + std::string imageSemaphoreName = "Image Acquired Semaphore " + std::to_string(semaphoreIndex); + SetObjectName(vk.device, reinterpret_cast(vk.imageAcquiredSemaphore[semaphoreIndex]), imageSemaphoreName.c_str(), VK_OBJECT_TYPE_SEMAPHORE); + + std::string presentSemaphoreName = "Present Semaphore " + std::to_string(semaphoreIndex); + SetObjectName(vk.device, reinterpret_cast(vk.presentSemaphore[semaphoreIndex]), presentSemaphoreName.c_str(), VK_OBJECT_TYPE_SEMAPHORE); + #endif + } return true; } @@ -1534,23 +1554,39 @@ namespace Graphics return true; } + /** + * Destroy the existing GBuffer resources. + */ + void CleanupGBuffer(Globals& vk, Resources& resources) + { + vkDestroyImageView(vk.device, resources.rt.GBufferAView, nullptr); + vkFreeMemory(vk.device, resources.rt.GBufferAMemory, nullptr); + vkDestroyImage(vk.device, resources.rt.GBufferA, nullptr); + + vkDestroyImageView(vk.device, resources.rt.GBufferBView, nullptr); + vkFreeMemory(vk.device, resources.rt.GBufferBMemory, nullptr); + vkDestroyImage(vk.device, resources.rt.GBufferB, nullptr); + + vkDestroyImageView(vk.device, resources.rt.GBufferCView, nullptr); + vkFreeMemory(vk.device, resources.rt.GBufferCMemory, nullptr); + vkDestroyImage(vk.device, resources.rt.GBufferC, nullptr); + + vkDestroyImageView(vk.device, resources.rt.GBufferDView, nullptr); + vkFreeMemory(vk.device, resources.rt.GBufferDMemory, nullptr); + vkDestroyImage(vk.device, resources.rt.GBufferD, nullptr); + } + /** * Destroy the existing swapchain and associated resources. */ void CleanupSwapchain(Globals& vk) { - for (uint32_t resourceIndex = 0; resourceIndex < 2; resourceIndex++) + for (uint32_t resourceIndex = 0; resourceIndex < MAX_FRAMES_IN_FLIGHT; resourceIndex++) { vkDestroyFramebuffer(vk.device, vk.frameBuffer[resourceIndex], nullptr); vkDestroyImageView(vk.device, vk.swapChainImageView[resourceIndex], nullptr); } - - vkFreeCommandBuffers(vk.device, vk.commandPool, 2, vk.cmdBuffer); - vkDestroySemaphore(vk.device, vk.imageAcquiredSemaphore, nullptr); - vkDestroySemaphore(vk.device, vk.renderingCompleteSemaphore, nullptr); - vkDestroySwapchainKHR(vk.device, vk.swapChain, nullptr); - vkDestroySurfaceKHR(vk.instance, vk.surface, nullptr); } /** @@ -1671,24 +1707,19 @@ namespace Graphics Shaders::Cleanup(vk.shaderCompiler); // Release core Vulkan objects - vkDestroySemaphore(vk.device, vk.imageAcquiredSemaphore, nullptr); - vkDestroySemaphore(vk.device, vk.renderingCompleteSemaphore, nullptr); - vkFreeCommandBuffers(vk.device, vk.commandPool, 2, vk.cmdBuffer); - vkDestroyCommandPool(vk.device, vk.commandPool, nullptr); - - for (resourceIndex = 0; resourceIndex < 2; resourceIndex++) + for (resourceIndex = 0; resourceIndex < MAX_FRAMES_IN_FLIGHT; resourceIndex++) { + vkDestroySemaphore(vk.device, vk.imageAcquiredSemaphore[resourceIndex], nullptr); + vkDestroySemaphore(vk.device, vk.presentSemaphore[resourceIndex], nullptr); vkDestroyFramebuffer(vk.device, vk.frameBuffer[resourceIndex], nullptr); - } - - vkDestroyRenderPass(vk.device, vk.renderPass, nullptr); - - for (resourceIndex = 0; resourceIndex < 2; resourceIndex++) - { vkDestroyFence(vk.device, vk.fences[resourceIndex], nullptr); vkDestroyImageView(vk.device, vk.swapChainImageView[resourceIndex], nullptr); } + vkFreeCommandBuffers(vk.device, vk.commandPool, MAX_FRAMES_IN_FLIGHT, vk.cmdBuffer); + vkDestroyCommandPool(vk.device, vk.commandPool, nullptr); + vkDestroyRenderPass(vk.device, vk.renderPass, nullptr); + vkDestroyFence(vk.device, vk.immediateFence, nullptr); vkDestroySwapchainKHR(vk.device, vk.swapChain, nullptr); vkDestroySurfaceKHR(vk.instance, vk.surface, nullptr); vkDestroyDevice(vk.device, nullptr); @@ -2210,23 +2241,28 @@ namespace Graphics SetImageMemoryBarrier(commandBuffer, image, barrier); } - // Staging (read-back) texture resources - std::vector stagingResources; // linear layout - std::vector optimalStagingResources; // optimal tiled layout - std::vector stagingResourcesMemory; - std::vector optimalStagingResourcesMemory; + // Staging (read-back) resources + std::vector stagingBuffer; // linear layout + std::vector stagingImage; // optimal tiled layout + std::vector stagingBufferMemory; + std::vector stagingImageMemory; // Loop over the subresources (array slices), copying them from the GPU for(uint32_t subresourceIndex = 0; subresourceIndex < arraySize; subresourceIndex++) { // Add new resource entries - stagingResources.emplace_back(); - optimalStagingResources.emplace_back(); - stagingResourcesMemory.emplace_back(); - optimalStagingResourcesMemory.emplace_back(); + stagingBuffer.emplace_back(); + stagingImage.emplace_back(); + stagingBufferMemory.emplace_back(); + stagingImageMemory.emplace_back(); - // Create the staging texture resources + // Create the staging buffer and texture resources { + // Create the staging linear buffer + uint32_t sizeInBytes = width * height * ImageCapture::NumChannels; + BufferDesc bufferDesc = { sizeInBytes, VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT }; + if (!CreateBuffer(vk, bufferDesc, &stagingBuffer[subresourceIndex], &stagingBufferMemory[subresourceIndex])) return false; + // Describe the staging resource VkImageCreateInfo imageCreateInfo = {}; imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; @@ -2243,34 +2279,20 @@ namespace Graphics imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - // Create the resource (linear layout) - VKCHECK(vkCreateImage(vk.device, &imageCreateInfo, nullptr, &stagingResources[subresourceIndex])); - - // Create the resource (optimal tiling) + // Create the (optimal tiling) texture imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; imageCreateInfo.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; - VKCHECK(vkCreateImage(vk.device, &imageCreateInfo, nullptr, &optimalStagingResources[subresourceIndex])); + VKCHECK(vkCreateImage(vk.device, &imageCreateInfo, nullptr, &stagingImage[subresourceIndex])); - // Get the memory requirements for the linear resource + // Get the memory requirements for the optimal tiled texture AllocateMemoryDesc desc = {}; - vkGetImageMemoryRequirements(vk.device, stagingResources[subresourceIndex], &desc.requirements); - desc.properties = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; - desc.flags = 0; - - // Allocate and bind the memory for the linear resource - if (!AllocateMemory(vk, desc, &stagingResourcesMemory[subresourceIndex])) return false; - VKCHECK(vkBindImageMemory(vk.device, stagingResources[subresourceIndex], stagingResourcesMemory[subresourceIndex], 0)); + vkGetImageMemoryRequirements(vk.device, stagingImage[subresourceIndex], &desc.requirements); - // Get the memory requirements for the optimal tiled resource - vkGetImageMemoryRequirements(vk.device, optimalStagingResources[subresourceIndex], &desc.requirements); - desc.properties = 0; - desc.flags = 0; + // Allocate and bind the memory for the optimal tiled texture + if (!AllocateMemory(vk, desc, &stagingImageMemory[subresourceIndex])) return false; + VKCHECK(vkBindImageMemory(vk.device, stagingImage[subresourceIndex], stagingImageMemory[subresourceIndex], 0)); - // Allocate and bind the memory for the optimal tiled resource - if (!AllocateMemory(vk, desc, &optimalStagingResourcesMemory[subresourceIndex])) return false; - VKCHECK(vkBindImageMemory(vk.device, optimalStagingResources[subresourceIndex], optimalStagingResourcesMemory[subresourceIndex], 0)); - - // Transition the staging resources to copy destinations + // Transition the staging texture to a copy destination ImageBarrierDesc barrier = { VK_IMAGE_LAYOUT_UNDEFINED, @@ -2279,11 +2301,10 @@ namespace Graphics VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } }; - SetImageMemoryBarrier(commandBuffer, stagingResources[subresourceIndex], barrier); - SetImageMemoryBarrier(commandBuffer, optimalStagingResources[subresourceIndex], barrier); + SetImageMemoryBarrier(commandBuffer, stagingImage[subresourceIndex], barrier); } - // Copy the source resource (slice) to the optimal tiled resource + // Copy the source resource (slice) to the optimal tiled texture { VkImageSubresourceLayers source = {}; source.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -2307,12 +2328,12 @@ namespace Graphics commandBuffer, image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - optimalStagingResources[subresourceIndex], + stagingImage[subresourceIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion, VK_FILTER_NEAREST); } - // Transition the optimal tiled resource to a copy source + // Transition the optimal tiled texture to a copy source ImageBarrierDesc barrier = { VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, @@ -2321,40 +2342,29 @@ namespace Graphics VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } }; - SetImageMemoryBarrier(commandBuffer, optimalStagingResources[subresourceIndex], barrier); + SetImageMemoryBarrier(commandBuffer, stagingImage[subresourceIndex], barrier); - // Copy the optimal tiled resource to the linear resource (for CPU copy) + // Copy the optimal tiled texture to the linear buffer (for CPU copy) { VkImageSubresourceLayers resource = {}; resource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; resource.layerCount = 1; resource.baseArrayLayer = 0; - VkImageCopy region = {}; - region.srcSubresource = resource; - region.dstSubresource = resource; - region.extent.width = width; - region.extent.height = height; - region.extent.depth = 1; + VkBufferImageCopy region = {}; + region.bufferOffset = 0; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource = resource; + region.imageExtent = { width, height, 1 }; - vkCmdCopyImage( + // Copy the tiled image to a linear buffer + vkCmdCopyImageToBuffer( commandBuffer, - optimalStagingResources[subresourceIndex], + stagingImage[subresourceIndex], VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - stagingResources[subresourceIndex], - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + stagingBuffer[subresourceIndex], 1, ®ion); - - // Transition the linear resource to general read - ImageBarrierDesc barrier = - { - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_GENERAL, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } - }; - SetImageMemoryBarrier(commandBuffer, stagingResources[subresourceIndex], barrier); } } @@ -2380,42 +2390,19 @@ namespace Graphics submitInfo.pCommandBuffers = &commandBuffer; VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE)); - VKCHECK(vkQueueWaitIdle(vk.queue)); WaitForGPU(vk); - // Copy the linear resources to CPU memory + // Copy the linear buffer to memory for writing to disk bool result = true; for (uint32_t subresourceIndex = 0; subresourceIndex < arraySize; subresourceIndex++) { - VkImageSubresource subResource{ VK_IMAGE_ASPECT_COLOR_BIT, 0, 0 }; - VkSubresourceLayout subResourceLayout; - vkGetImageSubresourceLayout(vk.device, stagingResources[subresourceIndex], &subResource, &subResourceLayout); - - // Map the linear resource's memory + // Map the linear buffer's memory uint8_t* pData = nullptr; - VKCHECK(vkMapMemory(vk.device, stagingResourcesMemory[subresourceIndex], 0, VK_WHOLE_SIZE, 0, (void**)&pData)); + VKCHECK(vkMapMemory(vk.device, stagingBufferMemory[subresourceIndex], 0, VK_WHOLE_SIZE, 0, (void**)&pData)); std::vector converted(width * height * ImageCapture::NumChannels); - - // Copy the linear resource to CPU memory - uint32_t rowSizeInBytes = width * ImageCapture::NumChannels; // * sizeof(uint8_t); - if(rowSizeInBytes < 64) - { - // Copy the row texels, ignoring the padding added from 64B row alignment - uint8_t* dst = converted.data(); - for(uint32_t rowIndex = 0; rowIndex < height; rowIndex++) - { - memcpy(dst, pData, rowSizeInBytes); - dst += rowSizeInBytes; - pData += 64; - } - } - else - { - // Copy the texels, they are 256 aligned already and don't include padding - memcpy(converted.data(), pData, converted.size()); - } + memcpy(converted.data(), pData, converted.size()); // Write the resource to disk as a PNG file (using STB) std::string filename = file; @@ -2423,17 +2410,17 @@ namespace Graphics filename.append(".png"); result &= ImageCapture::CapturePng(filename, width, height, converted.data()); - // Unmap the linear resource's memory - vkUnmapMemory(vk.device, stagingResourcesMemory[subresourceIndex]); + // Unmap the linear buffers's memory + vkUnmapMemory(vk.device, stagingBufferMemory[subresourceIndex]); } // Clean up for (uint32_t subresourceIndex = 0; subresourceIndex < arraySize; subresourceIndex++) { - vkFreeMemory(vk.device, stagingResourcesMemory[subresourceIndex], nullptr); - vkDestroyImage(vk.device, stagingResources[subresourceIndex], nullptr); - vkFreeMemory(vk.device, optimalStagingResourcesMemory[subresourceIndex], nullptr); - vkDestroyImage(vk.device, optimalStagingResources[subresourceIndex], nullptr); + vkFreeMemory(vk.device, stagingBufferMemory[subresourceIndex], nullptr); + vkDestroyBuffer(vk.device, stagingBuffer[subresourceIndex], nullptr); + vkFreeMemory(vk.device, stagingImageMemory[subresourceIndex], nullptr); + vkDestroyImage(vk.device, stagingImage[subresourceIndex], nullptr); } vkFreeCommandBuffers(vk.device, commandPool, 1, &commandBuffer); vkDestroyCommandPool(vk.device, commandPool, nullptr); @@ -2516,7 +2503,7 @@ namespace Graphics return true; } - /* + /** * Add an image memory barrier on the given command buffer. */ void SetImageMemoryBarrier(VkCommandBuffer cmdBuffer, VkImage image, const ImageBarrierDesc info) @@ -2578,7 +2565,7 @@ namespace Graphics vkCmdPipelineBarrier(cmdBuffer, info.srcMask, info.dstMask, 0, 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier); } - /* + /** * Add an image layout barrier on the given command buffer. */ void SetImageLayoutBarrier(VkCommandBuffer cmdBuffer, VkImage image, const ImageBarrierDesc info) @@ -3109,23 +3096,25 @@ namespace Graphics // Initialize the shader compiler CHECK(Shaders::Initialize(config, vk.shaderCompiler), "initialize the shader compiler!", log); - // Create core Vulkan objects + // Create Vulkan device objects CHECK(CreateCommandPool(vk), "create command pool!", log); CHECK(CreateCommandBuffers(vk), "create command buffers!", log); - CHECK(ResetCmdList(vk), "reset command buffer!", log); CHECK(CreateFences(vk), "create fences!", log); - CHECK(CreateSwapChain(vk), "create swap chain!", log); - CHECK(CreateRenderPass(vk), "create render pass!", log); - CHECK(CreateFrameBuffers(vk), "create frame buffers!", log); CHECK(CreateSemaphores(vk), "create semaphores!", log); CHECK(CreateDescriptorPool(vk, resources), "create descriptor pool!", log); - CHECK(CreateQueryPools(vk, resources), "create query pools!", log); CHECK(CreateGlobalPipelineLayout(vk, resources), "create global pipeline layout!", log); - CHECK(CreateRenderTargets(vk, resources), "create render targets!", log); CHECK(CreateSamplers(vk, resources), "create samplers!", log); CHECK(CreateViewport(vk), "create viewport!", log); CHECK(CreateScissor(vk), "create scissor!", log); + // Create Vulkan device objects that require command buffer operations (e.g. transitions) + CHECK(ResetCmdList(vk), "reset command buffer!", log); + CHECK(CreateSwapChain(vk), "create swap chain!", log); + CHECK(CreateRenderPass(vk), "create render pass!", log); + CHECK(CreateFrameBuffers(vk), "create frame buffers!", log); + CHECK(CreateRenderTargets(vk, resources), "create render targets!", log); + CHECK(CreateQueryPools(vk, resources), "create query pools!", log); + // Create default graphics resources CHECK(LoadAndCreateDefaultTextures(vk, resources, config, log), "load and create default textures!", log); @@ -3148,11 +3137,12 @@ namespace Graphics submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; - VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE)); - VKCHECK(vkQueueWaitIdle(vk.queue)); + // Submit command buffer and block until GPU work finishes + VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, vk.immediateFence)); + VKCHECK(vkWaitForFences(vk.device, 1, &vk.immediateFence, VK_TRUE, UINT64_MAX)); + VKCHECK(vkResetFences(vk.device, 1, &vk.immediateFence)); - WaitForGPU(vk); - MoveToNextFrame(vk); + CHECK(ResetCmdList(vk), "reset command buffer!", log); // Release upload buffers vkDestroyBuffer(vk.device, resources.materialsSTBUploadBuffer, nullptr); @@ -3205,6 +3195,26 @@ namespace Graphics return true; } + /** + * Post initialization tasks. + */ + bool PostInitialize(Globals& vk, std::ofstream& log) + { + VKCHECK(vkEndCommandBuffer(vk.cmdBuffer[vk.frameIndex])); + + VkSubmitInfo endInfo = {}; + endInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + endInfo.commandBufferCount = 1; + endInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; + + // Submit command buffer and block until GPU work finishes + VKCHECK(vkQueueSubmit(vk.queue, 1, &endInfo, vk.immediateFence)); + VKCHECK(vkWaitForFences(vk.device, 1, &vk.immediateFence, VK_TRUE, UINT64_MAX)); + VKCHECK(vkResetFences(vk.device, 1, &vk.immediateFence)); + + return true; + } + /** * Update constant buffers. */ @@ -3245,9 +3255,9 @@ namespace Graphics } /** - * Update the swap chain. + * Resize the swap chain and open a command buffer for other resize operations (resource transitions). */ - bool Resize(Globals& vk, GlobalResources& resources, int width, int height, std::ofstream& log) + bool ResizeBegin(Globals& vk, GlobalResources& resources, int width, int height, std::ofstream& log) { vk.width = width; vk.height = height; @@ -3260,44 +3270,36 @@ namespace Graphics // Wait for the GPU to finish up any work VKCHECK(vkDeviceWaitIdle(vk.device)); - // Release the swapchain and associated resources + // Release the Swapchain and GBuffer resources CleanupSwapchain(vk); + CleanupGBuffer(vk, resources); - // Release the GBuffer resources - vkDestroyImageView(vk.device, resources.rt.GBufferAView, nullptr); - vkFreeMemory(vk.device, resources.rt.GBufferAMemory, nullptr); - vkDestroyImage(vk.device, resources.rt.GBufferA, nullptr); - - vkDestroyImageView(vk.device, resources.rt.GBufferBView, nullptr); - vkFreeMemory(vk.device, resources.rt.GBufferBMemory, nullptr); - vkDestroyImage(vk.device, resources.rt.GBufferB, nullptr); - - vkDestroyImageView(vk.device, resources.rt.GBufferCView, nullptr); - vkFreeMemory(vk.device, resources.rt.GBufferCMemory, nullptr); - vkDestroyImage(vk.device, resources.rt.GBufferC, nullptr); - - vkDestroyImageView(vk.device, resources.rt.GBufferDView, nullptr); - vkFreeMemory(vk.device, resources.rt.GBufferDMemory, nullptr); - vkDestroyImage(vk.device, resources.rt.GBufferD, nullptr); + // Reset the command buffer + vkResetCommandBuffer(vk.cmdBuffer[vk.frameIndex], 0); - // Reset the fences - VKCHECK(vkResetFences(vk.device, 2, vk.fences)); + // Start recording + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + VKCHECK(vkBeginCommandBuffer(vk.cmdBuffer[vk.frameIndex], &beginInfo)); - // Recreate the new swap chain, associated resources, GBuffer resources, and wait for the GPU - if (!CreateCommandBuffers(vk)) return false; - if (!ResetCmdList(vk)) return false; - if (!CreateSurface(vk)) return false; + // Recreate the Swapchain and GBuffer resources if (!CreateSwapChain(vk)) return false; if (!CreateFrameBuffers(vk)) return false; - if (!CreateSemaphores(vk)) return false; if (!CreateRenderTargets(vk, resources)) return false; - #ifdef GFX_PERF_INSTRUMENTATION - // Reset the GPU timestamp queries - vkCmdResetQueryPool(vk.cmdBuffer[vk.frameIndex], resources.timestampPool, 0, MAX_TIMESTAMPS * 2); - #endif + log << "Back buffer resize, " << vk.width << "x" << vk.height << "\n"; + log << "GBuffer resize, " << vk.width << "x" << vk.height << "\n"; + std::flush(log); - // Execute GPU work + return true; + } + + /** + * Close and submit the resize command buffer. Wait on the CPU for the GPU to complete. + */ + bool ResizeEnd(Globals& vk) + { + // Execute GPU work to finish initialization VKCHECK(vkEndCommandBuffer(vk.cmdBuffer[vk.frameIndex])); VkSubmitInfo submitInfo = {}; @@ -3305,48 +3307,32 @@ namespace Graphics submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; - VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE)); - VKCHECK(vkQueueWaitIdle(vk.queue)); - - // Wait for GPU to finish - if (!WaitForGPU(vk)) return false; - - // Get the next available image from the swapchain - VKCHECK(vkAcquireNextImageKHR(vk.device, vk.swapChain, UINT64_MAX, vk.imageAcquiredSemaphore, VK_NULL_HANDLE, &vk.frameIndex)); - - // Reset the command list - if (!ResetCmdList(vk)) return false; - - // Reset the frame number - vk.frameNumber = 1; - - #ifdef GFX_PERF_INSTRUMENTATION - // Reset the GPU timestamp queries - vkCmdResetQueryPool(vk.cmdBuffer[vk.frameIndex], resources.timestampPool, 0, MAX_TIMESTAMPS * 2); - vkCmdWriteTimestamp(vk.cmdBuffer[vk.frameIndex], VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, resources.timestampPool, 0); - #endif - - log << "Back buffer resize, " << vk.width << "x" << vk.height << "\n"; - log << "GBuffer resize, " << vk.width << "x" << vk.height << "\n"; - std::flush(log); + // Submit command buffer and block until GPU work finishes + VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, vk.immediateFence)); + VKCHECK(vkWaitForFences(vk.device, 1, &vk.immediateFence, VK_TRUE, UINT64_MAX)); + VKCHECK(vkResetFences(vk.device, 1, &vk.immediateFence)); return true; } /** - * Reset the command list. + * Reset the current frame's command list and begin recording. */ bool ResetCmdList(Globals& vk) { - // Start the command buffer for the next frame - VkCommandBufferBeginInfo commandBufferBeginInfo = {}; - commandBufferBeginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - VKCHECK(vkBeginCommandBuffer(vk.cmdBuffer[vk.frameIndex], &commandBufferBeginInfo)); + // Reset the command buffer + vkResetCommandBuffer(vk.cmdBuffer[vk.frameIndex], 0); + + // Start recording + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + VKCHECK(vkBeginCommandBuffer(vk.cmdBuffer[vk.frameIndex], &beginInfo)); + return true; } /** - * Submit the command list. + * Close and Submit the current frame's command list. */ bool SubmitCmdList(Globals& vk) { @@ -3358,12 +3344,12 @@ namespace Graphics VkSubmitInfo submitInfo = {}; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = &vk.imageAcquiredSemaphore; + submitInfo.pWaitSemaphores = &vk.imageAcquiredSemaphore[vk.frameIndex]; submitInfo.pWaitDstStageMask = &waitDstStageMask; submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = &vk.renderingCompleteSemaphore; + submitInfo.pSignalSemaphores = &vk.presentSemaphore[vk.frameIndex]; // Submit the command buffer to the graphics queue VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, vk.fences[vk.frameIndex])); @@ -3380,50 +3366,31 @@ namespace Graphics VkPresentInfoKHR presentInfo = {}; presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = &vk.renderingCompleteSemaphore; + presentInfo.pWaitSemaphores = &vk.presentSemaphore[vk.frameIndex]; presentInfo.swapchainCount = 1; presentInfo.pSwapchains = &vk.swapChain; - presentInfo.pImageIndices = &vk.frameIndex; - - VKCHECK(vkQueuePresentKHR(vk.queue, &presentInfo)); - - // Wait for command buffers to complete before moving to the next frame - VKCHECK(vkWaitForFences(vk.device, 1, &vk.fences[vk.frameIndex], VK_TRUE, UINT64_MAX)); - VKCHECK(vkResetFences(vk.device, 1, &vk.fences[vk.frameIndex])); + presentInfo.pImageIndices = &vk.imageIndex; - vk.frameNumber++; - return true; - } - - /* - * Wait for pending GPU work to complete. - */ - bool WaitForGPU(Globals& vk) - { - return (vkDeviceWaitIdle(vk.device) == VK_SUCCESS); - } + VkResult result = vkQueuePresentKHR(vk.queue, &presentInfo); - /** - * Prepare to render the next frame. - */ - bool MoveToNextFrame(Globals& vk) - { if (vk.vsyncChanged) { + // Wait for the GPU to finish all work + VKCHECK(vkDeviceWaitIdle(vk.device)); + CleanupSwapchain(vk); + vkResetCommandBuffer(vk.cmdBuffer[vk.frameIndex], 0); - // Reset the fences - VKCHECK(vkResetFences(vk.device, 2, vk.fences)); + // Start recording + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + VKCHECK(vkBeginCommandBuffer(vk.cmdBuffer[vk.frameIndex], &beginInfo)); - // Recreate the new swap chain and associated resources - if (!CreateCommandBuffers(vk)) return false; - if (!ResetCmdList(vk)) return false; - if (!CreateSurface(vk)) return false; + // Recreate the Swapchain if (!CreateSwapChain(vk)) return false; if (!CreateFrameBuffers(vk)) return false; - if (!CreateSemaphores(vk)) return false; - // Execute GPU work + // Execute GPU work to finish initialization VKCHECK(vkEndCommandBuffer(vk.cmdBuffer[vk.frameIndex])); VkSubmitInfo submitInfo = {}; @@ -3431,17 +3398,45 @@ namespace Graphics submitInfo.commandBufferCount = 1; submitInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; - VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE)); - VKCHECK(vkQueueWaitIdle(vk.queue)); - - // Wait for the GPU to finish - if (!WaitForGPU(vk)) return false; + // Submit command buffer and block until GPU work finishes + VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, vk.immediateFence)); + VKCHECK(vkWaitForFences(vk.device, 1, &vk.immediateFence, VK_TRUE, UINT64_MAX)); + VKCHECK(vkResetFences(vk.device, 1, &vk.immediateFence)); vk.vsyncChanged = false; } + vk.frameNumber++; + vk.frameIndex = (vk.frameIndex + 1) % MAX_FRAMES_IN_FLIGHT; + + return true; + } + + /** + * Wait for the previous frame's graphics commands to complete on the GPU. + */ + bool WaitForPrevGPUFrame(Globals& vk) + { + VKCHECK(vkWaitForFences(vk.device, 1, &vk.fences[vk.frameIndex], VK_TRUE, UINT64_MAX)); + VKCHECK(vkResetFences(vk.device, 1, &vk.fences[vk.frameIndex])); + return true; + } + + /** + * Wait (right now) for all GPU work to complete. + */ + bool WaitForGPU(Globals& vk) + { + return (vkDeviceWaitIdle(vk.device) == VK_SUCCESS); + } + + /** + * Prepare to render the next frame. + */ + bool MoveToNextFrame(Globals& vk) + { // Get the next available image from the swapchain - VKCHECK(vkAcquireNextImageKHR(vk.device, vk.swapChain, UINT64_MAX, vk.imageAcquiredSemaphore, VK_NULL_HANDLE, &vk.frameIndex)); + VKCHECK(vkAcquireNextImageKHR(vk.device, vk.swapChain, UINT64_MAX, vk.imageAcquiredSemaphore[vk.frameIndex], VK_NULL_HANDLE, &vk.imageIndex)); return true; } @@ -3470,10 +3465,10 @@ namespace Graphics std::vector queries; queries.resize(performance.GetNumActiveGPUQueries()); - // Copy the query results to the CPU read-back buffer + // Schedule a copy of the query results to the CPU read-back buffer vkCmdCopyQueryPoolResults(vk.cmdBuffer[vk.frameIndex], resources.timestampPool, 0, performance.GetNumActiveGPUQueries(), resources.timestamps, 0, sizeof(Timestamp), VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_WITH_AVAILABILITY_BIT); - // Copy the timestamps from the read-back buffer + // Copy the (previous frame's) timestamps from the read-back buffer uint8_t* pData = nullptr; VKCHECK(vkMapMemory(vk.device, resources.timestampsMemory, 0, VK_WHOLE_SIZE, 0, reinterpret_cast(&pData))); memcpy(queries.data(), pData, sizeof(Timestamp) * performance.GetNumActiveGPUQueries()); @@ -3496,12 +3491,11 @@ namespace Graphics { elapsedTicks = end.timestamp - start.timestamp; s->elapsed = std::max(static_cast(elapsedTicks) / 1000000, (double)0); + if (s->elapsed < 10000000) // sometimes timestamps are invalid, don't include those + { + Instrumentation::Resolve(s); + } } - else - { - s->elapsed = 0; - } - Instrumentation::Resolve(s); // Reset the GPU query indices for a new frame s->ResetGPUQueryIndices(); @@ -3540,13 +3534,21 @@ namespace Graphics } /** - * Create a graphics device. + * Initialize Vulkan. */ bool Initialize(const Configs::Config& config, Scenes::Scene& scene, Globals& gfx, GlobalResources& resources, std::ofstream& log) { return Graphics::Vulkan::Initialize(config, scene, gfx, resources, log); } + /** + * Post initializationm tasks. + */ + bool PostInitialize(Globals& gfx, std::ofstream& log) + { + return Graphics::Vulkan::PostInitialize(gfx, log); + } + /** * Update root constants and constant buffers. */ @@ -3556,11 +3558,19 @@ namespace Graphics } /** - * Resize the swapchain. + * Resize the swapchain and open a command buffer for other resize operations. + */ + bool ResizeBegin(Globals& gfx, GlobalResources& gfxResources, int width, int height, std::ofstream& log) + { + return Graphics::Vulkan::ResizeBegin(gfx, gfxResources, width, height, log); + } + + /** + * Close and submit the resize command buffer. Wait on the CPU for the GPU to complete. */ - bool Resize(Globals& gfx, GlobalResources& gfxResources, int width, int height, std::ofstream& log) + bool ResizeEnd(Globals& gfx) { - return Graphics::Vulkan::Resize(gfx, gfxResources, width, height, log); + return Graphics::Vulkan::ResizeEnd(gfx); } /** @@ -3572,7 +3582,7 @@ namespace Graphics } /** - * Reset the graphics command list. + * Reset the current frame's command list. */ bool ResetCmdList(Globals& gfx) { @@ -3580,7 +3590,7 @@ namespace Graphics } /** - * Submit the graphics command list. + * Submit the current frame's command list. */ bool SubmitCmdList(Globals& gfx) { @@ -3596,13 +3606,21 @@ namespace Graphics } /** - * Wait for the graphics device to idle. + * Wait (right now) for the graphics device to idle. */ bool WaitForGPU(Globals& gfx) { return Graphics::Vulkan::WaitForGPU(gfx); } + /** + * Wait for the previous frame's graphics commands to complete on the GPU. + */ + bool WaitForPrevGPUFrame(Globals& gfx) + { + return Graphics::Vulkan::WaitForPrevGPUFrame(gfx); + } + /** * Move to the next the next frame. */ diff --git a/samples/test-harness/src/graphics/Composite_D3D12.cpp b/samples/test-harness/src/graphics/Composite_D3D12.cpp index 1bbef64..ba7a084 100644 --- a/samples/test-harness/src/graphics/Composite_D3D12.cpp +++ b/samples/test-harness/src/graphics/Composite_D3D12.cpp @@ -33,14 +33,14 @@ namespace Graphics resources.shaders.vs.entryPoint = L"VS"; resources.shaders.vs.targetProfile = L"vs_6_6"; Shaders::AddDefine(resources.shaders.vs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.vs, true), "compile composition vertex shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.vs), "compile composition vertex shader!\n", log); // Load and compile the pixel shader resources.shaders.ps.filepath = root + L"shaders/Composite.hlsl"; resources.shaders.ps.entryPoint = L"PS"; resources.shaders.ps.targetProfile = L"ps_6_6"; Shaders::AddDefine(resources.shaders.ps, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.ps, true), "compile composition pixel shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.ps), "compile composition pixel shader!\n", log); return true; } @@ -158,7 +158,7 @@ namespace Graphics void Execute(Globals& d3d, GlobalResources& d3dResources, Resources& resources) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_BLUE), "Composite"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_BLUE), "Composite"); #endif CPU_TIMESTAMP_BEGIN(resources.cpuStat); @@ -170,49 +170,49 @@ namespace Graphics barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; // Wait for the transition to complete - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); // Set the CBV/SRV/UAV and sampler descriptor heaps ID3D12DescriptorHeap* ppHeaps[] = { d3dResources.srvDescHeap, d3dResources.samplerDescHeap }; - d3d.cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + d3d.cmdList[d3d.frameIndex]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // Set the root signature - d3d.cmdList->SetGraphicsRootSignature(d3dResources.rootSignature); + d3d.cmdList[d3d.frameIndex]->SetGraphicsRootSignature(d3dResources.rootSignature); // Update the root constants UINT offset = 0; GlobalConstants consts = d3dResources.constants; - d3d.cmdList->SetGraphicsRoot32BitConstants(0, AppConsts::GetNum32BitValues(), consts.app.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetGraphicsRoot32BitConstants(0, AppConsts::GetNum32BitValues(), consts.app.GetData(), offset); offset += AppConsts::GetAlignedNum32BitValues(); offset += PathTraceConsts::GetAlignedNum32BitValues(); offset += LightingConsts::GetAlignedNum32BitValues(); offset += RTAOConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetGraphicsRoot32BitConstants(0, CompositeConsts::GetNum32BitValues(), consts.composite.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetGraphicsRoot32BitConstants(0, CompositeConsts::GetNum32BitValues(), consts.composite.GetData(), offset); offset += CompositeConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetGraphicsRoot32BitConstants(0, PostProcessConsts::GetNum32BitValues(), consts.post.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetGraphicsRoot32BitConstants(0, PostProcessConsts::GetNum32BitValues(), consts.post.GetData(), offset); // Set the render target D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle = d3dResources.rtvDescHeap->GetCPUDescriptorHandleForHeapStart(); rtvHandle.ptr += (d3dResources.rtvDescHeapEntrySize * d3d.frameIndex); - d3d.cmdList->OMSetRenderTargets(1, &rtvHandle, false, nullptr); + d3d.cmdList[d3d.frameIndex]->OMSetRenderTargets(1, &rtvHandle, false, nullptr); // Set the root parameter descriptor tables #if RTXGI_BINDLESS_TYPE == RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS - d3d.cmdList->SetGraphicsRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); - d3d.cmdList->SetGraphicsRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetGraphicsRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetGraphicsRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); #endif // Set raster state - d3d.cmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - d3d.cmdList->RSSetViewports(1, &d3d.viewport); - d3d.cmdList->RSSetScissorRects(1, &d3d.scissor); + d3d.cmdList[d3d.frameIndex]->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + d3d.cmdList[d3d.frameIndex]->RSSetViewports(1, &d3d.viewport); + d3d.cmdList[d3d.frameIndex]->RSSetScissorRects(1, &d3d.scissor); // Set the pipeline state object - d3d.cmdList->SetPipelineState(resources.pso); + d3d.cmdList[d3d.frameIndex]->SetPipelineState(resources.pso); // Draw GPU_TIMESTAMP_BEGIN(resources.gpuStat->GetGPUQueryBeginIndex()); - d3d.cmdList->DrawInstanced(3, 1, 0, 0); + d3d.cmdList[d3d.frameIndex]->DrawInstanced(3, 1, 0, 0); GPU_TIMESTAMP_END(resources.gpuStat->GetGPUQueryEndIndex()); // Transition the back buffer to present @@ -220,11 +220,11 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; // Wait for the transition to complete - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); CPU_TIMESTAMP_ENDANDRESOLVE(resources.cpuStat); #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif } diff --git a/samples/test-harness/src/graphics/Composite_VK.cpp b/samples/test-harness/src/graphics/Composite_VK.cpp index 637e667..b4b98cd 100644 --- a/samples/test-harness/src/graphics/Composite_VK.cpp +++ b/samples/test-harness/src/graphics/Composite_VK.cpp @@ -34,7 +34,7 @@ namespace Graphics resources.shaders.vs.targetProfile = L"vs_6_6"; resources.shaders.vs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.shaders.vs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.vs, true), "compile composition vertex shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.vs), "compile composition vertex shader!\n", log); // Load and compile the pixel shader resources.shaders.ps.filepath = root + L"shaders/Composite.hlsl"; @@ -42,7 +42,7 @@ namespace Graphics resources.shaders.ps.targetProfile = L"ps_6_6"; resources.shaders.ps.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.shaders.ps, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.ps, true), "compile composition pixel shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.ps), "compile composition pixel shader!\n", log); return true; } @@ -201,6 +201,7 @@ namespace Graphics bool Reload(Globals& vk, GlobalResources& vkResources, Resources& resources, std::ofstream& log) { log << "Reloading Composition shaders..."; + vkDeviceWaitIdle(vk.device); if (!LoadAndCompileShaders(vk, resources, log)) return false; if (!CreatePipelines(vk, vkResources, resources, log)) return false; log << "done.\n"; diff --git a/samples/test-harness/src/graphics/DDGI.cpp b/samples/test-harness/src/graphics/DDGI.cpp index f65ce75..0aca739 100644 --- a/samples/test-harness/src/graphics/DDGI.cpp +++ b/samples/test-harness/src/graphics/DDGI.cpp @@ -161,7 +161,7 @@ namespace Graphics #endif // Load and compile the shader - CHECK(Shaders::Compile(gfx.shaderCompiler, shader, true), "compile the RTXGI probe irradiance blending compute shader!\n", log); + CHECK(Shaders::Compile(gfx.shaderCompiler, shader), "compile the RTXGI probe irradiance blending compute shader!\n", log); } // Probe Blending (distance) @@ -191,7 +191,7 @@ namespace Graphics #endif // Load and compile the shader - CHECK(Shaders::Compile(gfx.shaderCompiler, shader, true), "load and compile the RTXGI probe distance blending compute shader!\n", log); + CHECK(Shaders::Compile(gfx.shaderCompiler, shader), "load and compile the RTXGI probe distance blending compute shader!\n", log); } // Probe Relocation @@ -206,7 +206,7 @@ namespace Graphics // Add common shader defines AddCommonShaderDefines(shader, volumeDesc, spirv); - CHECK(Shaders::Compile(gfx.shaderCompiler, shader, true), "load and compile the RTXGI probe relocation compute shader!\n", log); + CHECK(Shaders::Compile(gfx.shaderCompiler, shader), "load and compile the RTXGI probe relocation compute shader!\n", log); // Reset shader Shaders::ShaderProgram& shader2 = volumeShaders.emplace_back(); @@ -218,7 +218,7 @@ namespace Graphics // Add common shader defines AddCommonShaderDefines(shader2, volumeDesc, spirv); - CHECK(Shaders::Compile(gfx.shaderCompiler, shader2, true), "load and compile the RTXGI probe relocation reset compute shader!\n", log); + CHECK(Shaders::Compile(gfx.shaderCompiler, shader2), "load and compile the RTXGI probe relocation reset compute shader!\n", log); } // Probe Classification @@ -233,7 +233,7 @@ namespace Graphics // Add common shader defines AddCommonShaderDefines(shader, volumeDesc, spirv); - CHECK(Shaders::Compile(gfx.shaderCompiler, shader, true), "load and compile the RTXGI probe classification compute shader!\n", log); + CHECK(Shaders::Compile(gfx.shaderCompiler, shader), "load and compile the RTXGI probe classification compute shader!\n", log); // Reset shader Shaders::ShaderProgram& shader2 = volumeShaders.emplace_back(); @@ -245,7 +245,7 @@ namespace Graphics // Add common shader defines AddCommonShaderDefines(shader2, volumeDesc, spirv); - CHECK(Shaders::Compile(gfx.shaderCompiler, shader2, true), "load and compile the RTXGI probe classification reset compute shader!\n", log); + CHECK(Shaders::Compile(gfx.shaderCompiler, shader2), "load and compile the RTXGI probe classification reset compute shader!\n", log); } // Probe variability reduction @@ -262,7 +262,7 @@ namespace Graphics // Add shader specific defines Shaders::AddDefine(shader, L"RTXGI_DDGI_PROBE_NUM_INTERIOR_TEXELS", numIrradianceInteriorTexels.c_str()); Shaders::AddDefine(shader, L"RTXGI_DDGI_WAVE_LANE_COUNT", waveLaneCount); - CHECK(Shaders::Compile(gfx.shaderCompiler, shader, true), "load and compile the RTXGI reduction compute shader!\n", log); + CHECK(Shaders::Compile(gfx.shaderCompiler, shader), "load and compile the RTXGI reduction compute shader!\n", log); } // Extra reduction passes @@ -279,7 +279,7 @@ namespace Graphics // Add shader specific defines Shaders::AddDefine(shader, L"RTXGI_DDGI_PROBE_NUM_INTERIOR_TEXELS", numIrradianceInteriorTexels.c_str()); Shaders::AddDefine(shader, L"RTXGI_DDGI_WAVE_LANE_COUNT", waveLaneCount); - CHECK(Shaders::Compile(gfx.shaderCompiler, shader, true), "load and compile the RTXGI extra reduction compute shader!\n", log); + CHECK(Shaders::Compile(gfx.shaderCompiler, shader), "load and compile the RTXGI extra reduction compute shader!\n", log); } log << "done.\n"; diff --git a/samples/test-harness/src/graphics/DDGIVisualizations_D3D12.cpp b/samples/test-harness/src/graphics/DDGIVisualizations_D3D12.cpp index 3949470..5e64a96 100644 --- a/samples/test-harness/src/graphics/DDGIVisualizations_D3D12.cpp +++ b/samples/test-harness/src/graphics/DDGIVisualizations_D3D12.cpp @@ -80,7 +80,7 @@ namespace Graphics resources.shaderTableUpload->Unmap(0, nullptr); // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(resources.shaderTable, 0, resources.shaderTableUpload, 0, resources.shaderTableSize); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.shaderTable, 0, resources.shaderTableUpload, 0, resources.shaderTableSize); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -90,7 +90,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); return true; } @@ -149,7 +149,7 @@ namespace Graphics resources.tlas.instancesUpload->Unmap(0, nullptr); // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(resources.tlas.instances, 0, resources.tlas.instancesUpload, 0, size); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.tlas.instances, 0, resources.tlas.instancesUpload, 0, size); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -159,7 +159,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); return true; } @@ -167,7 +167,7 @@ namespace Graphics bool UpdateTLAS(Globals& d3d, GlobalResources& d3dResources, Resources& resources, const Configs::Config& config) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_GREEN), "Update DDGI Visualizations TLAS"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_GREEN), "Update DDGI Visualizations TLAS"); #endif // Update the instances and copy them to the GPU @@ -185,23 +185,23 @@ namespace Graphics barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; // Wait for the transition to finish - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); // Set the descriptor heap ID3D12DescriptorHeap* ppHeaps[] = { d3dResources.srvDescHeap, d3dResources.samplerDescHeap }; - d3d.cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + d3d.cmdList[d3d.frameIndex]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // Set the root signature - d3d.cmdList->SetComputeRootSignature(d3dResources.rootSignature); + d3d.cmdList[d3d.frameIndex]->SetComputeRootSignature(d3dResources.rootSignature); // Set the root parameter descriptor tables #if RTXGI_BINDLESS_TYPE == RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS - d3d.cmdList->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); - d3d.cmdList->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); #endif // Set the compute PSO - d3d.cmdList->SetPipelineState(resources.updateTlasPSO); + d3d.cmdList[d3d.frameIndex]->SetPipelineState(resources.updateTlasPSO); UINT instanceOffset = 0; for (UINT volumeIndex = 0; volumeIndex < static_cast(resources.volumes->size()); volumeIndex++) @@ -218,17 +218,17 @@ namespace Graphics // Update the vis root constants UINT offset = GlobalConstants::GetAlignedNum32BitValues() - DDGIVisConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, DDGIVisConsts::GetNum32BitValues(), d3dResources.constants.ddgivis.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, DDGIVisConsts::GetNum32BitValues(), d3dResources.constants.ddgivis.GetData(), offset); // Update the DDGIRootConstants DDGIRootConstants ddgiConsts = { volumeIndex, DescriptorHeapOffsets::STB_DDGI_VOLUME_CONSTS, DescriptorHeapOffsets::STB_DDGI_VOLUME_RESOURCE_INDICES }; - d3d.cmdList->SetComputeRoot32BitConstants(1, DDGIRootConstants::GetNum32BitValues(), ddgiConsts.GetData(), 0); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(1, DDGIRootConstants::GetNum32BitValues(), ddgiConsts.GetData(), 0); // Dispatch the compute shader float groupSize = 32.f; UINT numProbes = static_cast(volume->GetNumProbes()); UINT numGroups = (UINT)ceil((float)numProbes / groupSize); - d3d.cmdList->Dispatch(numGroups, 1, 1); + d3d.cmdList[d3d.frameIndex]->Dispatch(numGroups, 1, 1); // Increment the instance offset instanceOffset += resources.volumes->at(volumeIndex)->GetNumProbes(); @@ -239,7 +239,7 @@ namespace Graphics barrier.UAV.pResource = resources.tlas.instances; // Wait for the compute passes to finish - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); // Transition the TLAS instances barrier = {}; @@ -250,7 +250,7 @@ namespace Graphics barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; // Wait for the transition to finish - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAGS buildFlags = D3D12_RAYTRACING_ACCELERATION_STRUCTURE_BUILD_FLAG_PREFER_FAST_TRACE; @@ -268,17 +268,17 @@ namespace Graphics buildDesc.ScratchAccelerationStructureData = resources.tlas.scratch->GetGPUVirtualAddress(); buildDesc.DestAccelerationStructureData = resources.tlas.as->GetGPUVirtualAddress(); - d3d.cmdList->BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr); + d3d.cmdList[d3d.frameIndex]->BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr); // Wait for the TLAS build to complete barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.UAV.pResource = resources.tlas.as; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif return true; @@ -305,7 +305,7 @@ namespace Graphics Shaders::AddDefine(resources.rtShaders.rgs, L"CONSTS_SPACE", L"space1"); // for DDGIRootConstants, see Direct3D12.cpp::CreateGlobalRootSignature(...) Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_COORDINATE_SYSTEM", std::to_wstring(RTXGI_COORDINATE_SYSTEM)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.rgs, true), "compile DDGI Visualizations ray generation shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.rgs), "compile DDGI Visualizations ray generation shader!\n", log); // Load and compile alternate RGS resources.rtShaders2.rgs.filepath = root + L"shaders/ddgi/visualizations/ProbesRGS.hlsl"; @@ -315,7 +315,7 @@ namespace Graphics Shaders::AddDefine(resources.rtShaders2.rgs, L"CONSTS_SPACE", L"space1"); // for DDGIRootConstants, see Direct3D12.cpp::CreateGlobalRootSignature(...) Shaders::AddDefine(resources.rtShaders2.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); Shaders::AddDefine(resources.rtShaders2.rgs, L"RTXGI_COORDINATE_SYSTEM", std::to_wstring(RTXGI_COORDINATE_SYSTEM)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders2.rgs, true), "compile DDGI Visualizations ray generation shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders2.rgs), "compile DDGI Visualizations ray generation shader!\n", log); } // Load and compile the miss shader @@ -326,7 +326,7 @@ namespace Graphics // Load and compile Shaders::AddDefine(resources.rtShaders.miss, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.miss, true), "compile DDGI Visualizations miss shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.miss), "compile DDGI Visualizations miss shader!\n", log); // Copy to the alternate RT pipeline resources.rtShaders2.miss = resources.rtShaders.miss; @@ -346,7 +346,7 @@ namespace Graphics // Load and compile Shaders::AddDefine(group.chs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, group.chs, true), "compile DDGI Visualizations closest hit shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, group.chs), "compile DDGI Visualizations closest hit shader!\n", log); // Set the payload size resources.rtShaders.payloadSizeInBytes = sizeof(ProbeVisualizationPayload); @@ -367,7 +367,7 @@ namespace Graphics Shaders::AddDefine(resources.textureVisCS, L"RTXGI_COORDINATE_SYSTEM", std::to_wstring(RTXGI_COORDINATE_SYSTEM)); Shaders::AddDefine(resources.textureVisCS, L"THGP_DIM_X", L"8"); Shaders::AddDefine(resources.textureVisCS, L"THGP_DIM_Y", L"4"); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.textureVisCS, true), "compile DDGI Visualizations volume textures compute shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.textureVisCS), "compile DDGI Visualizations volume textures compute shader!\n", log); } // Load and compile the TLAS update compute shader @@ -379,7 +379,7 @@ namespace Graphics Shaders::AddDefine(resources.updateTlasCS, L"CONSTS_SPACE", L"space1"); // for DDGIRootConstants, see Direct3D12.cpp::CreateGlobalRootSignature(...) Shaders::AddDefine(resources.updateTlasCS, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); Shaders::AddDefine(resources.updateTlasCS, L"RTXGI_COORDINATE_SYSTEM", std::to_wstring(RTXGI_COORDINATE_SYSTEM)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.updateTlasCS, true), "compile DDGI Visualizations probes update compute shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.updateTlasCS), "compile DDGI Visualizations probes update compute shader!\n", log); } return true; @@ -597,14 +597,14 @@ namespace Graphics buildDesc.ScratchAccelerationStructureData = resources.blas.scratch->GetGPUVirtualAddress(); buildDesc.DestAccelerationStructureData = resources.blas.as->GetGPUVirtualAddress(); - d3d.cmdList->BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr); + d3d.cmdList[d3d.frameIndex]->BuildRaytracingAccelerationStructure(&buildDesc, 0, nullptr); // Wait for the BLAS build to complete D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.UAV.pResource = resources.blas.as; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); return true; } @@ -832,25 +832,25 @@ namespace Graphics if (resources.probeInstances.size() > 0) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_GREEN), "Vis: DDGIVolume Probes"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_GREEN), "Vis: DDGIVolume Probes"); #endif // Set the descriptor heaps ID3D12DescriptorHeap* ppHeaps[] = { d3dResources.srvDescHeap, d3dResources.samplerDescHeap }; - d3d.cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + d3d.cmdList[d3d.frameIndex]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // Set the root signature - d3d.cmdList->SetComputeRootSignature(d3dResources.rootSignature); + d3d.cmdList[d3d.frameIndex]->SetComputeRootSignature(d3dResources.rootSignature); // Update the vis root constants GlobalConstants consts = d3dResources.constants; UINT offset = GlobalConstants::GetAlignedNum32BitValues() - DDGIVisConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, DDGIVisConsts::GetNum32BitValues(), consts.ddgivis.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, DDGIVisConsts::GetNum32BitValues(), consts.ddgivis.GetData(), offset); // Set the root parameter descriptor tables #if RTXGI_BINDLESS_TYPE == RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS - d3d.cmdList->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); - d3d.cmdList->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); #endif // Describe the shaders and dispatch (EDDGIVolumeProbeVisType::Default) @@ -872,11 +872,11 @@ namespace Graphics desc.Depth = 1; // Set the PSO - d3d.cmdList->SetPipelineState1(resources.rtpso); + d3d.cmdList[d3d.frameIndex]->SetPipelineState1(resources.rtpso); // Dispatch rays GPU_TIMESTAMP_BEGIN(resources.gpuProbeStat->GetGPUQueryBeginIndex()); - d3d.cmdList->DispatchRays(&desc); + d3d.cmdList[d3d.frameIndex]->DispatchRays(&desc); GPU_TIMESTAMP_END(resources.gpuProbeStat->GetGPUQueryEndIndex()); D3D12_RESOURCE_BARRIER barriers[2] = {}; @@ -886,7 +886,7 @@ namespace Graphics barriers[1].UAV.pResource = d3dResources.rt.GBufferB; // Wait for the ray trace to complete - d3d.cmdList->ResourceBarrier(2, barriers); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(2, barriers); } // Describe the shaders and dispatch (EDDGIVolumeProbeVisType::Hide_Inactive) @@ -908,11 +908,11 @@ namespace Graphics desc.Depth = 1; // Set the PSO - d3d.cmdList->SetPipelineState1(resources.rtpso2); + d3d.cmdList[d3d.frameIndex]->SetPipelineState1(resources.rtpso2); // Dispatch rays GPU_TIMESTAMP_BEGIN(resources.gpuProbeStat->GetGPUQueryBeginIndex()); - d3d.cmdList->DispatchRays(&desc); + d3d.cmdList[d3d.frameIndex]->DispatchRays(&desc); GPU_TIMESTAMP_END(resources.gpuProbeStat->GetGPUQueryEndIndex()); D3D12_RESOURCE_BARRIER barriers[2] = {}; @@ -922,11 +922,11 @@ namespace Graphics barriers[1].UAV.pResource = d3dResources.rt.GBufferB; // Wait for the ray trace to complete - d3d.cmdList->ResourceBarrier(2, barriers); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(2, barriers); } #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif } } @@ -935,50 +935,50 @@ namespace Graphics if (resources.flags & VIS_FLAG_SHOW_TEXTURES) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_GREEN), "Vis: DDGIVolume Textures"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_GREEN), "Vis: DDGIVolume Textures"); #endif // Set the descriptor heaps ID3D12DescriptorHeap* ppHeaps[] = { d3dResources.srvDescHeap, d3dResources.samplerDescHeap }; - d3d.cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + d3d.cmdList[d3d.frameIndex]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // Set the root signature - d3d.cmdList->SetComputeRootSignature(d3dResources.rootSignature); + d3d.cmdList[d3d.frameIndex]->SetComputeRootSignature(d3dResources.rootSignature); // Update the vis root constants GlobalConstants consts = d3dResources.constants; UINT offset = GlobalConstants::GetAlignedNum32BitValues() - DDGIVisConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, DDGIVisConsts::GetNum32BitValues(), consts.ddgivis.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, DDGIVisConsts::GetNum32BitValues(), consts.ddgivis.GetData(), offset); // Update the DDGIRootConstants DDGIRootConstants ddgiConsts = { resources.selectedVolume, DescriptorHeapOffsets::STB_DDGI_VOLUME_CONSTS, DescriptorHeapOffsets::STB_DDGI_VOLUME_RESOURCE_INDICES }; - d3d.cmdList->SetComputeRoot32BitConstants(1, DDGIRootConstants::GetNum32BitValues(), ddgiConsts.GetData(), 0); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(1, DDGIRootConstants::GetNum32BitValues(), ddgiConsts.GetData(), 0); // Set the root parameter descriptor tables #if RTXGI_BINDLESS_TYPE == RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS - d3d.cmdList->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); - d3d.cmdList->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); #endif // Set the PSO - d3d.cmdList->SetPipelineState(resources.texturesVisPSO); + d3d.cmdList[d3d.frameIndex]->SetPipelineState(resources.texturesVisPSO); // Dispatch threads UINT groupsX = DivRoundUp(d3d.width, 8); UINT groupsY = DivRoundUp(d3d.height, 4); GPU_TIMESTAMP_BEGIN(resources.gpuTextureStat->GetGPUQueryBeginIndex()); - d3d.cmdList->Dispatch(groupsX, groupsY, 1); + d3d.cmdList[d3d.frameIndex]->Dispatch(groupsX, groupsY, 1); GPU_TIMESTAMP_END(resources.gpuTextureStat->GetGPUQueryEndIndex()); // Wait for the compute pass to finish D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.UAV.pResource = d3dResources.rt.GBufferA; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif } diff --git a/samples/test-harness/src/graphics/DDGIVisualizations_VK.cpp b/samples/test-harness/src/graphics/DDGIVisualizations_VK.cpp index 832b1a9..b19329f 100644 --- a/samples/test-harness/src/graphics/DDGIVisualizations_VK.cpp +++ b/samples/test-harness/src/graphics/DDGIVisualizations_VK.cpp @@ -461,7 +461,7 @@ namespace Graphics resources.rtShaders.rgs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_COORDINATE_SYSTEM", std::to_wstring(RTXGI_COORDINATE_SYSTEM)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.rgs, true), "compile DDGI Visualizations ray generation shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.rgs), "compile DDGI Visualizations ray generation shader!\n", log); // Load and compile alternate RGS resources.rtShaders2.rgs.filepath = root + L"shaders/ddgi/visualizations/ProbesRGS.hlsl"; @@ -470,7 +470,7 @@ namespace Graphics resources.rtShaders2.rgs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.rtShaders2.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); Shaders::AddDefine(resources.rtShaders2.rgs, L"RTXGI_COORDINATE_SYSTEM", std::to_wstring(RTXGI_COORDINATE_SYSTEM)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders2.rgs, true), "compile DDGI Visualizations ray generation shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders2.rgs), "compile DDGI Visualizations ray generation shader!\n", log); } // Load and compile the miss shader @@ -480,7 +480,7 @@ namespace Graphics resources.rtShaders.miss.exportName = L"DDGIVisProbesMiss"; resources.rtShaders.miss.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.rtShaders.miss, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.miss, true), "compile DDGI Visualizations miss shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.miss), "compile DDGI Visualizations miss shader!\n", log); // Copy to the alternate RT pipeline resources.rtShaders2.miss = resources.rtShaders.miss; @@ -501,7 +501,7 @@ namespace Graphics // Load and compile Shaders::AddDefine(group.chs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, group.chs, true), "compile DDGI Visualizations closest hit shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, group.chs), "compile DDGI Visualizations closest hit shader!\n", log); // Set the payload size resources.rtShaders.payloadSizeInBytes = sizeof(ProbeVisualizationPayload); @@ -528,7 +528,7 @@ namespace Graphics Shaders::AddDefine(resources.textureVisCS, L"RTXGI_COORDINATE_SYSTEM", std::to_wstring(RTXGI_COORDINATE_SYSTEM)); Shaders::AddDefine(resources.textureVisCS, L"THGP_DIM_X", L"8"); Shaders::AddDefine(resources.textureVisCS, L"THGP_DIM_Y", L"4"); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.textureVisCS, true), "compile DDGI Visualizations volume textures compute shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.textureVisCS), "compile DDGI Visualizations volume textures compute shader!\n", log); } // Load and compile the TLAS update compute shader @@ -546,7 +546,7 @@ namespace Graphics Shaders::AddDefine(resources.updateTlasCS, L"RTXGI_PUSH_CONSTS_FIELD_DDGI_REDUCTION_INPUT_SIZE_Z_NAME", L"ddgi_reductionInputSizeZ"); Shaders::AddDefine(resources.updateTlasCS, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); Shaders::AddDefine(resources.updateTlasCS, L"RTXGI_COORDINATE_SYSTEM", std::to_wstring(RTXGI_COORDINATE_SYSTEM)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.updateTlasCS, true), "compile DDGI Visualizations probes update compute shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.updateTlasCS), "compile DDGI Visualizations probes update compute shader!\n", log); } return true; @@ -972,9 +972,6 @@ namespace Graphics resources.volumeConstantsSTB = ddgiResources.volumeConstantsSTB; resources.volumeResourceIndicesSTB = ddgiResources.volumeResourceIndicesSTB; - // Reset the command list before initialization - CHECK(ResetCmdList(vk), "reset command list!", log); - if (!LoadAndCompileShaders(vk, resources, log)) return false; if (!CreateDescriptorSets(vk, vkResources, resources, log)) return false; if (!CreatePipelines(vk, vkResources, resources, log)) return false; @@ -990,19 +987,6 @@ namespace Graphics resources.gpuProbeStat = perf.AddGPUStat("DDGI Probe Vis"); resources.gpuTextureStat = perf.AddGPUStat("DDGI Texture Vis"); - // Execute GPU work to finish initialization - VKCHECK(vkEndCommandBuffer(vk.cmdBuffer[vk.frameIndex])); - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; - - VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE)); - VKCHECK(vkQueueWaitIdle(vk.queue)); - - WaitForGPU(vk); - return true; } @@ -1016,6 +1000,7 @@ namespace Graphics resources.volumeResourceIndicesSTB = ddgiResources.volumeResourceIndicesSTB; log << "Reloading DDGI Visualization shaders..."; + vkDeviceWaitIdle(vk.device); if (!LoadAndCompileShaders(vk, resources, log)) return false; if (!CreatePipelines(vk, vkResources, resources, log)) return false; if (!UpdateShaderTable(vk, vkResources, resources)) return false; diff --git a/samples/test-harness/src/graphics/DDGI_D3D12.cpp b/samples/test-harness/src/graphics/DDGI_D3D12.cpp index 1605e13..0f41a9a 100644 --- a/samples/test-harness/src/graphics/DDGI_D3D12.cpp +++ b/samples/test-harness/src/graphics/DDGI_D3D12.cpp @@ -789,7 +789,7 @@ namespace Graphics Shaders::AddDefine(resources.rtShaders.rgs, L"CONSTS_SPACE", L"space1"); // for DDGIRootConstants, see Direct3D12.cpp::CreateGlobalRootSignature(...) Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_COORDINATE_SYSTEM", std::to_wstring(RTXGI_COORDINATE_SYSTEM)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.rgs, true), "compile DDGI probe tracing ray generation shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.rgs), "compile DDGI probe tracing ray generation shader!\n", log); } // Load and compile the miss shader @@ -798,7 +798,7 @@ namespace Graphics resources.rtShaders.miss.entryPoint = L"Miss"; resources.rtShaders.miss.exportName = L"DDGIProbeTraceMiss"; Shaders::AddDefine(resources.rtShaders.miss, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.miss, true), "compile DDGI probe tracing miss shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.miss), "compile DDGI probe tracing miss shader!\n", log); } // Add the hit group @@ -813,14 +813,14 @@ namespace Graphics group.chs.entryPoint = L"CHS_GI"; group.chs.exportName = L"DDGIProbeTraceCHS"; Shaders::AddDefine(group.chs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, group.chs, true), "compile DDGI probe tracing closest hit shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, group.chs), "compile DDGI probe tracing closest hit shader!\n", log); // Load and compile the AHS group.ahs.filepath = root + L"shaders/AHS.hlsl"; group.ahs.entryPoint = L"AHS_GI"; group.ahs.exportName = L"DDGIProbeTraceAHS"; Shaders::AddDefine(group.ahs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, group.ahs, true), "compile DDGI probe tracing any hit shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, group.ahs), "compile DDGI probe tracing any hit shader!\n", log); // Set the payload size resources.rtShaders.payloadSizeInBytes = sizeof(PackedPayload); @@ -840,7 +840,7 @@ namespace Graphics Shaders::AddDefine(resources.indirectCS, L"RTXGI_DDGI_NUM_VOLUMES", std::to_wstring(numVolumes)); Shaders::AddDefine(resources.indirectCS, L"THGP_DIM_X", L"8"); Shaders::AddDefine(resources.indirectCS, L"THGP_DIM_Y", L"4"); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.indirectCS, true), "compile indirect lighting compute shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.indirectCS), "compile indirect lighting compute shader!\n", log); } return true; @@ -960,7 +960,7 @@ namespace Graphics resources.shaderTableUpload->Unmap(0, nullptr); // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(resources.shaderTable, 0, resources.shaderTableUpload, 0, resources.shaderTableSize); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.shaderTable, 0, resources.shaderTableUpload, 0, resources.shaderTableSize); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -970,7 +970,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); return true; } @@ -978,33 +978,33 @@ namespace Graphics void RayTraceVolumes(Globals& d3d, GlobalResources& d3dResources, Resources& resources) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_GREEN), "Ray Trace DDGIVolumes"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_GREEN), "Ray Trace DDGIVolumes"); #endif // Set the descriptor heaps ID3D12DescriptorHeap* ppHeaps[] = { d3dResources.srvDescHeap, d3dResources.samplerDescHeap }; - d3d.cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + d3d.cmdList[d3d.frameIndex]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // Set the root signature - d3d.cmdList->SetComputeRootSignature(d3dResources.rootSignature); + d3d.cmdList[d3d.frameIndex]->SetComputeRootSignature(d3dResources.rootSignature); // Update the root constants UINT offset = 0; GlobalConstants consts = d3dResources.constants; - d3d.cmdList->SetComputeRoot32BitConstants(0, AppConsts::GetNum32BitValues(), consts.app.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, AppConsts::GetNum32BitValues(), consts.app.GetData(), offset); offset += AppConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, PathTraceConsts::GetNum32BitValues(), consts.pt.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, PathTraceConsts::GetNum32BitValues(), consts.pt.GetData(), offset); offset += PathTraceConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, LightingConsts::GetNum32BitValues(), consts.lights.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, LightingConsts::GetNum32BitValues(), consts.lights.GetData(), offset); // Set the root parameter descriptor tables #if RTXGI_BINDLESS_TYPE == RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS - d3d.cmdList->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); - d3d.cmdList->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); #endif // Set the RTPSO - d3d.cmdList->SetPipelineState1(resources.rtpso); + d3d.cmdList[d3d.frameIndex]->SetPipelineState1(resources.rtpso); // Describe the shader table D3D12_DISPATCH_RAYS_DESC desc = {}; @@ -1031,16 +1031,16 @@ namespace Graphics const DDGIVolume* volume = resources.selectedVolumes[volumeIndex]; // Update the root constants - d3d.cmdList->SetComputeRoot32BitConstants(1, DDGIRootConstants::GetNum32BitValues(), volume->GetRootConstants().GetData(), 0); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(1, DDGIRootConstants::GetNum32BitValues(), volume->GetRootConstants().GetData(), 0); // Get the ray dispatch dimensions volume->GetRayDispatchDimensions(desc.Width, desc.Height, desc.Depth); // Dispatch the rays - d3d.cmdList->DispatchRays(&desc); + d3d.cmdList[d3d.frameIndex]->DispatchRays(&desc); // Transition the volume's irradiance, distance, and probe data texture arrays from read-only (non-pixel shader) to read-write (UAV) - volume->TransitionResources(d3d.cmdList, EDDGIExecutionStage::POST_PROBE_TRACE); + volume->TransitionResources(d3d.cmdList[d3d.frameIndex], EDDGIExecutionStage::POST_PROBE_TRACE); // Barrier(s) barrier.UAV.pResource = volume->GetProbeRayData(); @@ -1050,18 +1050,18 @@ namespace Graphics // Wait for the ray traces to complete if (!barriers.empty()) { - d3d.cmdList->ResourceBarrier(static_cast(barriers.size()), barriers.data()); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(static_cast(barriers.size()), barriers.data()); } #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif } void GatherIndirectLighting(Globals& d3d, GlobalResources& d3dResources, Resources& resources) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_GREEN), "Indirect Lighting"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_GREEN), "Indirect Lighting"); #endif // Transition the selected volume's irradiance, distance, and data texture arrays from read-write (UAV) to read-only (non-pixel shader) @@ -1069,29 +1069,29 @@ namespace Graphics for (UINT volumeIndex = 0; volumeIndex < static_cast(resources.selectedVolumes.size()); volumeIndex++) { const DDGIVolume* volume = resources.selectedVolumes[volumeIndex]; - volume->TransitionResources(d3d.cmdList, EDDGIExecutionStage::PRE_GATHER_CS); + volume->TransitionResources(d3d.cmdList[d3d.frameIndex], EDDGIExecutionStage::PRE_GATHER_CS); } // Set the descriptor heaps ID3D12DescriptorHeap* ppHeaps[] = { d3dResources.srvDescHeap, d3dResources.samplerDescHeap }; - d3d.cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + d3d.cmdList[d3d.frameIndex]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // Set the root signature - d3d.cmdList->SetComputeRootSignature(d3dResources.rootSignature); + d3d.cmdList[d3d.frameIndex]->SetComputeRootSignature(d3dResources.rootSignature); // Set the root parameter descriptor tables #if RTXGI_BINDLESS_TYPE == RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS - d3d.cmdList->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); - d3d.cmdList->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); #endif // Set the PSO - d3d.cmdList->SetPipelineState(resources.indirectPSO); + d3d.cmdList[d3d.frameIndex]->SetPipelineState(resources.indirectPSO); // Dispatch threads UINT groupsX = DivRoundUp(d3d.width, 8); UINT groupsY = DivRoundUp(d3d.height, 4); - d3d.cmdList->Dispatch(groupsX, groupsY, 1); + d3d.cmdList[d3d.frameIndex]->Dispatch(groupsX, groupsY, 1); // Note: if using the pixel shader (instead of compute) to gather indirect light, transition // the selected volume's resources to D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE @@ -1105,10 +1105,10 @@ namespace Graphics D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.UAV.pResource = resources.output; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif } @@ -1124,8 +1124,8 @@ namespace Graphics // Validate the SDK version assert(RTXGI_VERSION::major == 1); assert(RTXGI_VERSION::minor == 3); - assert(RTXGI_VERSION::revision == 6); - assert(std::strcmp(RTXGI_VERSION::getVersionString(), "1.3.6") == 0); + assert(RTXGI_VERSION::revision == 7); + assert(std::strcmp(RTXGI_VERSION::getVersionString(), "1.3.7") == 0); UINT numVolumes = static_cast(config.ddgi.volumes.size()); @@ -1152,7 +1152,7 @@ namespace Graphics // Clear the volume's probes at initialization DDGIVolume* volume = static_cast(resources.volumes[volumeIndex]); - volume->ClearProbes(d3d.cmdList); + volume->ClearProbes(d3d.cmdList[d3d.frameIndex]); } // Setup performance stats @@ -1220,7 +1220,7 @@ namespace Graphics if (config.ddgi.volumes[config.ddgi.selectedVolume].clearProbes) { DDGIVolume* volume = static_cast(resources.volumes[config.ddgi.selectedVolume]); - volume->ClearProbes(d3d.cmdList); + volume->ClearProbes(d3d.cmdList[d3d.frameIndex]); config.ddgi.volumes[config.ddgi.selectedVolume].clearProbes = 0; resources.numVolumeVariabilitySamples[config.ddgi.selectedVolume] = 0; @@ -1266,7 +1266,7 @@ namespace Graphics void Execute(Globals& d3d, GlobalResources& d3dResources, Resources& resources) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_GREEN), "RTXGI: DDGI"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_GREEN), "RTXGI: DDGI"); #endif CPU_TIMESTAMP_BEGIN(resources.cpuStat); GPU_TIMESTAMP_BEGIN(resources.gpuStat->GetGPUQueryBeginIndex()); @@ -1275,8 +1275,8 @@ namespace Graphics UINT numVolumes = static_cast(resources.selectedVolumes.size()); // Upload volume resource indices and constants - rtxgi::d3d12::UploadDDGIVolumeResourceIndices(d3d.cmdList, d3d.frameIndex, numVolumes, resources.selectedVolumes.data()); - rtxgi::d3d12::UploadDDGIVolumeConstants(d3d.cmdList, d3d.frameIndex, numVolumes, resources.selectedVolumes.data()); + rtxgi::d3d12::UploadDDGIVolumeResourceIndices(d3d.cmdList[d3d.frameIndex], d3d.frameIndex, numVolumes, resources.selectedVolumes.data()); + rtxgi::d3d12::UploadDDGIVolumeConstants(d3d.cmdList[d3d.frameIndex], d3d.frameIndex, numVolumes, resources.selectedVolumes.data()); // Trace rays from DDGI probes to sample the environment GPU_TIMESTAMP_BEGIN(resources.rtStat->GetGPUQueryBeginIndex()); @@ -1285,22 +1285,22 @@ namespace Graphics // Update volume probes GPU_TIMESTAMP_BEGIN(resources.blendStat->GetGPUQueryBeginIndex()); - rtxgi::d3d12::UpdateDDGIVolumeProbes(d3d.cmdList, numVolumes, resources.selectedVolumes.data()); + rtxgi::d3d12::UpdateDDGIVolumeProbes(d3d.cmdList[d3d.frameIndex], numVolumes, resources.selectedVolumes.data()); GPU_TIMESTAMP_END(resources.blendStat->GetGPUQueryEndIndex()); // Relocate probes if the feature is enabled GPU_TIMESTAMP_BEGIN(resources.relocateStat->GetGPUQueryBeginIndex()); - rtxgi::d3d12::RelocateDDGIVolumeProbes(d3d.cmdList, numVolumes, resources.selectedVolumes.data()); + rtxgi::d3d12::RelocateDDGIVolumeProbes(d3d.cmdList[d3d.frameIndex], numVolumes, resources.selectedVolumes.data()); GPU_TIMESTAMP_END(resources.relocateStat->GetGPUQueryEndIndex()); // Classify probes if the feature is enabled GPU_TIMESTAMP_BEGIN(resources.classifyStat->GetGPUQueryBeginIndex()); - rtxgi::d3d12::ClassifyDDGIVolumeProbes(d3d.cmdList, numVolumes, resources.selectedVolumes.data()); + rtxgi::d3d12::ClassifyDDGIVolumeProbes(d3d.cmdList[d3d.frameIndex], numVolumes, resources.selectedVolumes.data()); GPU_TIMESTAMP_END(resources.classifyStat->GetGPUQueryEndIndex()); // Calculate variability GPU_TIMESTAMP_BEGIN(resources.variabilityStat->GetGPUQueryBeginIndex()); - rtxgi::d3d12::CalculateDDGIVolumeVariability(d3d.cmdList, numVolumes, resources.selectedVolumes.data()); + rtxgi::d3d12::CalculateDDGIVolumeVariability(d3d.cmdList[d3d.frameIndex], numVolumes, resources.selectedVolumes.data()); // The readback happens immediately, not recorded on the command list, so will return a value from a previous update rtxgi::d3d12::ReadbackDDGIVolumeVariability(numVolumes, resources.selectedVolumes.data()); GPU_TIMESTAMP_END(resources.variabilityStat->GetGPUQueryEndIndex()); @@ -1314,7 +1314,7 @@ namespace Graphics CPU_TIMESTAMP_ENDANDRESOLVE(resources.cpuStat); #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif } diff --git a/samples/test-harness/src/graphics/DDGI_VK.cpp b/samples/test-harness/src/graphics/DDGI_VK.cpp index 7536061..e9d8cdf 100644 --- a/samples/test-harness/src/graphics/DDGI_VK.cpp +++ b/samples/test-harness/src/graphics/DDGI_VK.cpp @@ -908,7 +908,7 @@ namespace Graphics Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_PUSH_CONSTS_FIELD_DDGI_REDUCTION_INPUT_SIZE_Z_NAME", L"ddgi_reductionInputSizeZ"); Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_COORDINATE_SYSTEM", std::to_wstring(RTXGI_COORDINATE_SYSTEM)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.rgs, true), "compile DDGI probe tracing ray generation shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.rgs), "compile DDGI probe tracing ray generation shader!\n", log); } // Load and compile the miss shader @@ -918,7 +918,7 @@ namespace Graphics resources.rtShaders.miss.exportName = L"DDGIProbeTraceMiss"; resources.rtShaders.miss.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.rtShaders.miss, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.miss, true), "compile DDGI probe tracing miss shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.miss), "compile DDGI probe tracing miss shader!\n", log); } // Add the hit group @@ -934,7 +934,7 @@ namespace Graphics group.chs.exportName = L"DDGIProbeTraceCHS"; group.chs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(group.chs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, group.chs, true), "compile DDGI probe tracing closest hit shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, group.chs), "compile DDGI probe tracing closest hit shader!\n", log); // Load and compile the AHS group.ahs.filepath = root + L"shaders/AHS.hlsl"; @@ -942,7 +942,7 @@ namespace Graphics group.ahs.exportName = L"DDGIProbeTraceAHS"; group.ahs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(group.ahs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, group.ahs, true), "compile DDGI probe tracing any hit shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, group.ahs), "compile DDGI probe tracing any hit shader!\n", log); // Set the payload size resources.rtShaders.payloadSizeInBytes = sizeof(PackedPayload); @@ -968,7 +968,7 @@ namespace Graphics Shaders::AddDefine(resources.indirectCS, L"RTXGI_DDGI_NUM_VOLUMES", std::to_wstring(numVolumes)); Shaders::AddDefine(resources.indirectCS, L"THGP_DIM_X", L"8"); Shaders::AddDefine(resources.indirectCS, L"THGP_DIM_Y", L"4"); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.indirectCS, true), "compile indirect lighting compute shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.indirectCS), "compile indirect lighting compute shader!\n", log); } return true; @@ -1490,11 +1490,8 @@ namespace Graphics // Validate the SDK version assert(RTXGI_VERSION::major == 1); assert(RTXGI_VERSION::minor == 3); - assert(RTXGI_VERSION::revision == 6); - assert(std::strcmp(RTXGI_VERSION::getVersionString(), "1.3.6") == 0); - - // Reset the command list before initialization - CHECK(ResetCmdList(vk), "reset command list!", log); + assert(RTXGI_VERSION::revision == 7); + assert(std::strcmp(RTXGI_VERSION::getVersionString(), "1.3.7") == 0); uint32_t numVolumes = static_cast(config.ddgi.volumes.size()); @@ -1550,19 +1547,6 @@ namespace Graphics resources.lightingStat = perf.AddGPUStat(" Lighting"); resources.variabilityStat = perf.AddGPUStat(" Variability"); - // Execute GPU work to finish initialization - VKCHECK(vkEndCommandBuffer(vk.cmdBuffer[vk.frameIndex])); - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; - - VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE)); - VKCHECK(vkQueueWaitIdle(vk.queue)); - - WaitForGPU(vk); - return true; } @@ -1572,6 +1556,7 @@ namespace Graphics bool Reload(Globals& vk, GlobalResources& vkResources, Resources& resources, const Configs::Config& config, std::ofstream& log) { log << "Reloading DDGI shaders..."; + vkDeviceWaitIdle(vk.device); uint32_t numVolumes = static_cast(config.ddgi.volumes.size()); diff --git a/samples/test-harness/src/graphics/GBuffer_D3D12.cpp b/samples/test-harness/src/graphics/GBuffer_D3D12.cpp index 4a36cf3..8a228a8 100644 --- a/samples/test-harness/src/graphics/GBuffer_D3D12.cpp +++ b/samples/test-harness/src/graphics/GBuffer_D3D12.cpp @@ -33,14 +33,14 @@ namespace Graphics resources.shaders.rgs.entryPoint = L"RayGen"; resources.shaders.rgs.exportName = L"GBufferRGS"; Shaders::AddDefine(resources.shaders.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.rgs, true), "compile GBuffer ray generation shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.rgs), "compile GBuffer ray generation shader!\n", log); // Load and compile the miss shader resources.shaders.miss.filepath = root + L"shaders/Miss.hlsl"; resources.shaders.miss.entryPoint = L"Miss"; resources.shaders.miss.exportName = L"GBufferMiss"; Shaders::AddDefine(resources.shaders.miss, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.miss, true), "compile GBuffer miss shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.miss), "compile GBuffer miss shader!\n", log); // Add the hit group resources.shaders.hitGroups.emplace_back(); @@ -53,14 +53,14 @@ namespace Graphics group.chs.entryPoint = L"CHS_PRIMARY"; group.chs.exportName = L"GBufferCHS"; Shaders::AddDefine(group.chs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, group.chs, true), "compile GBuffer closest hit shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, group.chs), "compile GBuffer closest hit shader!\n", log); // Load and compile the AHS group.ahs.filepath = root + L"shaders/AHS.hlsl"; group.ahs.entryPoint = L"AHS_PRIMARY"; group.ahs.exportName = L"GBufferAHS"; Shaders::AddDefine(group.ahs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, group.ahs, true), "compile GBuffer any hit shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, group.ahs), "compile GBuffer any hit shader!\n", log); // Set the payload size resources.shaders.payloadSizeInBytes = sizeof(PackedPayload); @@ -171,7 +171,7 @@ namespace Graphics resources.shaderTableUpload->Unmap(0, nullptr); // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(resources.shaderTable, 0, resources.shaderTableUpload, 0, resources.shaderTableSize); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.shaderTable, 0, resources.shaderTableUpload, 0, resources.shaderTableSize); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -181,7 +181,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); return true; } @@ -240,30 +240,30 @@ namespace Graphics void Execute(Globals& d3d, GlobalResources& d3dResources, Resources& resources) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_ORANGE), "GBuffer"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_ORANGE), "GBuffer"); #endif CPU_TIMESTAMP_BEGIN(resources.cpuStat); // Set the descriptor heaps ID3D12DescriptorHeap* ppHeaps[] = { d3dResources.srvDescHeap, d3dResources.samplerDescHeap }; - d3d.cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + d3d.cmdList[d3d.frameIndex]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // Set the root signature - d3d.cmdList->SetComputeRootSignature(d3dResources.rootSignature); + d3d.cmdList[d3d.frameIndex]->SetComputeRootSignature(d3dResources.rootSignature); // Update the root constants UINT offset = 0; GlobalConstants consts = d3dResources.constants; - d3d.cmdList->SetComputeRoot32BitConstants(0, AppConsts::GetNum32BitValues(), consts.app.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, AppConsts::GetNum32BitValues(), consts.app.GetData(), offset); offset += AppConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, PathTraceConsts::GetNum32BitValues(), consts.pt.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, PathTraceConsts::GetNum32BitValues(), consts.pt.GetData(), offset); offset += PathTraceConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, LightingConsts::GetNum32BitValues(), consts.lights.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, LightingConsts::GetNum32BitValues(), consts.lights.GetData(), offset); // Set the root parameter descriptor tables #if RTXGI_BINDLESS_TYPE == RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS - d3d.cmdList->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); - d3d.cmdList->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); #endif // Dispatch rays @@ -284,11 +284,11 @@ namespace Graphics desc.Depth = 1; // Set the PSO - d3d.cmdList->SetPipelineState1(resources.rtpso); + d3d.cmdList[d3d.frameIndex]->SetPipelineState1(resources.rtpso); // Dispatch rays GPU_TIMESTAMP_BEGIN(resources.gpuStat->GetGPUQueryBeginIndex()); - d3d.cmdList->DispatchRays(&desc); + d3d.cmdList[d3d.frameIndex]->DispatchRays(&desc); GPU_TIMESTAMP_END(resources.gpuStat->GetGPUQueryEndIndex()); D3D12_RESOURCE_BARRIER barriers[4] = {}; @@ -302,11 +302,11 @@ namespace Graphics barriers[3].UAV.pResource = d3dResources.rt.GBufferD; // Wait for the ray trace to complete - d3d.cmdList->ResourceBarrier(4, barriers); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(4, barriers); CPU_TIMESTAMP_ENDANDRESOLVE(resources.cpuStat); #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif } diff --git a/samples/test-harness/src/graphics/GBuffer_VK.cpp b/samples/test-harness/src/graphics/GBuffer_VK.cpp index 029bd27..6f53e3f 100644 --- a/samples/test-harness/src/graphics/GBuffer_VK.cpp +++ b/samples/test-harness/src/graphics/GBuffer_VK.cpp @@ -34,7 +34,7 @@ namespace Graphics resources.shaders.rgs.exportName = L"GBufferRGS"; resources.shaders.rgs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.shaders.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.rgs, true), "compile GBuffer ray generation shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.rgs), "compile GBuffer ray generation shader!\n", log); // Load and compile the miss shader resources.shaders.miss.filepath = root + L"shaders/Miss.hlsl"; @@ -42,7 +42,7 @@ namespace Graphics resources.shaders.miss.exportName = L"GBufferMiss"; resources.shaders.miss.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.shaders.miss, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.miss, true), "compile GBuffer miss shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.miss), "compile GBuffer miss shader!\n", log); // Add the hit group resources.shaders.hitGroups.emplace_back(); @@ -56,7 +56,7 @@ namespace Graphics group.chs.exportName = L"GBufferCHS"; group.chs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(group.chs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, group.chs, true), "compile GBuffer closest hit shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, group.chs), "compile GBuffer closest hit shader!\n", log); // Load and compile the AHS group.ahs.filepath = root + L"shaders/AHS.hlsl"; @@ -64,7 +64,7 @@ namespace Graphics group.ahs.exportName = L"GBufferAHS"; group.ahs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(group.ahs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, group.ahs, true), "compile GBuffer any hit shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, group.ahs), "compile GBuffer any hit shader!\n", log); return true; } @@ -366,9 +366,6 @@ namespace Graphics */ bool Initialize(Globals& vk, GlobalResources& vkResources, Resources& resources, Instrumentation::Performance& perf, std::ofstream& log) { - // Reset the command list before initialization - CHECK(ResetCmdList(vk), "reset command list!", log); - if (!LoadAndCompileShaders(vk, resources, log)) return false; if (!CreateDescriptorSets(vk, vkResources, resources, log)) return false; if (!CreatePipelines(vk, vkResources, resources, log)) return false; @@ -377,19 +374,6 @@ namespace Graphics if (!UpdateShaderTable(vk, vkResources, resources, log)) return false; if (!UpdateDescriptorSets(vk, vkResources, resources, log)) return false; - // Execute GPU work to finish initialization - VKCHECK(vkEndCommandBuffer(vk.cmdBuffer[vk.frameIndex])); - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; - - VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE)); - VKCHECK(vkQueueWaitIdle(vk.queue)); - - WaitForGPU(vk); - perf.AddStat("GBuffer", resources.cpuStat, resources.gpuStat); return true; @@ -401,6 +385,7 @@ namespace Graphics bool Reload(Globals& vk, GlobalResources& vkResources, Resources& resources, std::ofstream& log) { log << "Reloading GBuffer shaders..."; + vkDeviceWaitIdle(vk.device); if (!LoadAndCompileShaders(vk, resources, log)) return false; if (!CreatePipelines(vk, vkResources, resources, log)) return false; if (!UpdateShaderTable(vk, vkResources, resources, log)) return false; diff --git a/samples/test-harness/src/graphics/PathTracing_D3D12.cpp b/samples/test-harness/src/graphics/PathTracing_D3D12.cpp index 43b4ff1..f62596e 100644 --- a/samples/test-harness/src/graphics/PathTracing_D3D12.cpp +++ b/samples/test-harness/src/graphics/PathTracing_D3D12.cpp @@ -67,14 +67,14 @@ namespace Graphics resources.shaders.rgs.exportName = L"PathTraceRGS"; Shaders::AddDefine(resources.shaders.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); Shaders::AddDefine(resources.shaders.rgs, L"GFX_NVAPI", std::to_wstring(1)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.rgs, true), "compile path tracing ray generation shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.rgs), "compile path tracing ray generation shader!\n", log); // Load and compile the miss shader resources.shaders.miss.filepath = root + L"shaders/Miss.hlsl"; resources.shaders.miss.entryPoint = L"Miss"; resources.shaders.miss.exportName = L"PathTraceMiss"; Shaders::AddDefine(resources.shaders.miss, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.miss, true), "compile path tracing miss shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.shaders.miss), "compile path tracing miss shader!\n", log); // Add the hit group resources.shaders.hitGroups.emplace_back(); @@ -87,14 +87,14 @@ namespace Graphics group.chs.entryPoint = L"CHS_LOD0"; group.chs.exportName = L"PathTraceCHS"; Shaders::AddDefine(group.chs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, group.chs, true), "compile path tracing closest hit shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, group.chs), "compile path tracing closest hit shader!\n", log); // Load and compile the AHS group.ahs.filepath = root + L"shaders/AHS.hlsl"; group.ahs.entryPoint = L"AHS_LOD0"; group.ahs.exportName = L"PathTraceAHS"; Shaders::AddDefine(group.ahs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, group.ahs, true), "compile path tracing any hit shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, group.ahs), "compile path tracing any hit shader!\n", log); // Set the payload size resources.shaders.payloadSizeInBytes = sizeof(PackedPayload); @@ -206,7 +206,7 @@ namespace Graphics resources.shaderTableUpload->Unmap(0, nullptr); // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(resources.shaderTable, 0, resources.shaderTableUpload, 0, resources.shaderTableSize); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.shaderTable, 0, resources.shaderTableUpload, 0, resources.shaderTableSize); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -216,7 +216,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); return true; } @@ -284,6 +284,7 @@ namespace Graphics d3dResources.constants.pt.numBounces = config.pathTrace.numBounces; d3dResources.constants.pt.samplesPerPixel = config.pathTrace.samplesPerPixel; d3dResources.constants.pt.SetAntialiasing(config.pathTrace.antialiasing); + d3dResources.constants.pt.SetProgressive(config.pathTrace.progressive); d3dResources.constants.pt.SetShaderExecutionReordering(config.pathTrace.shaderExecutionReordering); // Post Process constants @@ -306,7 +307,7 @@ namespace Graphics void Execute(Globals& d3d, GlobalResources& d3dResources, Resources& resources) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_YELLOW), "Path Tracing"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_YELLOW), "Path Tracing"); #endif CPU_TIMESTAMP_BEGIN(resources.cpuStat); @@ -319,32 +320,32 @@ namespace Graphics barriers[0].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; // Wait for the transitions to complete - d3d.cmdList->ResourceBarrier(1, &barriers[0]); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barriers[0]); // Set the descriptor heaps ID3D12DescriptorHeap* ppHeaps[] = { d3dResources.srvDescHeap, d3dResources.samplerDescHeap }; - d3d.cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + d3d.cmdList[d3d.frameIndex]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // Set the root signature - d3d.cmdList->SetComputeRootSignature(d3dResources.rootSignature); + d3d.cmdList[d3d.frameIndex]->SetComputeRootSignature(d3dResources.rootSignature); // Update the root constants UINT offset = 0; GlobalConstants consts = d3dResources.constants; - d3d.cmdList->SetComputeRoot32BitConstants(0, AppConsts::GetNum32BitValues(), consts.app.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, AppConsts::GetNum32BitValues(), consts.app.GetData(), offset); offset += AppConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, PathTraceConsts::GetNum32BitValues(), consts.pt.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, PathTraceConsts::GetNum32BitValues(), consts.pt.GetData(), offset); offset += PathTraceConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, LightingConsts::GetNum32BitValues(), consts.lights.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, LightingConsts::GetNum32BitValues(), consts.lights.GetData(), offset); offset += LightingConsts::GetAlignedNum32BitValues(); offset += RTAOConsts::GetAlignedNum32BitValues(); offset += CompositeConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, PostProcessConsts::GetNum32BitValues(), consts.post.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, PostProcessConsts::GetNum32BitValues(), consts.post.GetData(), offset); // Set the root parameter descriptor tables #if RTXGI_BINDLESS_TYPE == RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS - d3d.cmdList->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); - d3d.cmdList->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); #endif // Dispatch rays @@ -365,11 +366,11 @@ namespace Graphics desc.Depth = 1; // Set the PSO - d3d.cmdList->SetPipelineState1(resources.rtpso); + d3d.cmdList[d3d.frameIndex]->SetPipelineState1(resources.rtpso); // Dispatch rays GPU_TIMESTAMP_BEGIN(resources.gpuStat->GetGPUQueryBeginIndex()); - d3d.cmdList->DispatchRays(&desc); + d3d.cmdList[d3d.frameIndex]->DispatchRays(&desc); GPU_TIMESTAMP_END(resources.gpuStat->GetGPUQueryEndIndex()); // Transition the output buffer to a copy source (from UAV) @@ -383,21 +384,21 @@ namespace Graphics barriers[1].Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; // Wait for the transitions to complete - d3d.cmdList->ResourceBarrier(2, barriers); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(2, barriers); // Copy the output to the back buffer - d3d.cmdList->CopyResource(d3d.backBuffer[d3d.frameIndex], resources.PTOutput); + d3d.cmdList[d3d.frameIndex]->CopyResource(d3d.backBuffer[d3d.frameIndex], resources.PTOutput); // Transition back buffer to present (from a copy destination) barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST; barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; // Wait for the buffer transitions to complete - d3d.cmdList->ResourceBarrier(1, &barriers[1]); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barriers[1]); CPU_TIMESTAMP_ENDANDRESOLVE(resources.cpuStat); #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif } diff --git a/samples/test-harness/src/graphics/PathTracing_VK.cpp b/samples/test-harness/src/graphics/PathTracing_VK.cpp index 0651a27..38150fd 100644 --- a/samples/test-harness/src/graphics/PathTracing_VK.cpp +++ b/samples/test-harness/src/graphics/PathTracing_VK.cpp @@ -70,7 +70,7 @@ namespace Graphics resources.shaders.rgs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2"};\ Shaders::AddDefine(resources.shaders.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); Shaders::AddDefine(resources.shaders.rgs, L"GFX_NVAPI", std::to_wstring(0)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.rgs, true), "compile path tracing ray generation shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.rgs), "compile path tracing ray generation shader!\n", log); // Load and compile the miss shader resources.shaders.miss.filepath = root + L"shaders/Miss.hlsl"; @@ -78,7 +78,7 @@ namespace Graphics resources.shaders.miss.exportName = L"PathTraceMiss"; resources.shaders.miss.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.shaders.miss, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.miss, true), "compile path tracing miss shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.shaders.miss), "compile path tracing miss shader!\n", log); // Add the hit group resources.shaders.hitGroups.emplace_back(); @@ -92,7 +92,7 @@ namespace Graphics group.chs.exportName = L"PathTraceCHS"; group.chs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(group.chs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, group.chs, true), "compile path tracing closest hit shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, group.chs), "compile path tracing closest hit shader!\n", log); // Load and compile the AHS group.ahs.filepath = root + L"shaders/AHS.hlsl"; @@ -100,7 +100,7 @@ namespace Graphics group.ahs.exportName = L"PathTraceAHS"; group.ahs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(group.ahs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, group.ahs, true), "compile path tracing any hit shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, group.ahs), "compile path tracing any hit shader!\n", log); return true; } @@ -396,9 +396,6 @@ namespace Graphics */ bool Initialize(Globals& vk, GlobalResources& vkResources, Resources& resources, Instrumentation::Performance& perf, std::ofstream& log) { - // Reset the command list before initialization - CHECK(ResetCmdList(vk), "reset command list!", log); - if (!CreateTextures(vk, vkResources, resources, log)) return false; if (!LoadAndCompileShaders(vk, resources, log)) return false; if (!CreateDescriptorSets(vk, vkResources, resources, log)) return false; @@ -408,19 +405,6 @@ namespace Graphics if (!UpdateDescriptorSets(vk, vkResources, resources, log)) return false; if (!UpdateShaderTable(vk, vkResources, resources, log)) return false; - // Execute GPU work to finish initialization - VKCHECK(vkEndCommandBuffer(vk.cmdBuffer[vk.frameIndex])); - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; - - VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE)); - VKCHECK(vkQueueWaitIdle(vk.queue)); - - WaitForGPU(vk); - perf.AddStat("Path Tracing", resources.cpuStat, resources.gpuStat); return true; @@ -432,9 +416,11 @@ namespace Graphics bool Reload(Globals& vk, GlobalResources& vkResources, Resources& resources, std::ofstream& log) { log << "Reloading Path Tracing shaders..."; + vkDeviceWaitIdle(vk.device); if (!LoadAndCompileShaders(vk, resources, log)) return false; if (!CreatePipelines(vk, vkResources, resources, log)) return false; if (!UpdateShaderTable(vk, vkResources, resources, log)) return false; + log << "done.\n"; log << std::flush; @@ -477,6 +463,7 @@ namespace Graphics vkResources.constants.pt.numBounces = config.pathTrace.numBounces; vkResources.constants.pt.samplesPerPixel = config.pathTrace.samplesPerPixel; vkResources.constants.pt.SetAntialiasing(config.pathTrace.antialiasing); + vkResources.constants.pt.SetProgressive(config.pathTrace.progressive); vkResources.constants.pt.SetShaderExecutionReordering(false); // Post Process constants diff --git a/samples/test-harness/src/graphics/RTAO_D3D12.cpp b/samples/test-harness/src/graphics/RTAO_D3D12.cpp index de564bc..09a425f 100644 --- a/samples/test-harness/src/graphics/RTAO_D3D12.cpp +++ b/samples/test-harness/src/graphics/RTAO_D3D12.cpp @@ -66,14 +66,14 @@ namespace Graphics resources.rtShaders.rgs.entryPoint = L"RayGen"; resources.rtShaders.rgs.exportName = L"RTAOTraceRGS"; Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.rgs, true), "compile RTAO ray generation shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.rgs), "compile RTAO ray generation shader!\n", log); // Load and compile the miss shader resources.rtShaders.miss.filepath = root + L"shaders/Miss.hlsl"; resources.rtShaders.miss.entryPoint = L"Miss"; resources.rtShaders.miss.exportName = L"RTAOMiss"; Shaders::AddDefine(resources.rtShaders.miss, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.miss, true), "compile RTAO miss shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.rtShaders.miss), "compile RTAO miss shader!\n", log); // Add the hit group resources.rtShaders.hitGroups.emplace_back(); @@ -86,14 +86,14 @@ namespace Graphics group.chs.entryPoint = L"CHS_VISIBILITY"; group.chs.exportName = L"RTAOCHS"; Shaders::AddDefine(group.chs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, group.chs, true), "compile RTAO closest hit shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, group.chs), "compile RTAO closest hit shader!\n", log); // Load and compile the AHS group.ahs.filepath = root + L"shaders/AHS.hlsl"; group.ahs.entryPoint = L"AHS_GI"; group.ahs.exportName = L"RTAOAHS"; Shaders::AddDefine(group.ahs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); - CHECK(Shaders::Compile(d3d.shaderCompiler, group.ahs, true), "compile RTAO any hit shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, group.ahs), "compile RTAO any hit shader!\n", log); // Set the payload size resources.rtShaders.payloadSizeInBytes = sizeof(PackedPayload); @@ -106,7 +106,7 @@ namespace Graphics resources.filterCS.targetProfile = L"cs_6_6"; Shaders::AddDefine(resources.filterCS, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE)); Shaders::AddDefine(resources.filterCS, L"BLOCK_SIZE", blockSize); - CHECK(Shaders::Compile(d3d.shaderCompiler, resources.filterCS, true), "compile RTAO filter compute shader!\n", log); + CHECK(Shaders::Compile(d3d.shaderCompiler, resources.filterCS), "compile RTAO filter compute shader!\n", log); return true; } @@ -225,7 +225,7 @@ namespace Graphics resources.shaderTableUpload->Unmap(0, nullptr); // Schedule a copy of the upload buffer to the device buffer - d3d.cmdList->CopyBufferRegion(resources.shaderTable, 0, resources.shaderTableUpload, 0, resources.shaderTableSize); + d3d.cmdList[d3d.frameIndex]->CopyBufferRegion(resources.shaderTable, 0, resources.shaderTableUpload, 0, resources.shaderTableSize); // Transition the default heap resource to generic read after the copy is complete D3D12_RESOURCE_BARRIER barrier = {}; @@ -235,7 +235,7 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_GENERIC_READ; barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); return true; } @@ -333,7 +333,7 @@ namespace Graphics void Execute(Globals& d3d, GlobalResources& d3dResources, Resources& resources) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_RED), "RTAO"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_RED), "RTAO"); #endif CPU_TIMESTAMP_BEGIN(resources.cpuStat); GPU_TIMESTAMP_BEGIN(resources.gpuStat->GetGPUQueryBeginIndex()); @@ -342,10 +342,10 @@ namespace Graphics { // Set the descriptor heaps ID3D12DescriptorHeap* ppHeaps[] = { d3dResources.srvDescHeap, d3dResources.samplerDescHeap }; - d3d.cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + d3d.cmdList[d3d.frameIndex]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // Set the global root signature - d3d.cmdList->SetComputeRootSignature(d3dResources.rootSignature); + d3d.cmdList[d3d.frameIndex]->SetComputeRootSignature(d3dResources.rootSignature); // Update the root constants UINT offset = 0; @@ -353,12 +353,12 @@ namespace Graphics offset += AppConsts::GetAlignedNum32BitValues(); offset += PathTraceConsts::GetAlignedNum32BitValues(); offset += LightingConsts::GetAlignedNum32BitValues(); - d3d.cmdList->SetComputeRoot32BitConstants(0, RTAOConsts::GetNum32BitValues(), consts.rtao.GetData(), offset); + d3d.cmdList[d3d.frameIndex]->SetComputeRoot32BitConstants(0, RTAOConsts::GetNum32BitValues(), consts.rtao.GetData(), offset); // Set the root parameter descriptor tables #if RTXGI_BINDLESS_TYPE == RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS - d3d.cmdList->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); - d3d.cmdList->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(2, d3dResources.samplerDescHeap->GetGPUDescriptorHandleForHeapStart()); + d3d.cmdList[d3d.frameIndex]->SetComputeRootDescriptorTable(3, d3dResources.srvDescHeap->GetGPUDescriptorHandleForHeapStart()); #endif // Dispatch rays @@ -379,36 +379,36 @@ namespace Graphics desc.Depth = 1; // Set the PSO - d3d.cmdList->SetPipelineState1(resources.rtpso); + d3d.cmdList[d3d.frameIndex]->SetPipelineState1(resources.rtpso); // Dispatch rays - d3d.cmdList->DispatchRays(&desc); + d3d.cmdList[d3d.frameIndex]->DispatchRays(&desc); D3D12_RESOURCE_BARRIER barrier = {}; barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_UAV; barrier.UAV.pResource = resources.RTAORaw; // Wait for the ray trace to complete - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); // --- Run the filter compute shader --------------------------------- // Set the PSO and dispatch threads - d3d.cmdList->SetPipelineState(resources.filterPSO); + d3d.cmdList[d3d.frameIndex]->SetPipelineState(resources.filterPSO); uint32_t groupsX = DivRoundUp(d3d.width, RTAO_FILTER_BLOCK_SIZE); uint32_t groupsY = DivRoundUp(d3d.height, RTAO_FILTER_BLOCK_SIZE); - d3d.cmdList->Dispatch(groupsX, groupsY, 1); + d3d.cmdList[d3d.frameIndex]->Dispatch(groupsX, groupsY, 1); // Wait for the compute pass to finish barrier.UAV.pResource = resources.RTAOOutput; - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); } GPU_TIMESTAMP_END(resources.gpuStat->GetGPUQueryEndIndex()); CPU_TIMESTAMP_ENDANDRESOLVE(resources.cpuStat); #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif } diff --git a/samples/test-harness/src/graphics/RTAO_VK.cpp b/samples/test-harness/src/graphics/RTAO_VK.cpp index dd2a6b2..0d43079 100644 --- a/samples/test-harness/src/graphics/RTAO_VK.cpp +++ b/samples/test-harness/src/graphics/RTAO_VK.cpp @@ -73,7 +73,7 @@ namespace Graphics resources.rtShaders.rgs.exportName = L"RTAOTraceRGS"; resources.rtShaders.rgs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.rtShaders.rgs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.rgs, true), "compile RTAO ray generation shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.rgs), "compile RTAO ray generation shader!\n", log); // Load and compile the miss shader resources.rtShaders.miss.filepath = root + L"shaders/Miss.hlsl"; @@ -81,7 +81,7 @@ namespace Graphics resources.rtShaders.miss.exportName = L"RTAOMiss"; resources.rtShaders.miss.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.rtShaders.miss, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.miss, true), "compile RTAO miss shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.rtShaders.miss), "compile RTAO miss shader!\n", log); // Add the hit group resources.rtShaders.hitGroups.emplace_back(); @@ -95,7 +95,7 @@ namespace Graphics group.chs.exportName = L"RTAOCHS"; group.chs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(group.chs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, group.chs, true), "compile RTAO closest hit shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, group.chs), "compile RTAO closest hit shader!\n", log); // Load and compile the AHS group.ahs.filepath = root + L"shaders/AHS.hlsl"; @@ -103,7 +103,7 @@ namespace Graphics group.ahs.exportName = L"RTAOAHS"; group.ahs.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(group.ahs, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); - CHECK(Shaders::Compile(vk.shaderCompiler, group.ahs, true), "compile RTAO any hit shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, group.ahs), "compile RTAO any hit shader!\n", log); // Load and compile the filter compute shader std::wstring blockSize = std::to_wstring(static_cast(RTAO_FILTER_BLOCK_SIZE)); @@ -114,7 +114,7 @@ namespace Graphics resources.filterCS.arguments = { L"-spirv", L"-D __spirv__", L"-fspv-target-env=vulkan1.2" }; Shaders::AddDefine(resources.filterCS, L"RTXGI_BINDLESS_TYPE", std::to_wstring(RTXGI_BINDLESS_TYPE_RESOURCE_ARRAYS)); Shaders::AddDefine(resources.filterCS, L"BLOCK_SIZE", blockSize); - CHECK(Shaders::Compile(vk.shaderCompiler, resources.filterCS, true), "compile RTAO filter compute shader!\n", log); + CHECK(Shaders::Compile(vk.shaderCompiler, resources.filterCS), "compile RTAO filter compute shader!\n", log); return true; } @@ -402,9 +402,6 @@ namespace Graphics */ bool Initialize(Globals& vk, GlobalResources& vkResources, Resources& resources, Instrumentation::Performance& perf, std::ofstream& log) { - // Reset the command list before initialization - CHECK(ResetCmdList(vk), "reset command list!", log); - if (!CreateTextures(vk, vkResources, resources, log)) return false; if (!LoadAndCompileShaders(vk, resources, log)) return false; if (!CreateDescriptorSets(vk, vkResources, resources, log)) return false; @@ -416,18 +413,6 @@ namespace Graphics perf.AddStat("RTAO", resources.cpuStat, resources.gpuStat); - // Execute GPU work to finish initialization - VKCHECK(vkEndCommandBuffer(vk.cmdBuffer[vk.frameIndex])); - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; - - VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, VK_NULL_HANDLE)); - VKCHECK(vkQueueWaitIdle(vk.queue)); - - WaitForGPU(vk); return true; } @@ -437,6 +422,7 @@ namespace Graphics bool Reload(Globals& vk, GlobalResources& vkResources, Resources& resources, std::ofstream& log) { log << "Reloading RTAO shaders..."; + vkDeviceWaitIdle(vk.device); if (!LoadAndCompileShaders(vk, resources, log)) return false; if (!CreatePipelines(vk, vkResources, resources, log)) return false; if (!UpdateShaderTable(vk, vkResources, resources, log)) return false; diff --git a/samples/test-harness/src/graphics/UI_D3D12.cpp b/samples/test-harness/src/graphics/UI_D3D12.cpp index 247d67b..fb6f3ae 100644 --- a/samples/test-harness/src/graphics/UI_D3D12.cpp +++ b/samples/test-harness/src/graphics/UI_D3D12.cpp @@ -86,7 +86,7 @@ namespace Graphics if (config.app.showUI) { #ifdef GFX_PERF_MARKERS - PIXBeginEvent(d3d.cmdList, PIX_COLOR(GFX_PERF_MARKER_GREY), "ImGui"); + PIXBeginEvent(d3d.cmdList[d3d.frameIndex], PIX_COLOR(GFX_PERF_MARKER_GREY), "ImGui"); #endif // Transition the back buffer to a render target D3D12_RESOURCE_BARRIER barrier = {}; @@ -96,21 +96,21 @@ namespace Graphics barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; // Wait for the transition to complete - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); // Set the render target D3D12_CPU_DESCRIPTOR_HANDLE rtvHandle; rtvHandle.ptr = d3dResources.rtvDescHeapStart.ptr + (d3d.frameIndex * d3dResources.rtvDescHeapEntrySize); - d3d.cmdList->OMSetRenderTargets(1, &rtvHandle, false, nullptr); + d3d.cmdList[d3d.frameIndex]->OMSetRenderTargets(1, &rtvHandle, false, nullptr); // Set the resources descriptor heap ID3D12DescriptorHeap* ppHeaps[] = { d3dResources.srvDescHeap }; - d3d.cmdList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); + d3d.cmdList[d3d.frameIndex]->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps); // Render GPU_TIMESTAMP_BEGIN(resources.gpuStat->GetGPUQueryBeginIndex()); ImGui::Render(); - ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), d3d.cmdList); + ImGui_ImplDX12_RenderDrawData(ImGui::GetDrawData(), d3d.cmdList[d3d.frameIndex]); GPU_TIMESTAMP_END(resources.gpuStat->GetGPUQueryEndIndex()); // Transition the back buffer back to present @@ -118,10 +118,10 @@ namespace Graphics barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT; // Wait for the transition to complete - d3d.cmdList->ResourceBarrier(1, &barrier); + d3d.cmdList[d3d.frameIndex]->ResourceBarrier(1, &barrier); #ifdef GFX_PERF_MARKERS - PIXEndEvent(d3d.cmdList); + PIXEndEvent(d3d.cmdList[d3d.frameIndex]); #endif } diff --git a/samples/test-harness/src/graphics/UI_VK.cpp b/samples/test-harness/src/graphics/UI_VK.cpp index 5c9dd2c..c64ffeb 100644 --- a/samples/test-harness/src/graphics/UI_VK.cpp +++ b/samples/test-harness/src/graphics/UI_VK.cpp @@ -53,27 +53,23 @@ namespace Graphics CHECK(ImGui_ImplVulkan_Init(&initInfo, vk.renderPass),"initialize ImGui Vulkan!\n", log); // Setup the fonts texture - VKCHECK(vkResetCommandPool(vk.device, vk.commandPool, 0)); - - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags |= VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - VKCHECK(vkBeginCommandBuffer(vk.cmdBuffer[vk.frameIndex], &beginInfo)); - ImGui_ImplVulkan_CreateFontsTexture(vk.cmdBuffer[vk.frameIndex]); - VkSubmitInfo endInfo = {}; - endInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - endInfo.commandBufferCount = 1; - endInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; - VKCHECK(vkEndCommandBuffer(vk.cmdBuffer[vk.frameIndex])); - VKCHECK(vkQueueSubmit(vk.queue, 1, &endInfo, VK_NULL_HANDLE)); - VKCHECK(vkDeviceWaitIdle(vk.device)); + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &vk.cmdBuffer[vk.frameIndex]; + + // Submit command buffer and block until GPU work finishes + VKCHECK(vkQueueSubmit(vk.queue, 1, &submitInfo, vk.immediateFence)); + VKCHECK(vkWaitForFences(vk.device, 1, &vk.immediateFence, VK_TRUE, UINT64_MAX)); + VKCHECK(vkResetFences(vk.device, 1, &vk.immediateFence)); ImGui_ImplVulkan_DestroyFontUploadObjects(); - Graphics::ResetCmdList(vk); + ResetCmdList(vk); Graphics::UI::s_initialized = true; @@ -109,13 +105,13 @@ namespace Graphics void Execute(Graphics::Globals& vk, Graphics::GlobalResources& vkResources, Resources& resources, const Configs::Config& config) { + #ifdef GFX_PERF_MARKERS + AddPerfMarker(vk, GFX_PERF_MARKER_GREY, "ImGui"); + #endif + CPU_TIMESTAMP_BEGIN(resources.cpuStat); + if (config.app.showUI) { - #ifdef GFX_PERF_MARKERS - AddPerfMarker(vk, GFX_PERF_MARKER_GREY, "ImGui" ); - #endif - CPU_TIMESTAMP_BEGIN(resources.cpuStat); - // Note: Clear is ignored since vk.renderPass attachment load op is VK_ATTACHMENT_LOAD_OP_DONT_CARE VkClearValue clearValue; clearValue.color = { 0.f, 0.f, 0.f, 0.f }; @@ -140,13 +136,13 @@ namespace Graphics // End the render pass vkCmdEndRenderPass(vk.cmdBuffer[vk.frameIndex]); GPU_TIMESTAMP_END(resources.gpuStat->GetGPUQueryEndIndex()); + } - #ifdef GFX_PERF_MARKERS - vkCmdEndDebugUtilsLabelEXT(vk.cmdBuffer[vk.frameIndex]); - #endif + #ifdef GFX_PERF_MARKERS + vkCmdEndDebugUtilsLabelEXT(vk.cmdBuffer[vk.frameIndex]); + #endif - CPU_TIMESTAMP_ENDANDRESOLVE(resources.cpuStat); - } + CPU_TIMESTAMP_ENDANDRESOLVE(resources.cpuStat); } void Cleanup() diff --git a/samples/test-harness/src/main.cpp b/samples/test-harness/src/main.cpp index b7ec4df..d33c7c7 100644 --- a/samples/test-harness/src/main.cpp +++ b/samples/test-harness/src/main.cpp @@ -87,10 +87,14 @@ int Run(const std::vector& arguments) // Performance Timers Instrumentation::Stat startupShutdown; Instrumentation::Performance perf; - perf.AddCPUStat("Frame"); + Instrumentation::Stat* frameStat = perf.AddCPUStat("Frame"); + Instrumentation::Stat* waitStat = perf.AddCPUStat("Wait For GPU"); + Instrumentation::Stat* resetStat = perf.AddCPUStat("Reset"); + Instrumentation::Stat* timestampBeginStat = perf.AddCPUStat("TimestampBegin"); + Instrumentation::Stat* inputStat = perf.AddCPUStat("Input"); + Instrumentation::Stat* updateStat = perf.AddCPUStat("Update"); perf.AddGPUStat("Frame"); - perf.AddCPUStat("Input"); - perf.AddCPUStat("Update"); + Benchmark::BenchmarkRun benchmarkRun; CPU_TIMESTAMP_BEGIN(&startupShutdown); @@ -122,6 +126,7 @@ int Run(const std::vector& arguments) log.close(); return EXIT_FAILURE; } + log << "done.\n"; // Input @@ -194,7 +199,19 @@ int Run(const std::vector& arguments) } log << "done.\n"; - perf.AddCPUStat("Submit/Present"); + log << "Post initialization..."; + if (!Graphics::PostInitialize(gfx, log)) + { + log << "\nFailed post-initialize!"; + log.close(); + return EXIT_FAILURE; + } + log << "done\n"; + + // Add a few more CPU stats + Instrumentation::Stat* timestampEndStat = perf.AddCPUStat("TimestampEnd"); + Instrumentation::Stat* submitStat = perf.AddCPUStat("Submit"); + Instrumentation::Stat* presentStat = perf.AddCPUStat("Present"); CPU_TIMESTAMP_END(&startupShutdown); log << "Startup complete in " << startupShutdown.elapsed << " milliseconds\n"; @@ -202,66 +219,35 @@ int Run(const std::vector& arguments) log << "Main loop...\n"; std::flush(log); -#ifdef GFX_PERF_INSTRUMENTATION - Graphics::BeginFrame(gfx, gfxResources, perf); -#endif - // Main loop while(!glfwWindowShouldClose(gfx.window)) { - CPU_TIMESTAMP_BEGIN(perf.cpuTimes[0]); // frame - CPU_TIMESTAMP_BEGIN(perf.cpuTimes[1]); // input - - glfwPollEvents(); - - // Handle resize events - if (Windows::GetWindowEvent() == Windows::EWindowEvent::RESIZE) - { - Graphics::WaitForGPU(gfx); - - // Get the new back buffer dimensions from GLFW - int width, height; - glfwGetFramebufferSize(gfx.window, &width, &height); - - // Wait for the window to have valid dimensions - while(width == 0 || height == 0) - { - glfwGetFramebufferSize(gfx.window, &width, &height); - glfwWaitEvents(); - } + CPU_TIMESTAMP_BEGIN(frameStat); - // Resize all screen-space buffers - if (!Graphics::Resize(gfx, gfxResources, width, height, log)) break; // Back buffers and GBuffer textures - if (!Graphics::PathTracing::Resize(gfx, gfxResources, pt, log)) break; // PT Output and Accumulation - if (!Graphics::GBuffer::Resize(gfx, gfxResources, gbuffer, log)) break; // GBuffer - if (!Graphics::DDGI::Resize(gfx, gfxResources, ddgi, log)) break; // DDGI - if (!Graphics::DDGI::Visualizations::Resize(gfx, gfxResources, ddgiVis, log)) break; // DDGI Visualizations - if (!Graphics::RTAO::Resize(gfx, gfxResources, rtao, log)) break; // RTAO Raw and Output textures - if (!Graphics::Composite::Resize(gfx, gfxResources, composite, log)) break; // Composite - Windows::ResetWindowEvent(); + // Wait for the previous frame's GPU work to complete + CPU_TIMESTAMP_BEGIN(waitStat); + if (!Graphics::WaitForPrevGPUFrame(gfx)) { log << "GPU took too long to complete, device removed!"; break; } + CPU_TIMESTAMP_ENDANDRESOLVE(waitStat); - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[0]); // frame ended early - continue; - } + // Move to the next frame and reset the frame's command list + CPU_TIMESTAMP_BEGIN(resetStat); + if (!Graphics::MoveToNextFrame(gfx)) break; + if (!Graphics::ResetCmdList(gfx)) break; + CPU_TIMESTAMP_ENDANDRESOLVE(resetStat); - // Initialize the benchmark - if (!config.app.benchmarkRunning && input.event == Inputs::EInputEvent::RUN_BENCHMARK) - { - Benchmark::StartBenchmark(benchmarkRun, perf, config, gfx); - input.event = Inputs::EInputEvent::NONE; - } + CPU_TIMESTAMP_BEGIN(timestampBeginStat); + #ifdef GFX_PERF_INSTRUMENTATION + if (!Graphics::UpdateTimestamps(gfx, gfxResources, perf)) break; + Graphics::BeginFrame(gfx, gfxResources, perf); + #endif + CPU_TIMESTAMP_ENDANDRESOLVE(timestampBeginStat); - // Reload shaders and PSOs for graphics workloads + // Reload shaders, recreate PSOs, and update shader tables { if (config.pathTrace.reload) { if (!Graphics::PathTracing::Reload(gfx, gfxResources, pt, log)) break; config.pathTrace.reload = false; - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[0]); // frame ended early - #ifdef GFX_PERF_INSTRUMENTATION - Graphics::BeginFrame(gfx, gfxResources, perf); - #endif - continue; } if (config.ddgi.reload) @@ -269,52 +255,33 @@ int Run(const std::vector& arguments) if (!Graphics::DDGI::Reload(gfx, gfxResources, ddgi, config, log)) break; if (!Graphics::DDGI::Visualizations::Reload(gfx, gfxResources, ddgi, ddgiVis, config, log)) break; config.ddgi.reload = false; - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[0]); // frame ended early - #ifdef GFX_PERF_INSTRUMENTATION - Graphics::EndFrame(gfx, gfxResources, perf); - Graphics::ResolveTimestamps(gfx, gfxResources, perf); - if (!Graphics::UpdateTimestamps(gfx, gfxResources, perf)) break; - Graphics::BeginFrame(gfx, gfxResources, perf); - #endif - continue; } if (config.rtao.reload) { if (!Graphics::RTAO::Reload(gfx, gfxResources, rtao, log)) break; config.rtao.reload = false; - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[0]); // frame ended early - #ifdef GFX_PERF_INSTRUMENTATION - Graphics::BeginFrame(gfx, gfxResources, perf); - #endif - continue; } if (config.postProcess.reload) { if (!Graphics::Composite::Reload(gfx, gfxResources, composite, log)) break; config.postProcess.reload = false; - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[0]); // frame ended early - #ifdef GFX_PERF_INSTRUMENTATION - Graphics::BeginFrame(gfx, gfxResources, perf); - #endif - continue; } } + CPU_TIMESTAMP_BEGIN(inputStat); + + glfwPollEvents(); + // Exit the application if (input.event == Inputs::EInputEvent::QUIT) break; - // Fullscreen transition - if (input.event == Inputs::EInputEvent::FULLSCREEN_CHANGE || gfx.fullscreenChanged) + // Initialize the benchmark + if (!config.app.benchmarkRunning && input.event == Inputs::EInputEvent::RUN_BENCHMARK) { - Graphics::ToggleFullscreen(gfx); + Benchmark::StartBenchmark(benchmarkRun, perf, config, gfx); input.event = Inputs::EInputEvent::NONE; - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[0]); // frame ended early - #ifdef GFX_PERF_INSTRUMENTATION - Graphics::BeginFrame(gfx, gfxResources, perf); - #endif - continue; } // Handle mouse and keyboard input @@ -327,12 +294,12 @@ int Run(const std::vector& arguments) input.event = Inputs::EInputEvent::NONE; } - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[1]); // input + CPU_TIMESTAMP_ENDANDRESOLVE(inputStat); - // Update constant buffers - CPU_TIMESTAMP_BEGIN(perf.cpuTimes[2]); + // Update the simulation / constant buffers + CPU_TIMESTAMP_BEGIN(updateStat); Graphics::Update(gfx, gfxResources, config, scene); - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[2]); + CPU_TIMESTAMP_ENDANDRESOLVE(updateStat); if(config.app.renderMode == ERenderMode::PATH_TRACE) { @@ -363,33 +330,70 @@ int Run(const std::vector& arguments) } // UI - CPU_TIMESTAMP_BEGIN(perf.cpuTimes[perf.cpuTimes.size() - 2]); + CPU_TIMESTAMP_BEGIN(perf.cpuTimes[Instrumentation::EStatIndex::UI]); Graphics::UI::Update(gfx, ui, config, input, scene, ddgi.volumes, perf); Graphics::UI::Execute(gfx, gfxResources, ui, config); - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[perf.cpuTimes.size() - 2]); + CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[Instrumentation::EStatIndex::UI]); - // Timestamps + // GPU Timestamps + CPU_TIMESTAMP_BEGIN(timestampEndStat); #ifdef GFX_PERF_INSTRUMENTATION Graphics::EndFrame(gfx, gfxResources, perf); Graphics::ResolveTimestamps(gfx, gfxResources, perf); #endif + CPU_TIMESTAMP_ENDANDRESOLVE(timestampEndStat); - // Submit / Present - CPU_TIMESTAMP_BEGIN(perf.cpuTimes.back()); + // Submit + CPU_TIMESTAMP_BEGIN(submitStat); if (!Graphics::SubmitCmdList(gfx)) break; + CPU_TIMESTAMP_ENDANDRESOLVE(submitStat); + + // Present + CPU_TIMESTAMP_BEGIN(presentStat); if (!Graphics::Present(gfx)) continue; - if (!Graphics::WaitForGPU(gfx)) { log << "GPU took too long to complete, device removed!"; break; } + CPU_TIMESTAMP_ENDANDRESOLVE(presentStat); + CPU_TIMESTAMP_ENDANDRESOLVE(frameStat); // end of frame - // Image Capture (user triggered) - StoreImages(input.event, config, gfx, gfxResources, rtao, ddgi); + // Handle window resize events + if (Windows::GetWindowEvent() == Windows::EWindowEvent::RESIZE) + { + // Get the new back buffer dimensions from GLFW + int width, height; + glfwGetFramebufferSize(gfx.window, &width, &height); - if (!Graphics::MoveToNextFrame(gfx)) break; - if (!Graphics::ResetCmdList(gfx)) break; - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes.back()); - CPU_TIMESTAMP_ENDANDRESOLVE(perf.cpuTimes[0]); + // Wait for the window to have valid dimensions + while (width == 0 || height == 0) + { + glfwGetFramebufferSize(gfx.window, &width, &height); + glfwWaitEvents(); + } + + // Resize all screen-space buffers + if (!Graphics::ResizeBegin(gfx, gfxResources, width, height, log)) break; // Back buffers and GBuffer textures + if (!Graphics::PathTracing::Resize(gfx, gfxResources, pt, log)) break; // PT Output and Accumulation + if (!Graphics::GBuffer::Resize(gfx, gfxResources, gbuffer, log)) break; // GBuffer + if (!Graphics::DDGI::Resize(gfx, gfxResources, ddgi, log)) break; // DDGI + if (!Graphics::DDGI::Visualizations::Resize(gfx, gfxResources, ddgiVis, log)) break; // DDGI Visualizations + if (!Graphics::RTAO::Resize(gfx, gfxResources, rtao, log)) break; // RTAO Raw and Output textures + if (!Graphics::Composite::Resize(gfx, gfxResources, composite, log)) break; // Composite + if (!Graphics::ResizeEnd(gfx)) break; + Windows::ResetWindowEvent(); + } + + // Fullscreen transition + if (input.event == Inputs::EInputEvent::FULLSCREEN_CHANGE || gfx.fullscreenChanged) + { + Graphics::ToggleFullscreen(gfx); + input.event = Inputs::EInputEvent::NONE; + } + + // Image Capture (user triggered) + if (input.event == Inputs::EInputEvent::SAVE_IMAGES || input.event == Inputs::EInputEvent::SCREENSHOT) + { + StoreImages(input.event, config, gfx, gfxResources, rtao, ddgi); + } #ifdef GFX_PERF_INSTRUMENTATION - if (!Graphics::UpdateTimestamps(gfx, gfxResources, perf)) break; if (config.app.benchmarkRunning) { if (Benchmark::UpdateBenchmark(benchmarkRun, perf, config, gfx, log)) @@ -402,7 +406,6 @@ int Run(const std::vector& arguments) StoreImages(e, config, gfx, gfxResources, rtao, ddgi); } } - Graphics::BeginFrame(gfx, gfxResources, perf); #endif }