DXIL Debugger extended support for GPU Sampling instructions

DXOp::Sample
DXOp::SampleBias
DXOp::SampleLevel
DXOp::SampleGrad
DXOp::SampleCmp
DXOp::SampleCmpBias
DXOp::SampleCmpLevel
DXOp::SampleCmpGrad
DXOp::SampleCmpLevelZero
DXOp::TextureGather
DXOp::TextureGatherCmp
This commit is contained in:
Jake Turner
2024-10-24 12:47:50 +01:00
parent a5b63f2f26
commit f538e91b05
6 changed files with 276 additions and 97 deletions
+11 -7
View File
@@ -397,13 +397,17 @@ cbuffer DebugSampleOperation REG(b0)
#define DEBUG_SAMPLE_TEX_SAMPLE_GRAD 103
#define DEBUG_SAMPLE_TEX_SAMPLE_CMP 104
#define DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL_ZERO 105
#define DEBUG_SAMPLE_TEX_GATHER4 106
#define DEBUG_SAMPLE_TEX_GATHER4_CMP 107
#define DEBUG_SAMPLE_TEX_GATHER4_PO 108
#define DEBUG_SAMPLE_TEX_GATHER4_PO_CMP 109
#define DEBUG_SAMPLE_TEX_LOD 110
#define DEBUG_SAMPLE_TEX_LOAD 111
#define DEBUG_SAMPLE_TEX_LOAD_MS 112
#define DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL 106 // SM 6.7
#define DEBUG_SAMPLE_TEX_SAMPLE_CMP_BIAS 107 // SM 6.8
#define DEBUG_SAMPLE_TEX_SAMPLE_CMP_GRAD 108 // SM 6.8
#define DEBUG_SAMPLE_TEX_GATHER4 109
#define DEBUG_SAMPLE_TEX_GATHER4_CMP 110
#define DEBUG_SAMPLE_TEX_GATHER4_PO 111
#define DEBUG_SAMPLE_TEX_GATHER4_PO_CMP 112
#define DEBUG_SAMPLE_TEX_LOD 113
#define DEBUG_SAMPLE_TEX_LOAD 114
#define DEBUG_SAMPLE_TEX_LOAD_MS 115
#define DEBUG_SAMPLE_TEX1D 1
#define DEBUG_SAMPLE_TEX2D 2
+97 -1
View File
@@ -269,7 +269,7 @@ float4 DoFloatOpcode(float4 uv)
}
}
}
else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_CMP)
else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_CMP || opcode == DEBUG_SAMPLE_TEX_SAMPLE_CMP_BIAS)
{
switch(debugSampleTexDim)
{
@@ -660,6 +660,102 @@ float4 DoFloatOpcode(float4 uv)
}
}
}
#if __SHADER_TARGET_MAJOR >= 6
#if __SHADER_TARGET_MINOR >= 7
else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL) // SM6.7
{
switch(debugSampleTexDim)
{
default:
case DEBUG_SAMPLE_TEX1D:
{
switch(debugSampleRetType)
{
case DEBUG_SAMPLE_UNORM:
return t1D_unorm.SampleCmpLevel(sc, uv.xy, compare, lod, offsets.x);
case DEBUG_SAMPLE_SNORM:
return t1D_snorm.SampleCmpLevel(sc, uv.xy, compare, lod, offsets.x);
default: return t1D_float.SampleCmpLevel(sc, uv.xy, compare, lod, offsets.x);
}
}
case DEBUG_SAMPLE_TEX2D:
{
switch(debugSampleRetType)
{
case DEBUG_SAMPLE_UNORM:
return t2D_unorm.SampleCmpLevel(sc, uv.xyz, compare, lod, offsets.xy);
case DEBUG_SAMPLE_SNORM:
return t2D_snorm.SampleCmpLevel(sc, uv.xyz, compare, lod, offsets.xy);
default: return t2D_float.SampleCmpLevel(sc, uv.xyz, compare, lod, offsets.xy);
}
}
case DEBUG_SAMPLE_TEXCUBE:
{
switch(debugSampleRetType)
{
case DEBUG_SAMPLE_UNORM: return tCube_unorm.SampleCmpLevel(sc, uv, compare, lod);
case DEBUG_SAMPLE_SNORM: return tCube_snorm.SampleCmpLevel(sc, uv, compare, lod);
default: return tCube_float.SampleCmpLevel(sc, uv, compare, lod);
}
}
}
}
#endif // #if __SHADER_TARGET_MINOR >= 7
#if __SHADER_TARGET_MINOR >= 8
else if(opcode == DEBUG_SAMPLE_TEX_SAMPLE_CMP_GRAD) // SM6.8
{
switch(debugSampleTexDim)
{
default:
case DEBUG_SAMPLE_TEX1D:
{
switch(debugSampleRetType)
{
case DEBUG_SAMPLE_UNORM:
return t1D_unorm.SampleCmpGrad(s, uv.xy, compare, ddx_.x, ddy_.x, offsets.x);
case DEBUG_SAMPLE_SNORM:
return t1D_snorm.SampleCmpGrad(s, uv.xy, compare, ddx_.x, ddy_.x, offsets.x);
default: return t1D_float.SampleCmpGrad(s, uv.xy, compare, ddx_.x, ddy_.x, offsets.x);
}
}
case DEBUG_SAMPLE_TEX2D:
{
switch(debugSampleRetType)
{
case DEBUG_SAMPLE_UNORM:
return t2D_unorm.SampleCmpGrad(s, uv.xyz, compare, ddx_.xy, ddy_.xy, offsets.xy);
case DEBUG_SAMPLE_SNORM:
return t2D_snorm.SampleCmpGrad(s, uv.xyz, compare, ddx_.xy, ddy_.xy, offsets.xy);
default: return t2D_float.SampleCmpGrad(s, uv.xyz, compare, ddx_.xy, ddy_.xy, offsets.xy);
}
}
case DEBUG_SAMPLE_TEX3D:
{
switch(debugSampleRetType)
{
case DEBUG_SAMPLE_UNORM:
return t3D_unorm.SampleCmpGrad(s, uv.xyz, compare, ddx_.xyz, ddy_.xyz, offsets.xyz);
case DEBUG_SAMPLE_SNORM:
return t3D_snorm.SampleCmpGrad(s, uv.xyz, compare, ddx_.xyz, ddy_.xyz, offsets.xyz);
default:
return t3D_float.SampleCmpGrad(s, uv.xyz, compare, ddx_.xyz, ddy_.xyz, offsets.xyz);
}
}
case DEBUG_SAMPLE_TEXCUBE:
{
switch(debugSampleRetType)
{
case DEBUG_SAMPLE_UNORM:
return tCube_unorm.SampleCmpGrad(s, uv, compare, ddx_.xyz, ddy_.xyz);
case DEBUG_SAMPLE_SNORM:
return tCube_snorm.SampleCmpGrad(s, uv, compare, ddx_.xyz, ddy_.xyz);
default: return tCube_float.SampleCmpGrad(s, uv, compare, ddx_.xyz, ddy_.xyz);
}
}
}
}
#endif // #if __SHADER_TARGET_MINOR >= 8
#endif // #if __SHADER_TARGET_MAJOR >= 6
else
{
return float4(0, 0, 0, 0);
+5 -1
View File
@@ -836,8 +836,12 @@ bool D3D12DebugManager::CreateShaderDebugResources()
return false;
}
ID3DBlob *dxilPsBlob = NULL;
D3D12_FEATURE_DATA_SHADER_MODEL smMaxSupport = {D3D_SHADER_MODEL_6_8};
m_pDevice->CheckFeatureSupport(D3D12_FEATURE_SHADER_MODEL, &smMaxSupport, sizeof(smMaxSupport));
D3D_SHADER_MODEL smModel = smMaxSupport.HighestShaderModel;
rdcstr psSM = StringFormat::Fmt("ps_%d_%d", (smModel >> 4), (smModel & 0xf));
if(m_pDevice->GetShaderCache()->GetShaderBlob(hlsl.c_str(), "RENDERDOC_DebugSamplePS",
D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, "ps_6_0",
D3DCOMPILE_WARNINGS_ARE_ERRORS, {}, psSM.c_str(),
&dxilPsBlob) != "")
{
RDCASSERT(!dxilPsBlob);
+6 -6
View File
@@ -1118,23 +1118,23 @@ bool D3D12APIWrapper::CalculateSampleGather(
switch(dxOp)
{
case DXOp::Sample: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE; break;
case DXOp::SampleLevel: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_LEVEL; break;
case DXOp::SampleBias: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_BIAS; break;
case DXOp::SampleCmp: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP; break;
case DXOp::SampleLevel: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_LEVEL; break;
case DXOp::SampleGrad: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_GRAD; break;
case DXOp::SampleCmp: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP; break;
case DXOp::SampleCmpBias: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP_BIAS; break;
case DXOp::SampleCmpLevel: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL; break;
case DXOp::SampleCmpGrad: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP_GRAD; break;
case DXOp::SampleCmpLevelZero: sampleOp = DEBUG_SAMPLE_TEX_SAMPLE_CMP_LEVEL_ZERO; break;
case DXOp::TextureGather: sampleOp = DEBUG_SAMPLE_TEX_GATHER4; break;
case DXOp::TextureGatherCmp: sampleOp = DEBUG_SAMPLE_TEX_GATHER4_CMP; break;
case DXOp::CalculateLOD: sampleOp = DEBUG_SAMPLE_TEX_LOD; break;
// In the shader DEBUG_SAMPLE_TEX_LOAD and DEBUG_SAMPLE_TEX_LOAD_MS behave equivalently
case DXOp::TextureLoad: sampleOp = DEBUG_SAMPLE_TEX_LOAD; break;
// TODO: consider these DXIL opcode operations
// DXOp::SampleCmpBias
// DXOp::SampleCmpGrad
// DXOp::SampleCmpLevel
// DXOp::TextureGatherRaw
// TODO: consider these DXBC opcode operations
// DEBUG_SAMPLE_TEX_GATHER4_PARAM_OFFSET_CMP
// DEBUG_SAMPLE_TEX_LOAD_MS
default:
// To support a new instruction, the shader created in
// D3D12DebugManager::CreateShaderDebugResources will need updating
+157 -74
View File
@@ -1389,16 +1389,17 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
break;
}
case DXOp::Sample:
case DXOp::SampleBias:
case DXOp::SampleLevel:
case DXOp::SampleGrad:
case DXOp::SampleCmp:
case DXOp::SampleCmpBias:
case DXOp::SampleCmpLevel:
case DXOp::SampleCmpGrad:
case DXOp::SampleCmpLevelZero:
case DXOp::TextureGather:
case DXOp::TextureGatherCmp:
{
// TODO
// case DXOp::SampleBias:
// case DXOp::SampleGrad:
// case DXOp::SampleCmp:
// case DXOp::SampleCmpLevel:
// case DXOp::SampleCmpGrad:
// case DXOp::SampleCmpBias:
rdcstr handleId = GetArgumentName(1);
const ResourceReference *resRef = GetResource(handleId);
if(!resRef)
@@ -2067,13 +2068,8 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
case DXOp::Ubfe:
case DXOp::Bfi:
case DXOp::CBufferLoad:
case DXOp::SampleBias:
case DXOp::SampleGrad:
case DXOp::SampleCmp:
case DXOp::BufferUpdateCounter:
case DXOp::CheckAccessFullyMapped:
case DXOp::TextureGather:
case DXOp::TextureGatherCmp:
case DXOp::AtomicBinOp:
case DXOp::AtomicCompareExchange:
case DXOp::Barrier:
@@ -2210,7 +2206,6 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
case DXOp::IsHelperLane:
case DXOp::QuadVote:
case DXOp::TextureGatherRaw:
case DXOp::SampleCmpLevel:
case DXOp::TextureStoreSample:
case DXOp::WaveMatrix_Annotate:
case DXOp::WaveMatrix_Depth:
@@ -2240,8 +2235,6 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
case DXOp::AnnotateNodeRecordHandle:
case DXOp::NodeOutputIsValid:
case DXOp::GetRemainingRecursionLevels:
case DXOp::SampleCmpGrad:
case DXOp::SampleCmpBias:
case DXOp::StartVertexLocation:
case DXOp::StartInstanceLocation:
case DXOp::NumOpCodes:
@@ -2439,7 +2432,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
}
RDCASSERT((resultType->type == DXIL::Type::TypeKind::Scalar) ||
(resultType->type == DXIL::Type::TypeKind::Struct));
// TODO: NEED TO DEMANGLE THE NAME TO DEMANGLE TO MATCH DISASSEMBLY
// TODO: NEED TO DEMANGLE THE NAME TO MATCH DISASSEMBLY
result.type = baseType;
result.rows = (uint8_t)countElems;
result.members.resize(countElems);
@@ -3334,7 +3327,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
case Operation::AtomicUMax:
case Operation::AtomicUMin:
{
// JAKE TODO: full proper load and store from/to memory i.e. group shared
// TODO: full proper load and store from/to memory i.e. group shared
// Currently only supporting Stack allocated pointers
size_t allocSize = 0;
void *allocMemoryBackingPtr = NULL;
@@ -3810,16 +3803,18 @@ void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups,
{
// TextureLoad(srv,mipLevelOrSampleCount,coord0,coord1,coord2,offset0,offset1,offset2)
// Sample(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,clamp)
// SampleLevel(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,LOD)
// SampleCmpLevelZero(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue)
// TODO
// SampleBias(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,bias,clamp)
// SampleLevel(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,LOD)
// SampleGrad(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,ddx0,ddx1,ddx2,ddy0,ddy1,ddy2,clamp)
// SampleCmp(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue,clamp)
// SampleCmpBias(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue,bias,clamp)
// SampleCmpLevel(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue,lod)
// SampleCmpGrad(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue,ddx0,ddx1,ddx2,ddy0,ddy1,ddy2,clamp)
// SampleCmpBias(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue,bias,clamp)
// SampleCmpLevelZero(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,compareValue)
// CalculateLOD(handle,sampler,coord0,coord1,coord2,clamped)
// TextureGather(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,channel)
// TextureGatherCmp(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,channel,compareValue)
// DXIL reports the vector result as a struct of N members of Element type, plus an int.
const Type *retType = inst.type;
@@ -3855,8 +3850,39 @@ void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups,
samplerData.mode = SamplerMode::NUM_SAMPLERS;
bool uvDDXY[4] = {false, false, false, false};
GatherChannel gatherChannel = GatherChannel::Red;
if(dxOpCode != DXOp::TextureLoad)
if(dxOpCode == DXOp::TextureLoad)
{
ShaderVariable arg;
// mipLevelOrSampleCount is in arg 2
if(GetShaderVariable(inst.args[2], opCode, dxOpCode, arg, false))
{
uint32_t mipLevelOrSampleCount = arg.value.u32v[0];
// The debug shader uses arrays of resources for 1D, 2D textures
// mipLevel goes into UV[N] : N = 1D: 2, 2D: 3, 3D: 3
switch(srv.shape)
{
case DXIL::ResourceKind::Texture1D: uv.value.u32v[2] = mipLevelOrSampleCount; break;
case DXIL::ResourceKind::Texture2D: uv.value.u32v[3] = mipLevelOrSampleCount; break;
case DXIL::ResourceKind::Texture3D: uv.value.u32v[3] = mipLevelOrSampleCount; break;
case DXIL::ResourceKind::Texture2DMS: msIndex = mipLevelOrSampleCount; break;
case DXIL::ResourceKind::Texture2DMSArray: msIndex = mipLevelOrSampleCount; break;
default: break;
}
}
// UV is int data in args 3,4,5
// Offset is int data in args 6,7,8
for(uint32_t i = 0; i < 3; ++i)
{
if(GetShaderVariable(inst.args[3 + i], opCode, dxOpCode, arg, false))
uv.value.s32v[i] = arg.value.s32v[0];
if(GetShaderVariable(inst.args[6 + i], opCode, dxOpCode, arg, false))
texelOffsets[i] = (int8_t)arg.value.s32v[0];
}
}
else
{
// Sampler is in arg 2
rdcstr samplerId = GetArgumentName(2);
@@ -3867,15 +3893,63 @@ void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups,
RDCASSERTEQUAL(samplerRef->resourceBase.resClass, ResourceClass::Sampler);
// samplerRef->resourceBase must be a Sampler
const DXIL::EntryPointInterface::Sampler &sampler = resRef->resourceBase.samplerData;
// TODO: BIAS COMES FROM THE Sample*Bias arguments
samplerData.bias = 0.0f;
samplerData.binding.registerSpace = samplerRef->resourceBase.space;
samplerData.binding.shaderRegister = samplerRef->resourceBase.regBase;
samplerData.mode = ConvertSamplerKindToSamplerMode(sampler.samplerType);
int32_t biasArg = -1;
int32_t lodArg = -1;
int32_t compareArg = -1;
int32_t gatherArg = -1;
uint32_t countOffset = 3;
uint32_t countUV = 4;
// TODO: Sample*: Clamp is in arg 10
// TODO: CalculateLOD: clamped is in arg 6
// CalculateSampleGather returns {CalculateLevelOfDetail(), CalculateLevelOfDetailUnclamped()}
// SampleBias : bias is arg 10
// SampleLevel: lod is in arg 10
// SampleCmp: compare is in arg 10
// SampleCmpBias: compare is in arg 10, bias is in arg 11
// SampleCmpLevel: compare is in arg 10, LOD is in arg 11
// SampleCmpGrad: compare is in arg 10
// SampleCmpLevelZero: compare is in arg 10
// TextureGather: compare is in arg 10, gather is in 9
// TextureGatherCmp: compare is in arg 10, gather is in 9
switch(dxOpCode)
{
case DXOp::Sample: break;
case DXOp::SampleBias: biasArg = 10; break;
case DXOp::SampleLevel: lodArg = 10; break;
case DXOp::SampleGrad: break;
case DXOp::SampleCmp: compareArg = 10; break;
case DXOp::SampleCmpBias:
compareArg = 10;
biasArg = 11;
break;
case DXOp::SampleCmpLevel:
compareArg = 10;
lodArg = 11;
break;
case DXOp::SampleCmpGrad: compareArg = 10; break;
case DXOp::SampleCmpLevelZero: compareArg = 10; break;
case DXOp::TextureGather:
countOffset = 2;
gatherArg = 9;
break;
case DXOp::CalculateLOD: countUV = 3; break;
case DXOp::TextureGatherCmp:
countOffset = 2;
gatherArg = 9;
compareArg = 10;
break;
default: RDCERR("Unhandled DX Operation %s", ToStr(dxOpCode).c_str()); break;
}
ShaderVariable arg;
// UV is float data in args 3,4,5,6
for(uint32_t i = 0; i < 4; ++i)
// UV is float data in args: Sample* 3,4,5,6 ; CalculateLOD 3,4,5
for(uint32_t i = 0; i < countUV; ++i)
{
if(GetShaderVariable(inst.args[3 + i], opCode, dxOpCode, arg))
{
@@ -3886,62 +3960,54 @@ void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups,
}
}
// Offset is int data in args 7,8,9
if(GetShaderVariable(inst.args[7], opCode, dxOpCode, arg, false))
texelOffsets[0] = (int8_t)arg.value.s32v[0];
if(GetShaderVariable(inst.args[8], opCode, dxOpCode, arg, false))
texelOffsets[1] = (int8_t)arg.value.s32v[0];
if(GetShaderVariable(inst.args[9], opCode, dxOpCode, arg, false))
texelOffsets[2] = (int8_t)arg.value.s32v[0];
// TODO: Sample: Clamp is in arg 10
// SampleLevel: LOD is in arg 10
// SampleCmpLevelZero: compare is in arg 10
if((dxOpCode == DXOp::SampleLevel) || (dxOpCode == DXOp::SampleCmpLevelZero))
// Offset is int data in args: Sample* 7,8,9 ; Gather* 7,8
for(uint32_t i = 0; i < countOffset; ++i)
{
if(GetShaderVariable(inst.args[10], opCode, dxOpCode, arg))
if(GetShaderVariable(inst.args[7 + i], opCode, dxOpCode, arg, false))
texelOffsets[i] = (int8_t)arg.value.s32v[0];
}
if((lodArg > 0))
{
if(GetShaderVariable(inst.args[lodArg], opCode, dxOpCode, arg))
{
RDCASSERTEQUAL(arg.type, VarType::Float);
lodValue = arg.value.f32v[0];
}
}
if((compareArg > 0))
{
if(GetShaderVariable(inst.args[compareArg], opCode, dxOpCode, arg))
{
RDCASSERTEQUAL(arg.type, VarType::Float);
compareValue = arg.value.f32v[0];
}
}
}
else
{
ShaderVariable arg;
// TODO : mipLevelOrSampleCount is in arg 2
if(GetShaderVariable(inst.args[2], opCode, dxOpCode, arg))
if(biasArg > 0)
{
msIndex = arg.value.u32v[0];
lodValue = arg.value.f32v[0];
compareValue = arg.value.f32v[0];
if(GetShaderVariable(inst.args[biasArg], opCode, dxOpCode, arg))
{
RDCASSERTEQUAL(arg.type, VarType::Float);
samplerData.bias = arg.value.f32v[0];
}
}
// UV is int data in args 3,4,5
if(GetShaderVariable(inst.args[3], opCode, dxOpCode, arg))
uv.value.s32v[0] = arg.value.s32v[0];
if(GetShaderVariable(inst.args[4], opCode, dxOpCode, arg))
uv.value.s32v[1] = arg.value.s32v[0];
if(GetShaderVariable(inst.args[5], opCode, dxOpCode, arg))
uv.value.s32v[2] = arg.value.s32v[0];
// Offset is int data in args 6,7,8
if(GetShaderVariable(inst.args[6], opCode, dxOpCode, arg))
texelOffsets[0] = (int8_t)arg.value.s32v[0];
if(GetShaderVariable(inst.args[7], opCode, dxOpCode, arg))
texelOffsets[1] = (int8_t)arg.value.s32v[0];
if(GetShaderVariable(inst.args[8], opCode, dxOpCode, arg))
texelOffsets[2] = (int8_t)arg.value.s32v[0];
if(gatherArg > 0)
{
if(GetShaderVariable(inst.args[gatherArg], opCode, dxOpCode, arg))
{
RDCASSERTEQUAL(arg.type, VarType::SInt);
// Red = 0, Green = 1, Blue = 2, Alpha = 3
gatherChannel = (DXILDebug::GatherChannel)arg.value.s32v[0];
}
}
}
// TODO: DDX & DDY
ShaderVariable ddx;
ShaderVariable ddy;
// Sample, SampleBias, SampleCmp, CalculateLOD need DDX, DDY
if((dxOpCode == DXOp::Sample) || (dxOpCode == DXOp::SampleBias) ||
(dxOpCode == DXOp::SampleCmp) || (dxOpCode == DXOp::CalculateLOD))
// Sample, SampleBias, CalculateLOD need DDX, DDY
if((dxOpCode == DXOp::Sample) || (dxOpCode == DXOp::SampleBias) || (dxOpCode == DXOp::CalculateLOD))
{
if(m_ShaderType != DXBC::ShaderType::Pixel || workgroups.size() != 4)
{
@@ -3950,7 +4016,6 @@ void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups,
else
{
// texture samples use coarse derivatives
// TODO: the UV should be the ID per UV compponent
ShaderValue delta;
for(uint32_t i = 0; i < 4; i++)
{
@@ -3964,19 +4029,37 @@ void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups,
}
}
}
else if(dxOpCode == DXOp::SampleGrad)
else if((dxOpCode == DXOp::SampleGrad) || (dxOpCode == DXOp::SampleCmpGrad))
{
// TODO: get from arguments
// SampleGrad DDX is argument 10, DDY is argument 14
// SampleCmpGrad DDX is argument 11, DDY is argument 15
uint32_t ddx0 = dxOpCode == DXOp::SampleGrad ? 10 : 11;
uint32_t ddy0 = ddx0 + 4;
ShaderVariable arg;
for(uint32_t i = 0; i < 4; i++)
{
if(uvDDXY[i])
{
RDCASSERT(GetShaderVariable(inst.args[ddx0 + i], opCode, dxOpCode, arg));
ddx.value.f32v[i] = arg.value.f32v[0];
RDCASSERT(GetShaderVariable(inst.args[ddy0 + i], opCode, dxOpCode, arg));
ddy.value.f32v[i] = arg.value.f32v[0];
}
}
}
uint8_t swizzle[4] = {0, 1, 2, 3};
// TODO: GATHER CHANNEL
GatherChannel gatherChannel = GatherChannel::Red;
uint32_t instructionIdx = m_FunctionInstructionIdx - 1;
const char *opString = ToStr(dxOpCode).c_str();
ShaderVariable data;
// TODO: TextureGatherRaw // SM 6.7
// Return types for TextureGatherRaw
// DXGI_FORMAT_R16_UINT : u16
// DXGI_FORMAT_R32_UINT : u32
// DXGI_FORMAT_R32G32_UINT : u32x2
ShaderVariable data;
apiWrapper->CalculateSampleGather(dxOpCode, resourceData, samplerData, uv, ddx, ddy, texelOffsets,
msIndex, lodValue, compareValue, swizzle, gatherChannel,
m_ShaderType, instructionIdx, opString, data);
@@ -1806,13 +1806,8 @@ rdcstr Program::GetDebugStatus()
case DXOp::Ubfe:
case DXOp::Bfi:
case DXOp::CBufferLoad:
case DXOp::SampleBias:
case DXOp::SampleGrad:
case DXOp::SampleCmp:
case DXOp::BufferUpdateCounter:
case DXOp::CheckAccessFullyMapped:
case DXOp::TextureGather:
case DXOp::TextureGatherCmp:
case DXOp::AtomicBinOp:
case DXOp::AtomicCompareExchange:
case DXOp::Barrier:
@@ -1949,7 +1944,6 @@ rdcstr Program::GetDebugStatus()
case DXOp::IsHelperLane:
case DXOp::QuadVote:
case DXOp::TextureGatherRaw:
case DXOp::SampleCmpLevel:
case DXOp::TextureStoreSample:
case DXOp::WaveMatrix_Annotate:
case DXOp::WaveMatrix_Depth:
@@ -1979,8 +1973,6 @@ rdcstr Program::GetDebugStatus()
case DXOp::AnnotateNodeRecordHandle:
case DXOp::NodeOutputIsValid:
case DXOp::GetRemainingRecursionLevels:
case DXOp::SampleCmpGrad:
case DXOp::SampleCmpBias:
case DXOp::StartVertexLocation:
case DXOp::StartInstanceLocation:
case DXOp::NumOpCodes: