DXIL Debugger support for bindless resources

Change to find resource references by DXILDebug::Id
This commit is contained in:
Jake Turner
2024-10-31 18:26:14 +00:00
parent 3c0e64d97a
commit fc109ce3ac
5 changed files with 110 additions and 77 deletions
@@ -1617,7 +1617,7 @@ protected:
uint32_t GetMetaSlot(const DebugLocation *l) const;
void AssignMetaSlot(rdcarray<Metadata *> &metaSlots, uint32_t &nextMetaSlot, DebugLocation &l);
const ResourceReference *GetResourceReference(const rdcstr &handleStr) const;
const ResourceReference *GetResourceReference(const DXILDebug::Id handleId) const;
rdcstr GetHandleAlias(const rdcstr &handleStr) const;
static DXILDebug::Id GetResultSSAId(const DXIL::Instruction &inst);
static void MakeResultId(const Instruction &inst, rdcstr &resultId);
@@ -1693,7 +1693,7 @@ protected:
rdcstr m_Triple, m_Datalayout;
rdcarray<EntryPointInterface> m_EntryPointInterfaces;
std::map<rdcstr, size_t> m_ResourceHandles;
std::map<DXILDebug::Id, size_t> m_ResourceByIdHandles;
std::map<rdcstr, rdcstr> m_SsaAliases;
std::map<rdcstr, uint32_t> m_ResourceAnnotateCounts;
rdcarray<LocalSourceVariable> m_Locals;
+87 -60
View File
@@ -1427,12 +1427,14 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
case DXOp::GetDimensions:
{
// GetDimensions(handle,mipLevel)
rdcstr handleId = GetArgumentName(1);
const ResourceReference *resRef = GetResource(handleId);
Id handleId = GetArgumentId(1);
ShaderBindIndex bindIndex;
const DXIL::ResourceReference *resRef = GetResource(handleId, bindIndex);
if(!resRef)
break;
BindingSlot binding(resRef->resourceBase.regBase, resRef->resourceBase.space);
BindingSlot binding(resRef->resourceBase.regBase + bindIndex.arrayElement,
resRef->resourceBase.space);
ShaderVariable data;
uint32_t mipLevel = 0;
if(!isUndef(inst.args[2]))
@@ -1460,12 +1462,14 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
case DXOp::Texture2DMSGetSamplePosition:
{
// Texture2DMSGetSamplePosition(srv,index)
rdcstr handleId = GetArgumentName(1);
const ResourceReference *resRef = GetResource(handleId);
Id handleId = GetArgumentId(1);
ShaderBindIndex bindIndex;
const DXIL::ResourceReference *resRef = GetResource(handleId, bindIndex);
if(!resRef)
break;
BindingSlot binding(resRef->resourceBase.regBase, resRef->resourceBase.space);
BindingSlot binding(resRef->resourceBase.regBase + bindIndex.arrayElement,
resRef->resourceBase.space);
ShaderVariable arg;
RDCASSERT(GetShaderVariable(inst.args[2], opCode, dxOpCode, arg));
const char *opString = ToStr(dxOpCode).c_str();
@@ -1528,12 +1532,14 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
case DXOp::TextureGather:
case DXOp::TextureGatherCmp:
{
rdcstr handleId = GetArgumentName(1);
const ResourceReference *resRef = GetResource(handleId);
Id handleId = GetArgumentId(1);
ShaderBindIndex bindIndex;
const DXIL::ResourceReference *resRef = GetResource(handleId, bindIndex);
if(!resRef)
break;
PerformGPUResourceOp(workgroups, opCode, dxOpCode, resRef, apiWrapper, inst, result);
PerformGPUResourceOp(workgroups, opCode, dxOpCode, resRef, bindIndex, apiWrapper, inst,
result);
eventFlags |= ShaderEvents::SampleLoadGather;
break;
}
@@ -1550,8 +1556,9 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
// BufferStore(uav,coord0,coord1,value0,value1,value2,value3,mask)
// RawBufferLoad(srv,index,elementOffset,mask,alignment)
// RawBufferStore(uav,index,elementOffset,value0,value1,value2,value3,mask,alignment)
rdcstr handleId = GetArgumentName(1);
const ResourceReference *resRef = GetResource(handleId);
Id handleId = GetArgumentId(1);
ShaderBindIndex bindIndex;
const DXIL::ResourceReference *resRef = GetResource(handleId, bindIndex);
if(!resRef)
break;
@@ -1559,7 +1566,8 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
// SRV TextureLoad is done on the GPU
if((dxOpCode == DXOp::TextureLoad) && (resClass == ResourceClass::SRV))
{
PerformGPUResourceOp(workgroups, opCode, dxOpCode, resRef, apiWrapper, inst, result);
PerformGPUResourceOp(workgroups, opCode, dxOpCode, resRef, bindIndex, apiWrapper,
inst, result);
eventFlags |= ShaderEvents::SampleLoadGather;
break;
}
@@ -1809,10 +1817,17 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
// CreateHandleFromBinding(bind,index,nonUniformIndex)
rdcstr baseResource = result.name;
result.name.clear();
uint32_t resIndexArgId = ~0U;
if(dxOpCode == DXOp::AnnotateHandle)
baseResource = GetArgumentName(1);
else if(dxOpCode == DXOp::CreateHandle)
resIndexArgId = 3;
else if(dxOpCode == DXOp::CreateHandleFromBinding)
resIndexArgId = 2;
else
RDCERR("Unhandled DXOp %s", ToStr(dxOpCode).c_str());
const ResourceReference *resRef = m_Program.GetResourceReference(baseResource);
const ResourceReference *resRef = m_Program.GetResourceReference(resultId);
if(resRef)
{
const rdcarray<ShaderVariable> *list = NULL;
@@ -1843,35 +1858,41 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
recordChange = false;
if(result.name.isEmpty())
{
// TODO: support for dynamic handles i.e. array lookups
RDCERR("Unhandled dynamic handle %s", resName.c_str());
// Need to make a shader variable for the return : it needs to have a binding point
// DescriptorCategory category;
// uint32_t index;
// uint32_t arrayElement = 0;
// result.SetBindIndex(ShaderBindIndex(category, index, arrayElement));
if(resIndexArgId < inst.args.size())
{
// Make the ShaderVariable to represent the dynamic binding
// The base binding exists : array index is in argument "resIndexArgId"
ShaderVariable arg;
RDCASSERT(GetShaderVariable(inst.args[resIndexArgId], opCode, dxOpCode, arg));
uint32_t arrayIndex = arg.value.u32v[0];
bool isSRV = (resRef->resourceBase.resClass == ResourceClass::SRV);
DescriptorCategory category = isSRV ? DescriptorCategory::ReadOnlyResource
: DescriptorCategory::ReadWriteResource;
result.SetBindIndex(ShaderBindIndex(category, resRef->resourceIndex, arrayIndex));
baseResource = result.name = baseResource;
}
else
{
RDCERR("Unhandled dynamic handle %s with invalid resIndexArgId", resName.c_str(),
resIndexArgId);
}
}
}
else
{
RDCERR("Base Resource not found %s", baseResource.c_str());
RDCERR("Unknown Base Resource %s", baseResource.c_str());
}
break;
}
case DXOp::CBufferLoadLegacy:
{
// CBufferLoadLegacy(handle,regIndex)
// Need to find the resource
rdcstr handleName = GetArgumentName(1);
const ResourceReference *resRef = GetResource(handleName);
if(!resRef)
break;
Id handleId = GetArgumentId(1);
ShaderVariable arg;
RDCASSERT(GetShaderVariable(inst.args[2], opCode, dxOpCode, arg));
uint32_t regIndex = arg.value.u32v[0];
Id handleId = GetArgumentId(1);
RDCASSERT(m_Live.contains(handleId));
auto itVar = m_LiveVariables.find(handleId);
RDCASSERT(itVar != m_LiveVariables.end());
@@ -3899,8 +3920,9 @@ bool ThreadState::GetShaderVariable(const DXIL::Value *dxilValue, Operation op,
bool ThreadState::GetVariable(const Id &id, Operation op, DXOp dxOpCode, ShaderVariable &var) const
{
RDCASSERT(m_Live.contains(id));
RDCASSERTEQUAL(m_LiveVariables.count(id), 1);
var = m_LiveVariables.at(id);
auto it = m_LiveVariables.find(id);
RDCASSERT(it != m_LiveVariables.end());
var = it->second;
bool flushDenorm = OperationFlushing(op, dxOpCode);
if(var.type == VarType::Double)
@@ -3934,39 +3956,32 @@ void ThreadState::SetResult(const Id &id, ShaderVariable &result, Operation op,
}
}
void ThreadState::MarkResourceAccess(const rdcstr &name, const DXIL::ResourceReference *resRef)
void ThreadState::MarkResourceAccess(const rdcstr &name, const ShaderBindIndex &bindIndex)
{
if(m_State == NULL)
return;
ResourceClass resClass = resRef->resourceBase.resClass;
if(resClass != ResourceClass::UAV && resClass != ResourceClass::SRV)
if(bindIndex.category != DescriptorCategory::ReadOnlyResource &&
bindIndex.category != DescriptorCategory::ReadWriteResource)
return;
bool isSRV = (resClass == ResourceClass::SRV);
bool isSRV = (bindIndex.category == DescriptorCategory::ReadOnlyResource);
m_State->changes.push_back(ShaderVariableChange());
ShaderVariableChange &change = m_State->changes.back();
change.after.rows = change.after.columns = 1;
change.after.type = isSRV ? VarType::ReadOnlyResource : VarType::ReadWriteResource;
const DXIL::EntryPointInterface::ResourceBase &resourceBase = resRef->resourceBase;
change.after.SetBindIndex(bindIndex);
// The resource name will already have the array index appended to it (perhaps unresolved)
change.after.name = name;
// TODO: find the array index
uint32_t arrayIdx = 0;
if(resourceBase.regCount > 1)
change.after.name += StringFormat::Fmt("[%u]", arrayIdx);
change.after.SetBindIndex(ShaderBindIndex(
isSRV ? DescriptorCategory::ReadOnlyResource : DescriptorCategory::ReadWriteResource,
resRef->resourceIndex, arrayIdx));
// Check whether this resource was visited before
bool found = false;
ShaderBindIndex bp = change.after.GetBindIndex();
rdcarray<ShaderBindIndex> &accessed = isSRV ? m_accessedSRVs : m_accessedUAVs;
for(size_t i = 0; i < accessed.size(); ++i)
{
if(accessed[i] == bp)
if(accessed[i] == bindIndex)
{
found = true;
break;
@@ -3976,7 +3991,7 @@ void ThreadState::MarkResourceAccess(const rdcstr &name, const DXIL::ResourceRef
if(found)
change.before = change.after;
else
accessed.push_back(bp);
accessed.push_back(bindIndex);
}
void ThreadState::AllocateMemoryForType(const DXIL::Type *type, Id allocId, ShaderVariable &var)
@@ -4030,8 +4045,8 @@ void ThreadState::UpdateMemoryVariableFromBackingMemory(Id memoryId, const void
void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups, Operation opCode,
DXOp dxOpCode, const DXIL::ResourceReference *resRef,
DebugAPIWrapper *apiWrapper, const DXIL::Instruction &inst,
ShaderVariable &result)
const ShaderBindIndex &bindIndex, DebugAPIWrapper *apiWrapper,
const DXIL::Instruction &inst, ShaderVariable &result)
{
// TextureLoad(srv,mipLevelOrSampleCount,coord0,coord1,coord2,offset0,offset1,offset2)
// Sample(srv,sampler,coord0,coord1,coord2,coord3,offset0,offset1,offset2,clamp)
@@ -4070,7 +4085,7 @@ void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups,
resourceData.sampleCount = srv.sampleCount;
resourceData.binding.registerSpace = resRef->resourceBase.space;
resourceData.binding.shaderRegister = resRef->resourceBase.regBase;
resourceData.binding.shaderRegister = resRef->resourceBase.regBase + bindIndex.arrayElement;
ShaderVariable uv;
int8_t texelOffsets[3] = {0, 0, 0};
@@ -4117,8 +4132,9 @@ void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups,
else
{
// Sampler is in arg 2
rdcstr samplerId = GetArgumentName(2);
const ResourceReference *samplerRef = GetResource(samplerId);
Id samplerId = GetArgumentId(2);
ShaderBindIndex samplerBindIndex;
const DXIL::ResourceReference *samplerRef = GetResource(samplerId, samplerBindIndex);
if(!samplerRef)
return;
@@ -4127,7 +4143,8 @@ void ThreadState::PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups,
const DXIL::EntryPointInterface::Sampler &sampler = samplerRef->resourceBase.samplerData;
samplerData.bias = 0.0f;
samplerData.binding.registerSpace = samplerRef->resourceBase.space;
samplerData.binding.shaderRegister = samplerRef->resourceBase.regBase;
samplerData.binding.shaderRegister =
samplerRef->resourceBase.regBase + samplerBindIndex.arrayElement;
samplerData.mode = ConvertSamplerKindToSamplerMode(sampler.samplerType);
int32_t biasArg = -1;
@@ -4304,23 +4321,30 @@ rdcstr ThreadState::GetArgumentName(uint32_t i) const
return m_Program.GetArgId(*m_CurrentInstruction, i);
}
Id ThreadState::GetArgumentId(uint32_t i) const
DXILDebug::Id ThreadState::GetArgumentId(uint32_t i) const
{
DXIL::Value *arg = m_CurrentInstruction->args[i];
return GetSSAId(arg);
}
const DXIL::ResourceReference *ThreadState::GetResource(rdcstr handle)
const DXIL::ResourceReference *ThreadState::GetResource(Id handleId, ShaderBindIndex &bindIndex)
{
const DXIL::ResourceReference *resRef = m_Program.GetResourceReference(handle);
if(resRef)
RDCASSERT(m_Live.contains(handleId));
auto it = m_LiveVariables.find(handleId);
if(it != m_LiveVariables.end())
{
rdcstr alias = m_Program.GetHandleAlias(handle);
MarkResourceAccess(alias, resRef);
return resRef;
const ShaderVariable &var = m_LiveVariables.at(handleId);
const DXIL::ResourceReference *resRef = m_Program.GetResourceReference(handleId);
if(resRef)
{
rdcstr alias = m_Program.GetHandleAlias(resRef->handleID);
bindIndex = var.GetBindIndex();
MarkResourceAccess(alias, bindIndex);
return resRef;
}
}
RDCERR("Unknown resource handle '%s'", handle.c_str());
RDCERR("Unknown resource handle %u", handleId);
return NULL;
}
@@ -5535,6 +5559,9 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain
for(uint32_t i = 0; i < list.resources.size(); i++)
{
const ShaderResource &res = list.resources[i];
// Ignore arrays the debugger execution will mark specific array elements used
if(res.bindArraySize > 1)
continue;
// Fetch the resource name
BindingSlot slot(res.fixedBindNumber, res.fixedBindSetOrSpace);
+4 -4
View File
@@ -146,12 +146,12 @@ struct ThreadState
bool Finished() const;
bool ExecuteInstruction(DebugAPIWrapper *apiWrapper, const rdcarray<ThreadState> &workgroups);
void MarkResourceAccess(const rdcstr &name, const DXIL::ResourceReference *resRef);
void MarkResourceAccess(const rdcstr &name, const ShaderBindIndex &bindIndex);
void SetResult(const Id &id, ShaderVariable &result, DXIL::Operation op, DXIL::DXOp dxOpCode,
ShaderEvents flags);
rdcstr GetArgumentName(uint32_t i) const;
Id GetArgumentId(uint32_t i) const;
const DXIL::ResourceReference *GetResource(rdcstr handle);
const DXIL::ResourceReference *GetResource(Id handleId, ShaderBindIndex &bindIndex);
bool GetShaderVariable(const DXIL::Value *dxilValue, DXIL::Operation op, DXIL::DXOp dxOpCode,
ShaderVariable &var, bool flushDenormInput = true) const;
bool GetVariable(const Id &id, DXIL::Operation opCode, DXIL::DXOp dxOpCode,
@@ -162,8 +162,8 @@ struct ThreadState
void PerformGPUResourceOp(const rdcarray<ThreadState> &workgroups, DXIL::Operation opCode,
DXIL::DXOp dxOpCode, const DXIL::ResourceReference *resRef,
DebugAPIWrapper *apiWrapper, const DXIL::Instruction &inst,
ShaderVariable &result);
const ShaderBindIndex &bindIndex, DebugAPIWrapper *apiWrapper,
const DXIL::Instruction &inst, ShaderVariable &result);
void Sub(const ShaderVariable &a, const ShaderVariable &b, ShaderValue &ret) const;
ShaderValue DDX(bool fine, DXIL::Operation opCode, DXIL::DXOp dxOpCode,
@@ -3189,6 +3189,7 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection)
}
rdcstr resultIdStr;
MakeResultId(inst, resultIdStr);
DXILDebug::Id resultId = GetResultSSAId(inst);
bool showDxFuncName = false;
rdcstr commentStr;
@@ -3299,7 +3300,7 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection)
nonUniformIndexArgId = 3;
}
const ResourceReference *resRef = GetResourceReference(resultIdStr);
const ResourceReference *resRef = GetResourceReference(resultId);
if(resRef)
{
uint32_t index = 0;
@@ -3534,8 +3535,9 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection)
{
// CBufferLoad(handle,byteOffset,alignment)
// CBufferLoadLegacy(handle,regIndex)
DXILDebug::Id handleId = GetSSAId(inst.args[1]);
const ResourceReference *resRef = GetResourceReference(handleId);
rdcstr handleStr = GetArgId(inst, 1);
const ResourceReference *resRef = GetResourceReference(handleStr);
bool useFallback = true;
if(entryPoint && resRef)
{
@@ -3683,8 +3685,9 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection)
case DXOp::TextureLoad:
{
// TextureLoad(srv,mipLevelOrSampleCount,coord0,coord1,coord2,offset0,offset1,offset2)
DXILDebug::Id handleId = GetSSAId(inst.args[1]);
const ResourceReference *resRef = GetResourceReference(handleId);
rdcstr handleStr = GetArgId(inst, 1);
const ResourceReference *resRef = GetResourceReference(handleStr);
uint32_t sampleCount = 0;
if(entryPoint && resRef)
{
@@ -4928,6 +4931,7 @@ void Program::ParseReferences(const DXBC::Reflection *reflection)
{
rdcstr resultIdStr;
MakeResultId(inst, resultIdStr);
DXILDebug::Id resultId = GetResultSSAId(inst);
DXOp dxOpCode = DXOp::NumOpCodes;
RDCASSERT(getival<DXOp>(inst.args[0], dxOpCode));
@@ -5085,9 +5089,9 @@ void Program::ParseReferences(const DXBC::Reflection *reflection)
if(resourceBase)
{
RDCASSERT(!GetResourceReference(resultIdStr));
RDCASSERT(!GetResourceReference(resultId));
ResourceReference resRef(resultIdStr, *resourceBase, resIndex);
m_ResourceHandles[resultIdStr] = m_ResourceHandles.size();
m_ResourceByIdHandles[resultId] = m_ResourceByIdHandles.size();
m_ResourceReferences.push_back(resRef);
resName = resourceBase->name;
uint32_t index = 0;
@@ -5137,13 +5141,14 @@ void Program::ParseReferences(const DXBC::Reflection *reflection)
// If the underlying handle points to a known resource then duplicate the resource
// and register it as resultIdStr
DXILDebug::Id handleId = GetSSAId(inst.args[1]);
const ResourceReference *resRef = GetResourceReference(handleId);
rdcstr baseResource = GetArgId(inst, 1);
const ResourceReference *resRef = GetResourceReference(baseResource);
rdcstr resBaseName = "typed_descriptor";
if(resRef)
{
resBaseName = resRef->resourceBase.name;
m_ResourceHandles[resultIdStr] = m_ResourceHandles.size();
m_ResourceByIdHandles[resultId] = m_ResourceByIdHandles.size();
m_ResourceReferences.push_back(*resRef);
}
uint32_t annotateHandleCount = m_ResourceAnnotateCounts[resBaseName];
@@ -2076,12 +2076,13 @@ void Program::GetLocals(const DXBC::DXBCContainer *dxbc, size_t instruction, uin
}
}
const ResourceReference *Program::GetResourceReference(const rdcstr &handleStr) const
const ResourceReference *Program::GetResourceReference(const DXILDebug::Id handleId) const
{
if(m_ResourceHandles.count(handleStr) > 0)
auto it = m_ResourceByIdHandles.find(handleId);
if(it != m_ResourceByIdHandles.end())
{
size_t resRefIndex = m_ResourceHandles.find(handleStr)->second;
if(resRefIndex < m_ResourceHandles.size())
size_t resRefIndex = it->second;
if(resRefIndex < m_ResourceReferences.size())
{
return &m_ResourceReferences[resRefIndex];
}