diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index 1c3c96d09..82351a48c 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -222,7 +222,6 @@ struct ShaderVariable DOCUMENT(""); ShaderVariable() { - name = ""; rows = columns = 0; type = VarType::Unknown; memset(&value, 0, sizeof(value)); diff --git a/renderdoc/data/hlsl/hlsl_cbuffers.h b/renderdoc/data/hlsl/hlsl_cbuffers.h index 6486fda57..860190f79 100644 --- a/renderdoc/data/hlsl/hlsl_cbuffers.h +++ b/renderdoc/data/hlsl/hlsl_cbuffers.h @@ -27,10 +27,14 @@ // classes that represent a whole cbuffer #if defined(__cplusplus) +#include "maths/matrix.h" +#include "maths/vec.h" + #define cbuffer struct #define float2 Vec2f #define float3 Vec3f #define uint4 Vec4u +#define int4 Vec4i #define float4 Vec4f #define float4x4 Matrix4f #define uint uint32_t @@ -170,6 +174,58 @@ cbuffer HistogramCBufferData REG(b0) uint4 HistogramYUVAChannels; }; +cbuffer DebugMathOperation REG(b0) +{ + float4 mathInVal; + int mathOp; +}; + +cbuffer DebugSampleOperation REG(b0) +{ + float4 debugSampleUV; + float4 debugSampleDDX; + float4 debugSampleDDY; + int4 debugSampleUVInt; + int debugSampleTexDim; + int debugSampleRetType; + int debugSampleGatherChannel; + int debugSampleSampleIndex; + int debugSampleOperation; + 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_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_TEX1D 1 +#define DEBUG_SAMPLE_TEX2D 2 +#define DEBUG_SAMPLE_TEX3D 3 +#define DEBUG_SAMPLE_TEXMS 4 +#define DEBUG_SAMPLE_TEXCUBE 5 + +#define DEBUG_SAMPLE_UNORM 1 +#define DEBUG_SAMPLE_SNORM 2 +#define DEBUG_SAMPLE_INT 3 +#define DEBUG_SAMPLE_UINT 4 +#define DEBUG_SAMPLE_FLOAT 5 + // 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 new file mode 100644 index 000000000..2990bf73b --- /dev/null +++ b/renderdoc/data/hlsl/shaderdebug.hlsl @@ -0,0 +1,789 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2022 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. + ******************************************************************************/ + +#include "hlsl_cbuffers.h" + +struct OutStruct +{ + float4 outf[2]; + uint4 outu[2]; + int4 outi[2]; +}; + +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; + default: break; + } +} + +void RENDERDOC_DebugSampleVS(uint id + : SV_VertexID, out float4 pos + : SV_Position, out float4 uv + : UVS) +{ + if(id == 0) + uv = debugSampleUV + debugSampleDDX * 2.0f; + else if(id == 1) + uv = debugSampleUV; + else if(id == 2) + uv = debugSampleUV + debugSampleDDY * 2.0f; + else + uv = 0.0f.xxxx; + + pos = float4((id == 2) ? 3.0f : -1.0f, (id == 0) ? -3.0f : 1.0f, 0.5, 1.0); +} + +SamplerState s : register(s0); +SamplerComparisonState sc : register(s1); + +Texture1DArray t1D_unorm : register(t0); +Texture2DArray t2D_unorm : register(t1); +Texture3D t3D_unorm : register(t2); +Texture2DMSArray tMS_unorm : register(t3); +TextureCubeArray tCube_unorm : register(t4); + +Texture1DArray t1D_snorm : register(t5); +Texture2DArray t2D_snorm : register(t6); +Texture3D t3D_snorm : register(t7); +Texture2DMSArray tMS_snorm : register(t8); +TextureCubeArray tCube_snorm : register(t9); + +Texture1DArray t1D_int : register(t10); +Texture2DArray t2D_int : register(t11); +Texture3D t3D_int : register(t12); +Texture2DMSArray tMS_int : register(t13); +TextureCubeArray tCube_int : register(t14); + +Texture1DArray t1D_uint : register(t15); +Texture2DArray t2D_uint : register(t16); +Texture3D t3D_uint : register(t17); +Texture2DMSArray tMS_uint : register(t18); +TextureCubeArray tCube_uint : register(t19); + +Texture1DArray t1D_float : register(t20); +Texture2DArray t2D_float : register(t21); +Texture3D t3D_float : register(t22); +Texture2DMSArray tMS_float : register(t23); +TextureCubeArray tCube_float : register(t24); + +// disable implicit truncation of vector type to keep these switches simpler by dimension +#pragma warning(disable : 3206) + +#ifndef debugSampleOffsets +#define debugSampleOffsets int4(0, 0, 0, 0) +#endif + +float4 DoFloatOpcode(float4 uv) +{ + int4 uvInt = debugSampleUVInt; + int opcode = debugSampleOperation; + float4 ddx_ = debugSampleDDX; + float4 ddy_ = debugSampleDDY; + int4 offsets = debugSampleOffsets; + float lod = debugSampleLodCompare; + float compare = debugSampleLodCompare; + + if(opcode == DEBUG_SAMPLE_TEX_SAMPLE || opcode == DEBUG_SAMPLE_TEX_SAMPLE_B || + opcode == DEBUG_SAMPLE_TEX_SAMPLE_D) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX1D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t1D_unorm.SampleGrad(s, uv, ddx_, ddy_, offsets); + case DEBUG_SAMPLE_SNORM: return t1D_snorm.SampleGrad(s, uv, ddx_, ddy_, offsets); + default: return t1D_float.SampleGrad(s, uv, ddx_, ddy_, offsets); + } + } + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.SampleGrad(s, uv, ddx_, ddy_, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.SampleGrad(s, uv, ddx_, ddy_, offsets); + default: return t2D_float.SampleGrad(s, uv, ddx_, ddy_, offsets); + } + } + case DEBUG_SAMPLE_TEX3D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t3D_unorm.SampleGrad(s, uv, ddx_, ddy_, offsets); + case DEBUG_SAMPLE_SNORM: return t3D_snorm.SampleGrad(s, uv, ddx_, ddy_, offsets); + default: return t3D_float.SampleGrad(s, uv, ddx_, ddy_, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.SampleGrad(s, uv, ddx_, ddy_); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.SampleGrad(s, uv, ddx_, ddy_); + default: return tCube_float.SampleGrad(s, uv, ddx_, ddy_); + } + } + } + } + else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_L) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX1D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t1D_unorm.SampleLevel(s, uv, lod, offsets); + case DEBUG_SAMPLE_SNORM: return t1D_snorm.SampleLevel(s, uv, lod, offsets); + default: return t1D_float.SampleLevel(s, uv, lod, offsets); + } + } + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.SampleLevel(s, uv, lod, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.SampleLevel(s, uv, lod, offsets); + default: return t2D_float.SampleLevel(s, uv, lod, offsets); + } + } + case DEBUG_SAMPLE_TEX3D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t3D_unorm.SampleLevel(s, uv, lod, offsets); + case DEBUG_SAMPLE_SNORM: return t3D_snorm.SampleLevel(s, uv, lod, offsets); + default: return t3D_float.SampleLevel(s, uv, lod, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.SampleLevel(s, uv, lod); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.SampleLevel(s, uv, lod); + default: return tCube_float.SampleLevel(s, uv, lod); + } + } + } + } + else if(opcode == DEBUG_SAMPLE_TEX_LD || opcode == DEBUG_SAMPLE_TEX_LD_MS) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX1D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t1D_unorm.Load(uvInt, offsets); + case DEBUG_SAMPLE_SNORM: return t1D_snorm.Load(uvInt, offsets); + default: return t1D_float.Load(uvInt, offsets); + } + } + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.Load(uvInt, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.Load(uvInt, offsets); + default: return t2D_float.Load(uvInt, offsets); + } + } + case DEBUG_SAMPLE_TEX3D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t3D_unorm.Load(uvInt, offsets); + case DEBUG_SAMPLE_SNORM: return t3D_snorm.Load(uvInt, offsets); + default: return t3D_float.Load(uvInt, offsets); + } + } + case DEBUG_SAMPLE_TEXMS: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tMS_unorm.Load(uvInt, debugSampleSampleIndex, offsets); + case DEBUG_SAMPLE_SNORM: return tMS_snorm.Load(uvInt, debugSampleSampleIndex, offsets); + default: return tMS_float.Load(uvInt, debugSampleSampleIndex, offsets); + } + } + } + } + else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_C) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX1D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t1D_unorm.SampleCmp(sc, uv, compare, offsets); + case DEBUG_SAMPLE_SNORM: return t1D_snorm.SampleCmp(sc, uv, compare, offsets); + default: return t1D_float.SampleCmp(sc, uv, compare, offsets); + } + } + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.SampleCmp(sc, uv, compare, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.SampleCmp(sc, uv, compare, offsets); + default: return t2D_float.SampleCmp(sc, uv, compare, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.SampleCmp(sc, uv, compare); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.SampleCmp(sc, uv, compare); + default: return tCube_float.SampleCmp(sc, uv, compare); + } + } + } + } + else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_C_LZ) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX1D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t1D_unorm.SampleCmpLevelZero(sc, uv, compare, offsets); + case DEBUG_SAMPLE_SNORM: return t1D_snorm.SampleCmpLevelZero(sc, uv, compare, offsets); + default: return t1D_float.SampleCmpLevelZero(sc, uv, compare, offsets); + } + } + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.SampleCmpLevelZero(sc, uv, compare, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.SampleCmpLevelZero(sc, uv, compare, offsets); + default: return t2D_float.SampleCmpLevelZero(sc, uv, compare, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.SampleCmpLevelZero(sc, uv, compare); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.SampleCmpLevelZero(sc, uv, compare); + default: return tCube_float.SampleCmpLevelZero(sc, uv, compare); + } + } + } + } + else if(opcode == DEBUG_SAMPLE_TEX_LOD) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX1D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: + return float4(t1D_unorm.CalculateLevelOfDetail(s, uv), + t1D_unorm.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_SNORM: + return float4(t1D_snorm.CalculateLevelOfDetail(s, uv), + t1D_snorm.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_UINT: + return float4(t1D_uint.CalculateLevelOfDetail(s, uv), + t1D_uint.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_INT: + return float4(t1D_int.CalculateLevelOfDetail(s, uv), + t1D_int.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + default: + return float4(t1D_float.CalculateLevelOfDetail(s, uv), + t1D_float.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + } + } + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: + return float4(t2D_unorm.CalculateLevelOfDetail(s, uv), + t2D_unorm.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_SNORM: + return float4(t2D_snorm.CalculateLevelOfDetail(s, uv), + t2D_snorm.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_UINT: + return float4(t2D_uint.CalculateLevelOfDetail(s, uv), + t2D_uint.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_INT: + return float4(t2D_int.CalculateLevelOfDetail(s, uv), + t2D_int.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + default: + return float4(t2D_float.CalculateLevelOfDetail(s, uv), + t2D_float.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + } + } + case DEBUG_SAMPLE_TEX3D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: + return float4(t3D_unorm.CalculateLevelOfDetail(s, uv), + t3D_unorm.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_SNORM: + return float4(t3D_snorm.CalculateLevelOfDetail(s, uv), + t3D_snorm.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_UINT: + return float4(t3D_uint.CalculateLevelOfDetail(s, uv), + t3D_uint.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_INT: + return float4(t3D_int.CalculateLevelOfDetail(s, uv), + t3D_int.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + default: + return float4(t3D_float.CalculateLevelOfDetail(s, uv), + t3D_float.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: + return float4(tCube_unorm.CalculateLevelOfDetail(s, uv), + tCube_unorm.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_SNORM: + return float4(tCube_snorm.CalculateLevelOfDetail(s, uv), + tCube_snorm.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_UINT: + return float4(tCube_uint.CalculateLevelOfDetail(s, uv), + tCube_uint.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + case DEBUG_SAMPLE_INT: + return float4(tCube_int.CalculateLevelOfDetail(s, uv), + tCube_int.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + default: + return float4(tCube_float.CalculateLevelOfDetail(s, uv), + tCube_float.CalculateLevelOfDetailUnclamped(s, uv), 0.0f, 0.0f); + } + } + } + } + else if(opcode == DEBUG_SAMPLE_TEX_GATHER4 || opcode == DEBUG_SAMPLE_TEX_GATHER4_PO) + { + if(debugSampleGatherChannel == 0) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.GatherRed(s, uv, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.GatherRed(s, uv, offsets); + default: return t2D_float.GatherRed(s, uv, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.GatherRed(s, uv); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.GatherRed(s, uv); + default: return tCube_float.GatherRed(s, uv); + } + } + } + } + else if(debugSampleGatherChannel == 1) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.GatherGreen(s, uv, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.GatherGreen(s, uv, offsets); + default: return t2D_float.GatherGreen(s, uv, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.GatherGreen(s, uv); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.GatherGreen(s, uv); + default: return tCube_float.GatherGreen(s, uv); + } + } + } + } + else if(debugSampleGatherChannel == 2) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.GatherBlue(s, uv, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.GatherBlue(s, uv, offsets); + default: return t2D_float.GatherBlue(s, uv, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.GatherBlue(s, uv); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.GatherBlue(s, uv); + default: return tCube_float.GatherBlue(s, uv); + } + } + } + } + else + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.GatherAlpha(s, uv, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.GatherAlpha(s, uv, offsets); + default: return t2D_float.GatherAlpha(s, uv, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.GatherAlpha(s, uv); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.GatherAlpha(s, uv); + default: return tCube_float.GatherAlpha(s, uv); + } + } + } + } + } + else if(opcode == DEBUG_SAMPLE_TEX_GATHER4_C || opcode == DEBUG_SAMPLE_TEX_GATHER4_PO_C) + { + if(debugSampleGatherChannel == 0) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.GatherCmpRed(sc, uv, compare, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.GatherCmpRed(sc, uv, compare, offsets); + case DEBUG_SAMPLE_UINT: return t2D_uint.GatherCmpRed(sc, uv, compare, offsets); + case DEBUG_SAMPLE_INT: return t2D_int.GatherCmpRed(sc, uv, compare, offsets); + default: return t2D_float.GatherCmpRed(sc, uv, compare, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.GatherCmpRed(sc, uv, compare); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.GatherCmpRed(sc, uv, compare); + case DEBUG_SAMPLE_UINT: return tCube_uint.GatherCmpRed(sc, uv, compare); + case DEBUG_SAMPLE_INT: return tCube_int.GatherCmpRed(sc, uv, compare); + default: return tCube_float.GatherCmpRed(sc, uv, compare); + } + } + } + } + else if(debugSampleGatherChannel == 1) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.GatherCmpGreen(sc, uv, compare, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.GatherCmpGreen(sc, uv, compare, offsets); + case DEBUG_SAMPLE_UINT: return t2D_uint.GatherCmpGreen(sc, uv, compare, offsets); + case DEBUG_SAMPLE_INT: return t2D_int.GatherCmpGreen(sc, uv, compare, offsets); + default: return t2D_float.GatherCmpGreen(sc, uv, compare, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.GatherCmpGreen(sc, uv, compare); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.GatherCmpGreen(sc, uv, compare); + case DEBUG_SAMPLE_UINT: return tCube_uint.GatherCmpGreen(sc, uv, compare); + case DEBUG_SAMPLE_INT: return tCube_int.GatherCmpGreen(sc, uv, compare); + default: return tCube_float.GatherCmpGreen(sc, uv, compare); + } + } + } + } + else if(debugSampleGatherChannel == 2) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.GatherCmpBlue(sc, uv, compare, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.GatherCmpBlue(sc, uv, compare, offsets); + case DEBUG_SAMPLE_UINT: return t2D_uint.GatherCmpBlue(sc, uv, compare, offsets); + case DEBUG_SAMPLE_INT: return t2D_int.GatherCmpBlue(sc, uv, compare, offsets); + default: return t2D_float.GatherCmpBlue(sc, uv, compare, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.GatherCmpBlue(sc, uv, compare); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.GatherCmpBlue(sc, uv, compare); + case DEBUG_SAMPLE_UINT: return tCube_uint.GatherCmpBlue(sc, uv, compare); + case DEBUG_SAMPLE_INT: return tCube_int.GatherCmpBlue(sc, uv, compare); + default: return tCube_float.GatherCmpBlue(sc, uv, compare); + } + } + } + } + else + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return t2D_unorm.GatherCmpAlpha(sc, uv, compare, offsets); + case DEBUG_SAMPLE_SNORM: return t2D_snorm.GatherCmpAlpha(sc, uv, compare, offsets); + case DEBUG_SAMPLE_UINT: return t2D_uint.GatherCmpAlpha(sc, uv, compare, offsets); + case DEBUG_SAMPLE_INT: return t2D_int.GatherCmpAlpha(sc, uv, compare, offsets); + default: return t2D_float.GatherCmpAlpha(sc, uv, compare, offsets); + } + } + case DEBUG_SAMPLE_TEXCUBE: + { + switch(debugSampleRetType) + { + case DEBUG_SAMPLE_UNORM: return tCube_unorm.GatherCmpAlpha(sc, uv, compare); + case DEBUG_SAMPLE_SNORM: return tCube_snorm.GatherCmpAlpha(sc, uv, compare); + case DEBUG_SAMPLE_UINT: return tCube_uint.GatherCmpAlpha(sc, uv, compare); + case DEBUG_SAMPLE_INT: return tCube_int.GatherCmpAlpha(sc, uv, compare); + default: return tCube_float.GatherCmpAlpha(sc, uv, compare); + } + } + } + } + } + else + { + return float4(0, 0, 0, 0); + } +} + +int4 DoIntOpcode(float4 uv) +{ + int4 uvInt = debugSampleUVInt; + int opcode = debugSampleOperation; + float4 ddx_ = debugSampleDDX; + float4 ddy_ = debugSampleDDY; + int4 offsets = debugSampleOffsets; + float lod = debugSampleLodCompare; + + if(opcode == DEBUG_SAMPLE_TEX_LD || opcode == DEBUG_SAMPLE_TEX_LD_MS) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX1D: return t1D_int.Load(uvInt, offsets); + case DEBUG_SAMPLE_TEX2D: return t2D_int.Load(uvInt, offsets); + case DEBUG_SAMPLE_TEX3D: return t3D_int.Load(uvInt, offsets); + case DEBUG_SAMPLE_TEXMS: return tMS_int.Load(uvInt, debugSampleSampleIndex, offsets); + } + } + else if(opcode == DEBUG_SAMPLE_TEX_GATHER4 || opcode == DEBUG_SAMPLE_TEX_GATHER4_PO) + { + if(debugSampleGatherChannel == 0) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: return t2D_int.GatherRed(s, uv, offsets); + case DEBUG_SAMPLE_TEXCUBE: return tCube_int.GatherRed(s, uv); + } + } + else if(debugSampleGatherChannel == 1) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: return t2D_int.GatherGreen(s, uv, offsets); + case DEBUG_SAMPLE_TEXCUBE: return tCube_int.GatherGreen(s, uv); + } + } + else if(debugSampleGatherChannel == 2) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: return t2D_int.GatherBlue(s, uv, offsets); + case DEBUG_SAMPLE_TEXCUBE: return tCube_int.GatherBlue(s, uv); + } + } + else + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: return t2D_int.GatherAlpha(s, uv, offsets); + case DEBUG_SAMPLE_TEXCUBE: return tCube_int.GatherAlpha(s, uv); + } + } + } + else + { + return int4(0, 0, 0, 0); + } +} + +uint4 DoUIntOpcode(float4 uv) +{ + int4 uvInt = debugSampleUVInt; + int opcode = debugSampleOperation; + float4 ddx_ = debugSampleDDX; + float4 ddy_ = debugSampleDDY; + int4 offsets = debugSampleOffsets; + float lod = debugSampleLodCompare; + + if(opcode == DEBUG_SAMPLE_TEX_LD || opcode == DEBUG_SAMPLE_TEX_LD_MS) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX1D: return t1D_uint.Load(uvInt, offsets); + case DEBUG_SAMPLE_TEX2D: return t2D_uint.Load(uvInt, offsets); + case DEBUG_SAMPLE_TEX3D: return t3D_uint.Load(uvInt, offsets); + case DEBUG_SAMPLE_TEXMS: return tMS_uint.Load(uvInt, debugSampleSampleIndex, offsets); + } + } + else if(opcode == DEBUG_SAMPLE_TEX_GATHER4 || opcode == DEBUG_SAMPLE_TEX_GATHER4_PO) + { + if(debugSampleGatherChannel == 0) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: return t2D_uint.GatherRed(s, uv, offsets); + case DEBUG_SAMPLE_TEXCUBE: return tCube_uint.GatherRed(s, uv); + } + } + else if(debugSampleGatherChannel == 1) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: return t2D_uint.GatherGreen(s, uv, offsets); + case DEBUG_SAMPLE_TEXCUBE: return tCube_uint.GatherGreen(s, uv); + } + } + else if(debugSampleGatherChannel == 2) + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: return t2D_uint.GatherBlue(s, uv, offsets); + case DEBUG_SAMPLE_TEXCUBE: return tCube_uint.GatherBlue(s, uv); + } + } + else + { + switch(debugSampleTexDim) + { + default: + case DEBUG_SAMPLE_TEX2D: return t2D_uint.GatherAlpha(s, uv, offsets); + case DEBUG_SAMPLE_TEXCUBE: return tCube_uint.GatherAlpha(s, uv); + } + } + } + else + { + return float4(0, 0, 0, 0); + } +} + +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) + { + 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); + + if(!forceFloat && debugSampleRetType == DEBUG_SAMPLE_INT) + { + outBuf[0].outi[0] = DoIntOpcode(uv); + } + else if(!forceFloat && debugSampleRetType == DEBUG_SAMPLE_UINT) + { + outBuf[0].outu[0] = DoUIntOpcode(uv); + } + else if(debugSampleRetType == DEBUG_SAMPLE_UNORM || debugSampleRetType == DEBUG_SAMPLE_SNORM || + debugSampleRetType == DEBUG_SAMPLE_FLOAT) + { + outBuf[0].outf[0] = DoFloatOpcode(uv); + } +} diff --git a/renderdoc/data/renderdoc.rc b/renderdoc/data/renderdoc.rc index a731a4f88..d2cf025fc 100644 --- a/renderdoc/data/renderdoc.rc +++ b/renderdoc/data/renderdoc.rc @@ -114,6 +114,7 @@ RESOURCE_pixelhistory_hlsl TYPE_EMBED "hlsl/pixelhistory.hlsl" RESOURCE_quadoverdraw_hlsl TYPE_EMBED "hlsl/quadoverdraw.hlsl" RESOURCE_texremap_hlsl TYPE_EMBED "hlsl/texremap.hlsl" RESOURCE_fixedcol_hlsl TYPE_EMBED "hlsl/fixedcol.hlsl" +RESOURCE_shaderdebug_hlsl TYPE_EMBED "hlsl/shaderdebug.hlsl" #ifdef RENDERDOC_BAKED_DXC_SHADERS diff --git a/renderdoc/data/resource.h b/renderdoc/data/resource.h index c45021f3a..0ef0d8c96 100644 --- a/renderdoc/data/resource.h +++ b/renderdoc/data/resource.h @@ -17,6 +17,7 @@ #define RESOURCE_quadoverdraw_hlsl 110 #define RESOURCE_texremap_hlsl 111 #define RESOURCE_fixedcol_hlsl 112 +#define RESOURCE_shaderdebug_hlsl 118 #define RESOURCE_fixedcol_0_dxbc 113 #define RESOURCE_fixedcol_1_dxbc 114 diff --git a/renderdoc/driver/d3d11/d3d11_debug.cpp b/renderdoc/driver/d3d11/d3d11_debug.cpp index 2c4cc902e..bf539adee 100644 --- a/renderdoc/driver/d3d11/d3d11_debug.cpp +++ b/renderdoc/driver/d3d11/d3d11_debug.cpp @@ -1466,6 +1466,137 @@ void D3D11Replay::PixelPicking::Release() SAFE_RELEASE(StageTexture); } +void ShaderDebugging::Init(WrappedID3D11Device *device) +{ + D3D11ShaderCache *shaderCache = device->GetShaderCache(); + + HRESULT hr = S_OK; + + rdcstr hlsl = GetEmbeddedResource(shaderdebug_hlsl); + + MathCS = shaderCache->MakeCShader(hlsl.c_str(), "RENDERDOC_DebugMathOp", "cs_5_0"); + SampleVS = shaderCache->MakeVShader(hlsl.c_str(), "RENDERDOC_DebugSampleVS", "vs_5_0"); + SamplePS = shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_DebugSamplePS", "ps_5_0"); + + D3D11_BUFFER_DESC bDesc; + + bDesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; + bDesc.ByteWidth = 6 * sizeof(Vec4f); + bDesc.CPUAccessFlags = 0; + bDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED; + bDesc.StructureByteStride = 6 * sizeof(Vec4f); + bDesc.Usage = D3D11_USAGE_DEFAULT; + + hr = device->CreateBuffer(&bDesc, NULL, &OutBuf); + + if(FAILED(hr)) + RDCERR("Failed to create shader debugging output buffer HRESULT: %s", ToStr(hr).c_str()); + + bDesc.BindFlags = 0; + bDesc.MiscFlags = 0; + bDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + bDesc.Usage = D3D11_USAGE_STAGING; + + hr = device->CreateBuffer(&bDesc, NULL, &OutStageBuf); + + if(FAILED(hr)) + RDCERR("Failed to create shader debugging staging buffer HRESULT: %s", ToStr(hr).c_str()); + + bDesc.ByteWidth = 16 * sizeof(Vec4f); + bDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + bDesc.Usage = D3D11_USAGE_DYNAMIC; + + hr = device->CreateBuffer(&bDesc, NULL, &ParamBuf); + + if(FAILED(hr)) + RDCERR("Failed to create shader debugging parameter buffer HRESULT: %s", ToStr(hr).c_str()); + + D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; + + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.FirstElement = 0; + uavDesc.Buffer.NumElements = 1; + uavDesc.Buffer.Flags = 0; + + if(OutBuf) + hr = device->CreateUnorderedAccessView(OutBuf, &uavDesc, &OutUAV); + + if(FAILED(hr)) + RDCERR("Failed to create shader debugging UAV HRESULT: %s", ToStr(hr).c_str()); + + D3D11_TEXTURE2D_DESC tdesc = {}; + + tdesc.ArraySize = 1; + tdesc.BindFlags = D3D11_BIND_RENDER_TARGET; + tdesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + tdesc.Width = 1; + tdesc.Height = 1; + tdesc.SampleDesc.Count = 1; + + hr = device->CreateTexture2D(&tdesc, NULL, &DummyTex); + + if(FAILED(hr)) + RDCERR("Failed to create shader debugging dummy texture HRESULT: %s", ToStr(hr).c_str()); + + D3D11_RENDER_TARGET_VIEW_DESC rtDesc; + + rtDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; + rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; + rtDesc.Texture2D.MipSlice = 0; + + if(DummyTex) + hr = device->CreateRenderTargetView(DummyTex, &rtDesc, &DummyRTV); + + if(FAILED(hr)) + RDCERR("Failed to create shader debugging dummy RTV HRESULT: %s", ToStr(hr).c_str()); + + m_pDevice = device; +} + +void ShaderDebugging::Release() +{ + SAFE_RELEASE(MathCS); + SAFE_RELEASE(ParamBuf); + SAFE_RELEASE(OutBuf); + SAFE_RELEASE(OutStageBuf); + SAFE_RELEASE(OutUAV); + + SAFE_RELEASE(DummyTex); + SAFE_RELEASE(DummyRTV); + + for(auto it = m_OffsetSamplePS.begin(); it != m_OffsetSamplePS.end(); ++it) + it->second->Release(); +} + +ID3D11PixelShader *ShaderDebugging::GetSamplePS(const int8_t offsets[3]) +{ + uint32_t offsKey = offsets[0] | (offsets[1] << 8) | (offsets[2] << 16); + if(offsKey == 0) + return SamplePS; + + ID3D11PixelShader *ps = m_OffsetSamplePS[offsKey]; + if(ps) + return ps; + + D3D11ShaderCache *shaderCache = m_pDevice->GetShaderCache(); + + shaderCache->SetCaching(true); + + rdcstr hlsl = GetEmbeddedResource(shaderdebug_hlsl); + + hlsl = StringFormat::Fmt("#define debugSampleOffsets int4(%d,%d,%d,0)\n\n%s", offsets[0], + offsets[1], offsets[2], hlsl.c_str()); + + ps = m_OffsetSamplePS[offsKey] = + shaderCache->MakePShader(hlsl.c_str(), "RENDERDOC_DebugSamplePS", "ps_5_0"); + + shaderCache->SetCaching(false); + + return ps; +} + void D3D11Replay::HistogramMinMax::Init(WrappedID3D11Device *device) { D3D11ShaderCache *shaderCache = device->GetShaderCache(); diff --git a/renderdoc/driver/d3d11/d3d11_replay.cpp b/renderdoc/driver/d3d11/d3d11_replay.cpp index 82c65b870..e615d57dd 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.cpp +++ b/renderdoc/driver/d3d11/d3d11_replay.cpp @@ -182,6 +182,10 @@ void D3D11Replay::CreateResources(IDXGIFactory *factory) m_PixelPick.Init(m_pDevice); + RenderDoc::Inst().SetProgress(LoadProgress::DebugManagerInit, 0.65f); + + m_ShaderDebug.Init(m_pDevice); + RenderDoc::Inst().SetProgress(LoadProgress::DebugManagerInit, 0.7f); m_Histogram.Init(m_pDevice); @@ -266,6 +270,7 @@ void D3D11Replay::DestroyResources() m_MeshRender.Release(); m_VertexPick.Release(); m_PixelPick.Release(); + m_ShaderDebug.Release(); m_Histogram.Release(); m_PixelHistory.Release(); diff --git a/renderdoc/driver/d3d11/d3d11_replay.h b/renderdoc/driver/d3d11/d3d11_replay.h index ae7af9e36..6960fa2c7 100644 --- a/renderdoc/driver/d3d11/d3d11_replay.h +++ b/renderdoc/driver/d3d11/d3d11_replay.h @@ -97,6 +97,30 @@ enum TexDisplayFlags eTexDisplay_RemapSInt = 0x8, }; +struct ShaderDebugging +{ + void Init(WrappedID3D11Device *device); + void Release(); + + ID3D11PixelShader *GetSamplePS(const int8_t offsets[3]); + + ID3D11ComputeShader *MathCS = NULL; + ID3D11Buffer *ParamBuf = NULL; + ID3D11Buffer *OutBuf = NULL; + ID3D11Buffer *OutStageBuf = NULL; + ID3D11UnorderedAccessView *OutUAV = NULL; + + ID3D11VertexShader *SampleVS = NULL; + ID3D11PixelShader *SamplePS = NULL; + ID3D11Texture2D *DummyTex = NULL; + ID3D11RenderTargetView *DummyRTV = NULL; + +private: + WrappedID3D11Device *m_pDevice; + + std::map m_OffsetSamplePS; +}; + class D3D11Replay : public IReplayDriver { public: @@ -147,6 +171,7 @@ public: { m_D3D11PipelineState = d3d11; } + ShaderDebugging &GetShaderDebuggingData() { return m_ShaderDebug; } void SavePipelineState(uint32_t eventId); void FreeTargetResource(ResourceId id); void FreeCustomShader(ResourceId id); @@ -460,6 +485,8 @@ private: ID3D11Texture2D *StageTexture = NULL; } m_PixelPick; + ShaderDebugging m_ShaderDebug; + struct HistogramMinMax { void Init(WrappedID3D11Device *device); diff --git a/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp b/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp index c72172724..89ea017d1 100644 --- a/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp +++ b/renderdoc/driver/d3d11/d3d11_shaderdebug.cpp @@ -37,6 +37,8 @@ #include "d3d11_resources.h" #include "d3d11_shader_cache.h" +#include "data/hlsl/hlsl_cbuffers.h" + struct DebugHit { uint32_t numHits; @@ -142,7 +144,7 @@ void D3D11DebugAPIWrapper::FetchSRV(const DXBCDebug::BindingSlot &slot) pSRV->GetResource(&res); if(!res) - return; + return; // @NoCoverage D3D11_SHADER_RESOURCE_VIEW_DESC sdesc; pSRV->GetDesc(&sdesc); @@ -998,179 +1000,32 @@ bool D3D11DebugAPIWrapper::CalculateSampleGather( { using namespace DXBCBytecode; - rdcstr funcRet = ""; - DXGI_FORMAT retFmt = DXGI_FORMAT_UNKNOWN; + 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_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"); - if(opcode == OPCODE_SAMPLE_C || opcode == OPCODE_SAMPLE_C_LZ || opcode == OPCODE_GATHER4_C || - opcode == OPCODE_GATHER4_PO_C || opcode == OPCODE_LOD) - { - retFmt = DXGI_FORMAT_R32G32B32A32_FLOAT; - funcRet = "float4"; - } - - rdcstr samplerDecl = ""; - if(samplerData.mode == SAMPLER_MODE_DEFAULT) - samplerDecl = "SamplerState s"; - else if(samplerData.mode == SAMPLER_MODE_COMPARISON) - samplerDecl = "SamplerComparisonState s"; - - rdcstr textureDecl = ""; - int texdim = 2; - int offsetDim = 2; - bool useOffsets = true; - if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE1D) - { - textureDecl = "Texture1D"; - texdim = 1; - offsetDim = 1; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2D) - { - textureDecl = "Texture2D"; - texdim = 2; - offsetDim = 2; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMS) - { - textureDecl = "Texture2DMS"; - texdim = 2; - offsetDim = 2; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE3D) - { - textureDecl = "Texture3D"; - texdim = 3; - offsetDim = 3; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBE) - { - textureDecl = "TextureCube"; - texdim = 3; - offsetDim = 3; - useOffsets = false; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE1DARRAY) - { - textureDecl = "Texture1DArray"; - texdim = 2; - offsetDim = 1; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY) - { - textureDecl = "Texture2DArray"; - texdim = 3; - offsetDim = 2; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY) - { - textureDecl = "Texture2DMSArray"; - texdim = 3; - offsetDim = 2; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBEARRAY) - { - textureDecl = "TextureCubeArray"; - texdim = 4; - offsetDim = 3; - useOffsets = false; - } - else - { - RDCERR("Unsupported resource type %d in sample operation", resourceData.dim); - } - - { - char *typeStr[DXBC::NUM_RETURN_TYPES] = { - "", // enum starts at ==1 - "unorm float", - "snorm float", - "int", - "uint", - "float", - "__", // RETURN_TYPE_MIXED - "double", - "__", // RETURN_TYPE_CONTINUED - "__", // RETURN_TYPE_UNUSED - }; - - // obviously these may be overly optimistic in some cases - // but since we don't know at debug time what the source texture format is - // we just use the fattest one necessary. There's no harm in retrieving at - // higher precision - DXGI_FORMAT fmts[DXBC::NUM_RETURN_TYPES] = { - DXGI_FORMAT_UNKNOWN, // enum starts at ==1 - DXGI_FORMAT_R32G32B32A32_FLOAT, // unorm float - DXGI_FORMAT_R32G32B32A32_FLOAT, // snorm float - DXGI_FORMAT_R32G32B32A32_SINT, // int - DXGI_FORMAT_R32G32B32A32_UINT, // uint - DXGI_FORMAT_R32G32B32A32_FLOAT, // float - DXGI_FORMAT_UNKNOWN, // RETURN_TYPE_MIXED - - // should maybe be double, but there is no double texture format anyway! - // spec is unclear but I presume reads are done at most at float - // precision anyway since that's the source, and converted to doubles. - DXGI_FORMAT_R32G32B32A32_FLOAT, // double - - DXGI_FORMAT_UNKNOWN, // RETURN_TYPE_CONTINUED - DXGI_FORMAT_UNKNOWN, // RETURN_TYPE_UNUSED - }; - - rdcstr type = StringFormat::Fmt("%s4", typeStr[resourceData.retType]); - - if(retFmt == DXGI_FORMAT_UNKNOWN) - { - funcRet = type; - retFmt = fmts[resourceData.retType]; - } - - if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMS || - resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY) - { - if(resourceData.sampleCount > 0) - type += StringFormat::Fmt(", %d", resourceData.sampleCount); - } - - textureDecl += "<" + type + "> t"; - } - - char *formats[4][2] = { - {"float(%.10f)", "int(%d)"}, - {"float2(%.10f, %.10f)", "int2(%d, %d)"}, - {"float3(%.10f, %.10f, %.10f)", "int3(%d, %d, %d)"}, - {"float4(%.10f, %.10f, %.10f, %.10f)", "int4(%d, %d, %d, %d)"}, - }; - - int texcoordType = 0; - int texdimOffs = 0; - - if(opcode == OPCODE_SAMPLE || opcode == OPCODE_SAMPLE_L || opcode == OPCODE_SAMPLE_B || - opcode == OPCODE_SAMPLE_D || opcode == OPCODE_SAMPLE_C || opcode == OPCODE_SAMPLE_C_LZ || - opcode == OPCODE_GATHER4 || opcode == OPCODE_GATHER4_C || opcode == OPCODE_GATHER4_PO || - opcode == OPCODE_GATHER4_PO_C || opcode == OPCODE_LOD) - { - // all floats - texcoordType = 0; - } - else if(opcode == OPCODE_LD) - { - // int address, one larger than texdim (to account for mip/slice parameter) - texdimOffs = 1; - texcoordType = 1; - - if(texdim == 4) - { - RDCERR("Unexpectedly large texture in load operation"); - } - } - else if(opcode == OPCODE_LD_MS) - { - texcoordType = 1; - - if(texdim == 4) - { - RDCERR("Unexpectedly large texture in load operation"); - } - } + ShaderDebugging &debugData = m_pDevice->GetReplay()->GetShaderDebuggingData(); for(uint32_t i = 0; i < ddxCalc.columns; i++) { @@ -1200,7 +1055,7 @@ bool D3D11DebugAPIWrapper::CalculateSampleGather( for(uint32_t i = 0; i < uv.columns; i++) { - if(texcoordType == 0 && !RDCISFINITE(uv.value.f32v[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; @@ -1213,185 +1068,61 @@ bool D3D11DebugAPIWrapper::CalculateSampleGather( } } - rdcstr texcoords; + DebugSampleOperation cbufferData = {}; - // because of unions in .value we can pass the float versions and printf will interpret it as - // the right type according to formats - if(texcoordType == 0) - texcoords = StringFormat::Fmt(formats[texdim + texdimOffs - 1][texcoordType], uv.value.f32v[0], - uv.value.f32v[1], uv.value.f32v[2], uv.value.f32v[3]); + 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 - texcoords = StringFormat::Fmt(formats[texdim + texdimOffs - 1][texcoordType], uv.value.s32v[0], - uv.value.s32v[1], uv.value.s32v[2], uv.value.s32v[3]); - - rdcstr offsets = ""; - - if(useOffsets) { - if(offsetDim == 1) - offsets = StringFormat::Fmt(", int(%d)", texelOffsets[0]); - else if(offsetDim == 2) - offsets = StringFormat::Fmt(", int2(%d, %d)", texelOffsets[0], texelOffsets[1]); - else if(offsetDim == 3) - offsets = - StringFormat::Fmt(", int3(%d, %d, %d)", texelOffsets[0], texelOffsets[1], texelOffsets[2]); - // texdim == 4 is cube arrays, no offset supported + RDCERR("Unsupported resource type %d in sample operation", resourceData.dim); } - char elems[] = "xyzw"; - rdcstr strSwizzle = "."; - for(int i = 0; i < 4; ++i) - strSwizzle += elems[swizzle[i]]; + 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 + }; - rdcstr strGatherChannel; - switch(gatherChannel) - { - case DXBCDebug::GatherChannel::Red: strGatherChannel = "Red"; break; - case DXBCDebug::GatherChannel::Green: strGatherChannel = "Green"; break; - case DXBCDebug::GatherChannel::Blue: strGatherChannel = "Blue"; break; - case DXBCDebug::GatherChannel::Alpha: strGatherChannel = "Alpha"; break; - } + cbufferData.debugSampleRetType = retTypes[resourceData.retType]; - rdcstr vsProgram = "float4 main(uint id : SV_VertexID) : SV_Position {\n"; - vsProgram += "return float4((id == 2) ? 3.0f : -1.0f, (id == 0) ? -3.0f : 1.0f, 0.5, 1.0);\n"; - vsProgram += "}"; - - rdcstr sampleProgram; - - if(opcode == OPCODE_SAMPLE || opcode == OPCODE_SAMPLE_B || opcode == OPCODE_SAMPLE_D) - { - rdcstr ddx = - StringFormat::Fmt(formats[offsetDim + texdimOffs - 1][0], ddxCalc.value.f32v[0], - ddxCalc.value.f32v[1], ddxCalc.value.f32v[2], ddxCalc.value.f32v[3]); - - rdcstr ddy = - StringFormat::Fmt(formats[offsetDim + texdimOffs - 1][0], ddyCalc.value.f32v[0], - ddyCalc.value.f32v[1], ddyCalc.value.f32v[2], ddyCalc.value.f32v[3]); - - sampleProgram = StringFormat::Fmt("%s : register(t0);\n%s : register(s0);\n\n", - textureDecl.c_str(), samplerDecl.c_str()); - sampleProgram += funcRet + " main() : SV_Target0\n{\n"; - sampleProgram += - StringFormat::Fmt("return t.SampleGrad(s, %s, %s, %s %s)%s;\n", texcoords.c_str(), - ddx.c_str(), ddy.c_str(), offsets.c_str(), strSwizzle.c_str()); - sampleProgram += "}\n"; - } - else if(opcode == OPCODE_SAMPLE_L) - { - sampleProgram = StringFormat::Fmt("%s : register(t0);\n%s : register(s0);\n\n", - textureDecl.c_str(), samplerDecl.c_str()); - sampleProgram += funcRet + " main() : SV_Target0\n{\n"; - sampleProgram += - StringFormat::Fmt("return t.SampleLevel(s, %s, %.10f %s)%s;\n", texcoords.c_str(), - lodOrCompareValue, offsets.c_str(), strSwizzle.c_str()); - sampleProgram += "}\n"; - } - else if(opcode == OPCODE_SAMPLE_C || opcode == OPCODE_LOD) - { - // these operations need derivatives but have no hlsl function to call to provide them, so - // we fake it in the vertex shader - - rdcstr uvdecl = StringFormat::Fmt("float%d uv : uvs", texdim + texdimOffs); - - vsProgram = - "void main(uint id : SV_VertexID, out float4 pos : SV_Position, out " + uvdecl + ") {\n"; - - rdcstr uvPlusDDX = StringFormat::Fmt(formats[texdim + texdimOffs - 1][texcoordType], - uv.value.f32v[0] + ddyCalc.value.f32v[0] * 2.0f, - uv.value.f32v[1] + ddyCalc.value.f32v[1] * 2.0f, - uv.value.f32v[2] + ddyCalc.value.f32v[2] * 2.0f, - uv.value.f32v[3] + ddyCalc.value.f32v[3] * 2.0f); - - rdcstr uvPlusDDY = StringFormat::Fmt(formats[texdim + texdimOffs - 1][texcoordType], - uv.value.f32v[0] + ddxCalc.value.f32v[0] * 2.0f, - uv.value.f32v[1] + ddxCalc.value.f32v[1] * 2.0f, - uv.value.f32v[2] + ddxCalc.value.f32v[2] * 2.0f, - uv.value.f32v[3] + ddxCalc.value.f32v[3] * 2.0f); - - vsProgram += "if(id == 0) uv = " + uvPlusDDX + ";\n"; - vsProgram += "if(id == 1) uv = " + texcoords + ";\n"; - vsProgram += "if(id == 2) uv = " + uvPlusDDY + ";\n"; - vsProgram += "pos = float4((id == 2) ? 3.0f : -1.0f, (id == 0) ? -3.0f : 1.0f, 0.5, 1.0);\n"; - vsProgram += "}"; - - if(opcode == OPCODE_SAMPLE_C) - { - sampleProgram = StringFormat::Fmt("%s : register(t0);\n%s : register(s0);\n\n", - textureDecl.c_str(), samplerDecl.c_str()); - sampleProgram += - funcRet + " main(float4 pos : SV_Position, " + uvdecl + ") : SV_Target0\n{\n"; - sampleProgram += StringFormat::Fmt("return t.SampleCmpLevelZero(s, uv, %.10f %s).xxxx;\n", - lodOrCompareValue, offsets.c_str()); - sampleProgram += "}\n"; - } - else if(opcode == OPCODE_LOD) - { - sampleProgram = StringFormat::Fmt("%s : register(t0);\n%s : register(s0);\n\n", - textureDecl.c_str(), samplerDecl.c_str()); - sampleProgram += - funcRet + " main(float4 pos : SV_Position, " + uvdecl + ") : SV_Target0\n{\n"; - sampleProgram += - "return float4(t.CalculateLevelOfDetail(s, uv),\n" - " t.CalculateLevelOfDetailUnclamped(s, uv),\n" - " 0.0f, 0.0f);\n"; - sampleProgram += "}\n"; - } - } - else if(opcode == OPCODE_SAMPLE_C_LZ) - { - sampleProgram = StringFormat::Fmt("%s : register(t0);\n%s : register(s0);\n\n", - textureDecl.c_str(), samplerDecl.c_str()); - sampleProgram += funcRet + " main() : SV_Target0\n{\n"; - sampleProgram += - StringFormat::Fmt("return t.SampleCmpLevelZero(s, %s, %.10f %s)%s;\n", texcoords.c_str(), - lodOrCompareValue, offsets.c_str(), strSwizzle.c_str()); - sampleProgram += "}\n"; - } - else if(opcode == OPCODE_LD) - { - sampleProgram = StringFormat::Fmt("%s : register(t0);\n\n", textureDecl.c_str()); - sampleProgram += funcRet + " main() : SV_Target0\n{\n"; - sampleProgram += "return t.Load(" + texcoords + offsets + ")" + strSwizzle + ";"; - sampleProgram += "\n}\n"; - } - else if(opcode == OPCODE_LD_MS) - { - sampleProgram = StringFormat::Fmt("%s : register(t0);\n\n", textureDecl.c_str()); - sampleProgram += funcRet + " main() : SV_Target0\n{\n"; - sampleProgram += StringFormat::Fmt("return t.Load(%s, int(%d) %s)%s;\n", texcoords.c_str(), - multisampleIndex, offsets.c_str(), strSwizzle.c_str()); - sampleProgram += "\n}\n"; - } - else if(opcode == OPCODE_GATHER4 || opcode == OPCODE_GATHER4_PO) - { - sampleProgram = StringFormat::Fmt("%s : register(t0);\n%s : register(s0);\n\n", - textureDecl.c_str(), samplerDecl.c_str()); - sampleProgram += funcRet + " main() : SV_Target0\n{\n"; - sampleProgram += StringFormat::Fmt("return t.Gather%s(s, %s %s)%s;\n", strGatherChannel.c_str(), - texcoords.c_str(), offsets.c_str(), strSwizzle.c_str()); - sampleProgram += "}\n"; - } - else if(opcode == OPCODE_GATHER4_C || opcode == OPCODE_GATHER4_PO_C) - { - sampleProgram = StringFormat::Fmt("%s : register(t0);\n%s : register(s0);\n\n", - textureDecl.c_str(), samplerDecl.c_str()); - sampleProgram += funcRet + " main() : SV_Target0\n{\n"; - sampleProgram += StringFormat::Fmt("return t.GatherCmp%s(s, %s, %.10f %s)%s;\n", - strGatherChannel.c_str(), texcoords.c_str(), - lodOrCompareValue, offsets.c_str(), strSwizzle.c_str()); - sampleProgram += "}\n"; - } - - ID3D11VertexShader *vs = - m_pDevice->GetShaderCache()->MakeVShader(vsProgram.c_str(), "main", "vs_5_0"); - ID3D11PixelShader *ps = - m_pDevice->GetShaderCache()->MakePShader(sampleProgram.c_str(), "main", "ps_5_0"); - - if(!vs || !ps) - { - RDCERR("Sample VS or PS failed to compile"); - return false; - } + cbufferData.debugSampleGatherChannel = (int)gatherChannel; + cbufferData.debugSampleSampleIndex = multisampleIndex; + cbufferData.debugSampleOperation = (int)opcode; + cbufferData.debugSampleLodCompare = lodOrCompareValue; D3D11RenderStateTracker tracker(m_pDevice->GetImmediateContext()); @@ -1436,8 +1167,10 @@ bool D3D11DebugAPIWrapper::CalculateSampleGather( default: RDCERR("Unhandled shader type %d", GetShaderType()); break; } + texSlot = (cbufferData.debugSampleTexDim - 1) + 5 * (cbufferData.debugSampleRetType - 1); + // set onto PS while we perform the sample - context->PSSetShaderResources(0, 1, &usedSRV); + context->PSSetShaderResources(texSlot, 1, &usedSRV); if(opcode == OPCODE_SAMPLE_B && samplerData.bias != 0.0f) { RDCASSERT(usedSamp); @@ -1451,7 +1184,8 @@ bool D3D11DebugAPIWrapper::CalculateSampleGather( HRESULT hr = m_pDevice->CreateSamplerState(&desc, &replacementSamp); if(FAILED(hr)) { - RDCERR("Failed to create new sampler state in debugging HRESULT: %s", ToStr(hr).c_str()); + RDCERR("Failed to create new sampler state in debugging HRESULT: %s", + ToStr(hr).c_str()); // @NoCoverage } else { @@ -1461,14 +1195,33 @@ bool D3D11DebugAPIWrapper::CalculateSampleGather( } else { - context->PSSetSamplers(0, 1, &usedSamp); + if(opcode == OPCODE_SAMPLE_C || opcode == OPCODE_SAMPLE_C_LZ || opcode == OPCODE_GATHER4_C || + opcode == OPCODE_GATHER4_PO_C) + context->PSSetSamplers(1, 1, &usedSamp); + else + context->PSSetSamplers(0, 1, &usedSamp); } context->IASetInputLayout(NULL); context->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); - context->VSSetShader(vs, NULL, 0); - context->PSSetShader(ps, NULL, 0); + context->VSSetShader(debugData.SampleVS, NULL, 0); + context->PSSetShader(debugData.GetSamplePS(texelOffsets), NULL, 0); + + D3D11_MAPPED_SUBRESOURCE mapped; + HRESULT hr = context->Map(debugData.ParamBuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + if(FAILED(hr)) + { + RDCERR("Failed to map parameters HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return false; // @NoCoverage + } + + memcpy(mapped.pData, &cbufferData, sizeof(cbufferData)); + + context->Unmap(debugData.ParamBuf, 0); + + context->VSSetConstantBuffers(0, 1, &debugData.ParamBuf); + context->PSSetConstantBuffers(0, 1, &debugData.ParamBuf); D3D11_VIEWPORT view = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f}; context->RSSetViewports(1, &view); @@ -1484,88 +1237,44 @@ bool D3D11DebugAPIWrapper::CalculateSampleGather( context->OMSetBlendState(NULL, NULL, (UINT)~0); context->OMSetDepthStencilState(NULL, 0); - ID3D11RenderTargetView *rtv = NULL; - - ID3D11Texture2D *rtTex = NULL; - ID3D11Texture2D *copyTex = NULL; - - D3D11_TEXTURE2D_DESC tdesc; - - RDCASSERT(retFmt != DXGI_FORMAT_UNKNOWN); - - tdesc.ArraySize = 1; - tdesc.BindFlags = D3D11_BIND_RENDER_TARGET; - tdesc.CPUAccessFlags = 0; - tdesc.Format = retFmt; - tdesc.Width = 1; - tdesc.Height = 1; - tdesc.MipLevels = 0; - tdesc.MiscFlags = 0; - tdesc.SampleDesc.Count = 1; - tdesc.SampleDesc.Quality = 0; - tdesc.Usage = D3D11_USAGE_DEFAULT; - - HRESULT hr = S_OK; - - hr = m_pDevice->CreateTexture2D(&tdesc, NULL, &rtTex); - - if(FAILED(hr)) - { - RDCERR("Failed to create RT tex HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - tdesc.BindFlags = 0; - tdesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - tdesc.Usage = D3D11_USAGE_STAGING; - - hr = m_pDevice->CreateTexture2D(&tdesc, NULL, ©Tex); - - if(FAILED(hr)) - { - RDCERR("Failed to create copy tex HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - D3D11_RENDER_TARGET_VIEW_DESC rtDesc; - - rtDesc.Format = retFmt; - rtDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; - rtDesc.Texture2D.MipSlice = 0; - - hr = m_pDevice->CreateRenderTargetView(rtTex, &rtDesc, &rtv); - - if(FAILED(hr)) - { - RDCERR("Failed to create rt rtv HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - context->OMSetRenderTargetsAndUnorderedAccessViews(1, &rtv, NULL, 0, 0, NULL, NULL); + UINT uavCount = ~0U; + context->OMSetRenderTargetsAndUnorderedAccessViews(1, &debugData.DummyRTV, NULL, 1, 1, + &debugData.OutUAV, &uavCount); context->Draw(3, 0); - context->CopyResource(copyTex, rtTex); + context->CopyResource(debugData.OutStageBuf, debugData.OutBuf); - D3D11_MAPPED_SUBRESOURCE mapped; - hr = context->Map(copyTex, 0, D3D11_MAP_READ, 0, &mapped); + hr = context->Map(debugData.OutStageBuf, 0, D3D11_MAP_READ, 0, &mapped); if(FAILED(hr)) { - RDCERR("Failed to map results HRESULT: %s", ToStr(hr).c_str()); - return false; + RDCERR("Failed to map results HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return false; // @NoCoverage } ShaderVariable lookupResult("tex", 0.0f, 0.0f, 0.0f, 0.0f); - memcpy(lookupResult.value.u32v.data(), mapped.pData, sizeof(uint32_t) * 4); + float *retFloats = (float *)mapped.pData; + uint32_t *retUInts = (uint32_t *)(retFloats + 16); + int32_t *retSInts = (int32_t *)(retUInts + 16); - context->Unmap(copyTex, 0); + 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]]; + } - SAFE_RELEASE(rtTex); - SAFE_RELEASE(copyTex); - SAFE_RELEASE(rtv); - SAFE_RELEASE(vs); - SAFE_RELEASE(ps); + context->Unmap(debugData.OutStageBuf, 0); SAFE_RELEASE(context); @@ -1580,121 +1289,53 @@ bool D3D11DebugAPIWrapper::CalculateMathIntrinsic(DXBCBytecode::OpcodeType opcod const ShaderVariable &input, ShaderVariable &output1, ShaderVariable &output2) { - rdcstr csProgram = - "RWBuffer outval : register(u0);\n" - "cbuffer srcOper : register(b0) { float4 inval; };\n" - "[numthreads(1, 1, 1)]\n" - "void main() {\n"; - - switch(opcode) - { - case DXBCBytecode::OPCODE_RCP: csProgram += "outval[0] = rcp(inval);\n"; break; - case DXBCBytecode::OPCODE_RSQ: csProgram += "outval[0] = rsqrt(inval);\n"; break; - case DXBCBytecode::OPCODE_EXP: csProgram += "outval[0] = exp2(inval);\n"; break; - case DXBCBytecode::OPCODE_LOG: csProgram += "outval[0] = log2(inval);\n"; break; - case DXBCBytecode::OPCODE_SINCOS: csProgram += "sincos(inval, outval[0], outval[1]);\n"; break; - default: RDCERR("Unexpected opcode %d passed to CalculateMathIntrinsic", opcode); return false; - } - - csProgram += "}\n"; - - ID3D11ComputeShader *cs = - m_pDevice->GetShaderCache()->MakeCShader(csProgram.c_str(), "main", "cs_5_0"); - 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"); + ID3D11DeviceContext *context = NULL; m_pDevice->GetImmediateContext(&context); - ID3D11Buffer *constBuf = NULL; - - D3D11_BUFFER_DESC cdesc; - - cdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - cdesc.CPUAccessFlags = 0; - cdesc.MiscFlags = 0; - cdesc.StructureByteStride = sizeof(Vec4f); - cdesc.ByteWidth = sizeof(Vec4f); - cdesc.Usage = D3D11_USAGE_DEFAULT; - - D3D11_SUBRESOURCE_DATA operData = {}; - operData.pSysMem = &input.value.u32v[0]; - operData.SysMemPitch = sizeof(Vec4f); - operData.SysMemSlicePitch = sizeof(Vec4f); - - HRESULT hr = m_pDevice->CreateBuffer(&cdesc, &operData, &constBuf); - if(FAILED(hr)) - { - RDCERR("Failed to create constant buf HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - context->CSSetConstantBuffers(0, 1, &constBuf); - - context->CSSetShader(cs, NULL, 0); - - ID3D11UnorderedAccessView *uav = NULL; - - ID3D11Buffer *uavBuf = NULL; - ID3D11Buffer *copyBuf = NULL; - - D3D11_BUFFER_DESC bdesc; - - bdesc.BindFlags = D3D11_BIND_UNORDERED_ACCESS; - bdesc.CPUAccessFlags = 0; - bdesc.MiscFlags = 0; - bdesc.StructureByteStride = sizeof(Vec4f); - bdesc.ByteWidth = sizeof(Vec4f) * 2; - bdesc.Usage = D3D11_USAGE_DEFAULT; - - hr = m_pDevice->CreateBuffer(&bdesc, NULL, &uavBuf); - - if(FAILED(hr)) - { - RDCERR("Failed to create UAV buf HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - bdesc.BindFlags = 0; - bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - bdesc.Usage = D3D11_USAGE_STAGING; - - hr = m_pDevice->CreateBuffer(&bdesc, NULL, ©Buf); - - if(FAILED(hr)) - { - RDCERR("Failed to create copy buf HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc = {}; - - uavDesc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT; - uavDesc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER; - uavDesc.Buffer.FirstElement = 0; - uavDesc.Buffer.NumElements = 2; - uavDesc.Buffer.Flags = 0; - - hr = m_pDevice->CreateUnorderedAccessView(uavBuf, &uavDesc, &uav); - - if(FAILED(hr)) - { - RDCERR("Failed to create uav HRESULT: %s", ToStr(hr).c_str()); - return false; - } - - context->CSSetUnorderedAccessViews(0, 1, &uav, NULL); - context->Dispatch(1, 1, 1); - - context->CopyResource(copyBuf, uavBuf); + const ShaderDebugging &debugData = m_pDevice->GetReplay()->GetShaderDebuggingData(); D3D11_MAPPED_SUBRESOURCE mapped; - hr = context->Map(copyBuf, 0, D3D11_MAP_READ, 0, &mapped); + HRESULT hr = context->Map(debugData.ParamBuf, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); + if(FAILED(hr)) + { + RDCERR("Failed to map parameters HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return false; // @NoCoverage + } + + DebugMathOperation data; + data.mathOp = (int)opcode; + memcpy(&data.mathInVal, &input.value.u32v[0], sizeof(Vec4f)); + + memcpy(mapped.pData, &data, sizeof(data)); + + context->Unmap(debugData.ParamBuf, 0); + + context->CSSetConstantBuffers(0, 1, &debugData.ParamBuf); + context->CSSetShader(debugData.MathCS, NULL, 0); + context->CSSetUnorderedAccessViews(1, 1, &debugData.OutUAV, NULL); + context->Dispatch(1, 1, 1); + + context->CopyResource(debugData.OutStageBuf, debugData.OutBuf); + + hr = context->Map(debugData.OutStageBuf, 0, D3D11_MAP_READ, 0, &mapped); if(FAILED(hr)) { - RDCERR("Failed to map results HRESULT: %s", ToStr(hr).c_str()); - return false; + RDCERR("Failed to map results HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return false; // @NoCoverage } uint32_t *resA = (uint32_t *)mapped.pData; @@ -1703,13 +1344,7 @@ bool D3D11DebugAPIWrapper::CalculateMathIntrinsic(DXBCBytecode::OpcodeType opcod memcpy(output1.value.u32v.data(), resA, sizeof(uint32_t) * 4); memcpy(output2.value.u32v.data(), resB, sizeof(uint32_t) * 4); - context->Unmap(copyBuf, 0); - - SAFE_RELEASE(constBuf); - SAFE_RELEASE(uavBuf); - SAFE_RELEASE(copyBuf); - SAFE_RELEASE(uav); - SAFE_RELEASE(cs); + context->Unmap(debugData.OutStageBuf, 0); SAFE_RELEASE(context); @@ -2489,8 +2124,8 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, if(FAILED(hr)) { - RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); - return new ShaderDebugTrace; + RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return new ShaderDebugTrace; // @NoCoverage } ID3D11Buffer *evalBuf = NULL; @@ -2504,8 +2139,8 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, if(FAILED(hr)) { - RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); - return new ShaderDebugTrace; + RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return new ShaderDebugTrace; // @NoCoverage } } @@ -2521,8 +2156,8 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, if(FAILED(hr)) { - RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); - return new ShaderDebugTrace; + RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return new ShaderDebugTrace; // @NoCoverage } uint32_t evalStructStride = uint32_t(evalSampleCacheData.size() * sizeof(Vec4f)); @@ -2536,8 +2171,8 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, if(FAILED(hr)) { - RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); - return new ShaderDebugTrace; + RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return new ShaderDebugTrace; // @NoCoverage } } @@ -2553,8 +2188,8 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, if(FAILED(hr)) { - RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); - return new ShaderDebugTrace; + RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return new ShaderDebugTrace; // @NoCoverage } ID3D11UnorderedAccessView *evalUAV = NULL; @@ -2566,8 +2201,8 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, if(FAILED(hr)) { - RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); - return new ShaderDebugTrace; + RDCERR("Failed to create buffer HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return new ShaderDebugTrace; // @NoCoverage } } @@ -2601,8 +2236,8 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, if(FAILED(hr)) { - RDCERR("Failed to map stage buff HRESULT: %s", ToStr(hr).c_str()); - return new ShaderDebugTrace; + RDCERR("Failed to map stage buff HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + return new ShaderDebugTrace; // @NoCoverage } byte *initialData = new byte[structStride * (overdrawLevels + 1)]; @@ -2618,9 +2253,9 @@ void ExtractInputsPS(PSInput IN, float4 debug_pixelPos : SV_Position, if(FAILED(hr)) { - RDCERR("Failed to map stage buff HRESULT: %s", ToStr(hr).c_str()); - SAFE_DELETE_ARRAY(initialData); - return new ShaderDebugTrace; + RDCERR("Failed to map stage buff HRESULT: %s", ToStr(hr).c_str()); // @NoCoverage + SAFE_DELETE_ARRAY(initialData); // @NoCoverage + return new ShaderDebugTrace; // @NoCoverage } evalData = new byte[evalStructStride * (overdrawLevels + 1)]; diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index ea9bb677a..a300b3775 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -259,12 +259,12 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) rm->SetInternalResource(m_MeshRootSig); } - if(!CreateMathIntrinsicsResources()) + if(!CreateShaderDebugResources()) { RDCERR("Failed to create resources for shader debugging math intrinsics"); - SAFE_RELEASE(m_MathIntrinsicsRootSig); + SAFE_RELEASE(m_ShaderDebugRootSig); SAFE_RELEASE(m_MathIntrinsicsPso); - SAFE_RELEASE(m_MathIntrinsicsResultBuffer); + SAFE_RELEASE(m_ShaderDebugResultBuffer); } { @@ -433,9 +433,12 @@ D3D12DebugManager::~D3D12DebugManager() SAFE_RELEASE(m_MeshPS); SAFE_RELEASE(m_MeshRootSig); - SAFE_RELEASE(m_MathIntrinsicsRootSig); + SAFE_RELEASE(m_ShaderDebugRootSig); SAFE_RELEASE(m_MathIntrinsicsPso); - SAFE_RELEASE(m_MathIntrinsicsResultBuffer); + SAFE_RELEASE(m_ShaderDebugResultBuffer); + SAFE_RELEASE(m_TexSamplePso); + for(auto it = m_OffsetTexSamplePso.begin(); it != m_OffsetTexSamplePso.end(); ++it) + it->second->Release(); SAFE_RELEASE(m_ArrayMSAARootSig); SAFE_RELEASE(m_FullscreenVS); @@ -477,67 +480,59 @@ D3D12DebugManager::~D3D12DebugManager() RenderDoc::Inst().UnregisterMemoryRegion(this); } -bool D3D12DebugManager::CreateMathIntrinsicsResources() +bool D3D12DebugManager::CreateShaderDebugResources() { - rdcstr csProgram = - "RWStructuredBuffer outval : register(u0);\n" - "cbuffer srcOper : register(b0) { float4 inval; };\n" - "cbuffer srcInstr : register(b1) { uint operation; };\n"; + rdcstr hlsl = GetEmbeddedResource(shaderdebug_hlsl); - // Assign constants to each supported instruction - csProgram += StringFormat::Fmt("static const uint OPCODE_RCP = %u;\n", DXBCBytecode::OPCODE_RCP); - csProgram += StringFormat::Fmt("static const uint OPCODE_RSQ = %u;\n", DXBCBytecode::OPCODE_RSQ); - csProgram += StringFormat::Fmt("static const uint OPCODE_EXP = %u;\n", DXBCBytecode::OPCODE_EXP); - csProgram += StringFormat::Fmt("static const uint OPCODE_LOG = %u;\n", DXBCBytecode::OPCODE_LOG); - csProgram += - StringFormat::Fmt("static const uint OPCODE_SINCOS = %u;\n", DXBCBytecode::OPCODE_SINCOS); - - csProgram += - "[numthreads(1, 1, 1)]\n" - "void main(){\n" - " switch(operation){\n" - " case OPCODE_RCP: outval[0] = rcp(inval); break;\n" - " case OPCODE_RSQ: outval[0] = rsqrt(inval); break;\n" - " case OPCODE_EXP: outval[0] = exp2(inval); break;\n" - " case OPCODE_LOG: outval[0] = log2(inval); break;\n" - " case OPCODE_SINCOS: sincos(inval, outval[0], outval[1]); break;\n" - " }\n}\n"; + D3D12RootSignature rootSig; ID3DBlob *csBlob = NULL; - UINT flags = D3DCOMPILE_DEBUG | D3DCOMPILE_WARNINGS_ARE_ERRORS; - if(m_pDevice->GetShaderCache()->GetShaderBlob(csProgram.c_str(), "main", flags, {}, "cs_5_0", + if(m_pDevice->GetShaderCache()->GetShaderBlob(hlsl.c_str(), "RENDERDOC_DebugMathOp", + D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "cs_5_0", &csBlob) != "") { RDCERR("Failed to create shader to calculate math intrinsic"); return false; } - D3D12RootSignature rootSig; - - // Constants param for the operation inputs D3D12RootSignatureParameter constantParam; - constantParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTS; + constantParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_CBV; constantParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - constantParam.Constants.Num32BitValues = 4; // Input is 4 floats - constantParam.Constants.ShaderRegister = 0; - constantParam.Constants.RegisterSpace = 0; + constantParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE; + constantParam.Descriptor.ShaderRegister = 0; + constantParam.Descriptor.RegisterSpace = 0; rootSig.Parameters.push_back(constantParam); - // Constants param for the opcode - constantParam.Constants.Num32BitValues = 1; - constantParam.Constants.ShaderRegister = 1; - constantParam.Constants.RegisterSpace = 0; - rootSig.Parameters.push_back(constantParam); - - // UAV param for the output D3D12RootSignatureParameter uavParam; uavParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_UAV; uavParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; - uavParam.Descriptor.ShaderRegister = 0; + uavParam.Descriptor.ShaderRegister = 1; uavParam.Descriptor.RegisterSpace = 0; uavParam.Descriptor.Flags = D3D12_ROOT_DESCRIPTOR_FLAG_NONE; rootSig.Parameters.push_back(uavParam); + D3D12_DESCRIPTOR_RANGE1 range = {}; + range.BaseShaderRegister = 0; + range.RegisterSpace = 0; + range.NumDescriptors = 25; + range.OffsetInDescriptorsFromTableStart = 0; + range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SRV; + + D3D12RootSignatureParameter srvParam; + srvParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + srvParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + srvParam.ranges.push_back(range); + rootSig.Parameters.push_back(srvParam); + + range.NumDescriptors = 2; + range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER; + + D3D12RootSignatureParameter sampParam; + sampParam.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + sampParam.ShaderVisibility = D3D12_SHADER_VISIBILITY_ALL; + sampParam.ranges.push_back(range); + rootSig.Parameters.push_back(sampParam); + ID3DBlob *root = m_pDevice->GetShaderCache()->MakeRootSig(rootSig); if(root == NULL) { @@ -545,9 +540,10 @@ bool D3D12DebugManager::CreateMathIntrinsicsResources() SAFE_RELEASE(csBlob); return false; } - HRESULT hr = m_pDevice->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(), - __uuidof(ID3D12RootSignature), - (void **)&m_MathIntrinsicsRootSig); + + HRESULT hr = + m_pDevice->CreateRootSignature(0, root->GetBufferPointer(), root->GetBufferSize(), + __uuidof(ID3D12RootSignature), (void **)&m_ShaderDebugRootSig); m_pDevice->InternalRef(); SAFE_RELEASE(root); if(FAILED(hr)) @@ -556,10 +552,10 @@ bool D3D12DebugManager::CreateMathIntrinsicsResources() SAFE_RELEASE(csBlob); return false; } - m_pDevice->GetResourceManager()->SetInternalResource(m_MathIntrinsicsRootSig); + m_pDevice->GetResourceManager()->SetInternalResource(m_ShaderDebugRootSig); D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc; - psoDesc.pRootSignature = m_MathIntrinsicsRootSig; + psoDesc.pRootSignature = m_ShaderDebugRootSig; psoDesc.CS.BytecodeLength = csBlob->GetBufferSize(); psoDesc.CS.pShaderBytecode = csBlob->GetBufferPointer(); psoDesc.NodeMask = 0; @@ -574,7 +570,6 @@ bool D3D12DebugManager::CreateMathIntrinsicsResources() if(FAILED(hr)) { RDCERR("Failed to create PSO for shader debugging HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(m_MathIntrinsicsRootSig); return false; } m_pDevice->GetResourceManager()->SetInternalResource(m_MathIntrinsicsPso); @@ -583,7 +578,7 @@ bool D3D12DebugManager::CreateMathIntrinsicsResources() D3D12_RESOURCE_DESC rdesc; ZeroMemory(&rdesc, sizeof(D3D12_RESOURCE_DESC)); rdesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; - rdesc.Width = sizeof(Vec4f) * 2; // Output buffer is 2x float4 + rdesc.Width = sizeof(Vec4f) * 6; rdesc.Height = 1; rdesc.DepthOrArraySize = 1; rdesc.MipLevels = 1; @@ -602,20 +597,172 @@ bool D3D12DebugManager::CreateMathIntrinsicsResources() hr = m_pDevice->CreateCommittedResource( &heapProps, D3D12_HEAP_FLAG_NONE, &rdesc, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, NULL, - __uuidof(ID3D12Resource), (void **)&m_MathIntrinsicsResultBuffer); + __uuidof(ID3D12Resource), (void **)&m_ShaderDebugResultBuffer); m_pDevice->InternalRef(); if(FAILED(hr)) { RDCERR("Failed to create buffer for pixel shader debugging HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(m_MathIntrinsicsRootSig); - SAFE_RELEASE(m_MathIntrinsicsPso); return false; } - m_pDevice->GetResourceManager()->SetInternalResource(m_MathIntrinsicsResultBuffer); + m_pDevice->GetResourceManager()->SetInternalResource(m_ShaderDebugResultBuffer); + + // Create UAV to store the computed results + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; + ZeroMemory(&uavDesc, sizeof(D3D12_UNORDERED_ACCESS_VIEW_DESC)); + uavDesc.Format = DXGI_FORMAT_UNKNOWN; + uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; + uavDesc.Buffer.NumElements = 1; + uavDesc.Buffer.StructureByteStride = sizeof(Vec4f) * 6; + + D3D12_CPU_DESCRIPTOR_HANDLE uav = GetCPUHandle(SHADER_DEBUG_UAV); + m_pDevice->CreateUnorderedAccessView(m_ShaderDebugResultBuffer, NULL, &uavDesc, uav); + + ID3DBlob *vsBlob = NULL; + if(m_pDevice->GetShaderCache()->GetShaderBlob(hlsl.c_str(), "RENDERDOC_DebugSampleVS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "vs_5_0", + &vsBlob) != "") + { + RDCERR("Failed to create shader to do texture sample"); + SAFE_RELEASE(vsBlob); + return false; + } + + ID3DBlob *psBlob = NULL; + if(m_pDevice->GetShaderCache()->GetShaderBlob(hlsl.c_str(), "RENDERDOC_DebugSamplePS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "ps_5_0", + &psBlob) != "") + { + RDCERR("Failed to create shader to do texture sample"); + SAFE_RELEASE(vsBlob); + SAFE_RELEASE(psBlob); + return false; + } + + D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc = {}; + + pipeDesc.pRootSignature = m_ShaderDebugRootSig; + pipeDesc.VS.BytecodeLength = vsBlob->GetBufferSize(); + pipeDesc.VS.pShaderBytecode = vsBlob->GetBufferPointer(); + pipeDesc.PS.BytecodeLength = psBlob->GetBufferSize(); + pipeDesc.PS.pShaderBytecode = psBlob->GetBufferPointer(); + pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; + pipeDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; + pipeDesc.SampleMask = 0xFFFFFFFF; + pipeDesc.SampleDesc.Count = 1; + pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + pipeDesc.NumRenderTargets = 1; + pipeDesc.RTVFormats[0] = DXGI_FORMAT_R32G32B32A32_FLOAT; + pipeDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; + pipeDesc.BlendState.RenderTarget[0].BlendEnable = FALSE; + pipeDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + pipeDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + pipeDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0; + + hr = m_pDevice->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&m_TexSamplePso); + m_pDevice->InternalRef(); + SAFE_RELEASE(vsBlob); + SAFE_RELEASE(psBlob); + if(FAILED(hr)) + { + RDCERR("Failed to create PSO for shader debugging HRESULT: %s", ToStr(hr).c_str()); + return false; + } + m_pDevice->GetResourceManager()->SetInternalResource(m_TexSamplePso); return true; } +ID3D12PipelineState *D3D12DebugManager::GetTexSamplePso(const int8_t offsets[3]) +{ + uint32_t offsKey = offsets[0] | (offsets[1] << 8) | (offsets[2] << 16); + if(offsKey == 0) + return m_TexSamplePso; + + ID3D12PipelineState *ps = m_OffsetTexSamplePso[offsKey]; + if(ps) + return ps; + + D3D12ShaderCache *shaderCache = m_pDevice->GetShaderCache(); + + shaderCache->SetCaching(true); + + rdcstr hlsl = GetEmbeddedResource(shaderdebug_hlsl); + + hlsl = StringFormat::Fmt("#define debugSampleOffsets int4(%d,%d,%d,0)\n\n%s", offsets[0], + offsets[1], offsets[2], hlsl.c_str()); + + ID3DBlob *vsBlob = NULL; + if(m_pDevice->GetShaderCache()->GetShaderBlob(hlsl.c_str(), "RENDERDOC_DebugSampleVS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "vs_5_0", + &vsBlob) != "") + { + RDCERR("Failed to create shader to do texture sample"); + SAFE_RELEASE(vsBlob); + return false; + } + + ID3DBlob *psBlob = NULL; + if(m_pDevice->GetShaderCache()->GetShaderBlob(hlsl.c_str(), "RENDERDOC_DebugSamplePS", + D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "ps_5_0", + &psBlob) != "") + { + RDCERR("Failed to create shader to do texture sample"); + SAFE_RELEASE(vsBlob); + SAFE_RELEASE(psBlob); + return false; + } + + D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc = {}; + + pipeDesc.pRootSignature = m_ShaderDebugRootSig; + pipeDesc.VS.BytecodeLength = vsBlob->GetBufferSize(); + pipeDesc.VS.pShaderBytecode = vsBlob->GetBufferPointer(); + pipeDesc.PS.BytecodeLength = psBlob->GetBufferSize(); + pipeDesc.PS.pShaderBytecode = psBlob->GetBufferPointer(); + pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; + pipeDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; + pipeDesc.SampleMask = 0xFFFFFFFF; + pipeDesc.SampleDesc.Count = 1; + pipeDesc.IBStripCutValue = D3D12_INDEX_BUFFER_STRIP_CUT_VALUE_DISABLED; + pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + pipeDesc.NumRenderTargets = 1; + pipeDesc.RTVFormats[0] = DXGI_FORMAT_R32G32B32A32_FLOAT; + pipeDesc.DSVFormat = DXGI_FORMAT_UNKNOWN; + pipeDesc.BlendState.RenderTarget[0].BlendEnable = FALSE; + pipeDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD; + pipeDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA; + pipeDesc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD; + pipeDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = 0; + + ID3D12PipelineState *pso = NULL; + HRESULT hr = m_pDevice->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState), + (void **)&pso); + m_pDevice->InternalRef(); + SAFE_RELEASE(vsBlob); + SAFE_RELEASE(psBlob); + if(FAILED(hr)) + { + RDCERR("Failed to create PSO for shader debugging HRESULT: %s", ToStr(hr).c_str()); + return false; + } + m_pDevice->GetResourceManager()->SetInternalResource(pso); + + m_OffsetTexSamplePso[offsKey] = pso; + + shaderCache->SetCaching(false); + + return pso; +} + ID3D12Resource *D3D12DebugManager::MakeCBuffer(UINT64 size) { ID3D12Resource *ret; @@ -1085,6 +1232,13 @@ D3D12_CPU_DESCRIPTOR_HANDLE D3D12DebugManager::GetCPUHandle(DSVSlot slot) return ret; } +D3D12_CPU_DESCRIPTOR_HANDLE D3D12DebugManager::GetCPUHandle(SamplerSlot slot) +{ + D3D12_CPU_DESCRIPTOR_HANDLE ret = samplerHeap->GetCPUDescriptorHandleForHeapStart(); + ret.ptr += slot * sizeof(D3D12Descriptor); + return ret; +} + D3D12_GPU_DESCRIPTOR_HANDLE D3D12DebugManager::GetGPUHandle(CBVUAVSRVSlot slot) { D3D12_GPU_DESCRIPTOR_HANDLE ret = cbvsrvuavHeap->GetGPUDescriptorHandleForHeapStart(); @@ -1219,6 +1373,15 @@ void D3D12DebugManager::SetDescriptorHeaps(ID3D12GraphicsCommandList *list, bool } } +void D3D12DebugManager::SetDescriptorHeaps(rdcarray &heaps, bool cbvsrvuav, bool samplers) +{ + heaps.clear(); + if(cbvsrvuav) + heaps.push_back(GetResID(cbvsrvuavHeap)); + if(samplers) + heaps.push_back(GetResID(samplerHeap)); +} + D3D12_CPU_DESCRIPTOR_HANDLE D3D12DebugManager::GetUAVClearHandle(CBVUAVSRVSlot slot) { D3D12_CPU_DESCRIPTOR_HANDLE ret = uavClearHeap->GetCPUDescriptorHandleForHeapStart(); diff --git a/renderdoc/driver/d3d12/d3d12_debug.h b/renderdoc/driver/d3d12/d3d12_debug.h index 9d727abb9..2427ae477 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.h +++ b/renderdoc/driver/d3d12/d3d12_debug.h @@ -77,6 +77,9 @@ enum CBVUAVSRVSlot STENCIL_MSAA_SRV16x, STENCIL_MSAA_SRV32x, + FIRST_SHADDEBUG_SRV, + LAST_SHADDEBUG_SRV = FIRST_SHADDEBUG_SRV + 25, + MAX_SRV_SLOT, }; @@ -98,6 +101,8 @@ enum SamplerSlot POINT_SAMP, FIRST_SAMP = POINT_SAMP, LINEAR_SAMP, + SHADDEBUG_SAMPLER0, + SHADDEBUG_SAMPLER1, }; enum DSVSlot @@ -138,9 +143,11 @@ public: D3D12_GPU_VIRTUAL_ADDRESS UploadConstants(const void *data, size_t size); ID3D12RootSignature *GetMeshRootSig() { return m_MeshRootSig; } - ID3D12RootSignature *GetMathIntrinsicsRootSig() { return m_MathIntrinsicsRootSig; } + ID3D12RootSignature *GetShaderDebugRootSig() { return m_ShaderDebugRootSig; } ID3D12PipelineState *GetMathIntrinsicsPso() { return m_MathIntrinsicsPso; } - ID3D12Resource *GetMathIntrinsicsResultBuffer() { return m_MathIntrinsicsResultBuffer; } + ID3D12PipelineState *GetTexSamplePso(const int8_t offsets[3]); + ID3D12Resource *GetShaderDebugResultBuffer() { return m_ShaderDebugResultBuffer; } + ID3D12Resource *GetReadbackBuffer() { return m_ReadbackBuffer; } ID3D12GraphicsCommandListX *ResetDebugList(); void ResetDebugAlloc(); @@ -151,6 +158,7 @@ public: D3D12_CPU_DESCRIPTOR_HANDLE GetCPUHandle(CBVUAVSRVSlot slot); D3D12_CPU_DESCRIPTOR_HANDLE GetCPUHandle(RTVSlot slot); D3D12_CPU_DESCRIPTOR_HANDLE GetCPUHandle(DSVSlot slot); + D3D12_CPU_DESCRIPTOR_HANDLE GetCPUHandle(SamplerSlot slot); D3D12_GPU_DESCRIPTOR_HANDLE GetGPUHandle(CBVUAVSRVSlot slot); D3D12_GPU_DESCRIPTOR_HANDLE GetGPUHandle(RTVSlot slot); @@ -159,6 +167,7 @@ public: D3D12_CPU_DESCRIPTOR_HANDLE GetTempDescriptor(const D3D12Descriptor &desc, size_t idx = 0); + void SetDescriptorHeaps(rdcarray &heaps, bool cbvsrvuav, bool samplers); void SetDescriptorHeaps(ID3D12GraphicsCommandList *list, bool cbvsrvuav, bool samplers); D3D12_CPU_DESCRIPTOR_HANDLE GetUAVClearHandle(CBVUAVSRVSlot slot); @@ -174,7 +183,7 @@ public: void CopyArrayToTex2DMS(ID3D12Resource *destMS, ID3D12Resource *srcArray, UINT selectedSlice); private: - bool CreateMathIntrinsicsResources(); + bool CreateShaderDebugResources(); rdcpair D3D12DebugManager::GetMSToArrayPSOs( DXGI_FORMAT format); @@ -205,9 +214,11 @@ private: std::map m_CachedMeshPipelines; // Shader debugging resources - ID3D12RootSignature *m_MathIntrinsicsRootSig = NULL; + ID3D12RootSignature *m_ShaderDebugRootSig = NULL; ID3D12PipelineState *m_MathIntrinsicsPso = NULL; - ID3D12Resource *m_MathIntrinsicsResultBuffer = NULL; + ID3D12Resource *m_ShaderDebugResultBuffer = NULL; + ID3D12PipelineState *m_TexSamplePso = NULL; + std::map m_OffsetTexSamplePso; // GetBufferData static const uint64_t m_ReadbackSize = 16 * 1024 * 1024; diff --git a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp index 870e50377..3092a774d 100644 --- a/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp +++ b/renderdoc/driver/d3d12/d3d12_shaderdebug.cpp @@ -33,6 +33,8 @@ #include "d3d12_resources.h" #include "d3d12_shader_cache.h" +#include "data/hlsl/hlsl_cbuffers.h" + struct DebugHit { uint32_t numHits; @@ -81,6 +83,9 @@ public: const DXBCDebug::BindingSlot &slot, const char *opString); ShaderVariable GetBufferInfo(DXBCBytecode::OperandType type, const DXBCDebug::BindingSlot &slot, const char *opString); + + D3D12Descriptor FindDescriptor(DXBCBytecode::OperandType type, const DXBCDebug::BindingSlot &slot); + ShaderVariable GetResourceInfo(DXBCBytecode::OperandType type, const DXBCDebug::BindingSlot &slot, uint32_t mipLevel, int &dim); @@ -466,38 +471,53 @@ bool D3D12DebugAPIWrapper::CalculateMathIntrinsic(DXBCBytecode::OpcodeType opcod { 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) { // To support a new instruction, the shader created in - // D3D12DebugManager::CreateMathIntrinsicsResources will need updated + // D3D12DebugManager::CreateShaderDebugResources will need updated RDCERR("Unsupported instruction for CalculateMathIntrinsic: %u", opcode); return false; } - // Create UAV to store the computed results - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc; - ZeroMemory(&uavDesc, sizeof(D3D12_UNORDERED_ACCESS_VIEW_DESC)); - uavDesc.Format = DXGI_FORMAT_UNKNOWN; - uavDesc.ViewDimension = D3D12_UAV_DIMENSION_BUFFER; - uavDesc.Buffer.NumElements = 2; - uavDesc.Buffer.StructureByteStride = sizeof(Vec4f); + ID3D12Resource *pResultBuffer = m_pDevice->GetDebugManager()->GetShaderDebugResultBuffer(); + ID3D12Resource *pReadbackBuffer = m_pDevice->GetDebugManager()->GetReadbackBuffer(); - ID3D12Resource *pResultBuffer = m_pDevice->GetDebugManager()->GetMathIntrinsicsResultBuffer(); - D3D12_CPU_DESCRIPTOR_HANDLE uav = m_pDevice->GetDebugManager()->GetCPUHandle(SHADER_DEBUG_UAV); - m_pDevice->CreateUnorderedAccessView(pResultBuffer, NULL, &uavDesc, uav); + 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()->GetMathIntrinsicsRootSig()); - cmdList->SetComputeRoot32BitConstants(0, 4, &input.value.u32v[0], 0); - cmdList->SetComputeRoot32BitConstants(1, 1, &opcode, 0); - cmdList->SetComputeRootUnorderedAccessView(2, pResultBuffer->GetGPUVirtualAddress()); + 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)) { @@ -511,16 +531,211 @@ bool D3D12DebugAPIWrapper::CalculateMathIntrinsic(DXBCBytecode::OpcodeType opcod m_pDevice->GPUSync(); } - bytebuf results; - m_pDevice->GetDebugManager()->GetBufferData(pResultBuffer, 0, 0, results); - RDCASSERT(results.size() >= sizeof(Vec4f) * 2); + D3D12_RANGE range = {0, sizeof(Vec4f) * 6}; - memcpy(output1.value.u32v.data(), results.data(), sizeof(Vec4f)); - memcpy(output2.value.u32v.data(), results.data() + sizeof(Vec4f), sizeof(Vec4f)); + 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; } +D3D12Descriptor D3D12DebugAPIWrapper::FindDescriptor(DXBCBytecode::OperandType type, + const DXBCDebug::BindingSlot &slot) +{ + D3D12Descriptor descriptor; + + 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) + { + 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_DESC &samp : pD3D12RootSig->sig.StaticSamplers) + { + if(samp.RegisterSpace == slot.registerSpace && samp.ShaderRegister == slot.shaderRegister) + { + D3D12_SAMPLER_DESC desc; + + desc.Filter = samp.Filter; + desc.AddressU = samp.AddressU; + desc.AddressV = samp.AddressV; + desc.AddressW = samp.AddressW; + desc.MipLODBias = samp.MipLODBias; + desc.MaxAnisotropy = samp.MaxAnisotropy; + desc.ComparisonFunc = samp.ComparisonFunc; + switch(samp.BorderColor) + { + default: + case D3D12_STATIC_BORDER_COLOR_TRANSPARENT_BLACK: + desc.BorderColor[0] = desc.BorderColor[1] = desc.BorderColor[2] = + desc.BorderColor[3] = 0.0f; + break; + case D3D12_STATIC_BORDER_COLOR_OPAQUE_BLACK: + desc.BorderColor[0] = desc.BorderColor[1] = desc.BorderColor[2] = 0.0f; + desc.BorderColor[3] = 1.0f; + break; + case D3D12_STATIC_BORDER_COLOR_OPAQUE_WHITE: + desc.BorderColor[0] = desc.BorderColor[1] = desc.BorderColor[2] = + desc.BorderColor[3] = 1.0f; + break; + } + desc.MinLOD = samp.MinLOD; + desc.MaxLOD = samp.MaxLOD; + + 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_UNORDERED_ACCESS_VIEW) + { + 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]; + + if(range.RangeType != searchRangeType) + continue; + + // 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; + + D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr; + desc += element.offset; + desc += offset; + + 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; + + // 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; +} + ShaderVariable D3D12DebugAPIWrapper::GetSampleInfo(DXBCBytecode::OperandType type, bool isAbsoluteResource, const DXBCDebug::BindingSlot &slot, @@ -528,13 +743,14 @@ ShaderVariable D3D12DebugAPIWrapper::GetSampleInfo(DXBCBytecode::OperandType typ { ShaderVariable result("", 0U, 0U, 0U, 0U); - const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState; D3D12ResourceManager *rm = m_pDevice->GetResourceManager(); if(type == DXBCBytecode::TYPE_RASTERIZER) { if(GetShaderType() != DXBC::ShaderType::Compute) { + const D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState; + // try depth first - both should match sample count though to be valid ResourceId res = rs.GetDSVID(); if(res == ResourceId() && !rs.rts.empty()) @@ -550,105 +766,29 @@ ShaderVariable D3D12DebugAPIWrapper::GetSampleInfo(DXBCBytecode::OperandType typ return result; } - // Get the root signature - const D3D12RenderState::RootSignature *pRootSignature = NULL; - if(GetShaderType() == DXBC::ShaderType::Compute) + D3D12Descriptor descriptor = FindDescriptor(type, slot); + + if(descriptor.GetType() == D3D12DescriptorType::SRV && + type != DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) { - if(rs.compute.rootsig != ResourceId()) + ResourceId srvId = descriptor.GetResResourceId(); + ID3D12Resource *pResource = rm->GetCurrentAs(srvId); + D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = descriptor.GetSRV(); + if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_UNKNOWN) + srvDesc = MakeSRVDesc(resDesc); + + if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS || + srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY) { - pRootSignature = &rs.compute; + result.value.u32v[0] = resDesc.SampleDesc.Count; + result.value.u32v[1] = 0; + result.value.u32v[2] = 0; + result.value.u32v[3] = 0; } - } - else if(rs.graphics.rootsig != ResourceId()) - { - pRootSignature = &rs.graphics; - } - - if(pRootSignature) - { - WrappedID3D12RootSignature *pD3D12RootSig = - rm->GetCurrentAs(pRootSignature->rootsig); - - size_t numParams = RDCMIN(pD3D12RootSig->sig.Parameters.size(), pRootSignature->sigelems.size()); - for(size_t i = 0; i < numParams; ++i) + else { - const D3D12RootSignatureParameter ¶m = pD3D12RootSig->sig.Parameters[i]; - const D3D12RenderState::SignatureElement &element = pRootSignature->sigelems[i]; - if(IsShaderParameterVisible(GetShaderType(), param.ShaderVisibility)) - { - // Root SRV/UAV can only be buffers, so we don't need to check them for GetSampleInfo - 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; - - D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr; - desc += element.offset; - desc += offset; - - 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; - - // 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; - if(desc) - { - if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV && - type != DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) - { - ResourceId srvId = desc->GetResResourceId(); - ID3D12Resource *pResource = rm->GetCurrentAs(srvId); - D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = desc->GetSRV(); - if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_UNKNOWN) - srvDesc = MakeSRVDesc(resDesc); - - if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS || - srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY) - { - result.value.u32v[0] = resDesc.SampleDesc.Count; - result.value.u32v[1] = 0; - result.value.u32v[2] = 0; - result.value.u32v[3] = 0; - } - else - { - RDCERR("Invalid resource dimension for GetSampleInfo"); - } - return result; - } - } - } - } - } - } + RDCERR("Invalid resource dimension for GetSampleInfo"); } } @@ -661,152 +801,42 @@ ShaderVariable D3D12DebugAPIWrapper::GetBufferInfo(DXBCBytecode::OperandType typ { ShaderVariable result("", 0U, 0U, 0U, 0U); - 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) + D3D12Descriptor descriptor = FindDescriptor(type, slot); + + if(descriptor.GetType() == D3D12DescriptorType::SRV && + type != DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) { - if(rs.compute.rootsig != ResourceId()) + ID3D12Resource *pResource = rm->GetCurrentAs(descriptor.GetResResourceId()); + D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); + + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = descriptor.GetSRV(); + if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_UNKNOWN) + srvDesc = MakeSRVDesc(resDesc); + + if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_BUFFER) { - pRootSignature = &rs.compute; + result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = result.value.u32v[3] = + (uint32_t)srvDesc.Buffer.NumElements; } } - else if(rs.graphics.rootsig != ResourceId()) - { - pRootSignature = &rs.graphics; - } - if(pRootSignature) + if(descriptor.GetType() == D3D12DescriptorType::UAV && + type == DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) { - WrappedID3D12RootSignature *pD3D12RootSig = - rm->GetCurrentAs(pRootSignature->rootsig); + ID3D12Resource *pResource = rm->GetCurrentAs(descriptor.GetResResourceId()); + D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); - size_t numParams = RDCMIN(pD3D12RootSig->sig.Parameters.size(), pRootSignature->sigelems.size()); - for(size_t i = 0; i < numParams; ++i) + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = descriptor.GetUAV(); + + if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_UNKNOWN) + uavDesc = MakeUAVDesc(resDesc); + + if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_BUFFER) { - 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_UNORDERED_ACCESS_VIEW) - { - if(param.Descriptor.ShaderRegister == slot.shaderRegister && - param.Descriptor.RegisterSpace == slot.registerSpace) - { - // Found the requested SRV - ID3D12Resource *pResource = rm->GetCurrentAs(element.id); - D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); - - // Root descriptors are always buffers with each element 32-bit - uint32_t numElements = (uint32_t)((resDesc.Width - element.offset) / sizeof(uint32_t)); - result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = - result.value.u32v[3] = numElements; - return result; - } - } - 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) - { - // Found the requested UAV - ID3D12Resource *pResource = rm->GetCurrentAs(element.id); - D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); - - // Root descriptors are always buffers with each element 32-bit - uint32_t numElements = (uint32_t)((resDesc.Width - element.offset) / sizeof(uint32_t)); - result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = - result.value.u32v[3] = numElements; - return result; - } - } - 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; - - D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr; - desc += element.offset; - desc += offset; - - 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; - - // 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; - if(desc) - { - if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV && - type == DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) - { - ResourceId uavId = desc->GetResResourceId(); - ID3D12Resource *pResource = rm->GetCurrentAs(uavId); - D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = desc->GetUAV(); - - if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_UNKNOWN) - uavDesc = MakeUAVDesc(resDesc); - - if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_BUFFER) - { - result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = - result.value.u32v[3] = (uint32_t)uavDesc.Buffer.NumElements; - } - return result; - } - else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV && - type != DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) - { - ResourceId srvId = desc->GetResResourceId(); - ID3D12Resource *pResource = rm->GetCurrentAs(srvId); - D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = desc->GetSRV(); - if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_UNKNOWN) - srvDesc = MakeSRVDesc(resDesc); - - if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_BUFFER) - { - result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = - result.value.u32v[3] = (uint32_t)srvDesc.Buffer.NumElements; - } - return result; - } - } - } - } - } - } + result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = result.value.u32v[3] = + (uint32_t)uavDesc.Buffer.NumElements; } } @@ -819,279 +849,200 @@ ShaderVariable D3D12DebugAPIWrapper::GetResourceInfo(DXBCBytecode::OperandType t { ShaderVariable result("", 0U, 0U, 0U, 0U); - 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) - { - if(rs.compute.rootsig != ResourceId()) - { - pRootSignature = &rs.compute; - } - } - else if(rs.graphics.rootsig != ResourceId()) - { - pRootSignature = &rs.graphics; - } + D3D12Descriptor descriptor = FindDescriptor(type, slot); - if(pRootSignature) + if(descriptor.GetType() == D3D12DescriptorType::UAV && + type == DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) { - WrappedID3D12RootSignature *pD3D12RootSig = - rm->GetCurrentAs(pRootSignature->rootsig); + ResourceId uavId = descriptor.GetResResourceId(); + ID3D12Resource *pResource = rm->GetCurrentAs(uavId); + D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); + D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = descriptor.GetUAV(); - size_t numParams = RDCMIN(pD3D12RootSig->sig.Parameters.size(), pRootSignature->sigelems.size()); - for(size_t i = 0; i < numParams; ++i) + if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_UNKNOWN) + uavDesc = MakeUAVDesc(resDesc); + + switch(uavDesc.ViewDimension) { - const D3D12RootSignatureParameter ¶m = pD3D12RootSig->sig.Parameters[i]; - const D3D12RenderState::SignatureElement &element = pRootSignature->sigelems[i]; - if(IsShaderParameterVisible(GetShaderType(), param.ShaderVisibility)) + case D3D12_UAV_DIMENSION_UNKNOWN: + case D3D12_UAV_DIMENSION_BUFFER: { - // Root SRV/UAV can only be buffers, so we don't need to check them for GetResourceInfo - if(param.ParameterType == D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE && - element.type == eRootTable) + RDCWARN("Invalid view dimension for GetResourceInfo"); + break; + } + case D3D12_UAV_DIMENSION_TEXTURE1D: + case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: + { + dim = 1; + + bool isarray = uavDesc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE1DARRAY; + + result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); + result.value.u32v[1] = isarray ? uavDesc.Texture1DArray.ArraySize : 0; + result.value.u32v[2] = 0; + + // spec says "For UAVs (u#), the number of mip levels is always 1." + result.value.u32v[3] = 1; + + if(mipLevel >= result.value.u32v[3]) + result.value.u32v[0] = result.value.u32v[1] = 0; + + break; + } + case D3D12_UAV_DIMENSION_TEXTURE2D: + case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: + { + dim = 2; + + result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); + result.value.u32v[1] = RDCMAX(1U, (uint32_t)(resDesc.Height >> mipLevel)); + + if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2D) + result.value.u32v[2] = 0; + else if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY) + result.value.u32v[2] = uavDesc.Texture2DArray.ArraySize; + + // spec says "For UAVs (u#), the number of mip levels is always 1." + result.value.u32v[3] = 1; + + if(mipLevel >= result.value.u32v[3]) + result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = 0; + + break; + } + case D3D12_UAV_DIMENSION_TEXTURE3D: + { + dim = 3; + + result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); + result.value.u32v[1] = RDCMAX(1U, (uint32_t)(resDesc.Height >> mipLevel)); + result.value.u32v[2] = RDCMAX(1U, (uint32_t)(resDesc.DepthOrArraySize >> mipLevel)); + + // spec says "For UAVs (u#), the number of mip levels is always 1." + result.value.u32v[3] = 1; + + if(mipLevel >= result.value.u32v[3]) + result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = 0; + + break; + } + } + + return result; + } + else if(descriptor.GetType() == D3D12DescriptorType::SRV && + type != DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) + { + ResourceId srvId = descriptor.GetResResourceId(); + ID3D12Resource *pResource = rm->GetCurrentAs(srvId); + D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); + D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = descriptor.GetSRV(); + if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_UNKNOWN) + srvDesc = MakeSRVDesc(resDesc); + switch(srvDesc.ViewDimension) + { + case D3D12_SRV_DIMENSION_UNKNOWN: + case D3D12_SRV_DIMENSION_BUFFER: + { + RDCWARN("Invalid view dimension for GetResourceInfo"); + break; + } + case D3D12_SRV_DIMENSION_TEXTURE1D: + case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: + { + dim = 1; + + bool isarray = srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE1DARRAY; + + result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); + result.value.u32v[1] = isarray ? srvDesc.Texture1DArray.ArraySize : 0; + result.value.u32v[2] = 0; + result.value.u32v[3] = + isarray ? srvDesc.Texture1DArray.MipLevels : srvDesc.Texture1D.MipLevels; + + if(mipLevel >= result.value.u32v[3]) + result.value.u32v[0] = result.value.u32v[1] = 0; + + break; + } + case D3D12_SRV_DIMENSION_TEXTURE2D: + case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: + case D3D12_SRV_DIMENSION_TEXTURE2DMS: + case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: + { + dim = 2; + result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); + result.value.u32v[1] = RDCMAX(1U, (uint32_t)(resDesc.Height >> mipLevel)); + + if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D) { - 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; - - D3D12Descriptor *desc = (D3D12Descriptor *)heap->GetCPUDescriptorHandleForHeapStart().ptr; - desc += element.offset; - desc += offset; - - 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; - - // 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; - if(desc) - { - if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_UAV && - type == DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) - { - ResourceId uavId = desc->GetResResourceId(); - ID3D12Resource *pResource = rm->GetCurrentAs(uavId); - D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); - D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = desc->GetUAV(); - - if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_UNKNOWN) - uavDesc = MakeUAVDesc(resDesc); - - switch(uavDesc.ViewDimension) - { - case D3D12_UAV_DIMENSION_UNKNOWN: - case D3D12_UAV_DIMENSION_BUFFER: - { - RDCWARN("Invalid view dimension for GetResourceInfo"); - break; - } - case D3D12_UAV_DIMENSION_TEXTURE1D: - case D3D12_UAV_DIMENSION_TEXTURE1DARRAY: - { - dim = 1; - - bool isarray = uavDesc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE1DARRAY; - - result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); - result.value.u32v[1] = isarray ? uavDesc.Texture1DArray.ArraySize : 0; - result.value.u32v[2] = 0; - - // spec says "For UAVs (u#), the number of mip levels is always 1." - result.value.u32v[3] = 1; - - if(mipLevel >= result.value.u32v[3]) - result.value.u32v[0] = result.value.u32v[1] = 0; - - break; - } - case D3D12_UAV_DIMENSION_TEXTURE2D: - case D3D12_UAV_DIMENSION_TEXTURE2DARRAY: - { - dim = 2; - - result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); - result.value.u32v[1] = RDCMAX(1U, (uint32_t)(resDesc.Height >> mipLevel)); - - if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2D) - result.value.u32v[2] = 0; - else if(uavDesc.ViewDimension == D3D12_UAV_DIMENSION_TEXTURE2DARRAY) - result.value.u32v[2] = uavDesc.Texture2DArray.ArraySize; - - // spec says "For UAVs (u#), the number of mip levels is always 1." - result.value.u32v[3] = 1; - - if(mipLevel >= result.value.u32v[3]) - result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = 0; - - break; - } - case D3D12_UAV_DIMENSION_TEXTURE3D: - { - dim = 3; - - result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); - result.value.u32v[1] = RDCMAX(1U, (uint32_t)(resDesc.Height >> mipLevel)); - result.value.u32v[2] = - RDCMAX(1U, (uint32_t)(resDesc.DepthOrArraySize >> mipLevel)); - - // spec says "For UAVs (u#), the number of mip levels is always 1." - result.value.u32v[3] = 1; - - if(mipLevel >= result.value.u32v[3]) - result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = 0; - - break; - } - } - - return result; - } - else if(range.RangeType == D3D12_DESCRIPTOR_RANGE_TYPE_SRV && - type != DXBCBytecode::TYPE_UNORDERED_ACCESS_VIEW) - { - ResourceId srvId = desc->GetResResourceId(); - ID3D12Resource *pResource = rm->GetCurrentAs(srvId); - D3D12_RESOURCE_DESC resDesc = pResource->GetDesc(); - D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = desc->GetSRV(); - if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_UNKNOWN) - srvDesc = MakeSRVDesc(resDesc); - switch(srvDesc.ViewDimension) - { - case D3D12_SRV_DIMENSION_UNKNOWN: - case D3D12_SRV_DIMENSION_BUFFER: - { - RDCWARN("Invalid view dimension for GetResourceInfo"); - break; - } - case D3D12_SRV_DIMENSION_TEXTURE1D: - case D3D12_SRV_DIMENSION_TEXTURE1DARRAY: - { - dim = 1; - - bool isarray = srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE1DARRAY; - - result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); - result.value.u32v[1] = isarray ? srvDesc.Texture1DArray.ArraySize : 0; - result.value.u32v[2] = 0; - result.value.u32v[3] = - isarray ? srvDesc.Texture1DArray.MipLevels : srvDesc.Texture1D.MipLevels; - - if(mipLevel >= result.value.u32v[3]) - result.value.u32v[0] = result.value.u32v[1] = 0; - - break; - } - case D3D12_SRV_DIMENSION_TEXTURE2D: - case D3D12_SRV_DIMENSION_TEXTURE2DARRAY: - case D3D12_SRV_DIMENSION_TEXTURE2DMS: - case D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY: - { - dim = 2; - result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); - result.value.u32v[1] = RDCMAX(1U, (uint32_t)(resDesc.Height >> mipLevel)); - - if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2D) - { - result.value.u32v[2] = 0; - result.value.u32v[3] = srvDesc.Texture2D.MipLevels; - } - else if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY) - { - result.value.u32v[2] = srvDesc.Texture2DArray.ArraySize; - result.value.u32v[3] = srvDesc.Texture2DArray.MipLevels; - } - else if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS) - { - result.value.u32v[2] = 0; - result.value.u32v[3] = 1; - } - else if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY) - { - result.value.u32v[2] = srvDesc.Texture2DMSArray.ArraySize; - result.value.u32v[3] = 1; - } - if(mipLevel >= result.value.u32v[3]) - result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = 0; - - break; - } - case D3D12_SRV_DIMENSION_TEXTURE3D: - { - dim = 3; - - result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); - result.value.u32v[1] = RDCMAX(1U, (uint32_t)(resDesc.Height >> mipLevel)); - result.value.u32v[2] = - RDCMAX(1U, (uint32_t)(resDesc.DepthOrArraySize >> mipLevel)); - result.value.u32v[3] = srvDesc.Texture3D.MipLevels; - - if(mipLevel >= result.value.u32v[3]) - result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = 0; - - break; - } - case D3D12_SRV_DIMENSION_TEXTURECUBE: - case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: - { - // Even though it's a texture cube, an individual face's dimensions are - // returned - dim = 2; - - bool isarray = srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; - - result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); - result.value.u32v[1] = RDCMAX(1U, (uint32_t)(resDesc.Height >> mipLevel)); - - // the spec says "If srcResource is a TextureCubeArray, [...]. dest.z is set - // to an undefined value." - // but that's stupid, and implementations seem to return the number of cubes - result.value.u32v[2] = isarray ? srvDesc.TextureCubeArray.NumCubes : 0; - result.value.u32v[3] = isarray ? srvDesc.TextureCubeArray.MipLevels - : srvDesc.TextureCube.MipLevels; - - if(mipLevel >= result.value.u32v[3]) - result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = 0; - - break; - } - case D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE: - { - RDCERR("Raytracing is unsupported"); - break; - } - } - return result; - } - } - } - } + result.value.u32v[2] = 0; + result.value.u32v[3] = srvDesc.Texture2D.MipLevels; } + else if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DARRAY) + { + result.value.u32v[2] = srvDesc.Texture2DArray.ArraySize; + result.value.u32v[3] = srvDesc.Texture2DArray.MipLevels; + } + else if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMS) + { + result.value.u32v[2] = 0; + result.value.u32v[3] = 1; + } + else if(srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURE2DMSARRAY) + { + result.value.u32v[2] = srvDesc.Texture2DMSArray.ArraySize; + result.value.u32v[3] = 1; + } + if(mipLevel >= result.value.u32v[3]) + result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = 0; + + break; + } + case D3D12_SRV_DIMENSION_TEXTURE3D: + { + dim = 3; + + result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); + result.value.u32v[1] = RDCMAX(1U, (uint32_t)(resDesc.Height >> mipLevel)); + result.value.u32v[2] = RDCMAX(1U, (uint32_t)(resDesc.DepthOrArraySize >> mipLevel)); + result.value.u32v[3] = srvDesc.Texture3D.MipLevels; + + if(mipLevel >= result.value.u32v[3]) + result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = 0; + + break; + } + case D3D12_SRV_DIMENSION_TEXTURECUBE: + case D3D12_SRV_DIMENSION_TEXTURECUBEARRAY: + { + // Even though it's a texture cube, an individual face's dimensions are + // returned + dim = 2; + + bool isarray = srvDesc.ViewDimension == D3D12_SRV_DIMENSION_TEXTURECUBEARRAY; + + result.value.u32v[0] = RDCMAX(1U, (uint32_t)(resDesc.Width >> mipLevel)); + result.value.u32v[1] = RDCMAX(1U, (uint32_t)(resDesc.Height >> mipLevel)); + + // the spec says "If srcResource is a TextureCubeArray, [...]. dest.z is set + // to an undefined value." + // but that's stupid, and implementations seem to return the number of cubes + result.value.u32v[2] = isarray ? srvDesc.TextureCubeArray.NumCubes : 0; + result.value.u32v[3] = + isarray ? srvDesc.TextureCubeArray.MipLevels : srvDesc.TextureCube.MipLevels; + + if(mipLevel >= result.value.u32v[3]) + result.value.u32v[0] = result.value.u32v[1] = result.value.u32v[2] = 0; + + break; + } + case D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE: + { + RDCERR("Raytracing is unsupported"); + break; } } } @@ -1108,183 +1059,33 @@ bool D3D12DebugAPIWrapper::CalculateSampleGather( { 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_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"); - rdcstr funcRet = ""; - DXGI_FORMAT retFmt = DXGI_FORMAT_UNKNOWN; - - if(opcode == OPCODE_SAMPLE_C || opcode == OPCODE_SAMPLE_C_LZ || opcode == OPCODE_GATHER4_C || - opcode == OPCODE_GATHER4_PO_C || opcode == OPCODE_LOD) - { - retFmt = DXGI_FORMAT_R32G32B32A32_FLOAT; - funcRet = "float4"; - } - - rdcstr samplerDecl = ""; - if(samplerData.mode == SAMPLER_MODE_DEFAULT) - samplerDecl = "SamplerState s"; - else if(samplerData.mode == SAMPLER_MODE_COMPARISON) - samplerDecl = "SamplerComparisonState s"; - - rdcstr textureDecl = ""; - int texdim = 2; - int offsetDim = 2; - bool useOffsets = true; - - if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE1D) - { - textureDecl = "Texture1D"; - texdim = 1; - offsetDim = 1; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2D) - { - textureDecl = "Texture2D"; - texdim = 2; - offsetDim = 2; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMS) - { - textureDecl = "Texture2DMS"; - texdim = 2; - offsetDim = 2; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE3D) - { - textureDecl = "Texture3D"; - texdim = 3; - offsetDim = 3; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBE) - { - textureDecl = "TextureCube"; - texdim = 3; - offsetDim = 3; - useOffsets = false; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE1DARRAY) - { - textureDecl = "Texture1DArray"; - texdim = 2; - offsetDim = 1; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY) - { - textureDecl = "Texture2DArray"; - texdim = 3; - offsetDim = 2; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY) - { - textureDecl = "Texture2DMSArray"; - texdim = 3; - offsetDim = 2; - } - else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBEARRAY) - { - textureDecl = "TextureCubeArray"; - texdim = 4; - offsetDim = 3; - useOffsets = false; - } - else - { - RDCERR("Unsupported resource type %d in sample operation", resourceData.dim); - } - - { - char *typeStr[DXBC::NUM_RETURN_TYPES] = { - "", // enum starts at ==1 - "unorm float", - "snorm float", - "int", - "uint", - "float", - "__", // RETURN_TYPE_MIXED - "double", - "__", // RETURN_TYPE_CONTINUED - "__", // RETURN_TYPE_UNUSED - }; - - // obviously these may be overly optimistic in some cases - // but since we don't know at debug time what the source texture format is - // we just use the fattest one necessary. There's no harm in retrieving at - // higher precision - DXGI_FORMAT fmts[DXBC::NUM_RETURN_TYPES] = { - DXGI_FORMAT_UNKNOWN, // enum starts at ==1 - DXGI_FORMAT_R32G32B32A32_FLOAT, // unorm float - DXGI_FORMAT_R32G32B32A32_FLOAT, // snorm float - DXGI_FORMAT_R32G32B32A32_SINT, // int - DXGI_FORMAT_R32G32B32A32_UINT, // uint - DXGI_FORMAT_R32G32B32A32_FLOAT, // float - DXGI_FORMAT_UNKNOWN, // RETURN_TYPE_MIXED - - // should maybe be double, but there is no double texture format anyway! - // spec is unclear but I presume reads are done at most at float - // precision anyway since that's the source, and converted to doubles. - DXGI_FORMAT_R32G32B32A32_FLOAT, // double - - DXGI_FORMAT_UNKNOWN, // RETURN_TYPE_CONTINUED - DXGI_FORMAT_UNKNOWN, // RETURN_TYPE_UNUSED - }; - - rdcstr type = StringFormat::Fmt("%s4", typeStr[resourceData.retType]); - - if(retFmt == DXGI_FORMAT_UNKNOWN) - { - funcRet = type; - retFmt = fmts[resourceData.retType]; - } - - if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMS || - resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY) - { - if(resourceData.sampleCount > 0) - type += StringFormat::Fmt(", %d", resourceData.sampleCount); - } - - textureDecl += "<" + type + "> t"; - } - - char *formats[4][2] = { - {"float(%.10f)", "int(%d)"}, - {"float2(%.10f, %.10f)", "int2(%d, %d)"}, - {"float3(%.10f, %.10f, %.10f)", "int3(%d, %d, %d)"}, - {"float4(%.10f, %.10f, %.10f, %.10f)", "int4(%d, %d, %d, %d)"}, - }; - - int texcoordType = 0; - int texdimOffs = 0; - - if(opcode == OPCODE_SAMPLE || opcode == OPCODE_SAMPLE_L || opcode == OPCODE_SAMPLE_B || - opcode == OPCODE_SAMPLE_D || opcode == OPCODE_SAMPLE_C || opcode == OPCODE_SAMPLE_C_LZ || - opcode == OPCODE_GATHER4 || opcode == OPCODE_GATHER4_C || opcode == OPCODE_GATHER4_PO || - opcode == OPCODE_GATHER4_PO_C || opcode == OPCODE_LOD) - { - // all floats - texcoordType = 0; - } - else if(opcode == OPCODE_LD) - { - // int address, one larger than texdim (to account for mip/slice parameter) - texdimOffs = 1; - texcoordType = 1; - - if(texdim == 4) - { - RDCERR("Unexpectedly large texture in load operation"); - } - } - else if(opcode == OPCODE_LD_MS) - { - texcoordType = 1; - - if(texdim == 4) - { - RDCERR("Unexpectedly large texture in load operation"); - } - } - for(uint32_t i = 0; i < ddxCalc.columns; i++) { if(!RDCISFINITE(ddxCalc.value.f32v[i])) @@ -1313,7 +1114,7 @@ bool D3D12DebugAPIWrapper::CalculateSampleGather( for(uint32_t i = 0; i < uv.columns; i++) { - if(texcoordType == 0 && (!RDCISFINITE(uv.value.f32v[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; @@ -1326,331 +1127,70 @@ bool D3D12DebugAPIWrapper::CalculateSampleGather( } } - rdcstr texcoords; + DebugSampleOperation cbufferData = {}; - // because of unions in .value we can pass the float versions and printf will interpret it as - // the right type according to formats - if(texcoordType == 0) - texcoords = StringFormat::Fmt(formats[texdim + texdimOffs - 1][texcoordType], uv.value.f32v[0], - uv.value.f32v[1], uv.value.f32v[2], uv.value.f32v[3]); - else - texcoords = StringFormat::Fmt(formats[texdim + texdimOffs - 1][texcoordType], uv.value.s32v[0], - uv.value.s32v[1], uv.value.s32v[2], uv.value.s32v[3]); + 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)); - rdcstr offsets = ""; - - if(useOffsets) + if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE1D || + resourceData.dim == RESOURCE_DIMENSION_TEXTURE1DARRAY) { - if(offsetDim == 1) - offsets = StringFormat::Fmt(", int(%d)", texelOffsets[0]); - else if(offsetDim == 2) - offsets = StringFormat::Fmt(", int2(%d, %d)", texelOffsets[0], texelOffsets[1]); - else if(offsetDim == 3) - offsets = - StringFormat::Fmt(", int3(%d, %d, %d)", texelOffsets[0], texelOffsets[1], texelOffsets[2]); - // texdim == 4 is cube arrays, no offset supported + cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEX1D; } - - char elems[] = "xyzw"; - rdcstr strSwizzle = "."; - for(int i = 0; i < 4; ++i) - strSwizzle += elems[swizzle[i]]; - - rdcstr strGatherChannel; - switch(gatherChannel) + else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2D || + resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY) { - case DXBCDebug::GatherChannel::Red: strGatherChannel = "Red"; break; - case DXBCDebug::GatherChannel::Green: strGatherChannel = "Green"; break; - case DXBCDebug::GatherChannel::Blue: strGatherChannel = "Blue"; break; - case DXBCDebug::GatherChannel::Alpha: strGatherChannel = "Alpha"; break; + cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEX2D; } - - rdcstr uvSnippet = "float4 doUV(uint id) { return 0.0f.xxxx; }\n"; - rdcstr colSnippet = funcRet + " doCol() { return 0.0f.xxxx; }\n"; - rdcstr sampleSnippet; - - rdcstr strResourceBinding = StringFormat::Fmt("t%u, space%u", resourceData.binding.shaderRegister, - resourceData.binding.registerSpace); - rdcstr strSamplerBinding = StringFormat::Fmt("s%u, space%u", samplerData.binding.shaderRegister, - samplerData.binding.registerSpace); - - if(opcode == OPCODE_SAMPLE || opcode == OPCODE_SAMPLE_B || opcode == OPCODE_SAMPLE_D) + else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE3D) { - rdcstr ddx = - StringFormat::Fmt(formats[offsetDim + texdimOffs - 1][0], ddxCalc.value.f32v[0], - ddxCalc.value.f32v[1], ddxCalc.value.f32v[2], ddxCalc.value.f32v[3]); - - rdcstr ddy = - StringFormat::Fmt(formats[offsetDim + texdimOffs - 1][0], ddyCalc.value.f32v[0], - ddyCalc.value.f32v[1], ddyCalc.value.f32v[2], ddyCalc.value.f32v[3]); - - sampleSnippet = StringFormat::Fmt("%s : register(%s);\n%s : register(%s);\n\n", - textureDecl.c_str(), strResourceBinding.c_str(), - samplerDecl.c_str(), strSamplerBinding.c_str()); - sampleSnippet += funcRet + " doSample(float4 uv)\n{\nreturn "; - sampleSnippet += StringFormat::Fmt("t.SampleGrad(s, %s, %s, %s %s)%s;\n", texcoords.c_str(), - ddx.c_str(), ddy.c_str(), offsets.c_str(), strSwizzle.c_str()); - sampleSnippet += "}\n"; + cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEX3D; } - else if(opcode == OPCODE_SAMPLE_L) + else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMS || + resourceData.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY) { - // lod selection - sampleSnippet = StringFormat::Fmt("%s : register(%s);\n%s : register(%s);\n\n", - textureDecl.c_str(), strResourceBinding.c_str(), - samplerDecl.c_str(), strSamplerBinding.c_str()); - sampleSnippet += funcRet + " doSample(float4 uv)\n{\nreturn "; - sampleSnippet += StringFormat::Fmt("t.SampleLevel(s, %s, %.10f %s)%s;\n", texcoords.c_str(), - lodOrCompareValue, offsets.c_str(), strSwizzle.c_str()); - sampleSnippet += "}\n"; + cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEXMS; } - else if(opcode == OPCODE_SAMPLE_C || opcode == OPCODE_LOD) + else if(resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBE || + resourceData.dim == RESOURCE_DIMENSION_TEXTURECUBEARRAY) { - // these operations need derivatives but have no hlsl function to call to provide them, so - // we fake it in the vertex shader - - rdcstr uvswizzle = "xyzw"; - uvswizzle.resize(texdim); - - rdcstr uvPlusDDX = StringFormat::Fmt(formats[texdim + texdimOffs - 1][texcoordType], - uv.value.f32v[0] + ddyCalc.value.f32v[0] * 2.0f, - uv.value.f32v[1] + ddyCalc.value.f32v[1] * 2.0f, - uv.value.f32v[2] + ddyCalc.value.f32v[2] * 2.0f, - uv.value.f32v[3] + ddyCalc.value.f32v[3] * 2.0f); - - rdcstr uvPlusDDY = StringFormat::Fmt(formats[texdim + texdimOffs - 1][texcoordType], - uv.value.f32v[0] + ddxCalc.value.f32v[0] * 2.0f, - uv.value.f32v[1] + ddxCalc.value.f32v[1] * 2.0f, - uv.value.f32v[2] + ddxCalc.value.f32v[2] * 2.0f, - uv.value.f32v[3] + ddxCalc.value.f32v[3] * 2.0f); - - uvSnippet = "float4 uv(uint id) {\n"; - uvSnippet += "if(id == 0) return " + uvPlusDDX + ";\n"; - uvSnippet += "if(id == 1) return " + texcoords + ";\n"; - uvSnippet += " return " + uvPlusDDY + ";\n"; - uvSnippet += "}\n"; - - if(opcode == OPCODE_SAMPLE_C) - { - // comparison value - sampleSnippet = StringFormat::Fmt("%s : register(%s);\n%s : register(%s);\n\n", - textureDecl.c_str(), strResourceBinding.c_str(), - samplerDecl.c_str(), strSamplerBinding.c_str()); - sampleSnippet += funcRet + " doSample(float4 uv)\n{\n"; - sampleSnippet += StringFormat::Fmt("t.SampleCmpLevelZero(s, uv.%s, %.10f %s).xxxx;\n", - uvswizzle.c_str(), lodOrCompareValue, offsets.c_str()); - sampleSnippet += "}\n"; - } - else if(opcode == OPCODE_LOD) - { - sampleSnippet = StringFormat::Fmt("%s : register(%s);\n%s : register(%s);\n\n", - textureDecl.c_str(), strResourceBinding.c_str(), - samplerDecl.c_str(), strSamplerBinding.c_str()); - sampleSnippet += funcRet + " doSample(float4 uv)\n{\n"; - sampleSnippet += StringFormat::Fmt( - "return float4(t.CalculateLevelOfDetail(s, uv.%s),\n" - " t.CalculateLevelOfDetailUnclamped(s, uv.%s),\n" - " 0.0f, 0.0f);\n", - uvswizzle.c_str(), uvswizzle.c_str()); - sampleSnippet += "}\n"; - } - } - else if(opcode == OPCODE_SAMPLE_C_LZ) - { - // comparison value - sampleSnippet = StringFormat::Fmt("%s : register(%s);\n%s : register(%s);\n\n", - textureDecl.c_str(), strResourceBinding.c_str(), - samplerDecl.c_str(), strSamplerBinding.c_str()); - sampleSnippet += funcRet + " doSample(float4 uv)\n{\n"; - sampleSnippet += - StringFormat::Fmt("return t.SampleCmpLevelZero(s, %s, %.10f %s)%s;\n", texcoords.c_str(), - lodOrCompareValue, offsets.c_str(), strSwizzle.c_str()); - sampleSnippet += "}\n"; - } - else if(opcode == OPCODE_LD) - { - sampleSnippet = - StringFormat::Fmt("%s : register(%s);\n\n", textureDecl.c_str(), strResourceBinding.c_str()); - sampleSnippet += funcRet + " doSample(float4 uv)\n{\n"; - sampleSnippet += "return t.Load(" + texcoords + offsets + ")" + strSwizzle + ";"; - sampleSnippet += "\n}\n"; - } - else if(opcode == OPCODE_LD_MS) - { - sampleSnippet = - StringFormat::Fmt("%s : register(%s);\n\n", textureDecl.c_str(), strResourceBinding.c_str()); - sampleSnippet += funcRet + " doSample(float4 uv)\n{\n"; - sampleSnippet += StringFormat::Fmt("return t.Load(%s, int(%d) %s)%s;\n", texcoords.c_str(), - multisampleIndex, offsets.c_str(), strSwizzle.c_str()); - sampleSnippet += "\n}\n"; - } - else if(opcode == OPCODE_GATHER4 || opcode == OPCODE_GATHER4_PO) - { - sampleSnippet = StringFormat::Fmt("%s : register(%s);\n%s : register(%s);\n\n", - textureDecl.c_str(), strResourceBinding.c_str(), - samplerDecl.c_str(), strSamplerBinding.c_str()); - sampleSnippet += funcRet + " doSample(float4 uv)\n{\n"; - sampleSnippet += StringFormat::Fmt("return t.Gather%s(s, %s %s)%s;\n", strGatherChannel.c_str(), - texcoords.c_str(), offsets.c_str(), strSwizzle.c_str()); - sampleSnippet += "}\n"; - } - else if(opcode == OPCODE_GATHER4_C || opcode == OPCODE_GATHER4_PO_C) - { - // comparison value - sampleSnippet = StringFormat::Fmt("%s : register(%s);\n%s : register(%s);\n\n", - textureDecl.c_str(), strResourceBinding.c_str(), - samplerDecl.c_str(), strSamplerBinding.c_str()); - sampleSnippet += funcRet + " doSample(float4 uv)\n{\n"; - sampleSnippet += StringFormat::Fmt("return t.GatherCmp%s(s, %s, %.10f %s)%s;\n", - strGatherChannel.c_str(), texcoords.c_str(), - lodOrCompareValue, offsets.c_str(), strSwizzle.c_str()); - sampleSnippet += "}\n"; - } - - rdcstr evalSnippet; - - // if the sample happens in the vertex shader we need to do that too, otherwise root signature - // visibility may not match - if(GetShaderType() == DXBC::ShaderType::Vertex) - { - // include the sampleSnippet in the vertex shader and return it into the col - colSnippet = sampleSnippet; - // we can pass 0.0f to doSample() because the only doSample()s needing UVs are in the pixel - // shader - colSnippet += funcRet + " doCol() { return doSample(0.0f.xxxx); }\n"; - - // return the passed through col - evalSnippet = funcRet + " evalResult(" + funcRet + " col, float4 uv) { return col; }\n"; + cbufferData.debugSampleTexDim = DEBUG_SAMPLE_TEXCUBE; } else { - if(GetShaderType() != DXBC::ShaderType::Pixel && GetShaderType() != DXBC::ShaderType::Compute) - { - // other stages can't re-use the pixel shader visibility in the root signature, and it's not - // feasible to do the sampling in a fake geometry/tessellation shader. Instead if we intend to - // support other stages we need to stop re-using the root signature and instead patch it to be - // set up how we want for pixel shader sampling. - RDCERR("shader stages other than pixel/compute need special handling."); - } - - // include the sample snippet and forward to doSample - evalSnippet = sampleSnippet; - evalSnippet += - funcRet + " evalResult(" + funcRet + " col, float4 uv) { return doSample(uv); }\n"; + RDCERR("Unsupported resource type %d in sample operation", resourceData.dim); } - rdcstr vsProgram; + 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 + }; - vsProgram += uvSnippet; - vsProgram += colSnippet; - vsProgram += "void main(uint id : SV_VertexID, out float4 pos : SV_Position, out " + funcRet + - " col : COL, out float4 uv : UV) {\n"; - vsProgram += " pos = float4((id == 2) ? 3.0f : -1.0f, (id == 0) ? -3.0f : 1.0f, 0.5, 1.0);\n"; - vsProgram += " uv = doUV(id);\n"; - vsProgram += " col = doCol();\n"; - vsProgram += "}"; + cbufferData.debugSampleRetType = retTypes[resourceData.retType]; - rdcstr psProgram; + cbufferData.debugSampleGatherChannel = (int)gatherChannel; + cbufferData.debugSampleSampleIndex = multisampleIndex; + cbufferData.debugSampleOperation = (int)opcode; + cbufferData.debugSampleLodCompare = lodOrCompareValue; - psProgram += evalSnippet; - psProgram += funcRet + " main(float4 pos : SV_Position, " + funcRet + - " col : COL, float4 uv : UV) : SV_Target0 {\n"; - psProgram += " return evalResult(col, uv);\n"; - psProgram += "}"; - - // Create VS/PS to fetch the sample. Because the program being debugged might be using SM 5.1, we - // need to do that too, to support reusing the existing root signature that may use a non-zero - // register space for the resource or sampler. - ID3DBlob *vsBlob = NULL; - ID3DBlob *psBlob = NULL; - UINT flags = D3DCOMPILE_DEBUG | D3DCOMPILE_WARNINGS_ARE_ERRORS; - if(m_pDevice->GetShaderCache()->GetShaderBlob(vsProgram.c_str(), "main", flags, {}, "vs_5_1", - &vsBlob) != "") - { - RDCERR("Failed to create vertex shader for CalculateSampleGather"); - return false; - } - if(m_pDevice->GetShaderCache()->GetShaderBlob(psProgram.c_str(), "main", flags, {}, "ps_5_1", - &psBlob) != "") - { - RDCERR("Failed to create pixel shader for CalculateSampleGather"); - SAFE_RELEASE(vsBlob); - return false; - } - - // Create a PSO with our VS/PS and all other state from the original event D3D12RenderState &rs = m_pDevice->GetQueue()->GetCommandData()->m_RenderState; D3D12RenderState prevState = rs; - // If we're debugging a compute shader, we should be able to reuse the rootsig for a - // pixel shader, since the entries will have to use shader visibility all - bool isCompute = m_dxbc->m_Type == DXBC::ShaderType::Compute; - ResourceId sigId = isCompute ? rs.compute.rootsig : rs.graphics.rootsig; - WrappedID3D12RootSignature *pRootSig = - m_pDevice->GetResourceManager()->GetCurrentAs(sigId); - - // The root signature may deny access for certain shader types which will cause the - // PSO creation to fail, so ensure that VS/PS are allowed - D3D12RootSignature modsig = pRootSig->sig; - modsig.Flags &= ~(D3D12_ROOT_SIGNATURE_FLAG_DENY_VERTEX_SHADER_ROOT_ACCESS | - D3D12_ROOT_SIGNATURE_FLAG_DENY_PIXEL_SHADER_ROOT_ACCESS); - - ID3DBlob *pModifiedRoot = m_pDevice->GetShaderCache()->MakeRootSig(modsig); - if(!pModifiedRoot) - { - RDCERR("Failed to create root signature for CalculateSampleGather"); - SAFE_RELEASE(vsBlob); - SAFE_RELEASE(psBlob); - return false; - } - ID3D12RootSignature *pModifiedRootSignature = NULL; - HRESULT hr = m_pDevice->CreateRootSignature( - 0, pModifiedRoot->GetBufferPointer(), pModifiedRoot->GetBufferSize(), - __uuidof(ID3D12RootSignature), (void **)&pModifiedRootSignature); - if(FAILED(hr)) - { - RDCERR("Failed to create root signature for CalculateSampleGather HRESULT: %s", - ToStr(hr).c_str()); - SAFE_RELEASE(pModifiedRoot); - SAFE_RELEASE(vsBlob); - SAFE_RELEASE(psBlob); - return false; - } - SAFE_RELEASE(pModifiedRoot); - - D3D12_GRAPHICS_PIPELINE_STATE_DESC pipeDesc; - ZeroMemory(&pipeDesc, sizeof(D3D12_GRAPHICS_PIPELINE_STATE_DESC)); - - pipeDesc.pRootSignature = pModifiedRootSignature; - - pipeDesc.VS.BytecodeLength = vsBlob->GetBufferSize(); - pipeDesc.VS.pShaderBytecode = vsBlob->GetBufferPointer(); - pipeDesc.PS.BytecodeLength = psBlob->GetBufferSize(); - pipeDesc.PS.pShaderBytecode = psBlob->GetBufferPointer(); - - pipeDesc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID; - pipeDesc.RasterizerState.CullMode = D3D12_CULL_MODE_NONE; - pipeDesc.RasterizerState.FrontCounterClockwise = TRUE; - pipeDesc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL; - - pipeDesc.SampleMask = UINT_MAX; - pipeDesc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; - pipeDesc.NumRenderTargets = 1; - pipeDesc.RTVFormats[0] = retFmt; - pipeDesc.SampleDesc.Count = 1; - - ID3D12PipelineState *samplePso = NULL; - hr = m_pDevice->CreateGraphicsPipelineState(&pipeDesc, __uuidof(ID3D12PipelineState), - (void **)&samplePso); - SAFE_RELEASE(vsBlob); - SAFE_RELEASE(psBlob); - if(FAILED(hr)) - { - RDCERR("Failed to create PSO for shader debugging HRESULT: %s", ToStr(hr).c_str()); - return false; - } + ID3D12RootSignature *sig = m_pDevice->GetDebugManager()->GetShaderDebugRootSig(); + ID3D12PipelineState *pso = m_pDevice->GetDebugManager()->GetTexSamplePso(texelOffsets); ID3D12GraphicsCommandListX *cmdList = m_pDevice->GetDebugManager()->ResetDebugList(); - rs.pipe = GetResID(samplePso); + 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 @@ -1659,57 +1199,69 @@ bool D3D12DebugAPIWrapper::CalculateSampleGather( rs.scissors.clear(); rs.scissors.push_back({0, 0, 1, 1}); - // Set our modified root signature, and transfer sigelems if we're debugging a compute shader - rs.graphics.rootsig = GetResID(pModifiedRootSignature); - rs.graphics.sigelems = isCompute ? rs.compute.sigelems : rs.graphics.sigelems; - rs.compute.rootsig = ResourceId(); + 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); - // Create a 1x1 texture to store the sample result - D3D12_RESOURCE_DESC rdesc; - ZeroMemory(&rdesc, sizeof(D3D12_RESOURCE_DESC)); - rdesc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; - rdesc.Width = 1; - rdesc.Height = 1; - rdesc.DepthOrArraySize = 1; - rdesc.MipLevels = 0; - rdesc.Format = retFmt; - rdesc.Flags = D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET; - rdesc.SampleDesc.Count = 1; - rdesc.SampleDesc.Quality = 0; - - D3D12_HEAP_PROPERTIES heapProps; - heapProps.Type = D3D12_HEAP_TYPE_DEFAULT; - heapProps.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; - heapProps.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; - heapProps.CreationNodeMask = 1; - heapProps.VisibleNodeMask = 1; - - ID3D12Resource *pSampleResult = NULL; - D3D12_RESOURCE_STATES resourceState = D3D12_RESOURCE_STATE_RENDER_TARGET; - hr = m_pDevice->CreateCommittedResource(&heapProps, D3D12_HEAP_FLAG_NONE, &rdesc, resourceState, - NULL, __uuidof(ID3D12Resource), (void **)&pSampleResult); - if(FAILED(hr)) - { - RDCERR("Failed to create texture for shader debugging HRESULT: %s", ToStr(hr).c_str()); - SAFE_RELEASE(samplePso); - return false; - } - - D3D12_CPU_DESCRIPTOR_HANDLE rtv = m_pDevice->GetDebugManager()->GetCPUHandle(SHADER_DEBUG_RTV); - m_pDevice->CreateRenderTargetView(pSampleResult, NULL, rtv); + D3D12_CPU_DESCRIPTOR_HANDLE rtv = m_pDevice->GetDebugManager()->GetCPUHandle(PICK_PIXEL_RTV); cmdList->OMSetRenderTargets(1, &rtv, FALSE, NULL); cmdList->DrawInstanced(3, 1, 0, 0); - hr = cmdList->Close(); + 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()); - SAFE_RELEASE(samplePso); - SAFE_RELEASE(pSampleResult); return false; } @@ -1721,17 +1273,44 @@ bool D3D12DebugAPIWrapper::CalculateSampleGather( rs = prevState; - bytebuf sampleResult; - m_pDevice->GetReplay()->GetTextureData(GetResID(pSampleResult), Subresource(), - GetTextureDataParams(), sampleResult); + 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); - memcpy(lookupResult.value.u32v.data(), sampleResult.data(), - RDCMIN(sampleResult.size(), sizeof(uint32_t) * 4)); - output = lookupResult; - SAFE_RELEASE(samplePso); - SAFE_RELEASE(pSampleResult); + float *retFloats = (float *)results; + uint32_t *retUInts = (uint32_t *)(retFloats + 16); + int32_t *retSInts = (int32_t *)(retUInts + 16); + + 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; } diff --git a/renderdoc/driver/d3d12/d3d12_state.cpp b/renderdoc/driver/d3d12/d3d12_state.cpp index 304d8c1b4..a7cd212f5 100644 --- a/renderdoc/driver/d3d12/d3d12_state.cpp +++ b/renderdoc/driver/d3d12/d3d12_state.cpp @@ -28,6 +28,22 @@ #include "d3d12_manager.h" #include "d3d12_resources.h" +D3D12RenderState::SignatureElement::SignatureElement(SignatureElementType t, + D3D12_GPU_VIRTUAL_ADDRESS addr) +{ + type = t; + WrappedID3D12Resource::GetResIDFromAddr(addr, id, offset); +} + +D3D12RenderState::SignatureElement::SignatureElement(SignatureElementType t, + D3D12_CPU_DESCRIPTOR_HANDLE handle) +{ + type = t; + D3D12Descriptor *desc = (D3D12Descriptor *)handle.ptr; + id = desc->GetHeap()->GetResourceID(); + offset = desc->GetHeapIndex(); +} + rdcarray D3D12RenderState::GetRTVIDs() const { rdcarray ret; diff --git a/renderdoc/driver/d3d12/d3d12_state.h b/renderdoc/driver/d3d12/d3d12_state.h index 10c3b36a1..2dda699cf 100644 --- a/renderdoc/driver/d3d12/d3d12_state.h +++ b/renderdoc/driver/d3d12/d3d12_state.h @@ -76,6 +76,9 @@ struct D3D12RenderState { SignatureElement() : type(eRootUnknown), offset(0) {} SignatureElement(SignatureElementType t, ResourceId i, UINT64 o) : type(t), id(i), offset(o) {} + SignatureElement(SignatureElementType t, D3D12_GPU_VIRTUAL_ADDRESS addr); + SignatureElement(SignatureElementType t, D3D12_CPU_DESCRIPTOR_HANDLE handle); + void SetConstant(UINT offs, UINT val) { SetConstants(1, &val, offs); } void SetConstants(UINT numVals, const void *vals, UINT offs) { diff --git a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp index af2d5a43a..14ea3d867 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_debug.cpp @@ -1381,7 +1381,7 @@ ShaderVariable ThreadState::DDY(bool fine, const rdcarray &quad, ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, bool allowFlushing) const { - ShaderVariable v, s; + ShaderVariable v; uint32_t indices[4] = {0}; @@ -1422,21 +1422,21 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo variables[idx].members.size()); if(oper.indices.size() == 2 && indices[1] < variables[idx].members.size()) { - v = s = variables[idx].members[indices[1]]; + v = variables[idx].members[indices[1]]; } else { - v = s = ShaderVariable("", indices[0], indices[0], indices[0], indices[0]); + v = ShaderVariable(rdcstr(), indices[0], indices[0], indices[0], indices[0]); } } else { - v = s = variables[idx]; + v = variables[idx]; } } else { - v = s = ShaderVariable("", indices[0], indices[0], indices[0], indices[0]); + v = ShaderVariable(rdcstr(), indices[0], indices[0], indices[0], indices[0]); } break; @@ -1446,9 +1446,9 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo RDCASSERT(indices[0] < (uint32_t)inputs.size()); if(indices[0] < (uint32_t)inputs.size()) - v = s = inputs[indices[0]]; + v = inputs[indices[0]]; else - v = s = ShaderVariable("", indices[0], indices[0], indices[0], indices[0]); + v = ShaderVariable(rdcstr(), indices[0], indices[0], indices[0], indices[0]); break; } @@ -1469,26 +1469,26 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo // resource arrays, indices[0] will contain the logical identifier, and // indices[1] will contain the shader register correlating to the resource // array index requested (in absolute terms, not relative to the start register) - v = s = ShaderVariable("", indices[0], indices[1], indices[2], indices[3]); + v = ShaderVariable(rdcstr(), indices[0], indices[1], indices[2], indices[3]); flushable = false; break; } case TYPE_IMMEDIATE32: case TYPE_IMMEDIATE64: { - s.name = "Immediate"; + v.name = "Immediate"; flushable = false; if(oper.numComponents == NUMCOMPS_1) { - s.rows = 1; - s.columns = 1; + v.rows = 1; + v.columns = 1; } else if(oper.numComponents == NUMCOMPS_4) { - s.rows = 1; - s.columns = 4; + v.rows = 1; + v.columns = 4; } else { @@ -1497,9 +1497,9 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo if(oper.type == TYPE_IMMEDIATE32) { - for(size_t i = 0; i < s.columns; i++) + for(size_t i = 0; i < v.columns; i++) { - s.value.s32v[i] = (int32_t)oper.values[i]; + v.value.s32v[i] = (int32_t)oper.values[i]; } } else @@ -1508,8 +1508,6 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo "Encountered immediate 64bit value!"); // need to figure out what to do here. } - v = s; - break; } case TYPE_CONSTANT_BUFFER: @@ -1552,25 +1550,25 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo cbLookup, targetVars.count()); if(cbLookup < (uint32_t)targetVars.count()) - v = s = targetVars[cbLookup]; + v = targetVars[cbLookup]; else - v = s = ShaderVariable("", 0U, 0U, 0U, 0U); + v = ShaderVariable(rdcstr(), 0U, 0U, 0U, 0U); } else { - v = s = ShaderVariable("", 0U, 0U, 0U, 0U); + v = ShaderVariable(rdcstr(), 0U, 0U, 0U, 0U); } } else { - v = s = ShaderVariable("", 0U, 0U, 0U, 0U); + v = ShaderVariable(rdcstr(), 0U, 0U, 0U, 0U); } break; } case TYPE_IMMEDIATE_CONSTANT_BUFFER: { - v = s = ShaderVariable("", 0, 0, 0, 0); + v = ShaderVariable(rdcstr(), 0, 0, 0, 0); const rdcarray &icb = program->GetImmediateConstantBuffer(); @@ -1578,7 +1576,7 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo if(indices[0] <= icb.size() / 4 - 1) { for(size_t i = 0; i < 4; i++) - s.value.u32v[i] = icb[indices[0] * 4 + i]; + v.value.u32v[i] = icb[indices[0] * 4 + i]; } else { @@ -1593,8 +1591,8 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo } case TYPE_INPUT_THREAD_GROUP_ID: { - v = s = ShaderVariable("vThreadGroupID", semantics.GroupID[0], semantics.GroupID[1], - semantics.GroupID[2], (uint32_t)0); + v = ShaderVariable("vThreadGroupID", semantics.GroupID[0], semantics.GroupID[1], + semantics.GroupID[2], (uint32_t)0); break; } @@ -1619,8 +1617,7 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo RDCASSERT(numthreads[2] >= 1 && numthreads[2] <= 64); RDCASSERT(numthreads[0] * numthreads[1] * numthreads[2] <= 1024); - v = s = - ShaderVariable("vThreadID", semantics.GroupID[0] * numthreads[0] + semantics.ThreadID[0], + v = ShaderVariable("vThreadID", semantics.GroupID[0] * numthreads[0] + semantics.ThreadID[0], semantics.GroupID[1] * numthreads[1] + semantics.ThreadID[1], semantics.GroupID[2] * numthreads[2] + semantics.ThreadID[2], (uint32_t)0); @@ -1628,8 +1625,8 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo } case TYPE_INPUT_THREAD_ID_IN_GROUP: { - v = s = ShaderVariable("vThreadIDInGroup", semantics.ThreadID[0], semantics.ThreadID[1], - semantics.ThreadID[2], (uint32_t)0); + v = ShaderVariable("vThreadIDInGroup", semantics.ThreadID[0], semantics.ThreadID[1], + semantics.ThreadID[2], (uint32_t)0); break; } @@ -1657,26 +1654,26 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo uint32_t flattened = semantics.ThreadID[2] * numthreads[0] * numthreads[1] + semantics.ThreadID[1] * numthreads[0] + semantics.ThreadID[0]; - v = s = ShaderVariable("vThreadIDInGroupFlattened", flattened, flattened, flattened, flattened); + v = ShaderVariable("vThreadIDInGroupFlattened", flattened, flattened, flattened, flattened); break; } case TYPE_INPUT_COVERAGE_MASK: { - v = s = ShaderVariable("vCoverage", semantics.coverage, semantics.coverage, - semantics.coverage, semantics.coverage); + v = ShaderVariable("vCoverage", semantics.coverage, semantics.coverage, semantics.coverage, + semantics.coverage); break; } case TYPE_INPUT_PRIMITIVEID: { - v = s = ShaderVariable("vPrimitiveID", semantics.primID, semantics.primID, semantics.primID, - semantics.primID); + v = ShaderVariable("vPrimitiveID", semantics.primID, semantics.primID, semantics.primID, + semantics.primID); break; } default: { RDCERR("Currently unsupported operand type %d!", oper.type); - v = s = ShaderVariable("vUnsupported", (uint32_t)0, (uint32_t)0, (uint32_t)0, (uint32_t)0); + v = ShaderVariable("vUnsupported", (uint32_t)0, (uint32_t)0, (uint32_t)0, (uint32_t)0); break; } @@ -1684,11 +1681,13 @@ ShaderVariable ThreadState::GetSrc(const Operand &oper, const Operation &op, boo if(OperandSwizzle(op, oper)) { + ShaderValue s = v.value; + // perform swizzling - v.value.u32v[0] = s.value.u32v[oper.comps[0] == 0xff ? 0 : oper.comps[0]]; - v.value.u32v[1] = s.value.u32v[oper.comps[1] == 0xff ? 1 : oper.comps[1]]; - v.value.u32v[2] = s.value.u32v[oper.comps[2] == 0xff ? 2 : oper.comps[2]]; - v.value.u32v[3] = s.value.u32v[oper.comps[3] == 0xff ? 3 : oper.comps[3]]; + v.value.u32v[0] = s.u32v[oper.comps[0] == 0xff ? 0 : oper.comps[0]]; + v.value.u32v[1] = s.u32v[oper.comps[1] == 0xff ? 1 : oper.comps[1]]; + v.value.u32v[2] = s.u32v[oper.comps[2] == 0xff ? 2 : oper.comps[2]]; + v.value.u32v[3] = s.u32v[oper.comps[3] == 0xff ? 3 : oper.comps[3]]; if(oper.comps[0] != 0xff && oper.comps[1] == 0xff && oper.comps[2] == 0xff && oper.comps[3] == 0xff) @@ -2152,12 +2151,12 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, for(int i = 0; i < 4; i++) dst[i] = (uint32_t)(src[i] & 0xffffffff); - SetDst(state, op.operands[0], op, ShaderVariable("", dst[0], dst[1], dst[2], dst[3])); + SetDst(state, op.operands[0], op, ShaderVariable(rdcstr(), dst[0], dst[1], dst[2], dst[3])); // if not null, set the carry bits if(op.operands[1].type != TYPE_NULL) SetDst(state, op.operands[1], op, - ShaderVariable("", src[0] > 0xffffffff ? 1U : 0U, src[1] > 0xffffffff ? 1U : 0U, + ShaderVariable(rdcstr(), src[0] > 0xffffffff ? 1U : 0U, src[1] > 0xffffffff ? 1U : 0U, src[2] > 0xffffffff ? 1U : 0U, src[3] > 0xffffffff ? 1U : 0U)); break; @@ -2182,14 +2181,14 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, for(int i = 0; i < 4; i++) dst[i] = (uint32_t)(result[0] & 0xffffffff); - SetDst(state, op.operands[0], op, ShaderVariable("", dst[0], dst[1], dst[2], dst[3])); + SetDst(state, op.operands[0], op, ShaderVariable(rdcstr(), dst[0], dst[1], dst[2], dst[3])); // if not null, mark where the borrow bits were used if(op.operands[1].type != TYPE_NULL) - SetDst( - state, op.operands[1], op, - ShaderVariable("", result[0] <= 0xffffffff ? 1U : 0U, result[1] <= 0xffffffff ? 1U : 0U, - result[2] <= 0xffffffff ? 1U : 0U, result[3] <= 0xffffffff ? 1U : 0U)); + SetDst(state, op.operands[1], op, + ShaderVariable(rdcstr(), result[0] <= 0xffffffff ? 1U : 0U, + result[1] <= 0xffffffff ? 1U : 0U, result[2] <= 0xffffffff ? 1U : 0U, + result[3] <= 0xffffffff ? 1U : 0U)); break; } @@ -2213,13 +2212,14 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, if(op.operation >= OPCODE_DP4) sum += dot.value.f32v[3]; - SetDst(state, op.operands[0], op, ShaderVariable("", sum, sum, sum, sum)); + SetDst(state, op.operands[0], op, ShaderVariable(rdcstr(), sum, sum, sum, sum)); break; } case OPCODE_F16TOF32: { SetDst(state, op.operands[0], op, - ShaderVariable("", flush_denorm(ConvertFromHalf(srcOpers[0].value.u32v[0] & 0xffff)), + ShaderVariable(rdcstr(), + flush_denorm(ConvertFromHalf(srcOpers[0].value.u32v[0] & 0xffff)), flush_denorm(ConvertFromHalf(srcOpers[0].value.u32v[1] & 0xffff)), flush_denorm(ConvertFromHalf(srcOpers[0].value.u32v[2] & 0xffff)), flush_denorm(ConvertFromHalf(srcOpers[0].value.u32v[3] & 0xffff)))); @@ -2227,16 +2227,17 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, } case OPCODE_F32TOF16: { - SetDst(state, op.operands[0], op, - ShaderVariable("", (uint32_t)ConvertToHalf(flush_denorm(srcOpers[0].value.f32v[0])), - (uint32_t)ConvertToHalf(flush_denorm(srcOpers[0].value.f32v[1])), - (uint32_t)ConvertToHalf(flush_denorm(srcOpers[0].value.f32v[2])), - (uint32_t)ConvertToHalf(flush_denorm(srcOpers[0].value.f32v[3])))); + SetDst( + state, op.operands[0], op, + ShaderVariable(rdcstr(), (uint32_t)ConvertToHalf(flush_denorm(srcOpers[0].value.f32v[0])), + (uint32_t)ConvertToHalf(flush_denorm(srcOpers[0].value.f32v[1])), + (uint32_t)ConvertToHalf(flush_denorm(srcOpers[0].value.f32v[2])), + (uint32_t)ConvertToHalf(flush_denorm(srcOpers[0].value.f32v[3])))); break; } case OPCODE_FRC: SetDst(state, op.operands[0], op, - ShaderVariable("", srcOpers[0].value.f32v[0] - floorf(srcOpers[0].value.f32v[0]), + ShaderVariable(rdcstr(), srcOpers[0].value.f32v[0] - floorf(srcOpers[0].value.f32v[0]), srcOpers[0].value.f32v[1] - floorf(srcOpers[0].value.f32v[1]), srcOpers[0].value.f32v[2] - floorf(srcOpers[0].value.f32v[2]), srcOpers[0].value.f32v[3] - floorf(srcOpers[0].value.f32v[3]))); @@ -2244,20 +2245,23 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, // positive infinity case OPCODE_ROUND_PI: SetDst(state, op.operands[0], op, - ShaderVariable("", ceilf(srcOpers[0].value.f32v[0]), ceilf(srcOpers[0].value.f32v[1]), - ceilf(srcOpers[0].value.f32v[2]), ceilf(srcOpers[0].value.f32v[3]))); + ShaderVariable(rdcstr(), ceilf(srcOpers[0].value.f32v[0]), + ceilf(srcOpers[0].value.f32v[1]), ceilf(srcOpers[0].value.f32v[2]), + ceilf(srcOpers[0].value.f32v[3]))); break; // negative infinity case OPCODE_ROUND_NI: SetDst(state, op.operands[0], op, - ShaderVariable("", floorf(srcOpers[0].value.f32v[0]), floorf(srcOpers[0].value.f32v[1]), - floorf(srcOpers[0].value.f32v[2]), floorf(srcOpers[0].value.f32v[3]))); + ShaderVariable(rdcstr(), floorf(srcOpers[0].value.f32v[0]), + floorf(srcOpers[0].value.f32v[1]), floorf(srcOpers[0].value.f32v[2]), + floorf(srcOpers[0].value.f32v[3]))); break; // towards zero case OPCODE_ROUND_Z: SetDst(state, op.operands[0], op, - ShaderVariable("", srcOpers[0].value.f32v[0] < 0 ? ceilf(srcOpers[0].value.f32v[0]) - : floorf(srcOpers[0].value.f32v[0]), + ShaderVariable(rdcstr(), + srcOpers[0].value.f32v[0] < 0 ? ceilf(srcOpers[0].value.f32v[0]) + : floorf(srcOpers[0].value.f32v[0]), srcOpers[0].value.f32v[1] < 0 ? ceilf(srcOpers[0].value.f32v[1]) : floorf(srcOpers[0].value.f32v[1]), srcOpers[0].value.f32v[2] < 0 ? ceilf(srcOpers[0].value.f32v[2]) @@ -2267,10 +2271,10 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, break; // to nearest even int (banker's rounding) case OPCODE_ROUND_NE: - SetDst(state, op.operands[0], op, ShaderVariable("", round_ne(srcOpers[0].value.f32v[0]), - round_ne(srcOpers[0].value.f32v[1]), - round_ne(srcOpers[0].value.f32v[2]), - round_ne(srcOpers[0].value.f32v[3]))); + SetDst(state, op.operands[0], op, + ShaderVariable(rdcstr(), round_ne(srcOpers[0].value.f32v[0]), + round_ne(srcOpers[0].value.f32v[1]), round_ne(srcOpers[0].value.f32v[2]), + round_ne(srcOpers[0].value.f32v[3]))); break; case OPCODE_INEG: SetDst(state, op.operands[0], op, neg(srcOpers[0], optype)); break; case OPCODE_IMIN: @@ -2317,7 +2321,7 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, } case OPCODE_MIN: SetDst(state, op.operands[0], op, - ShaderVariable("", dxbc_min(srcOpers[0].value.f32v[0], srcOpers[1].value.f32v[0]), + ShaderVariable(rdcstr(), dxbc_min(srcOpers[0].value.f32v[0], srcOpers[1].value.f32v[0]), dxbc_min(srcOpers[0].value.f32v[1], srcOpers[1].value.f32v[1]), dxbc_min(srcOpers[0].value.f32v[2], srcOpers[1].value.f32v[2]), dxbc_min(srcOpers[0].value.f32v[3], srcOpers[1].value.f32v[3]))); @@ -2366,15 +2370,16 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, } case OPCODE_MAX: SetDst(state, op.operands[0], op, - ShaderVariable("", dxbc_max(srcOpers[0].value.f32v[0], srcOpers[1].value.f32v[0]), + ShaderVariable(rdcstr(), dxbc_max(srcOpers[0].value.f32v[0], srcOpers[1].value.f32v[0]), dxbc_max(srcOpers[0].value.f32v[1], srcOpers[1].value.f32v[1]), dxbc_max(srcOpers[0].value.f32v[2], srcOpers[1].value.f32v[2]), dxbc_max(srcOpers[0].value.f32v[3], srcOpers[1].value.f32v[3]))); break; case OPCODE_SQRT: SetDst(state, op.operands[0], op, - ShaderVariable("", sqrtf(srcOpers[0].value.f32v[0]), sqrtf(srcOpers[0].value.f32v[1]), - sqrtf(srcOpers[0].value.f32v[2]), sqrtf(srcOpers[0].value.f32v[3]))); + ShaderVariable(rdcstr(), sqrtf(srcOpers[0].value.f32v[0]), + sqrtf(srcOpers[0].value.f32v[1]), sqrtf(srcOpers[0].value.f32v[2]), + sqrtf(srcOpers[0].value.f32v[3]))); break; case OPCODE_DRCP: { @@ -2499,10 +2504,11 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, (op.operands[2].comps[2] < 4 && op.operands[2].comps[2] == 0xff)) shifts[3] = shifts[2] = shifts[1] = shifts[0]; - SetDst(state, op.operands[0], op, ShaderVariable("", srcOpers[0].value.s32v[0] << shifts[0], - srcOpers[0].value.s32v[1] << shifts[1], - srcOpers[0].value.s32v[2] << shifts[2], - srcOpers[0].value.s32v[3] << shifts[3])); + SetDst(state, op.operands[0], op, + ShaderVariable(rdcstr(), srcOpers[0].value.s32v[0] << shifts[0], + srcOpers[0].value.s32v[1] << shifts[1], + srcOpers[0].value.s32v[2] << shifts[2], + srcOpers[0].value.s32v[3] << shifts[3])); break; } case OPCODE_USHR: @@ -2518,10 +2524,11 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, (op.operands[2].comps[2] < 4 && op.operands[2].comps[2] == 0xff)) shifts[3] = shifts[2] = shifts[1] = shifts[0]; - SetDst(state, op.operands[0], op, ShaderVariable("", srcOpers[0].value.u32v[0] >> shifts[0], - srcOpers[0].value.u32v[1] >> shifts[1], - srcOpers[0].value.u32v[2] >> shifts[2], - srcOpers[0].value.u32v[3] >> shifts[3])); + SetDst(state, op.operands[0], op, + ShaderVariable(rdcstr(), srcOpers[0].value.u32v[0] >> shifts[0], + srcOpers[0].value.u32v[1] >> shifts[1], + srcOpers[0].value.u32v[2] >> shifts[2], + srcOpers[0].value.u32v[3] >> shifts[3])); break; } case OPCODE_ISHR: @@ -2537,36 +2544,37 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, (op.operands[2].comps[2] < 4 && op.operands[2].comps[2] == 0xff)) shifts[3] = shifts[2] = shifts[1] = shifts[0]; - SetDst(state, op.operands[0], op, ShaderVariable("", srcOpers[0].value.s32v[0] >> shifts[0], - srcOpers[0].value.s32v[1] >> shifts[1], - srcOpers[0].value.s32v[2] >> shifts[2], - srcOpers[0].value.s32v[3] >> shifts[3])); + SetDst(state, op.operands[0], op, + ShaderVariable(rdcstr(), srcOpers[0].value.s32v[0] >> shifts[0], + srcOpers[0].value.s32v[1] >> shifts[1], + srcOpers[0].value.s32v[2] >> shifts[2], + srcOpers[0].value.s32v[3] >> shifts[3])); break; } case OPCODE_AND: SetDst(state, op.operands[0], op, - ShaderVariable("", srcOpers[0].value.s32v[0] & srcOpers[1].value.s32v[0], + ShaderVariable(rdcstr(), srcOpers[0].value.s32v[0] & srcOpers[1].value.s32v[0], srcOpers[0].value.s32v[1] & srcOpers[1].value.s32v[1], srcOpers[0].value.s32v[2] & srcOpers[1].value.s32v[2], srcOpers[0].value.s32v[3] & srcOpers[1].value.s32v[3])); break; case OPCODE_OR: SetDst(state, op.operands[0], op, - ShaderVariable("", srcOpers[0].value.s32v[0] | srcOpers[1].value.s32v[0], + ShaderVariable(rdcstr(), srcOpers[0].value.s32v[0] | srcOpers[1].value.s32v[0], srcOpers[0].value.s32v[1] | srcOpers[1].value.s32v[1], srcOpers[0].value.s32v[2] | srcOpers[1].value.s32v[2], srcOpers[0].value.s32v[3] | srcOpers[1].value.s32v[3])); break; case OPCODE_XOR: SetDst(state, op.operands[0], op, - ShaderVariable("", srcOpers[0].value.u32v[0] ^ srcOpers[1].value.u32v[0], + ShaderVariable(rdcstr(), srcOpers[0].value.u32v[0] ^ srcOpers[1].value.u32v[0], srcOpers[0].value.u32v[1] ^ srcOpers[1].value.u32v[1], srcOpers[0].value.u32v[2] ^ srcOpers[1].value.u32v[2], srcOpers[0].value.u32v[3] ^ srcOpers[1].value.u32v[3])); break; case OPCODE_NOT: SetDst(state, op.operands[0], op, - ShaderVariable("", ~srcOpers[0].value.u32v[0], ~srcOpers[0].value.u32v[1], + ShaderVariable(rdcstr(), ~srcOpers[0].value.u32v[0], ~srcOpers[0].value.u32v[1], ~srcOpers[0].value.u32v[2], ~srcOpers[0].value.u32v[3])); break; @@ -2658,24 +2666,26 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, break; case OPCODE_ITOF: SetDst(state, op.operands[0], op, - ShaderVariable("", (float)srcOpers[0].value.s32v[0], (float)srcOpers[0].value.s32v[1], - (float)srcOpers[0].value.s32v[2], (float)srcOpers[0].value.s32v[3])); + ShaderVariable(rdcstr(), (float)srcOpers[0].value.s32v[0], + (float)srcOpers[0].value.s32v[1], (float)srcOpers[0].value.s32v[2], + (float)srcOpers[0].value.s32v[3])); break; case OPCODE_UTOF: SetDst(state, op.operands[0], op, - ShaderVariable("", (float)srcOpers[0].value.u32v[0], (float)srcOpers[0].value.u32v[1], - (float)srcOpers[0].value.u32v[2], (float)srcOpers[0].value.u32v[3])); + ShaderVariable(rdcstr(), (float)srcOpers[0].value.u32v[0], + (float)srcOpers[0].value.u32v[1], (float)srcOpers[0].value.u32v[2], + (float)srcOpers[0].value.u32v[3])); break; case OPCODE_FTOI: SetDst(state, op.operands[0], op, - ShaderVariable("", (int)srcOpers[0].value.f32v[0], (int)srcOpers[0].value.f32v[1], + ShaderVariable(rdcstr(), (int)srcOpers[0].value.f32v[0], (int)srcOpers[0].value.f32v[1], (int)srcOpers[0].value.f32v[2], (int)srcOpers[0].value.f32v[3])); break; case OPCODE_FTOU: - SetDst(state, op.operands[0], op, ShaderVariable("", (uint32_t)srcOpers[0].value.f32v[0], - (uint32_t)srcOpers[0].value.f32v[1], - (uint32_t)srcOpers[0].value.f32v[2], - (uint32_t)srcOpers[0].value.f32v[3])); + SetDst(state, op.operands[0], op, + ShaderVariable(rdcstr(), (uint32_t)srcOpers[0].value.f32v[0], + (uint32_t)srcOpers[0].value.f32v[1], (uint32_t)srcOpers[0].value.f32v[2], + (uint32_t)srcOpers[0].value.f32v[3])); break; case OPCODE_ITOD: case OPCODE_UTOD: @@ -2770,28 +2780,32 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, case OPCODE_EQ: SetDst(state, op.operands[0], op, - ShaderVariable("", (srcOpers[0].value.f32v[0] == srcOpers[1].value.f32v[0] ? ~0u : 0u), + ShaderVariable(rdcstr(), + (srcOpers[0].value.f32v[0] == srcOpers[1].value.f32v[0] ? ~0u : 0u), (srcOpers[0].value.f32v[1] == srcOpers[1].value.f32v[1] ? ~0u : 0u), (srcOpers[0].value.f32v[2] == srcOpers[1].value.f32v[2] ? ~0u : 0u), (srcOpers[0].value.f32v[3] == srcOpers[1].value.f32v[3] ? ~0u : 0u))); break; case OPCODE_NE: SetDst(state, op.operands[0], op, - ShaderVariable("", (srcOpers[0].value.f32v[0] != srcOpers[1].value.f32v[0] ? ~0u : 0u), + ShaderVariable(rdcstr(), + (srcOpers[0].value.f32v[0] != srcOpers[1].value.f32v[0] ? ~0u : 0u), (srcOpers[0].value.f32v[1] != srcOpers[1].value.f32v[1] ? ~0u : 0u), (srcOpers[0].value.f32v[2] != srcOpers[1].value.f32v[2] ? ~0u : 0u), (srcOpers[0].value.f32v[3] != srcOpers[1].value.f32v[3] ? ~0u : 0u))); break; case OPCODE_LT: SetDst(state, op.operands[0], op, - ShaderVariable("", (srcOpers[0].value.f32v[0] < srcOpers[1].value.f32v[0] ? ~0u : 0u), + ShaderVariable(rdcstr(), + (srcOpers[0].value.f32v[0] < srcOpers[1].value.f32v[0] ? ~0u : 0u), (srcOpers[0].value.f32v[1] < srcOpers[1].value.f32v[1] ? ~0u : 0u), (srcOpers[0].value.f32v[2] < srcOpers[1].value.f32v[2] ? ~0u : 0u), (srcOpers[0].value.f32v[3] < srcOpers[1].value.f32v[3] ? ~0u : 0u))); break; case OPCODE_GE: SetDst(state, op.operands[0], op, - ShaderVariable("", (srcOpers[0].value.f32v[0] >= srcOpers[1].value.f32v[0] ? ~0u : 0u), + ShaderVariable(rdcstr(), + (srcOpers[0].value.f32v[0] >= srcOpers[1].value.f32v[0] ? ~0u : 0u), (srcOpers[0].value.f32v[1] >= srcOpers[1].value.f32v[1] ? ~0u : 0u), (srcOpers[0].value.f32v[2] >= srcOpers[1].value.f32v[2] ? ~0u : 0u), (srcOpers[0].value.f32v[3] >= srcOpers[1].value.f32v[3] ? ~0u : 0u))); @@ -2851,42 +2865,48 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, } case OPCODE_IEQ: SetDst(state, op.operands[0], op, - ShaderVariable("", (srcOpers[0].value.s32v[0] == srcOpers[1].value.s32v[0] ? ~0u : 0u), + ShaderVariable(rdcstr(), + (srcOpers[0].value.s32v[0] == srcOpers[1].value.s32v[0] ? ~0u : 0u), (srcOpers[0].value.s32v[1] == srcOpers[1].value.s32v[1] ? ~0u : 0u), (srcOpers[0].value.s32v[2] == srcOpers[1].value.s32v[2] ? ~0u : 0u), (srcOpers[0].value.s32v[3] == srcOpers[1].value.s32v[3] ? ~0u : 0u))); break; case OPCODE_INE: SetDst(state, op.operands[0], op, - ShaderVariable("", (srcOpers[0].value.s32v[0] != srcOpers[1].value.s32v[0] ? ~0u : 0u), + ShaderVariable(rdcstr(), + (srcOpers[0].value.s32v[0] != srcOpers[1].value.s32v[0] ? ~0u : 0u), (srcOpers[0].value.s32v[1] != srcOpers[1].value.s32v[1] ? ~0u : 0u), (srcOpers[0].value.s32v[2] != srcOpers[1].value.s32v[2] ? ~0u : 0u), (srcOpers[0].value.s32v[3] != srcOpers[1].value.s32v[3] ? ~0u : 0u))); break; case OPCODE_IGE: SetDst(state, op.operands[0], op, - ShaderVariable("", (srcOpers[0].value.s32v[0] >= srcOpers[1].value.s32v[0] ? ~0u : 0u), + ShaderVariable(rdcstr(), + (srcOpers[0].value.s32v[0] >= srcOpers[1].value.s32v[0] ? ~0u : 0u), (srcOpers[0].value.s32v[1] >= srcOpers[1].value.s32v[1] ? ~0u : 0u), (srcOpers[0].value.s32v[2] >= srcOpers[1].value.s32v[2] ? ~0u : 0u), (srcOpers[0].value.s32v[3] >= srcOpers[1].value.s32v[3] ? ~0u : 0u))); break; case OPCODE_ILT: SetDst(state, op.operands[0], op, - ShaderVariable("", (srcOpers[0].value.s32v[0] < srcOpers[1].value.s32v[0] ? ~0u : 0u), + ShaderVariable(rdcstr(), + (srcOpers[0].value.s32v[0] < srcOpers[1].value.s32v[0] ? ~0u : 0u), (srcOpers[0].value.s32v[1] < srcOpers[1].value.s32v[1] ? ~0u : 0u), (srcOpers[0].value.s32v[2] < srcOpers[1].value.s32v[2] ? ~0u : 0u), (srcOpers[0].value.s32v[3] < srcOpers[1].value.s32v[3] ? ~0u : 0u))); break; case OPCODE_ULT: SetDst(state, op.operands[0], op, - ShaderVariable("", (srcOpers[0].value.u32v[0] < srcOpers[1].value.u32v[0] ? ~0u : 0u), + ShaderVariable(rdcstr(), + (srcOpers[0].value.u32v[0] < srcOpers[1].value.u32v[0] ? ~0u : 0u), (srcOpers[0].value.u32v[1] < srcOpers[1].value.u32v[1] ? ~0u : 0u), (srcOpers[0].value.u32v[2] < srcOpers[1].value.u32v[2] ? ~0u : 0u), (srcOpers[0].value.u32v[3] < srcOpers[1].value.u32v[3] ? ~0u : 0u))); break; case OPCODE_UGE: SetDst(state, op.operands[0], op, - ShaderVariable("", (srcOpers[0].value.u32v[0] >= srcOpers[1].value.u32v[0] ? ~0u : 0u), + ShaderVariable(rdcstr(), + (srcOpers[0].value.u32v[0] >= srcOpers[1].value.u32v[0] ? ~0u : 0u), (srcOpers[0].value.u32v[1] >= srcOpers[1].value.u32v[1] ? ~0u : 0u), (srcOpers[0].value.u32v[2] >= srcOpers[1].value.u32v[2] ? ~0u : 0u), (srcOpers[0].value.u32v[3] >= srcOpers[1].value.u32v[3] ? ~0u : 0u))); @@ -2911,7 +2931,7 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, // if it's not a buffer or the buffer is empty this UAV is NULL/invalid, return 0 for the // counter uint32_t count = uav->second.data.empty() ? 0 : uav->second.hiddenCounter++; - SetDst(state, op.operands[0], op, ShaderVariable("", count, count, count, count)); + SetDst(state, op.operands[0], op, ShaderVariable(rdcstr(), count, count, count, count)); break; } @@ -2931,7 +2951,7 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, // if it's not a buffer or the buffer is empty this UAV is NULL/invalid, return 0 for the // counter uint32_t count = uav->second.data.empty() ? 0 : --uav->second.hiddenCounter; - SetDst(state, op.operands[0], op, ShaderVariable("", count, count, count, count)); + SetDst(state, op.operands[0], op, ShaderVariable(rdcstr(), count, count, count, count)); break; } @@ -3104,7 +3124,7 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, if(beforeResult.type != TYPE_NULL) { - SetDst(state, beforeResult, op, ShaderVariable("", *udst, *udst, *udst, *udst)); + SetDst(state, beforeResult, op, ShaderVariable(rdcstr(), *udst, *udst, *udst, *udst)); } // not verified below since by definition the operations that expect usrc1 will have it @@ -3367,7 +3387,7 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, if(!data || (!texData && elemIdx >= numElems) || (texData && dataOffset >= dataSize)) { if(load) - SetDst(state, op.operands[0], op, ShaderVariable("", 0U, 0U, 0U, 0U)); + SetDst(state, op.operands[0], op, ShaderVariable(rdcstr(), 0U, 0U, 0U, 0U)); } else { @@ -3726,7 +3746,7 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, else { RDCERR("Unexpected relative addressing"); - SetDst(state, op.operands[0], op, ShaderVariable("", 0.0f, 0.0f, 0.0f, 0.0f)); + SetDst(state, op.operands[0], op, ShaderVariable(rdcstr(), 0.0f, 0.0f, 0.0f, 0.0f)); } break; @@ -3837,7 +3857,7 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, else { RDCERR("Unexpected relative addressing"); - SetDst(state, op.operands[0], op, ShaderVariable("", 0.0f, 0.0f, 0.0f, 0.0f)); + SetDst(state, op.operands[0], op, ShaderVariable(rdcstr(), 0.0f, 0.0f, 0.0f, 0.0f)); } break; @@ -3903,7 +3923,7 @@ void ThreadState::StepNext(ShaderDebugState *state, DebugAPIWrapper *apiWrapper, ShaderVariable result; { - result = ShaderVariable("", 0.0f, 0.0f, 0.0f, 0.0f); + result = ShaderVariable(rdcstr(), 0.0f, 0.0f, 0.0f, 0.0f); if(srcOpers[0].value.u32v[0] < numElems && data + srcOpers[0].value.u32v[0] * fmt.Stride() <= srv->second.data.end()) diff --git a/renderdoc/maths/vec.h b/renderdoc/maths/vec.h index 45d440c22..dbf66fb6c 100644 --- a/renderdoc/maths/vec.h +++ b/renderdoc/maths/vec.h @@ -186,6 +186,25 @@ struct Vec4u }; }; +struct Vec4i +{ + Vec4i(int32_t X = 0, int32_t Y = 0, int32_t Z = 0, int32_t W = 0) + { + x = X; + y = Y; + z = Z; + w = W; + } + union + { + struct + { + int32_t x, y, z, w; + }; + int32_t uv[4]; + }; +}; + #ifdef _MSC_VER #pragma warning(pop) #endif diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index 2ca40af87..131ec6266 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -727,6 +727,7 @@ + diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index 61ebca09b..03f31d0b7 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -1133,6 +1133,9 @@ Resources\glsl + + Resources\hlsl +