From 64b966f4df0b6c7ad8de0fe659f5310376d335ba Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Tue, 25 Jun 2024 10:07:48 +0100 Subject: [PATCH] D3D12 ShaderDebugging adding helper namespace D3D12ShaderDebug Added bool D3D12ShaderDebug::CalculateMathIntrinsic(WrappedID3D12Device* device, MathOp mathOp, const ShaderVariable &input, ShaderVariable &output1, ShaderVariable &output2); which is used by DXBC and DXIL ShaderDebugger CalculateMathIntrinsic methods Extended shaderdebug.hlsl math intrinsics to support DXIL math opcodes Use custom math operation values for DXBC and DXIL, not the DXBC OpCode value. Use custom sampler operation values for DXBC and DXIL, not the DXBC OpCode value. This changes DXBCDebug::DebugAPIWrapper, updated D3D11DebugAPIWrapper to match changes to interface and shader math and sample operation values. --- renderdoc/data/hlsl/hlsl_cbuffers.h | 50 +- renderdoc/data/hlsl/shaderdebug.hlsl | 52 +- renderdoc/driver/d3d11/d3d11_shaderdebug.cpp | 99 +- renderdoc/driver/d3d12/d3d12_shaderdebug.cpp | 1047 +++++++++-------- renderdoc/driver/d3d12/d3d12_shaderdebug.h | 57 + .../driver/d3d12/renderdoc_d3d12.vcxproj | 1 + .../d3d12/renderdoc_d3d12.vcxproj.filters | 3 + renderdoc/driver/shaders/dxbc/dxbc_common.h | 1 + renderdoc/driver/shaders/dxbc/dxbc_debug.cpp | 4 +- renderdoc/driver/shaders/dxbc/dxbc_debug.h | 58 +- .../driver/shaders/dxbc/dxbcdxil_debug.h | 84 ++ .../shaders/dxbc/renderdoc_dxbc.vcxproj | 1 + .../dxbc/renderdoc_dxbc.vcxproj.filters | 1 + 13 files changed, 826 insertions(+), 632 deletions(-) create mode 100644 renderdoc/driver/d3d12/d3d12_shaderdebug.h create mode 100644 renderdoc/driver/shaders/dxbc/dxbcdxil_debug.h diff --git a/renderdoc/data/hlsl/hlsl_cbuffers.h b/renderdoc/data/hlsl/hlsl_cbuffers.h index 88c4e9072..793f3828a 100644 --- a/renderdoc/data/hlsl/hlsl_cbuffers.h +++ b/renderdoc/data/hlsl/hlsl_cbuffers.h @@ -375,25 +375,25 @@ cbuffer DebugSampleOperation REG(b0) float debugSampleLodCompare; }; -#define DEBUG_SAMPLE_MATH_RCP 129 -#define DEBUG_SAMPLE_MATH_RSQ 68 -#define DEBUG_SAMPLE_MATH_EXP 25 -#define DEBUG_SAMPLE_MATH_LOG 47 -#define DEBUG_SAMPLE_MATH_SINCOS 77 +#define DEBUG_SAMPLE_MATH_DXBC_RCP 1000 +#define DEBUG_SAMPLE_MATH_DXBC_RSQ 1001 +#define DEBUG_SAMPLE_MATH_DXBC_EXP 1002 +#define DEBUG_SAMPLE_MATH_DXBC_LOG 1003 +#define DEBUG_SAMPLE_MATH_DXBC_SINCOS 1004 -#define DEBUG_SAMPLE_TEX_SAMPLE 69 -#define DEBUG_SAMPLE_TEX_SAMPLE_L 72 -#define DEBUG_SAMPLE_TEX_SAMPLE_B 74 -#define DEBUG_SAMPLE_TEX_SAMPLE_D 73 -#define DEBUG_SAMPLE_TEX_SAMPLE_C 70 -#define DEBUG_SAMPLE_TEX_SAMPLE_C_LZ 71 -#define DEBUG_SAMPLE_TEX_GATHER4 109 -#define DEBUG_SAMPLE_TEX_GATHER4_C 126 -#define DEBUG_SAMPLE_TEX_GATHER4_PO 127 -#define DEBUG_SAMPLE_TEX_GATHER4_PO_C 128 -#define DEBUG_SAMPLE_TEX_LOD 108 -#define DEBUG_SAMPLE_TEX_LD 45 -#define DEBUG_SAMPLE_TEX_LD_MS 46 +#define DEBUG_SAMPLE_TEX_SAMPLE 100 +#define DEBUG_SAMPLE_TEX_SAMPLE_LEVEL 101 +#define DEBUG_SAMPLE_TEX_SAMPLE_BIAS 102 +#define DEBUG_SAMPLE_TEX_SAMPLE_GRAD 103 +#define DEBUG_SAMPLE_TEX_SAMPLE_CMP 104 +#define DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL_ZERO 105 +#define DEBUG_SAMPLE_TEX_GATHER4 106 +#define DEBUG_SAMPLE_TEX_GATHER4_CMP 107 +#define DEBUG_SAMPLE_TEX_GATHER4_PO 108 +#define DEBUG_SAMPLE_TEX_GATHER4_PO_CMP 109 +#define DEBUG_SAMPLE_TEX_LOD 110 +#define DEBUG_SAMPLE_TEX_LOAD 111 +#define DEBUG_SAMPLE_TEX_LOAD_MS 112 #define DEBUG_SAMPLE_TEX1D 1 #define DEBUG_SAMPLE_TEX2D 2 @@ -407,6 +407,20 @@ cbuffer DebugSampleOperation REG(b0) #define DEBUG_SAMPLE_UINT 4 #define DEBUG_SAMPLE_FLOAT 5 +#define DEBUG_SAMPLE_MATH_DXIL_COS 10000 +#define DEBUG_SAMPLE_MATH_DXIL_SIN 10001 +#define DEBUG_SAMPLE_MATH_DXIL_TAN 10002 +#define DEBUG_SAMPLE_MATH_DXIL_ACOS 10003 +#define DEBUG_SAMPLE_MATH_DXIL_ASIN 10004 +#define DEBUG_SAMPLE_MATH_DXIL_ATAN 10005 +#define DEBUG_SAMPLE_MATH_DXIL_HCOS 10006 +#define DEBUG_SAMPLE_MATH_DXIL_HSIN 10007 +#define DEBUG_SAMPLE_MATH_DXIL_HTAN 10008 +#define DEBUG_SAMPLE_MATH_DXIL_EXP 10009 +#define DEBUG_SAMPLE_MATH_DXIL_LOG 10010 +#define DEBUG_SAMPLE_MATH_DXIL_SQRT 10011 +#define DEBUG_SAMPLE_MATH_DXIL_RSQRT 10012 + // some constants available to both C++ and HLSL for configuring display #define CUBEMAP_FACE_RIGHT 0 #define CUBEMAP_FACE_LEFT 1 diff --git a/renderdoc/data/hlsl/shaderdebug.hlsl b/renderdoc/data/hlsl/shaderdebug.hlsl index 8d2b99b4d..36e21b1fd 100644 --- a/renderdoc/data/hlsl/shaderdebug.hlsl +++ b/renderdoc/data/hlsl/shaderdebug.hlsl @@ -36,11 +36,26 @@ RWStructuredBuffer outBuf : register(u1); [numthreads(1, 1, 1)] void RENDERDOC_DebugMathOp() { switch(mathOp) { - case DEBUG_SAMPLE_MATH_RCP: outBuf[0].outf[0] = rcp(mathInVal); break; - case DEBUG_SAMPLE_MATH_RSQ: outBuf[0].outf[0] = rsqrt(mathInVal); break; - case DEBUG_SAMPLE_MATH_EXP: outBuf[0].outf[0] = exp2(mathInVal); break; - case DEBUG_SAMPLE_MATH_LOG: outBuf[0].outf[0] = log2(mathInVal); break; - case DEBUG_SAMPLE_MATH_SINCOS: sincos(mathInVal, outBuf[0].outf[0], outBuf[0].outf[1]); break; + case DEBUG_SAMPLE_MATH_DXBC_RCP: outBuf[0].outf[0] = rcp(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXBC_RSQ: outBuf[0].outf[0] = rsqrt(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXBC_EXP: outBuf[0].outf[0] = exp2(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXBC_LOG: outBuf[0].outf[0] = log2(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXBC_SINCOS: + sincos(mathInVal, outBuf[0].outf[0], outBuf[0].outf[1]); + break; + case DEBUG_SAMPLE_MATH_DXIL_COS: outBuf[0].outf[0] = cos(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_SIN: outBuf[0].outf[0] = sin(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_TAN: outBuf[0].outf[0] = tan(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_ACOS: outBuf[0].outf[0] = acos(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_ASIN: outBuf[0].outf[0] = asin(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_ATAN: outBuf[0].outf[0] = atan(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_HCOS: outBuf[0].outf[0] = cosh(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_HSIN: outBuf[0].outf[0] = sinh(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_HTAN: outBuf[0].outf[0] = tanh(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_EXP: outBuf[0].outf[0] = exp(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_LOG: outBuf[0].outf[0] = log(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_SQRT: outBuf[0].outf[0] = sqrt(mathInVal); break; + case DEBUG_SAMPLE_MATH_DXIL_RSQRT: outBuf[0].outf[0] = rsqrt(mathInVal); break; default: break; } } @@ -112,8 +127,8 @@ float4 DoFloatOpcode(float4 uv) float lod = debugSampleLodCompare; float compare = debugSampleLodCompare; - if(opcode == DEBUG_SAMPLE_TEX_SAMPLE || opcode == DEBUG_SAMPLE_TEX_SAMPLE_B || - opcode == DEBUG_SAMPLE_TEX_SAMPLE_D) + if(opcode == DEBUG_SAMPLE_TEX_SAMPLE || opcode == DEBUG_SAMPLE_TEX_SAMPLE_BIAS || + opcode == DEBUG_SAMPLE_TEX_SAMPLE_GRAD) { switch(debugSampleTexDim) { @@ -160,7 +175,7 @@ float4 DoFloatOpcode(float4 uv) } } } - else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_L) + else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_LEVEL) { switch(debugSampleTexDim) { @@ -203,7 +218,7 @@ float4 DoFloatOpcode(float4 uv) } } } - else if(opcode == DEBUG_SAMPLE_TEX_LD || opcode == DEBUG_SAMPLE_TEX_LD_MS) + else if(opcode == DEBUG_SAMPLE_TEX_LOAD || opcode == DEBUG_SAMPLE_TEX_LOAD_MS) { switch(debugSampleTexDim) { @@ -248,7 +263,7 @@ float4 DoFloatOpcode(float4 uv) } } } - else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_C) + else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_CMP) { switch(debugSampleTexDim) { @@ -282,7 +297,7 @@ float4 DoFloatOpcode(float4 uv) } } } - else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_C_LZ) + else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL_ZERO) { switch(debugSampleTexDim) { @@ -514,7 +529,7 @@ float4 DoFloatOpcode(float4 uv) } } } - else if(opcode == DEBUG_SAMPLE_TEX_GATHER4_C || opcode == DEBUG_SAMPLE_TEX_GATHER4_PO_C) + else if(opcode == DEBUG_SAMPLE_TEX_GATHER4_CMP || opcode == DEBUG_SAMPLE_TEX_GATHER4_PO_CMP) { if(debugSampleGatherChannel == 0) { @@ -654,7 +669,7 @@ int4 DoIntOpcode(float4 uv) int4 offsets = debugSampleOffsets; float lod = debugSampleLodCompare; - if(opcode == DEBUG_SAMPLE_TEX_LD || opcode == DEBUG_SAMPLE_TEX_LD_MS) + if(opcode == DEBUG_SAMPLE_TEX_LOAD || opcode == DEBUG_SAMPLE_TEX_LOAD_MS) { switch(debugSampleTexDim) { @@ -719,7 +734,7 @@ uint4 DoUIntOpcode(float4 uv) int4 offsets = debugSampleOffsets; float lod = debugSampleLodCompare; - if(opcode == DEBUG_SAMPLE_TEX_LD || opcode == DEBUG_SAMPLE_TEX_LD_MS) + if(opcode == DEBUG_SAMPLE_TEX_LOAD || opcode == DEBUG_SAMPLE_TEX_LOAD_MS) { switch(debugSampleTexDim) { @@ -779,14 +794,15 @@ void RENDERDOC_DebugSamplePS(in float4 pos : SV_Position, in float4 uv : UVS) { int opcode = debugSampleOperation; - if(opcode != DEBUG_SAMPLE_TEX_SAMPLE_C && opcode != DEBUG_SAMPLE_TEX_LOD) + if(opcode != DEBUG_SAMPLE_TEX_SAMPLE_CMP && opcode != DEBUG_SAMPLE_TEX_LOD) { uv = debugSampleUV; } - bool forceFloat = (opcode == DEBUG_SAMPLE_TEX_SAMPLE_C || opcode == DEBUG_SAMPLE_TEX_SAMPLE_C_LZ || - opcode == DEBUG_SAMPLE_TEX_GATHER4_C || - opcode == DEBUG_SAMPLE_TEX_GATHER4_PO_C || opcode == DEBUG_SAMPLE_TEX_LOD); + bool forceFloat = + (opcode == DEBUG_SAMPLE_TEX_SAMPLE_CMP || opcode == DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL_ZERO || + opcode == DEBUG_SAMPLE_TEX_GATHER4_CMP || opcode == DEBUG_SAMPLE_TEX_GATHER4_PO_CMP || + opcode == DEBUG_SAMPLE_TEX_LOD); if(!forceFloat && debugSampleRetType == DEBUG_SAMPLE_INT) { diff --git a/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp b/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp index c0b0a513b..0d7725952 100644 --- a/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp +++ b/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp @@ -77,12 +77,12 @@ public: bool CalculateSampleGather(DXBCBytecode::OpcodeType opcode, DXBCDebug::SampleGatherResourceData resourceData, - DXBCDebug::SampleGatherSamplerData samplerData, ShaderVariable uv, - ShaderVariable ddxCalc, ShaderVariable ddyCalc, - const int8_t texelOffsets[3], int multisampleIndex, - float lodOrCompareValue, const uint8_t swizzle[4], - DXBCDebug::GatherChannel gatherChannel, const char *opString, - ShaderVariable &output); + DXBCDebug::SampleGatherSamplerData samplerData, + const ShaderVariable &uvIn, const ShaderVariable &ddxCalcIn, + const ShaderVariable &ddyCalcIn, const int8_t texelOffsets[3], + int multisampleIndex, float lodOrCompareValue, + const uint8_t swizzle[4], DXBCDebug::GatherChannel gatherChannel, + const char *opString, ShaderVariable &output); private: DXBC::ShaderType GetShaderType() { return m_dxbc ? m_dxbc->m_Type : DXBC::ShaderType::Pixel; } @@ -1035,42 +1035,41 @@ ShaderVariable D3D11DebugAPIWrapper::GetResourceInfo(DXBCBytecode::OperandType t bool D3D11DebugAPIWrapper::CalculateSampleGather( DXBCBytecode::OpcodeType opcode, DXBCDebug::SampleGatherResourceData resourceData, - DXBCDebug::SampleGatherSamplerData samplerData, ShaderVariable uv, ShaderVariable ddxCalc, - ShaderVariable ddyCalc, const int8_t texelOffsets[3], int multisampleIndex, - float lodOrCompareValue, const uint8_t swizzle[4], DXBCDebug::GatherChannel gatherChannel, - const char *opString, ShaderVariable &output) + DXBCDebug::SampleGatherSamplerData samplerData, const ShaderVariable &uvIn, + const ShaderVariable &ddxCalcIn, const ShaderVariable &ddyCalcIn, const int8_t texelOffsets[3], + int multisampleIndex, float lodOrCompareValue, const uint8_t swizzle[4], + DXBCDebug::GatherChannel gatherChannel, const char *opString, ShaderVariable &output) { using namespace DXBCBytecode; - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE == DEBUG_SAMPLE_TEX_SAMPLE, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE_L == DEBUG_SAMPLE_TEX_SAMPLE_L, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE_B == DEBUG_SAMPLE_TEX_SAMPLE_B, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE_C == DEBUG_SAMPLE_TEX_SAMPLE_C, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE_D == DEBUG_SAMPLE_TEX_SAMPLE_D, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE_C_LZ == DEBUG_SAMPLE_TEX_SAMPLE_C_LZ, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_GATHER4 == DEBUG_SAMPLE_TEX_GATHER4, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_GATHER4_C == DEBUG_SAMPLE_TEX_GATHER4_C, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_GATHER4_PO == DEBUG_SAMPLE_TEX_GATHER4_PO, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_GATHER4_PO_C == DEBUG_SAMPLE_TEX_GATHER4_PO_C, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_LOD == DEBUG_SAMPLE_TEX_LOD, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_LD == DEBUG_SAMPLE_TEX_LD, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_LD_MS == DEBUG_SAMPLE_TEX_LD_MS, - "Opcode enum doesn't match shader define"); + int sampleOp; + switch(opcode) + { + case OPCODE_SAMPLE: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE; break; + case OPCODE_SAMPLE_L: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_LEVEL; break; + case OPCODE_SAMPLE_B: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_BIAS; break; + case OPCODE_SAMPLE_C: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP; break; + case OPCODE_SAMPLE_D: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_GRAD; break; + case OPCODE_SAMPLE_C_LZ: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL_ZERO; break; + case OPCODE_GATHER4: sampleOp = DEBUG_SAMPLE_TEX_GATHER4; break; + case OPCODE_GATHER4_C: sampleOp = DEBUG_SAMPLE_TEX_GATHER4_CMP; break; + case OPCODE_GATHER4_PO: sampleOp = DEBUG_SAMPLE_TEX_GATHER4_PO; break; + case OPCODE_GATHER4_PO_C: sampleOp = DEBUG_SAMPLE_TEX_GATHER4_PO_CMP; break; + case OPCODE_LOD: sampleOp = DEBUG_SAMPLE_TEX_LOD; break; + case OPCODE_LD: sampleOp = DEBUG_SAMPLE_TEX_LOAD; break; + case OPCODE_LD_MS: sampleOp = DEBUG_SAMPLE_TEX_LOAD_MS; break; + default: + // To support a new instruction, the shader created in + // ShaderDebugging::Init() will need updating + RDCERR("Unsupported instruction for CalculateSampleGather: %u", opcode); + return false; + } ShaderDebugging &debugData = m_pDevice->GetReplay()->GetShaderDebuggingData(); + ShaderVariable uv(uvIn); + ShaderVariable ddxCalc(ddxCalcIn); + ShaderVariable ddyCalc(ddyCalcIn); for(uint32_t i = 0; i < ddxCalc.columns; i++) { if(!RDCISFINITE(ddxCalc.value.f32v[i])) @@ -1174,7 +1173,7 @@ bool D3D11DebugAPIWrapper::CalculateSampleGather( cbufferData.debugSampleGatherChannel = (int)gatherChannel; cbufferData.debugSampleSampleIndex = multisampleIndex; - cbufferData.debugSampleOperation = (int)opcode; + cbufferData.debugSampleOperation = sampleOp; cbufferData.debugSampleLodCompare = lodOrCompareValue; D3D11RenderStateTracker tracker(m_pDevice->GetImmediateContext()); @@ -1357,16 +1356,20 @@ bool D3D11DebugAPIWrapper::CalculateMathIntrinsic(DXBCBytecode::OpcodeType opcod { D3D11RenderStateTracker tracker(m_pDevice->GetImmediateContext()); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_RCP == DEBUG_SAMPLE_MATH_RCP, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_RSQ == DEBUG_SAMPLE_MATH_RSQ, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_EXP == DEBUG_SAMPLE_MATH_EXP, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_LOG == DEBUG_SAMPLE_MATH_LOG, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SINCOS == DEBUG_SAMPLE_MATH_SINCOS, - "Opcode enum doesn't match shader define"); + int mathOp = 0; + switch(opcode) + { + case DXBCBytecode::OPCODE_RCP: mathOp = DEBUG_SAMPLE_MATH_DXBC_RCP; break; + case DXBCBytecode::OPCODE_RSQ: mathOp = DEBUG_SAMPLE_MATH_DXBC_RSQ; break; + case DXBCBytecode::OPCODE_EXP: mathOp = DEBUG_SAMPLE_MATH_DXBC_EXP; break; + case DXBCBytecode::OPCODE_LOG: mathOp = DEBUG_SAMPLE_MATH_DXBC_LOG; break; + case DXBCBytecode::OPCODE_SINCOS: mathOp = DEBUG_SAMPLE_MATH_DXBC_SINCOS; break; + default: + // To support a new instruction, the shader created in + // ShaderDebugging::Init() will need updating + RDCERR("Unsupported instruction for CalculateMathIntrinsic: %u", opcode); + return false; + } ID3D11DeviceContext *context = NULL; m_pDevice->GetImmediateContext(&context); @@ -1382,7 +1385,7 @@ bool D3D11DebugAPIWrapper::CalculateMathIntrinsic(DXBCBytecode::OpcodeType opcod } DebugMathOperation data; - data.mathOp = (int)opcode; + data.mathOp = mathOp; memcpy(&data.mathInVal, &input.value.u32v[0], sizeof(Vec4f)); memcpy(mapped.pData, &data, sizeof(data)); diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp index d60ccab50..741ac516a 100644 --- a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp @@ -22,6 +22,7 @@ * THE SOFTWARE. ******************************************************************************/ +#include "d3d12_shaderdebug.h" #include "driver/dx/official/d3dcompiler.h" #include "driver/dxgi/dxgi_common.h" #include "driver/shaders/dxbc/dxbc_debug.h" @@ -36,6 +37,8 @@ #include "data/hlsl/hlsl_cbuffers.h" +using namespace DXBCBytecode; + struct DebugHit { uint32_t numHits; @@ -71,6 +74,489 @@ static bool IsShaderParameterVisible(DXBC::ShaderType shaderType, return false; } +// Helpers used by DXBC and DXIL debuggers to interact with GPU and resources +bool D3D12ShaderDebug::CalculateMathIntrinsic(bool dxil, WrappedID3D12Device *device, int mathOp, + const ShaderVariable &input, ShaderVariable &output1, + ShaderVariable &output2) +{ + D3D12MarkerRegion region(device->GetQueue()->GetReal(), "CalculateMathIntrinsic"); + + ID3D12Resource *pResultBuffer = device->GetDebugManager()->GetShaderDebugResultBuffer(); + ID3D12Resource *pReadbackBuffer = device->GetDebugManager()->GetReadbackBuffer(); + + DebugMathOperation cbufferData = {}; + memcpy(&cbufferData.mathInVal, input.value.f32v.data(), sizeof(Vec4f)); + cbufferData.mathOp = mathOp; + + // Set root signature & sig params on command list, then execute the shader + ID3D12GraphicsCommandListX *cmdList = device->GetDebugManager()->ResetDebugList(); + device->GetDebugManager()->SetDescriptorHeaps(cmdList, true, false); + cmdList->SetPipelineState(dxil ? device->GetDebugManager()->GetDXILMathIntrinsicsPso() + : device->GetDebugManager()->GetMathIntrinsicsPso()); + cmdList->SetComputeRootSignature(device->GetDebugManager()->GetShaderDebugRootSig()); + cmdList->SetComputeRootConstantBufferView( + 0, device->GetDebugManager()->UploadConstants(&cbufferData, sizeof(cbufferData))); + cmdList->SetComputeRootUnorderedAccessView(1, pResultBuffer->GetGPUVirtualAddress()); + cmdList->Dispatch(1, 1, 1); + + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = pResultBuffer; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + cmdList->ResourceBarrier(1, &barrier); + + cmdList->CopyBufferRegion(pReadbackBuffer, 0, pResultBuffer, 0, sizeof(Vec4f) * 6); + + HRESULT hr = cmdList->Close(); + if(FAILED(hr)) + { + RDCERR("Failed to close command list HRESULT: %s", ToStr(hr).c_str()); + return false; + } + + { + ID3D12CommandList *l = cmdList; + device->GetQueue()->ExecuteCommandLists(1, &l); + device->GPUSync(); + } + + D3D12_RANGE range = {0, sizeof(Vec4f) * 6}; + + byte *results = NULL; + hr = pReadbackBuffer->Map(0, &range, (void **)&results); + + if(FAILED(hr)) + { + pReadbackBuffer->Unmap(0, &range); + RDCERR("Failed to map readback buffer HRESULT: %s", ToStr(hr).c_str()); + return false; + } + + memcpy(output1.value.u32v.data(), results, sizeof(Vec4f)); + memcpy(output2.value.u32v.data(), results + sizeof(Vec4f), sizeof(Vec4f)); + + range.End = 0; + pReadbackBuffer->Unmap(0, &range); + + return true; +} + +bool D3D12ShaderDebug::CalculateSampleGather( + bool dxil, WrappedID3D12Device *device, int sampleOp, SampleGatherResourceData resourceData, + SampleGatherSamplerData samplerData, const ShaderVariable &uvIn, + const ShaderVariable &ddxCalcIn, const ShaderVariable &ddyCalcIn, const int8_t texelOffsets[3], + int multisampleIndex, float lodOrCompareValue, const uint8_t swizzle[4], + GatherChannel gatherChannel, const DXBC::ShaderType shaderType, uint32_t instruction, + const char *opString, ShaderVariable &output) +{ + D3D12MarkerRegion region(device->GetQueue()->GetReal(), "CalculateSampleGather"); + + ShaderVariable uv(uvIn); + ShaderVariable ddxCalc(ddxCalcIn); + ShaderVariable ddyCalc(ddyCalcIn); + + for(uint32_t i = 0; i < ddxCalc.columns; i++) + { + if(!RDCISFINITE(ddxCalc.value.f32v[i])) + { + RDCWARN("NaN or Inf in texlookup"); + ddxCalc.value.f32v[i] = 0.0f; + + device->AddDebugMessage(MessageCategory::Shaders, MessageSeverity::High, + MessageSource::RuntimeWarning, + StringFormat::Fmt("Shader debugging %d: %s\nNaN or Inf found in " + "texture lookup ddx - using 0.0 instead", + instruction, opString)); + } + if(!RDCISFINITE(ddyCalc.value.f32v[i])) + { + RDCWARN("NaN or Inf in texlookup"); + ddyCalc.value.f32v[i] = 0.0f; + + device->AddDebugMessage(MessageCategory::Shaders, MessageSeverity::High, + MessageSource::RuntimeWarning, + StringFormat::Fmt("Shader debugging %d: %s\nNaN or Inf found in " + "texture lookup ddy - using 0.0 instead", + instruction, opString)); + } + } + + for(uint32_t i = 0; i < uv.columns; i++) + { + if(sampleOp != DEBUG_SAMPLE_TEX_LOAD && sampleOp != DEBUG_SAMPLE_TEX_LOAD_MS && + (!RDCISFINITE(uv.value.f32v[i]))) + { + RDCWARN("NaN or Inf in texlookup"); + uv.value.f32v[i] = 0.0f; + + device->AddDebugMessage(MessageCategory::Shaders, MessageSeverity::High, + MessageSource::RuntimeWarning, + StringFormat::Fmt("Shader debugging %d: %s\nNaN or Inf found in " + "texture lookup uv - using 0.0 instead", + instruction, opString)); + } + } + + // set array slice selection to 0 if the resource is declared non-arrayed + + if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE1D) + uv.value.f32v[1] = 0.0f; + else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2D || + resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMS || + resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBE) + uv.value.f32v[2] = 0.0f; + + DebugSampleOperation cbufferData = {}; + + memcpy(&cbufferData.debugSampleUV, uv.value.u32v.data(), sizeof(Vec4f)); + memcpy(&cbufferData.debugSampleDDX, ddxCalc.value.u32v.data(), sizeof(Vec4f)); + memcpy(&cbufferData.debugSampleDDY, ddyCalc.value.u32v.data(), sizeof(Vec4f)); + memcpy(&cbufferData.debugSampleUVInt, uv.value.u32v.data(), sizeof(Vec4f)); + + if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE1D || + resourceData.dim == RESOURCE_DIMENSION_TEXTURE1DARRAY) + { + cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEX1D; + } + else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2D || + resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY) + { + cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEX2D; + } + else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE3D) + { + cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEX3D; + } + else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMS || + resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY) + { + cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEXMS; + } + else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBE || + resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBEARRAY) + { + cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEXCUBE; + } + else + { + RDCERR("Unsupported resource type %d in sample operation", resourceData.dim); + } + + int retTypes[DXBC::NUM_RETURN_TYPES] = { + 0, // RETURN_TYPE_UNKNOWN + DEBUG_SAMPLE_UNORM, // RETURN_TYPE_UNORM + DEBUG_SAMPLE_SNORM, // RETURN_TYPE_UNORM + DEBUG_SAMPLE_INT, // RETURN_TYPE_SINT + DEBUG_SAMPLE_UINT, // RETURN_TYPE_UINT + DEBUG_SAMPLE_FLOAT, // RETURN_TYPE_FLOAT + 0, // RETURN_TYPE_MIXED + DEBUG_SAMPLE_FLOAT, // RETURN_TYPE_DOUBLE (treat as floats) + 0, // RETURN_TYPE_CONTINUED + 0, // RETURN_TYPE_UNUSED + }; + + cbufferData.debugSampleRetType = retTypes[resourceData.retType]; + + cbufferData.debugSampleGatherChannel = (int)gatherChannel; + cbufferData.debugSampleSampleIndex = multisampleIndex; + cbufferData.debugSampleOperation = sampleOp; + cbufferData.debugSampleLodCompare = lodOrCompareValue; + + D3D12RenderState &rs = device->GetQueue()->GetCommandData()->m_RenderState; + D3D12RenderState prevState = rs; + + ID3D12RootSignature *sig = device->GetDebugManager()->GetShaderDebugRootSig(); + ID3D12PipelineState *pso = dxil ? device->GetDebugManager()->GetDXILTexSamplePso(texelOffsets) + : device->GetDebugManager()->GetTexSamplePso(texelOffsets); + + ID3D12GraphicsCommandListX *cmdList = device->GetDebugManager()->ResetDebugList(); + rs.pipe = GetResID(pso); + rs.rts.clear(); + // Set viewport/scissor unconditionally - we need to set this all the time for sampling for a + // compute shader, but also a graphics action might exclude pixel (0, 0) from its view or scissor + rs.views.clear(); + rs.views.push_back({0, 0, 1, 1, 0, 1}); + rs.scissors.clear(); + rs.scissors.push_back({0, 0, 1, 1}); + + D3D12_CPU_DESCRIPTOR_HANDLE srv = device->GetDebugManager()->GetCPUHandle(FIRST_SHADDEBUG_SRV); + srv.ptr += ((cbufferData.debugSampleTexDim - 1) + 5 * (cbufferData.debugSampleRetType - 1)) * + sizeof(D3D12Descriptor); + { + D3D12Descriptor descriptor = + FindDescriptor(device, D3D12_DESCRIPTOR_RANGE_TYPE_SRV, resourceData.binding, shaderType); + + descriptor.Create(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, device, srv); + } + + if(samplerData.mode != SamplerMode::NUM_SAMPLERS) + { + D3D12Descriptor descriptor = + FindDescriptor(device, D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, samplerData.binding, shaderType); + + D3D12_CPU_DESCRIPTOR_HANDLE samp = device->GetDebugManager()->GetCPUHandle(SHADDEBUG_SAMPLER0); + + if(sampleOp == DEBUG_SAMPLE_TEX_SAMPLE_CMP || sampleOp == DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL_ZERO || + sampleOp == DEBUG_SAMPLE_TEX_GATHER4_CMP || sampleOp == DEBUG_SAMPLE_TEX_GATHER4_PO_CMP) + samp.ptr += sizeof(D3D12Descriptor); + + descriptor.Create(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, device, samp); + } + + device->GetDebugManager()->SetDescriptorHeaps(rs.heaps, true, true); + + // Set our modified root signature, and transfer sigelems if we're debugging a compute shader + rs.graphics.rootsig = GetResID(sig); + rs.graphics.sigelems.clear(); + rs.compute.rootsig = ResourceId(); + rs.compute.sigelems.clear(); + + ID3D12Resource *pResultBuffer = device->GetDebugManager()->GetShaderDebugResultBuffer(); + ID3D12Resource *pReadbackBuffer = device->GetDebugManager()->GetReadbackBuffer(); + + rs.graphics.sigelems = { + D3D12RenderState::SignatureElement( + eRootCBV, device->GetDebugManager()->UploadConstants(&cbufferData, sizeof(cbufferData))), + D3D12RenderState::SignatureElement(eRootUAV, pResultBuffer->GetGPUVirtualAddress()), + D3D12RenderState::SignatureElement( + eRootTable, device->GetDebugManager()->GetCPUHandle(FIRST_SHADDEBUG_SRV)), + D3D12RenderState::SignatureElement( + eRootTable, device->GetDebugManager()->GetCPUHandle(SHADDEBUG_SAMPLER0)), + }; + + rs.topo = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; + rs.ApplyState(device, cmdList); + + D3D12_CPU_DESCRIPTOR_HANDLE rtv = device->GetDebugManager()->GetCPUHandle(PICK_PIXEL_RTV); + cmdList->OMSetRenderTargets(1, &rtv, FALSE, NULL); + cmdList->DrawInstanced(3, 1, 0, 0); + + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = pResultBuffer; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + cmdList->ResourceBarrier(1, &barrier); + + cmdList->CopyBufferRegion(pReadbackBuffer, 0, pResultBuffer, 0, sizeof(Vec4f) * 6); + + HRESULT hr = cmdList->Close(); + if(FAILED(hr)) + { + RDCERR("Failed to close command list HRESULT: %s", ToStr(hr).c_str()); + return false; + } + + { + ID3D12CommandList *l = cmdList; + device->GetQueue()->ExecuteCommandLists(1, &l); + device->GPUSync(); + } + + rs = prevState; + + D3D12_RANGE range = {0, sizeof(Vec4f) * 6}; + + void *results = NULL; + hr = pReadbackBuffer->Map(0, &range, &results); + + if(FAILED(hr)) + { + pReadbackBuffer->Unmap(0, &range); + RDCERR("Failed to map readback buffer HRESULT: %s", ToStr(hr).c_str()); + return false; + } + + ShaderVariable lookupResult("tex", 0.0f, 0.0f, 0.0f, 0.0f); + + float *retFloats = (float *)results; + uint32_t *retUInts = (uint32_t *)(retFloats + 8); + int32_t *retSInts = (int32_t *)(retUInts + 8); + + if(cbufferData.debugSampleRetType == DEBUG_SAMPLE_UINT) + { + for(int i = 0; i < 4; i++) + lookupResult.value.u32v[i] = retUInts[swizzle[i]]; + } + else if(cbufferData.debugSampleRetType == DEBUG_SAMPLE_INT) + { + for(int i = 0; i < 4; i++) + lookupResult.value.s32v[i] = retSInts[swizzle[i]]; + } + else + { + for(int i = 0; i < 4; i++) + lookupResult.value.f32v[i] = retFloats[swizzle[i]]; + } + + range.End = 0; + pReadbackBuffer->Unmap(0, &range); + + output = lookupResult; + + return true; +} + +D3D12Descriptor D3D12ShaderDebug::FindDescriptor(WrappedID3D12Device *device, + D3D12_DESCRIPTOR_RANGE_TYPE type, + const BindingSlot &slot, + const DXBC::ShaderType shaderType) +{ + D3D12Descriptor descriptor; + + const D3D12RenderState &rs = device->GetQueue()->GetCommandData()->m_RenderState; + D3D12ResourceManager *rm = device->GetResourceManager(); + + // Get the root signature + const D3D12RenderState::RootSignature *pRootSignature = NULL; + if(shaderType == DXBC::ShaderType::Compute) + { + if(rs.compute.rootsig != ResourceId()) + { + pRootSignature = &rs.compute; + } + } + else if(rs.graphics.rootsig != ResourceId()) + { + pRootSignature = &rs.graphics; + } + + if(pRootSignature) + { + WrappedID3D12RootSignature *pD3D12RootSig = + rm->GetCurrentAs(pRootSignature->rootsig); + + D3D12_DESCRIPTOR_RANGE_TYPE searchRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + + if(type == DXBCBytecode::TYPE_SAMPLER) + searchRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + else if(type == DXBCBytecode::TYPE_RESOURCE) + searchRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + else if(type == DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) + searchRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + else if(type == DXBCBytecode::TYPE_CONSTANT_BUFFER) + searchRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; + + if(searchRangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER) + { + for(const D3D12_STATIC_SAMPLER_DESC1 &samp : pD3D12RootSig->sig.StaticSamplers) + { + if(samp.RegisterSpace == slot.registerSpace && samp.ShaderRegister == slot.shaderRegister) + { + D3D12_SAMPLER_DESC2 desc = ConvertStaticSampler(samp); + descriptor.Init(&desc); + return descriptor; + } + } + } + + size_t numParams = RDCMIN(pD3D12RootSig->sig.Parameters.size(), pRootSignature->sigelems.size()); + for(size_t i = 0; i < numParams; ++i) + { + const D3D12RootSignatureParameter ¶m = pD3D12RootSig->sig.Parameters[i]; + const D3D12RenderState::SignatureElement &element = pRootSignature->sigelems[i]; + if(IsShaderParameterVisible(shaderType, param.ShaderVisibility)) + { + if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_SRV && element.type == eRootSRV && + type == DXBCBytecode::TYPE_RESOURCE) + { + if(param.Descriptor.ShaderRegister == slot.shaderRegister && + param.Descriptor.RegisterSpace == slot.registerSpace) + { + ID3D12Resource *pResource = rm->GetCurrentAs(element.id); + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; + srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; + srvDesc.Format = DXGI_FORMAT_UNKNOWN; + srvDesc.Buffer.FirstElement = 0; + // we don't know the real length or structure stride from a root descriptor, so set + // defaults. This behaviour seems undefined in drivers, so returning 1 as the number of + // elements is as sensible as anything else + srvDesc.Buffer.NumElements = 1; + srvDesc.Buffer.StructureByteStride = 4; + srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; + descriptor.Init(pResource, &srvDesc); + return descriptor; + } + } + else if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_UAV && element.type == eRootUAV && + type == DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) + { + if(param.Descriptor.ShaderRegister == slot.shaderRegister && + param.Descriptor.RegisterSpace == slot.registerSpace) + { + ID3D12Resource *pResource = rm->GetCurrentAs(element.id); + + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + uavDesc.Buffer.FirstElement = 0; + // we don't know the real length or structure stride from a root descriptor, so set + // defaults. This behaviour seems undefined in drivers, so returning 1 as the number of + // elements is as sensible as anything else + uavDesc.Buffer.NumElements = 1; + uavDesc.Buffer.StructureByteStride = 4; + uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; + descriptor.Init(pResource, NULL, &uavDesc); + return descriptor; + } + } + else if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && + element.type == eRootTable) + { + UINT prevTableOffset = 0; + WrappedID3D12DescriptorHeap *heap = + rm->GetCurrentAs(element.id); + + size_t numRanges = param.ranges.size(); + for(size_t r = 0; r < numRanges; ++r) + { + const D3D12_DESCRIPTOR_RANGE1 &range = param.ranges[r]; + + // For every range, check the number of descriptors so that we are accessing the + // correct data for append descriptor tables, even if the range type doesn't match + // what we need to fetch + UINT offset = range.OffsetInDescriptorsFromTableStart; + if(range.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) + offset = prevTableOffset; + + UINT numDescriptors = range.NumDescriptors; + if(numDescriptors == UINT_MAX) + { + // Find out how many descriptors are left after + numDescriptors = heap->GetNumDescriptors() - offset - (UINT)element.offset; + + // TODO: Should we look up the bind point in the D3D12 state to try to get + // a better guess at the number of descriptors? + } + + prevTableOffset = offset + numDescriptors; + + if(range.RangeType != searchRangeType) + continue; + + D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr; + desc += element.offset; + desc += offset; + + // Check if the slot we want is contained + if(slot.shaderRegister >= range.BaseShaderRegister && + slot.shaderRegister < range.BaseShaderRegister + numDescriptors && + range.RegisterSpace == slot.registerSpace) + { + desc += slot.shaderRegister - range.BaseShaderRegister; + return *desc; + } + } + } + } + } + } + + return descriptor; +} + class D3D12DebugAPIWrapper : public DXBCDebug::DebugAPIWrapper { public: @@ -98,13 +584,13 @@ public: uint32_t mipLevel, int &dim); bool CalculateSampleGather(DXBCBytecode::OpcodeType opcode, - DXBCDebug::SampleGatherResourceData resourceData, - DXBCDebug::SampleGatherSamplerData samplerData, ShaderVariable uv, - ShaderVariable ddxCalc, ShaderVariable ddyCalc, - const int8_t texelOffsets[3], int multisampleIndex, - float lodOrCompareValue, const uint8_t swizzle[4], - DXBCDebug::GatherChannel gatherChannel, const char *opString, - ShaderVariable &output); + DXBCDXILDebug::SampleGatherResourceData resourceData, + DXBCDXILDebug::SampleGatherSamplerData samplerData, + const ShaderVariable &uv, const ShaderVariable &ddxCalc, + const ShaderVariable &ddyCalc, const int8_t texelOffsets[3], + int multisampleIndex, float lodOrCompareValue, + const uint8_t swizzle[4], DXBCDXILDebug::GatherChannel gatherChannel, + const char *opString, ShaderVariable &output); private: DXBC::ShaderType GetShaderType() { return m_dxbc ? m_dxbc->m_Type : DXBC::ShaderType::Pixel; } @@ -493,244 +979,41 @@ bool D3D12DebugAPIWrapper::CalculateMathIntrinsic(DXBCBytecode::OpcodeType opcod const ShaderVariable &input, ShaderVariable &output1, ShaderVariable &output2) { - D3D12MarkerRegion region(m_pDevice->GetQueue()->GetReal(), "CalculateMathIntrinsic"); - - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_RCP == DEBUG_SAMPLE_MATH_RCP, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_RSQ == DEBUG_SAMPLE_MATH_RSQ, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_EXP == DEBUG_SAMPLE_MATH_EXP, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_LOG == DEBUG_SAMPLE_MATH_LOG, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SINCOS == DEBUG_SAMPLE_MATH_SINCOS, - "Opcode enum doesn't match shader define"); - - if(opcode != DXBCBytecode::OPCODE_RCP && opcode != DXBCBytecode::OPCODE_RSQ && - opcode != DXBCBytecode::OPCODE_EXP && opcode != DXBCBytecode::OPCODE_LOG && - opcode != DXBCBytecode::OPCODE_SINCOS) + int mathOp; + switch(opcode) { - // To support a new instruction, the shader created in - // D3D12DebugManager::CreateShaderDebugResources will need updated - RDCERR("Unsupported instruction for CalculateMathIntrinsic: %u", opcode); - return false; + case DXBCBytecode::OPCODE_RCP: mathOp = DEBUG_SAMPLE_MATH_DXBC_RCP; break; + case DXBCBytecode::OPCODE_RSQ: mathOp = DEBUG_SAMPLE_MATH_DXBC_RSQ; break; + case DXBCBytecode::OPCODE_EXP: mathOp = DEBUG_SAMPLE_MATH_DXBC_EXP; break; + case DXBCBytecode::OPCODE_LOG: mathOp = DEBUG_SAMPLE_MATH_DXBC_LOG; break; + case DXBCBytecode::OPCODE_SINCOS: mathOp = DEBUG_SAMPLE_MATH_DXBC_SINCOS; break; + default: + // To support a new instruction, the shader created in + // D3D12DebugManager::CreateShaderDebugResources will need updating + RDCERR("Unsupported instruction for CalculateMathIntrinsic: %u", opcode); + return false; } - ID3D12Resource *pResultBuffer = m_pDevice->GetDebugManager()->GetShaderDebugResultBuffer(); - ID3D12Resource *pReadbackBuffer = m_pDevice->GetDebugManager()->GetReadbackBuffer(); - - DebugMathOperation cbufferData = {}; - memcpy(&cbufferData.mathInVal, input.value.f32v.data(), sizeof(Vec4f)); - cbufferData.mathOp = (int)opcode; - - // Set root signature & sig params on command list, then execute the shader - ID3D12GraphicsCommandListX *cmdList = m_pDevice->GetDebugManager()->ResetDebugList(); - m_pDevice->GetDebugManager()->SetDescriptorHeaps(cmdList, true, false); - cmdList->SetPipelineState(m_pDevice->GetDebugManager()->GetMathIntrinsicsPso()); - cmdList->SetComputeRootSignature(m_pDevice->GetDebugManager()->GetShaderDebugRootSig()); - cmdList->SetComputeRootConstantBufferView( - 0, m_pDevice->GetDebugManager()->UploadConstants(&cbufferData, sizeof(cbufferData))); - cmdList->SetComputeRootUnorderedAccessView(1, pResultBuffer->GetGPUVirtualAddress()); - cmdList->Dispatch(1, 1, 1); - - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = pResultBuffer; - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; - cmdList->ResourceBarrier(1, &barrier); - - cmdList->CopyBufferRegion(pReadbackBuffer, 0, pResultBuffer, 0, sizeof(Vec4f) * 6); - - HRESULT hr = cmdList->Close(); - if(FAILED(hr)) - { - RDCERR("Failed to close command list HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - { - ID3D12CommandList *l = cmdList; - m_pDevice->GetQueue()->ExecuteCommandLists(1, &l); - m_pDevice->GPUSync(); - } - - D3D12_RANGE range = {0, sizeof(Vec4f) * 6}; - - byte *results = NULL; - hr = pReadbackBuffer->Map(0, &range, (void **)&results); - - if(FAILED(hr)) - { - pReadbackBuffer->Unmap(0, &range); - RDCERR("Failed to map readback buffer HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - memcpy(output1.value.u32v.data(), results, sizeof(Vec4f)); - memcpy(output2.value.u32v.data(), results + sizeof(Vec4f), sizeof(Vec4f)); - - range.End = 0; - pReadbackBuffer->Unmap(0, &range); - - return true; + return D3D12ShaderDebug::CalculateMathIntrinsic(false, m_pDevice, mathOp, input, output1, output2); } D3D12Descriptor D3D12DebugAPIWrapper::FindDescriptor(DXBCBytecode::OperandType type, const DXBCDebug::BindingSlot &slot) { - D3D12Descriptor descriptor; + D3D12_DESCRIPTOR_RANGE_TYPE descType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState; - D3D12ResourceManager *rm = m_pDevice->GetResourceManager(); - - // Get the root signature - const D3D12RenderState::RootSignature *pRootSignature = NULL; - if(GetShaderType() == DXBC::ShaderType::Compute) + switch(type) { - if(rs.compute.rootsig != ResourceId()) - { - pRootSignature = &rs.compute; - } - } - else if(rs.graphics.rootsig != ResourceId()) - { - pRootSignature = &rs.graphics; - } + case DXBCBytecode::TYPE_SAMPLER: descType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; break; + case DXBCBytecode::TYPE_RESOURCE: descType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; break; + case DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW: + descType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; + break; + case DXBCBytecode::TYPE_CONSTANT_BUFFER: descType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; break; + default: RDCERR("Unknown descriptor type %s", ToStr(type).c_str()); + }; - if(pRootSignature) - { - WrappedID3D12RootSignature *pD3D12RootSig = - rm->GetCurrentAs(pRootSignature->rootsig); - - D3D12_DESCRIPTOR_RANGE_TYPE searchRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - - if(type == DXBCBytecode::TYPE_SAMPLER) - searchRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; - else if(type == DXBCBytecode::TYPE_RESOURCE) - searchRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; - else if(type == DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) - searchRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_UAV; - else if(type == DXBCBytecode::TYPE_CONSTANT_BUFFER) - searchRangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; - - if(searchRangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER) - { - for(const D3D12_STATIC_SAMPLER_DESC1 &samp : pD3D12RootSig->sig.StaticSamplers) - { - if(samp.RegisterSpace == slot.registerSpace && samp.ShaderRegister == slot.shaderRegister) - { - D3D12_SAMPLER_DESC2 desc = ConvertStaticSampler(samp); - descriptor.Init(&desc); - return descriptor; - } - } - } - - size_t numParams = RDCMIN(pD3D12RootSig->sig.Parameters.size(), pRootSignature->sigelems.size()); - for(size_t i = 0; i < numParams; ++i) - { - const D3D12RootSignatureParameter ¶m = pD3D12RootSig->sig.Parameters[i]; - const D3D12RenderState::SignatureElement &element = pRootSignature->sigelems[i]; - if(IsShaderParameterVisible(GetShaderType(), param.ShaderVisibility)) - { - if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_SRV && element.type == eRootSRV && - type == DXBCBytecode::TYPE_RESOURCE) - { - if(param.Descriptor.ShaderRegister == slot.shaderRegister && - param.Descriptor.RegisterSpace == slot.registerSpace) - { - ID3D12Resource *pResource = rm->GetCurrentAs(element.id); - - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {}; - srvDesc.ViewDimension = D3D12_SRV_DIMENSION_BUFFER; - srvDesc.Format = DXGI_FORMAT_UNKNOWN; - srvDesc.Buffer.FirstElement = 0; - // we don't know the real length or structure stride from a root descriptor, so set - // defaults. This behaviour seems undefined in drivers, so returning 1 as the number of - // elements is as sensible as anything else - srvDesc.Buffer.NumElements = 1; - srvDesc.Buffer.StructureByteStride = 4; - srvDesc.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE; - descriptor.Init(pResource, &srvDesc); - return descriptor; - } - } - else if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_UAV && element.type == eRootUAV && - type == DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) - { - if(param.Descriptor.ShaderRegister == slot.shaderRegister && - param.Descriptor.RegisterSpace == slot.registerSpace) - { - ID3D12Resource *pResource = rm->GetCurrentAs(element.id); - - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - uavDesc.Format = DXGI_FORMAT_UNKNOWN; - uavDesc.Buffer.FirstElement = 0; - // we don't know the real length or structure stride from a root descriptor, so set - // defaults. This behaviour seems undefined in drivers, so returning 1 as the number of - // elements is as sensible as anything else - uavDesc.Buffer.NumElements = 1; - uavDesc.Buffer.StructureByteStride = 4; - uavDesc.Buffer.Flags = D3D12_BUFFER_UAV_FLAG_NONE; - descriptor.Init(pResource, NULL, &uavDesc); - return descriptor; - } - } - else if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && - element.type == eRootTable) - { - UINT prevTableOffset = 0; - WrappedID3D12DescriptorHeap *heap = - rm->GetCurrentAs(element.id); - - size_t numRanges = param.ranges.size(); - for(size_t r = 0; r < numRanges; ++r) - { - const D3D12_DESCRIPTOR_RANGE1 &range = param.ranges[r]; - - // For every range, check the number of descriptors so that we are accessing the - // correct data for append descriptor tables, even if the range type doesn't match - // what we need to fetch - UINT offset = range.OffsetInDescriptorsFromTableStart; - if(range.OffsetInDescriptorsFromTableStart == D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND) - offset = prevTableOffset; - - UINT numDescriptors = range.NumDescriptors; - if(numDescriptors == UINT_MAX) - { - // Find out how many descriptors are left after - numDescriptors = heap->GetNumDescriptors() - offset - (UINT)element.offset; - - // TODO: Should we look up the bind point in the D3D12 state to try to get - // a better guess at the number of descriptors? - } - - prevTableOffset = offset + numDescriptors; - - if(range.RangeType != searchRangeType) - continue; - - D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr; - desc += element.offset; - desc += offset; - - // Check if the slot we want is contained - if(slot.shaderRegister >= range.BaseShaderRegister && - slot.shaderRegister < range.BaseShaderRegister + numDescriptors && - range.RegisterSpace == slot.registerSpace) - { - desc += slot.shaderRegister - range.BaseShaderRegister; - return *desc; - } - } - } - } - } - } - - return descriptor; + return D3D12ShaderDebug::FindDescriptor(m_pDevice, descType, slot, GetShaderType()); } ShaderVariable D3D12DebugAPIWrapper::GetSampleInfo(DXBCBytecode::OperandType type, @@ -1104,279 +1387,41 @@ ShaderVariable D3D12DebugAPIWrapper::GetResourceInfo(DXBCBytecode::OperandType t } bool D3D12DebugAPIWrapper::CalculateSampleGather( - DXBCBytecode::OpcodeType opcode, DXBCDebug::SampleGatherResourceData resourceData, - DXBCDebug::SampleGatherSamplerData samplerData, ShaderVariable uv, ShaderVariable ddxCalc, - ShaderVariable ddyCalc, const int8_t texelOffsets[3], int multisampleIndex, - float lodOrCompareValue, const uint8_t swizzle[4], DXBCDebug::GatherChannel gatherChannel, - const char *opString, ShaderVariable &output) + DXBCBytecode::OpcodeType opcode, DXBCDXILDebug::SampleGatherResourceData resourceData, + DXBCDXILDebug::SampleGatherSamplerData samplerData, const ShaderVariable &uv, + const ShaderVariable &ddxCalc, const ShaderVariable &ddyCalc, const int8_t texelOffsets[3], + int multisampleIndex, float lodOrCompareValue, const uint8_t swizzle[4], + DXBCDXILDebug::GatherChannel gatherChannel, const char *opString, ShaderVariable &output) { using namespace DXBCBytecode; - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE == DEBUG_SAMPLE_TEX_SAMPLE, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE_L == DEBUG_SAMPLE_TEX_SAMPLE_L, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE_B == DEBUG_SAMPLE_TEX_SAMPLE_B, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE_C == DEBUG_SAMPLE_TEX_SAMPLE_C, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE_D == DEBUG_SAMPLE_TEX_SAMPLE_D, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_SAMPLE_C_LZ == DEBUG_SAMPLE_TEX_SAMPLE_C_LZ, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_GATHER4 == DEBUG_SAMPLE_TEX_GATHER4, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_GATHER4_C == DEBUG_SAMPLE_TEX_GATHER4_C, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_GATHER4_PO == DEBUG_SAMPLE_TEX_GATHER4_PO, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_GATHER4_PO_C == DEBUG_SAMPLE_TEX_GATHER4_PO_C, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_LOD == DEBUG_SAMPLE_TEX_LOD, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_LD == DEBUG_SAMPLE_TEX_LD, - "Opcode enum doesn't match shader define"); - RDCCOMPILE_ASSERT((int)DXBCBytecode::OPCODE_LD_MS == DEBUG_SAMPLE_TEX_LD_MS, - "Opcode enum doesn't match shader define"); - - D3D12MarkerRegion region(m_pDevice->GetQueue()->GetReal(), "CalculateSampleGather"); - - for(uint32_t i = 0; i < ddxCalc.columns; i++) + int sampleOp; + switch(opcode) { - if(!RDCISFINITE(ddxCalc.value.f32v[i])) - { - RDCWARN("NaN or Inf in texlookup"); - ddxCalc.value.f32v[i] = 0.0f; - - m_pDevice->AddDebugMessage(MessageCategory::Shaders, MessageSeverity::High, - MessageSource::RuntimeWarning, - StringFormat::Fmt("Shader debugging %d: %s\nNaN or Inf found in " - "texture lookup ddx - using 0.0 instead", - m_instruction, opString)); - } - if(!RDCISFINITE(ddyCalc.value.f32v[i])) - { - RDCWARN("NaN or Inf in texlookup"); - ddyCalc.value.f32v[i] = 0.0f; - - m_pDevice->AddDebugMessage(MessageCategory::Shaders, MessageSeverity::High, - MessageSource::RuntimeWarning, - StringFormat::Fmt("Shader debugging %d: %s\nNaN or Inf found in " - "texture lookup ddy - using 0.0 instead", - m_instruction, opString)); - } + case OPCODE_SAMPLE: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE; break; + case OPCODE_SAMPLE_L: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_LEVEL; break; + case OPCODE_SAMPLE_B: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_BIAS; break; + case OPCODE_SAMPLE_C: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP; break; + case OPCODE_SAMPLE_D: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_GRAD; break; + case OPCODE_SAMPLE_C_LZ: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL_ZERO; break; + case OPCODE_GATHER4: sampleOp = DEBUG_SAMPLE_TEX_GATHER4; break; + case OPCODE_GATHER4_C: sampleOp = DEBUG_SAMPLE_TEX_GATHER4_CMP; break; + case OPCODE_GATHER4_PO: sampleOp = DEBUG_SAMPLE_TEX_GATHER4_PO; break; + case OPCODE_GATHER4_PO_C: sampleOp = DEBUG_SAMPLE_TEX_GATHER4_PO_CMP; break; + case OPCODE_LOD: sampleOp = DEBUG_SAMPLE_TEX_LOD; break; + case OPCODE_LD: sampleOp = DEBUG_SAMPLE_TEX_LOAD; break; + case OPCODE_LD_MS: sampleOp = DEBUG_SAMPLE_TEX_LOAD_MS; break; + default: + // To support a new instruction, the shader created in + // D3D12DebugManager::CreateShaderDebugResources will need updating + RDCERR("Unsupported instruction for CalculateSampleGather: %u", opcode); + return false; } - for(uint32_t i = 0; i < uv.columns; i++) - { - if(opcode != OPCODE_LD && opcode != OPCODE_LD_MS && (!RDCISFINITE(uv.value.f32v[i]))) - { - RDCWARN("NaN or Inf in texlookup"); - uv.value.f32v[i] = 0.0f; - - m_pDevice->AddDebugMessage(MessageCategory::Shaders, MessageSeverity::High, - MessageSource::RuntimeWarning, - StringFormat::Fmt("Shader debugging %d: %s\nNaN or Inf found in " - "texture lookup uv - using 0.0 instead", - m_instruction, opString)); - } - } - - // set array slice selection to 0 if the resource is declared non-arrayed - - if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE1D) - uv.value.f32v[1] = 0.0f; - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2D || - resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMS || - resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBE) - uv.value.f32v[2] = 0.0f; - - DebugSampleOperation cbufferData = {}; - - memcpy(&cbufferData.debugSampleUV, uv.value.u32v.data(), sizeof(Vec4f)); - memcpy(&cbufferData.debugSampleDDX, ddxCalc.value.u32v.data(), sizeof(Vec4f)); - memcpy(&cbufferData.debugSampleDDY, ddyCalc.value.u32v.data(), sizeof(Vec4f)); - memcpy(&cbufferData.debugSampleUVInt, uv.value.u32v.data(), sizeof(Vec4f)); - - if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE1D || - resourceData.dim == RESOURCE_DIMENSION_TEXTURE1DARRAY) - { - cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEX1D; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2D || - resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY) - { - cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEX2D; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE3D) - { - cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEX3D; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMS || - resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY) - { - cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEXMS; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBE || - resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBEARRAY) - { - cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEXCUBE; - } - else - { - RDCERR("Unsupported resource type %d in sample operation", resourceData.dim); - } - - int retTypes[DXBC::NUM_RETURN_TYPES] = { - 0, // RETURN_TYPE_UNKNOWN - DEBUG_SAMPLE_UNORM, // RETURN_TYPE_UNORM - DEBUG_SAMPLE_SNORM, // RETURN_TYPE_UNORM - DEBUG_SAMPLE_INT, // RETURN_TYPE_SINT - DEBUG_SAMPLE_UINT, // RETURN_TYPE_UINT - DEBUG_SAMPLE_FLOAT, // RETURN_TYPE_FLOAT - 0, // RETURN_TYPE_MIXED - DEBUG_SAMPLE_FLOAT, // RETURN_TYPE_DOUBLE (treat as floats) - 0, // RETURN_TYPE_CONTINUED - 0, // RETURN_TYPE_UNUSED - }; - - cbufferData.debugSampleRetType = retTypes[resourceData.retType]; - - cbufferData.debugSampleGatherChannel = (int)gatherChannel; - cbufferData.debugSampleSampleIndex = multisampleIndex; - cbufferData.debugSampleOperation = (int)opcode; - cbufferData.debugSampleLodCompare = lodOrCompareValue; - - D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState; - D3D12RenderState prevState = rs; - - ID3D12RootSignature *sig = m_pDevice->GetDebugManager()->GetShaderDebugRootSig(); - ID3D12PipelineState *pso = m_pDevice->GetDebugManager()->GetTexSamplePso(texelOffsets); - - ID3D12GraphicsCommandListX *cmdList = m_pDevice->GetDebugManager()->ResetDebugList(); - rs.pipe = GetResID(pso); - rs.rts.clear(); - // Set viewport/scissor unconditionally - we need to set this all the time for sampling for a - // compute shader, but also a graphics action might exclude pixel (0, 0) from its view or scissor - rs.views.clear(); - rs.views.push_back({0, 0, 1, 1, 0, 1}); - rs.scissors.clear(); - rs.scissors.push_back({0, 0, 1, 1}); - - D3D12_CPU_DESCRIPTOR_HANDLE srv = m_pDevice->GetDebugManager()->GetCPUHandle(FIRST_SHADDEBUG_SRV); - srv.ptr += ((cbufferData.debugSampleTexDim - 1) + 5 * (cbufferData.debugSampleRetType - 1)) * - sizeof(D3D12Descriptor); - { - D3D12Descriptor descriptor = FindDescriptor(DXBCBytecode::TYPE_RESOURCE, resourceData.binding); - - descriptor.Create(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, m_pDevice, srv); - } - - if(samplerData.mode != NUM_SAMPLERS) - { - D3D12Descriptor descriptor = FindDescriptor(DXBCBytecode::TYPE_SAMPLER, samplerData.binding); - - D3D12_CPU_DESCRIPTOR_HANDLE samp = m_pDevice->GetDebugManager()->GetCPUHandle(SHADDEBUG_SAMPLER0); - - if(opcode == OPCODE_SAMPLE_C || opcode == OPCODE_SAMPLE_C_LZ || opcode == OPCODE_GATHER4_C || - opcode == OPCODE_GATHER4_PO_C) - samp.ptr += sizeof(D3D12Descriptor); - - descriptor.Create(D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER, m_pDevice, samp); - } - - m_pDevice->GetDebugManager()->SetDescriptorHeaps(rs.heaps, true, true); - - // Set our modified root signature, and transfer sigelems if we're debugging a compute shader - rs.graphics.rootsig = GetResID(sig); - rs.graphics.sigelems.clear(); - rs.compute.rootsig = ResourceId(); - rs.compute.sigelems.clear(); - - ID3D12Resource *pResultBuffer = m_pDevice->GetDebugManager()->GetShaderDebugResultBuffer(); - ID3D12Resource *pReadbackBuffer = m_pDevice->GetDebugManager()->GetReadbackBuffer(); - - rs.graphics.sigelems = { - D3D12RenderState::SignatureElement(eRootCBV, m_pDevice->GetDebugManager()->UploadConstants( - &cbufferData, sizeof(cbufferData))), - D3D12RenderState::SignatureElement(eRootUAV, pResultBuffer->GetGPUVirtualAddress()), - D3D12RenderState::SignatureElement( - eRootTable, m_pDevice->GetDebugManager()->GetCPUHandle(FIRST_SHADDEBUG_SRV)), - D3D12RenderState::SignatureElement( - eRootTable, m_pDevice->GetDebugManager()->GetCPUHandle(SHADDEBUG_SAMPLER0)), - }; - - rs.topo = D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST; - rs.ApplyState(m_pDevice, cmdList); - - D3D12_CPU_DESCRIPTOR_HANDLE rtv = m_pDevice->GetDebugManager()->GetCPUHandle(PICK_PIXEL_RTV); - cmdList->OMSetRenderTargets(1, &rtv, FALSE, NULL); - cmdList->DrawInstanced(3, 1, 0, 0); - - D3D12_RESOURCE_BARRIER barrier = {}; - barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; - barrier.Transition.pResource = pResultBuffer; - barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_UNORDERED_ACCESS; - barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; - cmdList->ResourceBarrier(1, &barrier); - - cmdList->CopyBufferRegion(pReadbackBuffer, 0, pResultBuffer, 0, sizeof(Vec4f) * 6); - - HRESULT hr = cmdList->Close(); - if(FAILED(hr)) - { - RDCERR("Failed to close command list HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - { - ID3D12CommandList *l = cmdList; - m_pDevice->GetQueue()->ExecuteCommandLists(1, &l); - m_pDevice->GPUSync(); - } - - rs = prevState; - - D3D12_RANGE range = {0, sizeof(Vec4f) * 6}; - - void *results = NULL; - hr = pReadbackBuffer->Map(0, &range, &results); - - if(FAILED(hr)) - { - pReadbackBuffer->Unmap(0, &range); - RDCERR("Failed to map readback buffer HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - ShaderVariable lookupResult("tex", 0.0f, 0.0f, 0.0f, 0.0f); - - float *retFloats = (float *)results; - uint32_t *retUInts = (uint32_t *)(retFloats + 8); - int32_t *retSInts = (int32_t *)(retUInts + 8); - - if(cbufferData.debugSampleRetType == DEBUG_SAMPLE_UINT) - { - for(int i = 0; i < 4; i++) - lookupResult.value.u32v[i] = retUInts[swizzle[i]]; - } - else if(cbufferData.debugSampleRetType == DEBUG_SAMPLE_INT) - { - for(int i = 0; i < 4; i++) - lookupResult.value.s32v[i] = retSInts[swizzle[i]]; - } - else - { - for(int i = 0; i < 4; i++) - lookupResult.value.f32v[i] = retFloats[swizzle[i]]; - } - - range.End = 0; - pReadbackBuffer->Unmap(0, &range); - - output = lookupResult; - - return true; + return D3D12ShaderDebug::CalculateSampleGather( + false, m_pDevice, sampleOp, resourceData, samplerData, uv, ddxCalc, ddyCalc, texelOffsets, + multisampleIndex, lodOrCompareValue, swizzle, gatherChannel, GetShaderType(), m_instruction, + opString, output); } void GatherConstantBuffers(WrappedID3D12Device *pDevice, const DXBCBytecode::Program &program, diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.h b/renderdoc/driver/d3d12/d3d12_shaderdebug.h new file mode 100644 index 000000000..516b6ef8d --- /dev/null +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2024 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include "driver/shaders/dxbc/dxbc_common.h" +#include "driver/shaders/dxbc/dxbcdxil_debug.h" +#include "d3d12_manager.h" + +namespace D3D12ShaderDebug +{ +using namespace DXBCDXILDebug; + +typedef DXBCDXILDebug::SampleGatherResourceData SampleGatherResourceData; +typedef DXBCDXILDebug::SampleGatherSamplerData SampleGatherSamplerData; +typedef DXBCDXILDebug::BindingSlot BindingSlot; +typedef DXBCDXILDebug::GatherChannel GatherChannel; +typedef DXBCBytecode::SamplerMode SamplerMode; + +// Helpers used by DXBC and DXIL debuggers to interact with GPU and resources +bool CalculateMathIntrinsic(bool dxil, WrappedID3D12Device *device, int mathOp, + const ShaderVariable &input, ShaderVariable &output1, + ShaderVariable &output2); + +bool CalculateSampleGather(bool dxil, WrappedID3D12Device *device, int sampleOp, + SampleGatherResourceData resourceData, SampleGatherSamplerData samplerData, + const ShaderVariable &uv, const ShaderVariable &ddxCalc, + const ShaderVariable &ddyCalc, const int8_t texelOffsets[3], + int multisampleIndex, float lodOrCompareValue, const uint8_t swizzle[4], + GatherChannel gatherChannel, const DXBC::ShaderType shaderType, + uint32_t instruction, const char *opString, ShaderVariable &output); + +D3D12Descriptor FindDescriptor(WrappedID3D12Device *device, D3D12_DESCRIPTOR_RANGE_TYPE type, + const DXBCDXILDebug::BindingSlot &slot, + const DXBC::ShaderType shaderType); +}; diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj index 21844cded..37125f415 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj @@ -172,6 +172,7 @@ + diff --git a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters index cd542e394..28f337b71 100644 --- a/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters +++ b/renderdoc/driver/d3d12/renderdoc_d3d12.vcxproj.filters @@ -81,6 +81,9 @@ Util + + Replay + diff --git a/renderdoc/driver/shaders/dxbc/dxbc_common.h b/renderdoc/driver/shaders/dxbc/dxbc_common.h index 417b7aa4a..6f6719c88 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_common.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_common.h @@ -29,6 +29,7 @@ #include "api/replay/rdcpair.h" #include "api/replay/rdcstr.h" #include "api/replay/shader_types.h" +#include "dxbcdxil_debug.h" struct DXBCContainerDebugger : public ShaderDebugger { diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp index 9d5e63c4e..1333ef6ce 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp @@ -3903,8 +3903,8 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, if(op.operation != OPCODE_LOD && state) state->flags |= ShaderEvents::SampleLoadGather; - SamplerMode samplerMode = NUM_SAMPLERS; - ResourceDimension resourceDim = RESOURCE_DIMENSION_UNKNOWN; + DXBCBytecode::SamplerMode samplerMode = NUM_SAMPLERS; + DXBCBytecode::ResourceDimension resourceDim = RESOURCE_DIMENSION_UNKNOWN; DXBC::ResourceRetType resourceRetType = DXBC::RETURN_TYPE_UNKNOWN; int sampleCount = 0; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.h b/renderdoc/driver/shaders/dxbc/dxbc_debug.h index 1c647dae3..3734607a4 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.h @@ -27,6 +27,7 @@ #include "common/common.h" #include "dxbc_bytecode.h" +#include "dxbcdxil_debug.h" namespace DXBC { @@ -47,22 +48,12 @@ enum DXGI_FORMAT; namespace DXBCDebug { -struct BindingSlot -{ - BindingSlot() : shaderRegister(UINT32_MAX), registerSpace(UINT32_MAX) {} - BindingSlot(uint32_t shaderReg, uint32_t regSpace) - : shaderRegister(shaderReg), registerSpace(regSpace) - { - } - bool operator<(const BindingSlot &o) const - { - if(registerSpace != o.registerSpace) - return registerSpace < o.registerSpace; - return shaderRegister < o.shaderRegister; - } - uint32_t shaderRegister; - uint32_t registerSpace; -}; +using namespace DXBCDXILDebug; + +typedef DXBCDXILDebug::SampleGatherResourceData SampleGatherResourceData; +typedef DXBCDXILDebug::SampleGatherSamplerData SampleGatherSamplerData; +typedef DXBCDXILDebug::BindingSlot BindingSlot; +typedef DXBCDXILDebug::GatherChannel GatherChannel; BindingSlot GetBindingSlotForDeclaration(const DXBCBytecode::Program &program, const DXBCBytecode::Declaration &decl); @@ -213,29 +204,6 @@ void GatherPSInputDataForInitialValues(const DXBC::DXBCContainer *dxbc, rdcarray &floatInputs, rdcarray &inputVarNames, rdcstr &psInputDefinition, int &structureStride); -struct SampleGatherResourceData -{ - DXBCBytecode::ResourceDimension dim; - DXBC::ResourceRetType retType; - int sampleCount; - BindingSlot binding; -}; - -struct SampleGatherSamplerData -{ - DXBCBytecode::SamplerMode mode; - float bias; - BindingSlot binding; -}; - -enum class GatherChannel : uint8_t -{ - Red = 0, - Green = 1, - Blue = 2, - Alpha = 3, -}; - class DebugAPIWrapper { public: @@ -261,12 +229,12 @@ public: virtual bool CalculateSampleGather(DXBCBytecode::OpcodeType opcode, SampleGatherResourceData resourceData, - SampleGatherSamplerData samplerData, ShaderVariable uv, - ShaderVariable ddxCalc, ShaderVariable ddyCalc, - const int8_t texelOffsets[3], int multisampleIndex, - float lodOrCompareValue, const uint8_t swizzle[4], - GatherChannel gatherChannel, const char *opString, - ShaderVariable &output) = 0; + SampleGatherSamplerData samplerData, + const ShaderVariable &uvIn, const ShaderVariable &ddxCalcIn, + const ShaderVariable &ddyCalcIn, const int8_t texelOffsets[3], + int multisampleIndex, float lodOrCompareValue, + const uint8_t swizzle[4], GatherChannel gatherChannel, + const char *opString, ShaderVariable &output) = 0; }; class ThreadState diff --git a/renderdoc/driver/shaders/dxbc/dxbcdxil_debug.h b/renderdoc/driver/shaders/dxbc/dxbcdxil_debug.h new file mode 100644 index 000000000..76ddb2c62 --- /dev/null +++ b/renderdoc/driver/shaders/dxbc/dxbcdxil_debug.h @@ -0,0 +1,84 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2024 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +namespace DXBC +{ +enum ResourceRetType; +}; + +namespace DXBCBytecode +{ +enum ResourceDimension; +enum SamplerMode; +}; + +namespace DXBCDXILDebug +{ +typedef DXBC::ResourceRetType ResourceRetType; +typedef DXBCBytecode::ResourceDimension ResourceDimension; +typedef DXBCBytecode::SamplerMode SamplerMode; + +enum class GatherChannel : uint8_t +{ + Red = 0, + Green = 1, + Blue = 2, + Alpha = 3, +}; + +struct BindingSlot +{ + BindingSlot() : shaderRegister(UINT32_MAX), registerSpace(UINT32_MAX) {} + BindingSlot(uint32_t shaderReg, uint32_t regSpace) + : shaderRegister(shaderReg), registerSpace(regSpace) + { + } + bool operator<(const BindingSlot &o) const + { + if(registerSpace != o.registerSpace) + return registerSpace < o.registerSpace; + return shaderRegister < o.shaderRegister; + } + uint32_t shaderRegister; + uint32_t registerSpace; +}; + +struct SampleGatherResourceData +{ + ResourceDimension dim; + ResourceRetType retType; + int sampleCount; + BindingSlot binding; +}; + +struct SampleGatherSamplerData +{ + SamplerMode mode; + float bias; + BindingSlot binding; +}; + +}; diff --git a/renderdoc/driver/shaders/dxbc/renderdoc_dxbc.vcxproj b/renderdoc/driver/shaders/dxbc/renderdoc_dxbc.vcxproj index f4e005c92..607f0afae 100644 --- a/renderdoc/driver/shaders/dxbc/renderdoc_dxbc.vcxproj +++ b/renderdoc/driver/shaders/dxbc/renderdoc_dxbc.vcxproj @@ -117,6 +117,7 @@ + diff --git a/renderdoc/driver/shaders/dxbc/renderdoc_dxbc.vcxproj.filters b/renderdoc/driver/shaders/dxbc/renderdoc_dxbc.vcxproj.filters index 8973efeda..6e04dddcd 100644 --- a/renderdoc/driver/shaders/dxbc/renderdoc_dxbc.vcxproj.filters +++ b/renderdoc/driver/shaders/dxbc/renderdoc_dxbc.vcxproj.filters @@ -36,6 +36,7 @@ +