Skip to content

Commit

Permalink
DXIL Debugger support for CreateHandleFromHeap
Browse files Browse the repository at this point in the history
  • Loading branch information
Zorro666 committed Dec 4, 2024
1 parent 11870b1 commit c2f752a
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 89 deletions.
243 changes: 158 additions & 85 deletions renderdoc/driver/shaders/dxil/dxil_debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2110,19 +2110,126 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
}
break;
}
case DXOp::CreateHandleFromHeap:
{
// CreateHandleFromHeap(index,samplerHeap,nonUniformIndex)
// Make the ShaderVariable to represent the direct heap access binding
ShaderVariable arg;
RDCASSERT(GetShaderVariable(inst.args[1], opCode, dxOpCode, arg));
uint32_t descriptorIndex = arg.value.u32v[0];
RDCASSERT(GetShaderVariable(inst.args[2], opCode, dxOpCode, arg));
bool samplerHeap = arg.value.u32v[0] != 0;
HeapDescriptorType heapType =
samplerHeap ? HeapDescriptorType::Sampler : HeapDescriptorType::CBV_SRV_UAV;

// convert the direct heap access binding into ResourceReferenceIndo
BindingSlot slot(heapType, descriptorIndex);
ResourceReferenceInfo resRefInfo = apiWrapper->GetResourceReferenceInfo(slot);
RDCASSERT(m_DirectHeapAccessBindings.count(resultId) == 0);
m_DirectHeapAccessBindings[resultId] = resRefInfo;

ShaderDirectAccess access = apiWrapper->GetShaderDirectAccess(resRefInfo.category, slot);
// Default to unannotated handle
ClearAnnotatedHandle(result);
rdcstr resName = m_Program.GetHandleAlias(result.name);
result.type = resRefInfo.type;
result.name = resName;
result.SetDirectAccess(access);
break;
}
case DXOp::AnnotateHandle:
{
// AnnotateHandle(res,props)
// Do not record changes for annotate handle
recordChange = false;
rdcstr baseResource = GetArgumentName(1);

ShaderVariable resource;
RDCASSERT(GetShaderVariable(inst.args[1], opCode, dxOpCode, resource));
rdcstr resName;
if(resource.IsDirectAccess())
{
resName = m_Program.GetHandleAlias(result.name);
result = resource;
// Update m_DirectHeapAccessBindings for the annotated handle
// to use the data from the source resource
Id baseResourceId = GetSSAId(inst.args[1]);
RDCASSERT(m_DirectHeapAccessBindings.count(baseResourceId) > 0);
RDCASSERT(m_DirectHeapAccessBindings.count(resultId) == 0);
m_DirectHeapAccessBindings[resultId] = m_DirectHeapAccessBindings.at(baseResourceId);
}
else
{
resName = m_Program.GetHandleAlias(baseResource);
result = resource;
}
result.name = resName;

// Parse the packed annotate handle properties
// resKind : {compType, compCount} | {structStride}
ShaderVariable props;
RDCASSERT(GetShaderVariable(inst.args[2], opCode, dxOpCode, props));
uint32_t packedProps[2] = {};
packedProps[0] = props.members[0].value.u32v[0];
packedProps[1] = props.members[1].value.u32v[0];
bool uav = (packedProps[0] & (1 << 12)) != 0;
ResourceKind resKind = (ResourceKind)(packedProps[0] & 0xFF);
ResourceClass resClass;
if(resKind == ResourceKind::Sampler)
resClass = ResourceClass::Sampler;
else if(resKind == ResourceKind::CBuffer)
resClass = ResourceClass::CBuffer;
else if(uav)
resClass = ResourceClass::UAV;
else
resClass = ResourceClass::SRV;

// Set as an annotated handle
SetAnnotatedHandle(result);

uint32_t structStride = 0;
if((resKind == ResourceKind::StructuredBuffer) ||
(resKind == ResourceKind::StructuredBufferWithCounter))
{
structStride = packedProps[1];
}
else if(resKind == ResourceKind::Texture1D || resKind == ResourceKind::Texture2D ||
resKind == ResourceKind::Texture3D || resKind == ResourceKind::TextureCube ||
resKind == ResourceKind::Texture1DArray ||
resKind == ResourceKind::Texture2DArray ||
resKind == ResourceKind::TextureCubeArray ||
resKind == ResourceKind::TypedBuffer || resKind == ResourceKind::Texture2DMS ||
resKind == ResourceKind::Texture2DMSArray)
{
ComponentType dxilCompType = ComponentType(packedProps[1] & 0xFF);
VarType compType = VarTypeForComponentType(dxilCompType);
uint32_t compCount = (packedProps[1] & 0xFF00) >> 8;
uint32_t byteWidth = GetElementByteSize(compType);
structStride = compCount * byteWidth;
}
// Store the annotate properties for the result
auto it = m_AnnotatedProperties.find(resultId);
if(it == m_AnnotatedProperties.end())
{
m_AnnotatedProperties[resultId] = {resKind, resClass, structStride};
}
else
{
const AnnotationProperties &existingProps = it->second;
RDCASSERTEQUAL(existingProps.resKind, resKind);
RDCASSERTEQUAL(existingProps.resClass, resClass);
RDCASSERTEQUAL(existingProps.structStride, structStride);
}
break;
}
case DXOp::CreateHandle:
case DXOp::CreateHandleFromBinding:
{
// AnnotateHandle(res,props)
// CreateHandle(resourceClass,rangeId,index,nonUniformIndex
// 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)
if(dxOpCode == DXOp::CreateHandle)
resIndexArgId = 3;
else if(dxOpCode == DXOp::CreateHandleFromBinding)
resIndexArgId = 2;
Expand All @@ -2132,6 +2239,8 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
const ResourceReference *resRef = m_Program.GetResourceReference(resultId);
if(resRef)
{
// Do not record the change if the resource is already known
recordChange = false;
const rdcarray<ShaderVariable> *list = NULL;
// a static known handle which should be in the global resources container
switch(resRef->resourceBase.resClass)
Expand All @@ -2157,7 +2266,6 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
break;
}
}
recordChange = false;
if(result.name.isEmpty())
{
if((resRef->resourceBase.resClass == ResourceClass::SRV) ||
Expand Down Expand Up @@ -2190,68 +2298,6 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
ToStr(resRef->resourceBase.resClass).c_str());
}
}

