Refactor how builtins are gathered & provided for DXIL debugging

* Buitins can either be thread-varying or global, we pick the narrowest type to
  use
This commit is contained in:
baldurk
2025-03-19 18:31:55 +00:00
parent 5914b0641d
commit 6b0604f735
6 changed files with 108 additions and 79 deletions
+5 -5
View File
@@ -2209,8 +2209,8 @@ ShaderDebugTrace *D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
ins = interpreter->workgroup[hit->quadLaneIndex].inputs;
state.semantics.coverage = lane->coverage;
state.semantics.primID = hit->primitive;
state.semantics.isFrontFace = hit->isFrontFace;
state.semantics.primID = lane->primitive;
state.semantics.isFrontFace = lane->isFrontFace;
if(!ins.empty() && ins.back().name == dxbc->GetDXBCByteCode()->GetRegisterName(
DXBCBytecode::TYPE_INPUT_COVERAGE_MASK, 0))
@@ -2229,11 +2229,11 @@ ShaderDebugTrace *D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
if(fetcher.inputs[i].sysattribute == ShaderBuiltin::PrimitiveIndex)
{
invar.value.u32v[fetcher.inputs[i].elem] = hit->primitive;
invar.value.u32v[fetcher.inputs[i].elem] = lane->primitive;
}
else if(fetcher.inputs[i].sysattribute == ShaderBuiltin::MSAASampleIndex)
{
invar.value.u32v[fetcher.inputs[i].elem] = hit->sample;
invar.value.u32v[fetcher.inputs[i].elem] = lane->sample;
}
else if(fetcher.inputs[i].sysattribute == ShaderBuiltin::MSAACoverage)
{
@@ -2241,7 +2241,7 @@ ShaderDebugTrace *D3D11Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
}
else if(fetcher.inputs[i].sysattribute == ShaderBuiltin::IsFrontFace)
{
invar.value.u32v[fetcher.inputs[i].elem] = hit->isFrontFace ? ~0U : 0;
invar.value.u32v[fetcher.inputs[i].elem] = lane->isFrontFace ? ~0U : 0;
}
else
{
+27 -16
View File
@@ -2261,6 +2261,11 @@ ShaderDebugTrace *D3D12Replay::DebugVertex(uint32_t eventId, uint32_t vertid, ui
}
default: RDCERR("Unhandled system value semantic on VS input"); break;
}
if(sigParam.systemValue != ShaderBuiltin::Undefined)
{
activeState.m_Builtins[sigParam.systemValue] = inputs[i];
}
}
debugger->InitialiseWorkgroup(workgroupProperties);
@@ -2820,8 +2825,8 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
ins = interpreter->workgroup[hit->quadLaneIndex].inputs;
state.semantics.coverage = lane->coverage;
state.semantics.primID = hit->primitive;
state.semantics.isFrontFace = hit->isFrontFace;
state.semantics.primID = lane->primitive;
state.semantics.isFrontFace = lane->isFrontFace;
if(!ins.empty() && ins.back().name == dxbc->GetDXBCByteCode()->GetRegisterName(
DXBCBytecode::TYPE_INPUT_COVERAGE_MASK, 0))
@@ -2840,11 +2845,11 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
if(fetcher.inputs[i].sysattribute == ShaderBuiltin::PrimitiveIndex)
{
invar.value.u32v[fetcher.inputs[i].elem] = hit->primitive;
invar.value.u32v[fetcher.inputs[i].elem] = lane->primitive;
}
else if(fetcher.inputs[i].sysattribute == ShaderBuiltin::MSAASampleIndex)
{
invar.value.u32v[fetcher.inputs[i].elem] = hit->sample;
invar.value.u32v[fetcher.inputs[i].elem] = lane->sample;
}
else if(fetcher.inputs[i].sysattribute == ShaderBuiltin::MSAACoverage)
{
@@ -2852,7 +2857,7 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
}
else if(fetcher.inputs[i].sysattribute == ShaderBuiltin::IsFrontFace)
{
invar.value.u32v[fetcher.inputs[i].elem] = hit->isFrontFace ? ~0U : 0;
invar.value.u32v[fetcher.inputs[i].elem] = lane->isFrontFace ? ~0U : 0;
}
else
{
@@ -2956,9 +2961,12 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
data += inputElement.numwords * sizeof(uint32_t);
}
state.m_Semantics.coverage = lane->coverage;
state.m_Semantics.primID = hit->primitive;
state.m_Semantics.isFrontFace = hit->isFrontFace;
state.m_Builtins[ShaderBuiltin::PrimitiveIndex] =
ShaderVariable(rdcstr(), lane->primitive, 0U, 0U, 0U);
state.m_Builtins[ShaderBuiltin::MSAACoverage] =
ShaderVariable(rdcstr(), lane->coverage, 0U, 0U, 0U);
state.m_Builtins[ShaderBuiltin::IsFrontFace] =
ShaderVariable(rdcstr(), lane->isFrontFace, 0U, 0U, 0U);
for(const DXILDebug::PSInputData &psInput : psInputDatas)
{
@@ -2969,11 +2977,11 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
if(psInput.sysattribute == ShaderBuiltin::PrimitiveIndex)
{
invar.value.u32v[outElement] = hit->primitive;
invar.value.u32v[outElement] = lane->primitive;
}
else if(psInput.sysattribute == ShaderBuiltin::MSAASampleIndex)
{
invar.value.u32v[outElement] = hit->sample;
invar.value.u32v[outElement] = lane->sample;
}
else if(psInput.sysattribute == ShaderBuiltin::MSAACoverage)
{
@@ -2981,7 +2989,7 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
}
else if(psInput.sysattribute == ShaderBuiltin::IsFrontFace)
{
invar.value.u32v[outElement] = hit->isFrontFace ? ~0U : 0;
invar.value.u32v[outElement] = lane->isFrontFace ? ~0U : 0;
}
else
{
@@ -2992,6 +3000,9 @@ ShaderDebugTrace *D3D12Replay::DebugPixel(uint32_t eventId, uint32_t x, uint32_t
memcpy(rawout, psInput.data, psInput.numwords * 4);
}
if(psInput.sysattribute != ShaderBuiltin::Undefined)
state.m_Builtins[psInput.sysattribute] = invar;
}
// TODO: UPDATE INPUTS FROM SAMPLE CACHE
@@ -3168,7 +3179,7 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId,
ret = debugger->BeginDebug(eventId, dxbc, refl, 0, 1);
DXILDebug::GlobalState &globalState = debugger->GetGlobalState();
std::map<ShaderBuiltin, ShaderVariable> &builtins = globalState.builtinInputs;
rdcflatmap<ShaderBuiltin, ShaderVariable> &globalBuiltins = globalState.builtins;
rdcarray<DXILDebug::ThreadProperties> workgroupProperties;
workgroupProperties.resize(1);
@@ -3181,20 +3192,20 @@ ShaderDebugTrace *D3D12Replay::DebugThread(uint32_t eventId,
workgroupProperties[0][DXILDebug::ThreadProperty::Active] = 1;
// SV_DispatchThreadID
builtins[ShaderBuiltin::DispatchThreadIndex] = ShaderVariable(
globalBuiltins[ShaderBuiltin::DispatchThreadIndex] = ShaderVariable(
rdcstr(), groupid[0] * threadDim[0] + threadid[0], groupid[1] * threadDim[1] + threadid[1],
groupid[2] * threadDim[2] + threadid[2], 0U);
// SV_GroupID
builtins[ShaderBuiltin::GroupIndex] =
globalBuiltins[ShaderBuiltin::GroupIndex] =
ShaderVariable(rdcstr(), groupid[0], groupid[1], groupid[2], 0U);
// SV_GroupThreadID
builtins[ShaderBuiltin::GroupThreadIndex] =
globalBuiltins[ShaderBuiltin::GroupThreadIndex] =
ShaderVariable(rdcstr(), threadid[0], threadid[1], threadid[2], 0U);
// SV_GroupIndex
builtins[ShaderBuiltin::GroupFlatIndex] = ShaderVariable(
globalBuiltins[ShaderBuiltin::GroupFlatIndex] = ShaderVariable(
rdcstr(),
threadid[2] * threadDim[0] * threadDim[1] + threadid[1] * threadDim[0] + threadid[0], 0U,
0U, 0U);
+38 -12
View File
@@ -394,6 +394,11 @@ struct LaneData
uint quadLane;
uint coverage;
uint sample;
uint primitive;
uint isFrontFace;
uint pad2;
Inputs IN;
};
@@ -404,14 +409,13 @@ struct DebugHit
float3 pos_depth; // xy position and depth
float derivValid;
uint primitive;
uint isFrontFace;
uint sample;
uint quadLaneIndex;
uint laneIndex;
uint subgroupSize;
uint pad;
uint sample;
uint primitive;
uint2 pad;
uint4 globalBallot;
uint4 helperBallot;
@@ -462,7 +466,6 @@ void ExtractInputs(Inputs IN
HitBuffer[idx].primitive = primitive;
HitBuffer[idx].isFrontFace = isFrontFace;
HitBuffer[idx].sample = sample;
HitBuffer[idx].quadLaneIndex = quadLaneIndex;
@@ -472,6 +475,22 @@ void ExtractInputs(Inputs IN
HitBuffer[idx].globalBallot = 0;
HitBuffer[idx].helperBallot = 0;
// replicate these across the quad, we assume they do not vary
HitBuffer[idx].lanes[0].primitive = primitive;
HitBuffer[idx].lanes[1].primitive = primitive;
HitBuffer[idx].lanes[2].primitive = primitive;
HitBuffer[idx].lanes[3].primitive = primitive;
HitBuffer[idx].lanes[0].isFrontFace = isFrontFace;
HitBuffer[idx].lanes[1].isFrontFace = isFrontFace;
HitBuffer[idx].lanes[2].isFrontFace = isFrontFace;
HitBuffer[idx].lanes[3].isFrontFace = isFrontFace;
HitBuffer[idx].lanes[0].sample = sample;
HitBuffer[idx].lanes[1].sample = sample;
HitBuffer[idx].lanes[2].sample = sample;
HitBuffer[idx].lanes[3].sample = sample;
// quad pixelPos will be set with other derivatives for float inputs
// for the simple quad case, only the desired thread is considered non-helper
@@ -773,6 +792,11 @@ struct PSLaneData
uint quadId;
uint quadLane;
uint coverage;
uint sample;
uint primitive;
uint isFrontFace;
uint pad2;
#endif
};
@@ -804,14 +828,13 @@ struct DebugHit
float3 pos_depth; // xy position and depth
float derivValid;
uint primitive;
uint isFrontFace;
uint sample;
uint quadLaneIndex;
uint laneIndex;
uint subgroupSize;
uint pad;
uint sample;
uint primitive;
uint2 pad;
uint4 globalBallot;
uint4 helperBallot;
@@ -956,6 +979,10 @@ void ExtractInputs(Inputs IN
ps.quadId = quadId;
ps.quadLane = quadLaneIndex;
ps.coverage = coverage;
ps.sample = sample;
ps.primitive = primitive;
ps.isFrontFace = isFrontFace;
#elif STAGE == STAGE_CS
bool candidateThread = (threadid.x == DESTX && threadid.y == DESTY && threadid.z == DESTZ);
@@ -979,7 +1006,6 @@ void ExtractInputs(Inputs IN
HitBuffer[idx].pos_depth = debug_pixelPos.xyz;
HitBuffer[idx].derivValid = derivValid;
HitBuffer[idx].primitive = primitive;
HitBuffer[idx].isFrontFace = isFrontFace;
HitBuffer[idx].sample = sample;
HitBuffer[idx].laneIndex = laneIndex;
HitBuffer[idx].quadLaneIndex = quadLaneIndex;
+9 -5
View File
@@ -59,6 +59,11 @@ struct PSLaneData
uint32_t quadLane;
uint32_t coverage;
uint32_t sample;
uint32_t primitive;
uint32_t isFrontFace;
uint32_t pad2;
// user data PSInput below here
};
@@ -95,14 +100,13 @@ struct DebugHit
float depth;
float derivValid;
uint32_t primitive;
uint32_t isFrontFace;
uint32_t sample;
uint32_t quadLaneIndex;
uint32_t laneIndex;
uint32_t subgroupSize;
uint32_t pad;
uint32_t sample;
uint32_t primitive;
uint32_t pad[2];
Vec4u globalBallot;
Vec4u helperBallot;
+23 -32
View File
@@ -2688,9 +2688,8 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
RDCASSERTEQUAL(arg.type, VarType::SInt);
RDCASSERTEQUAL(result.type, VarType::SInt);
uint32_t component = arg.value.u32v[0];
RDCASSERT(m_GlobalState.builtinInputs.count(ShaderBuiltin::DispatchThreadIndex) != 0);
result.value.u32v[0] =
m_GlobalState.builtinInputs.at(ShaderBuiltin::DispatchThreadIndex).value.u32v[component];
GetBuiltin(ShaderBuiltin::DispatchThreadIndex).value.u32v[component];
break;
}
case DXOp::GroupId:
@@ -2701,9 +2700,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
RDCASSERTEQUAL(arg.type, VarType::SInt);
RDCASSERTEQUAL(result.type, VarType::SInt);
uint32_t component = arg.value.u32v[0];
RDCASSERT(m_GlobalState.builtinInputs.count(ShaderBuiltin::GroupIndex) != 0);
result.value.u32v[0] =
m_GlobalState.builtinInputs.at(ShaderBuiltin::GroupIndex).value.u32v[component];
result.value.u32v[0] = GetBuiltin(ShaderBuiltin::GroupIndex).value.u32v[component];
break;
}
case DXOp::ThreadIdInGroup:
@@ -2714,18 +2711,14 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
RDCASSERTEQUAL(arg.type, VarType::SInt);
RDCASSERTEQUAL(result.type, VarType::SInt);
uint32_t component = arg.value.u32v[0];
RDCASSERT(m_GlobalState.builtinInputs.count(ShaderBuiltin::GroupThreadIndex) != 0);
result.value.u32v[0] =
m_GlobalState.builtinInputs.at(ShaderBuiltin::GroupThreadIndex).value.u32v[component];
result.value.u32v[0] = GetBuiltin(ShaderBuiltin::GroupThreadIndex).value.u32v[component];
break;
}
case DXOp::FlattenedThreadIdInGroup:
{
// FlattenedThreadIdInGroup()->SV_GroupIndex
RDCASSERTEQUAL(result.type, VarType::SInt);
RDCASSERT(m_GlobalState.builtinInputs.count(ShaderBuiltin::GroupFlatIndex) != 0);
result.value.u32v[0] =
m_GlobalState.builtinInputs.at(ShaderBuiltin::GroupFlatIndex).value.u32v[0];
result.value.u32v[0] = GetBuiltin(ShaderBuiltin::GroupFlatIndex).value.u32v[0];
break;
}
case DXOp::DerivCoarseX:
@@ -3234,41 +3227,31 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
case DXOp::SampleIndex:
{
// SV_SampleIndex
RDCASSERT(m_GlobalState.builtinInputs.count(ShaderBuiltin::MSAASampleIndex) != 0);
result.value.u32v[0] =
m_GlobalState.builtinInputs.at(ShaderBuiltin::MSAASampleIndex).value.u32v[0];
result.value.u32v[0] = GetBuiltin(ShaderBuiltin::MSAASampleIndex).value.u32v[0];
break;
}
case DXOp::Coverage:
{
// SV_Coverage
RDCASSERT(m_GlobalState.builtinInputs.count(ShaderBuiltin::MSAACoverage) != 0);
result.value.u32v[0] =
m_GlobalState.builtinInputs.at(ShaderBuiltin::MSAACoverage).value.u32v[0];
result.value.u32v[0] = GetBuiltin(ShaderBuiltin::MSAACoverage).value.u32v[0];
break;
}
case DXOp::InnerCoverage:
{
// SV_InnerCoverage
RDCASSERT(m_GlobalState.builtinInputs.count(ShaderBuiltin::IsFullyCovered) != 0);
result.value.u32v[0] =
m_GlobalState.builtinInputs.at(ShaderBuiltin::IsFullyCovered).value.u32v[0];
result.value.u32v[0] = GetBuiltin(ShaderBuiltin::IsFullyCovered).value.u32v[0];
break;
}
case DXOp::ViewID:
{
// SV_ViewportArrayIndex
RDCASSERT(m_GlobalState.builtinInputs.count(ShaderBuiltin::ViewportIndex) != 0);
result.value.u32v[0] =
m_GlobalState.builtinInputs.at(ShaderBuiltin::ViewportIndex).value.u32v[0];
result.value.u32v[0] = GetBuiltin(ShaderBuiltin::ViewportIndex).value.u32v[0];
break;
}
case DXOp::PrimitiveID:
{
// SV_PrimitiveID
RDCASSERT(m_GlobalState.builtinInputs.count(ShaderBuiltin::PrimitiveIndex) != 0);
result.value.u32v[0] =
m_GlobalState.builtinInputs.at(ShaderBuiltin::PrimitiveIndex).value.u32v[0];
result.value.u32v[0] = GetBuiltin(ShaderBuiltin::PrimitiveIndex).value.u32v[0];
break;
}
case DXOp::IsHelperLane:
@@ -5512,6 +5495,20 @@ bool ThreadState::IsVariableAssigned(const Id id) const
}
}
ShaderVariable ThreadState::GetBuiltin(ShaderBuiltin builtin)
{
auto local = m_Builtins.find(builtin);
if(local != m_Builtins.end())
return local->second;
auto global = m_GlobalState.builtins.find(builtin);
if(global != m_GlobalState.builtins.end())
return global->second;
RDCERR("Couldn't find data for builtin %s", ToStr(builtin).c_str());
return {};
}
bool ThreadState::GetLiveVariable(const Id &id, Operation op, DXOp dxOpCode, ShaderVariable &var) const
{
if(id < m_Live.size())
@@ -8066,11 +8063,6 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
if(FindSigParameter(dxbcInParams, sig, sigParam))
{
v.name = sigParam.semanticIdxName;
if(sigParam.systemValue != ShaderBuiltin::Undefined)
{
RDCASSERT(m_GlobalState.builtinInputs.count(sigParam.systemValue) == 0);
m_GlobalState.builtinInputs[sigParam.systemValue] = v;
}
}
else
{
@@ -8328,7 +8320,6 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
if(i != m_ActiveLaneIndex)
{
lane.m_Input = state.m_Input;
lane.m_Semantics = state.m_Semantics;
lane.m_Variables = state.m_Variables;
lane.m_Assigned = state.m_Assigned;
lane.m_Live = state.m_Live;
+6 -9
View File
@@ -212,6 +212,8 @@ struct MemoryTracking
std::map<Id, Pointer> m_Pointers;
};
typedef rdcflatmap<ShaderBuiltin, ShaderVariable> BuiltinInputs;
struct ThreadState
{
ThreadState(Debugger &debugger, const GlobalState &globalState, uint32_t maxSSAId);
@@ -279,6 +281,8 @@ struct ThreadState
ShaderVariable &var, bool flushDenormInput, bool isLive) const;
bool IsVariableAssigned(const Id id) const;
ShaderVariable GetBuiltin(ShaderBuiltin builtin);
struct AnnotationProperties
{
DXIL::ResourceKind resKind;
@@ -286,12 +290,7 @@ struct ThreadState
uint32_t structStride;
};
struct
{
uint32_t coverage = ~0U;
uint32_t primID = ~0U;
uint32_t isFrontFace = false;
} m_Semantics;
BuiltinInputs m_Builtins;
Debugger &m_Debugger;
const DXIL::Program &m_Program;
@@ -355,11 +354,9 @@ struct ThreadState
struct GlobalState
{
typedef std::map<ShaderBuiltin, ShaderVariable> BuiltinInputs;
GlobalState() = default;
~GlobalState();
BuiltinInputs builtinInputs;
BuiltinInputs builtins;
struct ViewFmt
{