Add debug name for PSO catching on D3D12/Vulkan during profiling incl. Development builds

This commit is contained in:
Wojtek Figat
2025-07-28 23:08:26 +02:00
parent ad6764e6d7
commit 17c0892ff1
8 changed files with 95 additions and 47 deletions

View File

@@ -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

View File

@@ -172,11 +172,14 @@ protected:
GPUPipelineState();
public:
#if BUILD_DEBUG
#if !BUILD_RELEASE
/// <summary>
/// The description of the pipeline state cached on creation in debug builds. Can be used to help with rendering crashes or issues and validation.
/// </summary>
Description DebugDesc;
typedef Array<char, InlinedAllocation<200>> DebugName;
void GetDebugName(DebugName& name) const;
#endif
#if USE_EDITOR
int32 Complexity;

View File

@@ -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))
{

View File

@@ -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<char, InlinedAllocation<60>> DebugName;
void GetDebugName(DebugName& name) const;
#endif
public:
/// <summary>
/// Gets shader program stage type.

View File

@@ -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<char, InlinedAllocation<200>> 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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
}