// Parse the packed annotate handle properties
// resKind : {compType, compCount} | {structStride}
if(dxOpCode == DXOp::AnnotateHandle)
{
// Set as an annotated handle
if((resRef->resourceBase.resClass == ResourceClass::SRV) ||
(resRef->resourceBase.resClass == ResourceClass::UAV))
{
SetAnnotatedHandle(result);
}
ShaderVariable props;
RDCASSERT(GetShaderVariable(inst.args[2], opCode, dxOpCode, props));
uint32_t packedProps[2] = {};
packedProps[0] = props.members[0].value.u32v[0];
packedProps[1] = props.members[1].value.u32v[0];
bool uav = (packedProps[0] & (1 << 12)) != 0;
ResourceKind resKind = (ResourceKind)(packedProps[0] & 0xFF);
ResourceClass resClass;
if(resKind == ResourceKind::Sampler)
resClass = ResourceClass::Sampler;
else if(resKind == ResourceKind::CBuffer)
resClass = ResourceClass::CBuffer;
else if(uav)
resClass = ResourceClass::UAV;
else
resClass = ResourceClass::SRV;

uint32_t structStride = 0;
if((resKind == ResourceKind::StructuredBuffer) ||
(resKind == ResourceKind::StructuredBufferWithCounter))
{
structStride = packedProps[1];
}
else if(resKind == ResourceKind::Texture1D || resKind == ResourceKind::Texture2D ||
resKind == ResourceKind::Texture3D || resKind == ResourceKind::TextureCube ||
resKind == ResourceKind::Texture1DArray ||
resKind == ResourceKind::Texture2DArray ||
resKind == ResourceKind::TextureCubeArray ||
resKind == ResourceKind::TypedBuffer || resKind == ResourceKind::Texture2DMS ||
resKind == ResourceKind::Texture2DMSArray)
{
ComponentType dxilCompType = ComponentType(packedProps[1] & 0xFF);
VarType compType = VarTypeForComponentType(dxilCompType);
uint32_t compCount = (packedProps[1] & 0xFF00) >> 8;
uint32_t byteWidth = GetElementByteSize(compType);
structStride = compCount * byteWidth;
}
// Store the annotate properties for the result
auto it = m_AnnotatedProperties.find(resultId);
if(it == m_AnnotatedProperties.end())
{
m_AnnotatedProperties[resultId] = {resKind, resClass, structStride};
}
else
{
const AnnotationProperties &existingProps = it->second;
RDCASSERTEQUAL(existingProps.resKind, resKind);
RDCASSERTEQUAL(existingProps.resClass, resClass);
RDCASSERTEQUAL(existingProps.structStride, structStride);
}
}
}
else
{
Expand Down Expand Up @@ -2776,7 +2822,6 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper,
break;
}
// Likely to implement when required
case DXOp::CreateHandleFromHeap:
case DXOp::UAddc:
case DXOp::USubb:
case DXOp::Fma:
Expand Down Expand Up @@ -4476,32 +4521,37 @@ void ThreadState::SetResult(const Id &id, ShaderVariable &result, Operation op,
}
}

