From 17c0892ff1bd51c5c20b541206ad45a97a5c3de8 Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 28 Jul 2025 23:08:26 +0200 Subject: [PATCH] Add debug name for PSO catching on D3D12/Vulkan during profiling incl. Development builds --- Source/Engine/Graphics/GPUDevice.cpp | 33 +++++++++++++- Source/Engine/Graphics/GPUPipelineState.h | 5 ++- Source/Engine/Graphics/Shaders/GPUShader.cpp | 19 ++++++++ .../Graphics/Shaders/GPUShaderProgram.h | 8 ++++ .../DirectX/DX12/GPUPipelineStateDX12.cpp | 45 +++++-------------- .../DirectX/DX12/GPUShaderDX12.cpp | 7 +++ .../GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp | 8 ++-- .../Vulkan/GPUPipelineStateVulkan.cpp | 17 ++++--- 8 files changed, 95 insertions(+), 47 deletions(-) diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp index 18b9cdffc..d7f64de45 100644 --- a/Source/Engine/Graphics/GPUDevice.cpp +++ b/Source/Engine/Graphics/GPUDevice.cpp @@ -75,10 +75,39 @@ GPUPipelineState::GPUPipelineState() { } +#if !BUILD_RELEASE + +void GPUPipelineState::GetDebugName(DebugName& name) const +{ +#define GET_NAME(e) \ + if (DebugDesc.e) \ + { \ + GPUShaderProgram::DebugName n; \ + DebugDesc.e->GetDebugName(n); \ + name.Add(n.Get(), n.Count() - 1); \ + name.Add('+'); \ + } + GET_NAME(VS); +#if GPU_ALLOW_TESSELLATION_SHADERS + GET_NAME(HS); + GET_NAME(DS); +#endif +#if GPU_ALLOW_GEOMETRY_SHADERS + GET_NAME(GS); +#endif + GET_NAME(PS); +#undef GET_NAME + if (name.Count() != 0 && name[name.Count() - 1] == '+') + name.RemoveLast(); + name.Add('\0'); +} + +#endif + bool GPUPipelineState::Init(const Description& desc) { - // Cache description in debug builds -#if BUILD_DEBUG + // Cache description in development builds +#if !BUILD_RELEASE DebugDesc = desc; #endif diff --git a/Source/Engine/Graphics/GPUPipelineState.h b/Source/Engine/Graphics/GPUPipelineState.h index b00100953..4ddc73dde 100644 --- a/Source/Engine/Graphics/GPUPipelineState.h +++ b/Source/Engine/Graphics/GPUPipelineState.h @@ -172,11 +172,14 @@ protected: GPUPipelineState(); public: -#if BUILD_DEBUG +#if !BUILD_RELEASE /// /// The description of the pipeline state cached on creation in debug builds. Can be used to help with rendering crashes or issues and validation. /// Description DebugDesc; + + typedef Array> DebugName; + void GetDebugName(DebugName& name) const; #endif #if USE_EDITOR int32 Complexity; diff --git a/Source/Engine/Graphics/Shaders/GPUShader.cpp b/Source/Engine/Graphics/Shaders/GPUShader.cpp index 694b13f40..8b0996088 100644 --- a/Source/Engine/Graphics/Shaders/GPUShader.cpp +++ b/Source/Engine/Graphics/Shaders/GPUShader.cpp @@ -25,6 +25,25 @@ void GPUShaderProgram::Init(const GPUShaderProgramInitializer& initializer) #endif } +#if !BUILD_RELEASE + +void GPUShaderProgram::GetDebugName(DebugName& name) const +{ + StringView ownerName = StringUtils::GetFileNameWithoutExtension(_owner->GetName()); + name.AddUninitialized(ownerName.Length() + _name.Length() + 2); + char* dst = name.Get(); + for (int32 i = 0; i < ownerName.Length(); i++) + dst[i] = (char)ownerName.Get()[i]; + dst += ownerName.Length(); + *dst = ':'; + dst++; + for (int32 i = 0; i < _name.Length(); i++) + dst[i] = _name.Get()[i]; + dst[_name.Length()] = 0; +} + +#endif + GPUShader::GPUShader() : GPUResource(SpawnParams(Guid::New(), TypeInitializer)) { diff --git a/Source/Engine/Graphics/Shaders/GPUShaderProgram.h b/Source/Engine/Graphics/Shaders/GPUShaderProgram.h index 176c67709..43a62065b 100644 --- a/Source/Engine/Graphics/Shaders/GPUShaderProgram.h +++ b/Source/Engine/Graphics/Shaders/GPUShaderProgram.h @@ -4,6 +4,9 @@ #include "Engine/Core/Types/BaseTypes.h" #include "Engine/Core/Types/String.h" +#if !BUILD_RELEASE +#include "Engine/Core/Collections/Array.h" +#endif #include "Config.h" class GPUShader; @@ -93,6 +96,11 @@ public: return _flags; } +#if !BUILD_RELEASE + typedef Array> DebugName; + void GetDebugName(DebugName& name) const; +#endif + public: /// /// Gets shader program stage type. diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp index cfd8d487a..7695260cd 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUPipelineStateDX12.cpp @@ -73,7 +73,12 @@ ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, i #endif return state; } - PROFILE_CPU_NAMED("Create Pipeline State"); + PROFILE_CPU(); +#if !BUILD_RELEASE + DebugName name; + GetDebugName(name); + ZoneText(name.Get(), name.Count() - 1); +#endif // Update description to match the pipeline _desc.NumRenderTargets = key.RTsCount; @@ -103,41 +108,13 @@ ID3D12PipelineState* GPUPipelineStateDX12::GetState(GPUTextureViewDX12* depth, i const HRESULT result = _device->GetDevice()->CreateGraphicsPipelineState(&_desc, IID_PPV_ARGS(&state)); LOG_DIRECTX_RESULT(result); if (FAILED(result)) + { +#if !BUILD_RELEASE + LOG(Error, "CreateGraphicsPipelineState failed for {}", String(name.Get(), name.Count() - 1)); +#endif return nullptr; -#if GPU_ENABLE_RESOURCE_NAMING && BUILD_DEBUG - Array> name; - if (DebugDesc.VS) - { - name.Add(*DebugDesc.VS->GetName(), DebugDesc.VS->GetName().Length()); - name.Add('+'); } -#if GPU_ALLOW_TESSELLATION_SHADERS - if (DebugDesc.HS) - { - name.Add(*DebugDesc.HS->GetName(), DebugDesc.HS->GetName().Length()); - name.Add('+'); - } - if (DebugDesc.DS) - { - name.Add(*DebugDesc.DS->GetName(), DebugDesc.DS->GetName().Length()); - name.Add('+'); - } -#endif -#if GPU_ALLOW_GEOMETRY_SHADERS - if (DebugDesc.GS) - { - name.Add(*DebugDesc.GS->GetName(), DebugDesc.GS->GetName().Length()); - name.Add('+'); - } -#endif - if (DebugDesc.PS) - { - name.Add(*DebugDesc.PS->GetName(), DebugDesc.PS->GetName().Length()); - name.Add('+'); - } - if (name.Count() != 0 && name[name.Count() - 1] == '+') - name.RemoveLast(); - name.Add('\0'); +#if GPU_ENABLE_RESOURCE_NAMING && !BUILD_RELEASE SetDebugObjectName(state, name.Get(), name.Count() - 1); #endif diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp index 48e06aa78..951c4d1c2 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUShaderDX12.cpp @@ -4,6 +4,7 @@ #include "GPUShaderDX12.h" #include "Engine/Serialization/MemoryReadStream.h" +#include "Engine/Profiler/ProfilerCPU.h" #include "GPUShaderProgramDX12.h" #include "Types.h" #include "../RenderToolsDX.h" @@ -70,6 +71,12 @@ ID3D12PipelineState* GPUShaderProgramCSDX12::GetOrCreateState() { if (_state) return _state; + PROFILE_CPU(); +#if !BUILD_RELEASE + DebugName name; + GetDebugName(name); + ZoneText(name.Get(), name.Count() - 1); +#endif // Create description D3D12_COMPUTE_PIPELINE_STATE_DESC psDesc; diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp index 96b139bac..083748aaa 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp @@ -238,14 +238,14 @@ static VKAPI_ATTR VkBool32 VKAPI_PTR DebugUtilsCallback(VkDebugUtilsMessageSever LOG(Info, "[Vulkan] {0} {1}:{2} {3}", type, severity, callbackData->messageIdNumber, message); } -#if BUILD_DEBUG +#if !BUILD_RELEASE if (auto* context = (GPUContextVulkan*)GPUDevice::Instance->GetMainContext()) { if (auto* state = (GPUPipelineStateVulkan*)context->GetState()) { - const StringAnsi vsName = state->DebugDesc.VS ? state->DebugDesc.VS->GetName() : StringAnsi::Empty; - const StringAnsi psName = state->DebugDesc.PS ? state->DebugDesc.PS->GetName() : StringAnsi::Empty; - LOG(Warning, "[Vulkan] Error during rendering with VS={}, PS={}", String(vsName), String(psName)); + GPUPipelineState::DebugName name; + state->GetDebugName(name); + LOG(Warning, "[Vulkan] Error during rendering with {}", String(name.Get(), name.Count() - 1)); } } #endif diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp index ce60f1d39..b8357e29f 100644 --- a/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp +++ b/Source/Engine/GraphicsDevice/Vulkan/GPUPipelineStateVulkan.cpp @@ -90,6 +90,8 @@ ComputePipelineStateVulkan* GPUShaderProgramCSVulkan::GetOrCreateState() { if (_pipelineState) return _pipelineState; + PROFILE_CPU(); + ZoneText(*_name, _name.Length()); // Create pipeline layout DescriptorSetLayoutInfoVulkan descriptorSetLayoutInfo; @@ -110,7 +112,7 @@ ComputePipelineStateVulkan* GPUShaderProgramCSVulkan::GetOrCreateState() // Create pipeline object VkPipeline pipeline; - const VkResult result = vkCreateComputePipelines(_device->Device, _device->PipelineCache, 1, &desc, nullptr, &pipeline); + VkResult result = vkCreateComputePipelines(_device->Device, _device->PipelineCache, 1, &desc, nullptr, &pipeline); LOG_VULKAN_RESULT(result); if (result != VK_SUCCESS) return nullptr; @@ -220,7 +222,12 @@ VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass, GPUVer #endif return pipeline; } - PROFILE_CPU_NAMED("Create Pipeline"); + PROFILE_CPU(); +#if !BUILD_RELEASE + DebugName name; + GetDebugName(name); + ZoneText(name.Get(), name.Count() - 1); +#endif // Bind vertex input VkPipelineVertexInputStateCreateInfo vertexInputCreateInfo; @@ -310,10 +317,8 @@ VkPipeline GPUPipelineStateVulkan::GetState(RenderPassVulkan* renderPass, GPUVer LOG_VULKAN_RESULT(result); if (result != VK_SUCCESS) { -#if BUILD_DEBUG - const StringAnsi vsName = DebugDesc.VS ? DebugDesc.VS->GetName() : StringAnsi::Empty; - const StringAnsi psName = DebugDesc.PS ? DebugDesc.PS->GetName() : StringAnsi::Empty; - LOG(Error, "vkCreateGraphicsPipelines failed for VS={0}, PS={1}", String(vsName), String(psName)); +#if !BUILD_RELEASE + LOG(Error, "vkCreateGraphicsPipelines failed for {}", String(name.Get(), name.Count() - 1)); #endif return VK_NULL_HANDLE; }