RD DXIL Disassembly support for "CreateHandleFromBinding"

This commit is contained in:
Jake Turner
2024-05-27 17:01:24 +01:00
parent 10be601839
commit e84eed56ff
2 changed files with 176 additions and 49 deletions
@@ -1419,6 +1419,16 @@ struct EntryPointInterface
struct ResourceBase
{
ResourceBase(ResourceClass resourceClass, const Metadata *resourceBase);
bool MatchesBinding(uint32_t lowerBound, uint32_t upperBound, uint32_t spaceID) const
{
if(space != spaceID)
return false;
if(regBase > lowerBound)
return false;
if(regBase + regCount <= upperBound)
return false;
return true;
}
uint32_t id;
const Type *type;
rdcstr name;
@@ -3043,16 +3043,24 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection)
lineStr += "<OUT>." + name + rowStr + "." + componentStr;
lineStr += " = " + ArgToString(inst.args[4], false);
}
else if(dxOpCode == DXOp::CreateHandle)
else if((dxOpCode == DXOp::CreateHandle) || (dxOpCode == DXOp::CreateHandleFromBinding))
{
// CreateHandle(resourceClass,rangeId,index,nonUniformIndex)
showDxFuncName = false;
uint32_t resIndexArgId = 3;
uint32_t nonUniformIndexArgId = 4;
if(dxOpCode == DXOp::CreateHandleFromBinding)
{
resIndexArgId = 2;
nonUniformIndexArgId = 3;
}
const ResourceReference *resRef = GetResourceReference(resultIdStr);
if(resRef)
{
uint32_t index = 0;
if(getival<uint32_t>(inst.args[3], index))
if(getival<uint32_t>(inst.args[resIndexArgId], index))
{
if(index != resRef->resourceIndex)
commentStr += " index = " + ToStr(index);
@@ -3060,10 +3068,10 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection)
}
else
{
commentStr += " index = " + ArgToString(inst.args[3], false);
commentStr += " index = " + ArgToString(inst.args[resIndexArgId], false);
}
uint32_t value;
if(getival<uint32_t>(inst.args[4], value))
if(getival<uint32_t>(inst.args[nonUniformIndexArgId], value))
{
if(value != 0)
commentStr += " nonUniformIndex = true";
@@ -4645,58 +4653,158 @@ void Program::ParseReferences(const DXBC::Reflection *reflection)
{
DXOp dxOpCode;
RDCASSERT(getival<DXOp>(inst.args[0], dxOpCode));
if(dxOpCode == DXOp::CreateHandle)
if((dxOpCode == DXOp::CreateHandle) || (dxOpCode == DXOp::CreateHandleFromBinding))
{
// CreateHandle(resourceClass,rangeId,index,nonUniformIndex)
// CreateHandleFromBinding(bind,index,nonUniformIndex)
uint32_t resIndexArgId = 3;
uint32_t nonUniformIndexArgId = 4;
bool validBinding = false;
EntryPointInterface::ResourceBase *resourceBase = NULL;
rdcstr resName;
ResourceClass resClass;
uint32_t resIndex;
if(getival<ResourceClass>(inst.args[1], resClass) &&
getival<uint32_t>(inst.args[2], resIndex))
uint32_t resIndex = 0;
if(dxOpCode == DXOp::CreateHandle)
{
EntryPointInterface::ResourceBase *resourceBase = NULL;
switch(resClass)
ResourceClass resClass;
validBinding = getival<ResourceClass>(inst.args[1], resClass) &&
getival<uint32_t>(inst.args[2], resIndex);
if(validBinding)
{
case ResourceClass::SRV: resourceBase = &entryPoint->srvs[resIndex]; break;
case ResourceClass::UAV: resourceBase = &entryPoint->uavs[resIndex]; break;
case ResourceClass::CBuffer:
resourceBase = &entryPoint->cbuffers[resIndex];
break;
case ResourceClass::Sampler:
resourceBase = &entryPoint->samplers[resIndex];
break;
default: break;
};
if(resourceBase)
switch(resClass)
{
case ResourceClass::SRV: resourceBase = &entryPoint->srvs[resIndex]; break;
case ResourceClass::UAV: resourceBase = &entryPoint->uavs[resIndex]; break;
case ResourceClass::CBuffer:
resourceBase = &entryPoint->cbuffers[resIndex];
break;
case ResourceClass::Sampler:
resourceBase = &entryPoint->samplers[resIndex];
break;
default: break;
};
}
else
{
RDCASSERT(!GetResourceReference(resultIdStr));
ResourceReference resRef(resultIdStr, *resourceBase, resIndex);
m_ResourceHandles[resultIdStr] = m_ResourceHandles.size();
m_ResourceReferences.push_back(resRef);
resName = resourceBase->name;
uint32_t index = 0;
if(getival<uint32_t>(inst.args[3], index))
{
if(index != resIndex)
{
if(resourceBase->regCount > 1)
resName += StringFormat::Fmt("[%u]", index);
}
}
else
{
if(resourceBase->regCount > 1)
resName += "[" + ArgToString(inst.args[3], false) + "]";
}
resName = "ResourceClass:" + ArgToString(inst.args[1], false);
resName += "[" + ArgToString(inst.args[2], false) + "]";
resName += "[" + ArgToString(inst.args[resIndexArgId], false) + "]";
}
}
else
{
resName = "ResourceClass:" + ArgToString(inst.args[1], false);
resName += "[" + ArgToString(inst.args[2], false) + "]";
resName += "[" + ArgToString(inst.args[3], false) + "]";
resIndexArgId = 2;
nonUniformIndexArgId = 3;
if(const Constant *props = cast<Constant>(inst.args[1]))
{
if(props && !props->isNULL() && props->getMembers().size() >= 4)
{
const rdcarray<Value *> &members = props->getMembers();
uint32_t lowerBound;
uint32_t upperBound;
uint32_t spaceID;
ResourceClass resClass;
validBinding = getival<uint32_t>(members[0], lowerBound);
validBinding &= getival<uint32_t>(members[1], upperBound);
validBinding &= getival<uint32_t>(members[2], spaceID);
validBinding &= getival<ResourceClass>(members[3], resClass);
// Search through the resources to find the binding
if(validBinding)
{
switch(resClass)
{
case ResourceClass::SRV:
{
for(uint32_t r = 0; r < entryPoint->srvs.size(); ++r)
{
EntryPointInterface::ResourceBase *res = &entryPoint->srvs[r];
if(res->MatchesBinding(lowerBound, upperBound, spaceID))
{
resIndex = r;
resourceBase = res;
break;
}
}
break;
}
case ResourceClass::UAV:
{
for(uint32_t r = 0; r < entryPoint->uavs.size(); ++r)
{
EntryPointInterface::ResourceBase *res = &entryPoint->uavs[r];
if(res->MatchesBinding(lowerBound, upperBound, spaceID))
{
resIndex = r;
resourceBase = res;
break;
}
}
break;
}
case ResourceClass::CBuffer:
{
for(uint32_t r = 0; r < entryPoint->cbuffers.size(); ++r)
{
EntryPointInterface::ResourceBase *res = &entryPoint->cbuffers[r];
if(res->MatchesBinding(lowerBound, upperBound, spaceID))
{
resIndex = r;
resourceBase = res;
break;
}
}
break;
}
case ResourceClass::Sampler:
{
for(uint32_t r = 0; r < entryPoint->samplers.size(); ++r)
{
EntryPointInterface::ResourceBase *res = &entryPoint->samplers[r];
if(res->MatchesBinding(lowerBound, upperBound, spaceID))
{
resIndex = r;
resourceBase = res;
break;
}
}
break;
default: break;
}
}
if(!resourceBase)
{
resName = "ResourceClass:" + ArgToString(inst.args[1], false);
resName += "[" + ArgToString(inst.args[2], false) + "]";
resName += "[" + ArgToString(inst.args[resIndexArgId], false) + "]";
}
}
}
}
}
m_SsaAliases[resultIdStr] = resName;
if(resourceBase)
{
RDCASSERT(!GetResourceReference(resultIdStr));
ResourceReference resRef(resultIdStr, *resourceBase, resIndex);
m_ResourceHandles[resultIdStr] = m_ResourceHandles.size();
m_ResourceReferences.push_back(resRef);
resName = resourceBase->name;
uint32_t index = 0;
if(getival<uint32_t>(inst.args[resIndexArgId], index))
{
if(index != resIndex)
{
if(resourceBase->regCount > 1)
resName += StringFormat::Fmt("[%u]", index);
}
}
else
{
if(resourceBase->regCount > 1)
resName += "[" + ArgToString(inst.args[resIndexArgId], false) + "]";
}
}
if(!resName.isEmpty())
m_SsaAliases[resultIdStr] = resName;
}
else if(dxOpCode == DXOp::CreateHandleFromHeap)
{
@@ -4720,6 +4828,15 @@ void Program::ParseReferences(const DXBC::Reflection *reflection)
rdcstr resName = "__heap_descriptor_" + ToStr(heapDescriptorResourceCount);
heapDescriptorResourceCount += 1;
m_SsaAliases[resultIdStr] = resName;
// If the underlying handle points to a known resource then duplicate the resource and
// register it as resultIdStr
rdcstr baseResource = ArgToString(inst.args[1], false);
const ResourceReference *resRef = GetResourceReference(baseResource);
if(resRef)
{
m_ResourceHandles[resultIdStr] = m_ResourceHandles.size();
m_ResourceReferences.push_back(*resRef);
}
}
}
}
@@ -5018,8 +5135,8 @@ static void floatAppendToString(const Type *t, const ShaderValue &val, uint32_t
rdcstr flt = StringFormat::Fmt("%.6le", d);
#if ENABLED(DXC_COMPATIBLE_DISASM)
// dxc/llvm only prints floats as floats if they roundtrip, but our disassembly doesn't need
// to roundtrip so it's better to display the value in all cases
// dxc/llvm only prints floats as floats if they roundtrip, but our disassembly doesn't
// need to roundtrip so it's better to display the value in all cases
double reparse = strtod(flt.begin(), NULL);
if(d == reparse)
@@ -5408,8 +5525,8 @@ rdcstr DoStringise(const DXIL::Attribute &el)
{
STRINGISE_BITFIELD_CLASS_VALUE_NAMED(None, "");
// these bits are ordered not in declaration order (which matches how they're serialised) but in
// the (mostly but not quite) alphabetical order since that's how LLVM prints them
// these bits are ordered not in declaration order (which matches how they're serialised) but
// in the (mostly but not quite) alphabetical order since that's how LLVM prints them
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Alignment, "alignment");
STRINGISE_BITFIELD_CLASS_BIT_NAMED(AlwaysInline, "alwaysinline");
STRINGISE_BITFIELD_CLASS_BIT_NAMED(Builtin, "builtin");