void ThreadState::MarkResourceAccess(const rdcstr &name, const ShaderBindIndex &bindIndex)
void ThreadState::MarkResourceAccess(const rdcstr &name, const ResourceReferenceInfo &resRefInfo,
bool directAccess, const ShaderDirectAccess &access,
const ShaderBindIndex &bindIndex)
{
if(m_State == NULL)
return;

if(bindIndex.category != DescriptorCategory::ReadOnlyResource &&
bindIndex.category != DescriptorCategory::ReadWriteResource)
if(resRefInfo.category != DescriptorCategory::ReadOnlyResource &&
resRefInfo.category != DescriptorCategory::ReadWriteResource)
return;

bool isSRV = (bindIndex.category == DescriptorCategory::ReadOnlyResource);
bool isSRV = (resRefInfo.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;
change.after.SetBindIndex(bindIndex);
change.after.type = resRefInfo.type;
if(!directAccess)
change.after.SetBindIndex(bindIndex);
else
change.after.SetDirectAccess(access);
// The resource name will already have the array index appended to it (perhaps unresolved)
change.after.name = name;

// Check whether this resource was visited before
bool found = false;
rdcarray<ShaderBindIndex> &accessed = isSRV ? m_accessedSRVs : m_accessedUAVs;
rdcarray<BindingSlot> &accessed = isSRV ? m_accessedSRVs : m_accessedUAVs;
for(size_t i = 0; i < accessed.size(); ++i)
{
if(accessed[i] == bindIndex)
if(accessed[i] == resRefInfo.binding)
{
found = true;
break;
Expand All @@ -4511,7 +4561,7 @@ void ThreadState::MarkResourceAccess(const rdcstr &name, const ShaderBindIndex &
if(found)
change.before = change.after;
else
accessed.push_back(bindIndex);
accessed.push_back(resRefInfo.binding);
}

void ThreadState::UpdateBackingMemoryFromVariable(void *ptr, size_t &allocSize,
Expand Down Expand Up @@ -4862,18 +4912,41 @@ ResourceReferenceInfo ThreadState::GetResource(Id handleId, bool &annotatedHandl
if(it != m_Variables.end())
{
const ShaderVariable &var = m_Variables.at(handleId);
ShaderBindIndex bindIndex = var.GetBindIndex();
bool directAccess = var.IsDirectAccess();
ShaderBindIndex bindIndex;
ShaderDirectAccess access;
annotatedHandle = IsAnnotatedHandle(var);
RDCASSERT(!annotatedHandle || (m_AnnotatedProperties.count(handleId) == 1));
const DXIL::ResourceReference *resRef = NULL;
rdcstr alias = var.name;
resRef = m_Program.GetResourceReference(handleId);
if(resRef)
if(!directAccess)
{
alias = m_Program.GetHandleAlias(resRef->handleID);
resRefInfo.Create(resRef, bindIndex.arrayElement);
bindIndex = var.GetBindIndex();
const ResourceReference *resRef = m_Program.GetResourceReference(handleId);
if(resRef)
{
alias = m_Program.GetHandleAlias(resRef->handleID);
resRefInfo.Create(resRef, bindIndex.arrayElement);
}
else
{
RDCERR("Shader binding not found for handle %d", handleId);
return resRefInfo;
}
}
else
{
access = var.GetDirectAccess();
// Direct heap access bindings must be annotated
RDCASSERT(annotatedHandle);
auto directHeapAccessBinding = m_DirectHeapAccessBindings.find(handleId);
if(directHeapAccessBinding == m_DirectHeapAccessBindings.end())
{
RDCERR("Direct heap access binding not found for handle %d", handleId);
return resRefInfo;
}
resRefInfo = directHeapAccessBinding->second;
}
MarkResourceAccess(alias, bindIndex);
MarkResourceAccess(alias, resRefInfo, directAccess, access, bindIndex);
return resRefInfo;
}

Expand Down
10 changes: 7 additions & 3 deletions renderdoc/driver/shaders/dxil/dxil_debug.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,9 @@ struct ThreadState

bool ExecuteInstruction(DebugAPIWrapper *apiWrapper, const rdcarray<ThreadState> &workgroups);

void MarkResourceAccess(const rdcstr &name, const ShaderBindIndex &bindIndex);
void MarkResourceAccess(const rdcstr &name, const ResourceReferenceInfo &resRefInfo,
bool directAccess, const ShaderDirectAccess &access,
const ShaderBindIndex &bindIndex);
void SetResult(const Id &id, ShaderVariable &result, DXIL::Operation op, DXIL::DXOp dxOpCode,
ShaderEvents flags);
rdcstr GetArgumentName(uint32_t i) const;
Expand Down Expand Up @@ -286,6 +288,8 @@ struct ThreadState
rdcarray<Id> m_Dormant;
// Annotated handle properties
std::map<Id, AnnotationProperties> m_AnnotatedProperties;
// ResourceReferenceInfo for any direct heap access bindings created using createHandleFromHeap
std::map<Id, ResourceReferenceInfo> m_DirectHeapAccessBindings;

const FunctionInfo *m_FunctionInfo = NULL;
DXBC::ShaderType m_ShaderType;
Expand All @@ -305,8 +309,8 @@ struct ThreadState
// The PC of the active instruction that was or will be executed on the current simulation step
uint32_t m_ActiveGlobalInstructionIdx = ~0U;

rdcarray<ShaderBindIndex> m_accessedSRVs;
rdcarray<ShaderBindIndex> m_accessedUAVs;
rdcarray<BindingSlot> m_accessedSRVs;
rdcarray<BindingSlot> m_accessedUAVs;

// index in the pixel quad
uint32_t m_WorkgroupIndex = ~0U;
Expand Down
1 change: 0 additions & 1 deletion renderdoc/driver/shaders/dxil/dxil_reflect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1956,7 +1956,6 @@ rdcstr Program::GetDebugStatus()
case DXOp::GeometryIndex:
case DXOp::RayQuery_CandidateInstanceContributionToHitGroupIndex:
case DXOp::RayQuery_CommittedInstanceContributionToHitGroupIndex:
case DXOp::CreateHandleFromHeap:
case DXOp::Unpack4x8:
case DXOp::Pack4x8:
case DXOp::IsHelperLane:
Expand Down

0 comments on commit c2f752a

Please sign in to comment.