diff --git a/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp b/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp index d9647cf57..ce4d40550 100644 --- a/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_dxil_debug.cpp @@ -351,9 +351,10 @@ static void AddCBufferToGlobalState(const DXIL::Program *program, GlobalState &g : global.constantBlocks[i].members; RDCASSERTMSG("Reassigning previously filled cbuffer", targetVars.empty()); - global.constantBlocksData[i] = cbufData; - global.constantBlocks[i].name = - Debugger::GetResourceReferenceName(program, ResourceClass::CBuffer, slot); + ConstantBlockReference constantBlockRef = {i, arrayIndex}; + global.constantBlocksDatas[constantBlockRef] = cbufData; + rdcstr resName = Debugger::GetResourceReferenceName(program, ResourceClass::CBuffer, slot); + global.constantBlocks[i].name = resName; SourceVariableMapping cbSourceMapping; cbSourceMapping.name = refl.constantBlocks[i].name; diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.cpp b/renderdoc/driver/shaders/dxil/dxil_debug.cpp index a87aadaee..6bb494430 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_debug.cpp @@ -2201,6 +2201,7 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, { // AnnotateHandle(res,props) rdcstr baseResource = GetArgumentName(1); + Id baseResourceId = GetSSAId(inst.args[1]); ShaderVariable resource; RDCASSERT(GetShaderVariable(inst.args[1], opCode, dxOpCode, resource)); @@ -2210,7 +2211,6 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, resName = m_Program.GetHandleAlias(result.name); // 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); @@ -2264,6 +2264,20 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, uint32_t byteWidth = GetElementByteSize(compType); structStride = compCount * byteWidth; } + else if(resKind == ResourceKind::CBuffer) + { + // Create the cbuffer handle reference for the annotated handle + auto it = m_ConstantBlockHandles.find(baseResourceId); + if(it != m_ConstantBlockHandles.end()) + { + m_ConstantBlockHandles[resultId] = it->second; + } + else + { + RDCERR("Annotated handle resName:%s %s has no cbuffer handle reference %u", + resName.c_str(), baseResource.c_str(), baseResourceId); + } + } // Store the annotate properties for the result auto it = m_AnnotatedProperties.find(resultId); if(it == m_AnnotatedProperties.end()) @@ -2310,13 +2324,16 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, }; RDCASSERT(list); - rdcstr resName = m_Program.GetHandleAlias(baseResource); + rdcstr resName = Debugger::GetResourceBaseName(&m_Program, resRef); + const rdcarray &resources = *list; result.name.clear(); + size_t constantBlockIndex = ~0U; for(uint32_t i = 0; i < resources.size(); ++i) { if(resources[i].name == resName) { + constantBlockIndex = i; result = resources[i]; break; } @@ -2356,6 +2373,49 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, ToStr(resRef->resourceBase.resClass).c_str()); } } + else + { + if(resRef->resourceBase.resClass == ResourceClass::CBuffer) + { + uint32_t arrayIndex = 0; + // Look up the correct cbuffer variable for cbuffer arrays + if(resRef->resourceBase.regCount > 1) + { + if(resIndexArgId < inst.args.size()) + { + ShaderVariable arg; + RDCASSERT(GetShaderVariable(inst.args[resIndexArgId], opCode, dxOpCode, arg)); + arrayIndex = arg.value.u32v[0]; + RDCASSERT(arrayIndex >= resRef->resourceBase.regBase); + if(arrayIndex >= resRef->resourceBase.regBase) + { + arrayIndex -= resRef->resourceBase.regBase; + RDCASSERT(arrayIndex < result.members.size(), arrayIndex, + result.members.size()); + if(arrayIndex < result.members.size()) + { + RDCASSERT(!result.members[arrayIndex].members.empty()); + if(!result.members[arrayIndex].members.empty()) + { + rdcstr name = + StringFormat::Fmt("%s_%u_%u", result.name.c_str(), arrayIndex, 0); + result = result.members[arrayIndex].members[0]; + result.type = VarType::Float; + result.name = name; + } + } + } + } + else + { + RDCERR("Unhandled cbuffer handle %s with invalid resIndexArgId", + resName.c_str(), resIndexArgId); + } + } + // Create the cbuffer handle reference + m_ConstantBlockHandles[resultId] = {constantBlockIndex, arrayIndex}; + } + } } else { @@ -2384,46 +2444,46 @@ bool ThreadState::ExecuteInstruction(DebugAPIWrapper *apiWrapper, RDCASSERT(m_Live[handleId]); RDCASSERT(IsVariableAssigned(handleId)); - const ShaderVariable &cbufferVar = itVar->second; - // Find the cbuffer index in the global state (matching by name) - uint32_t cbufferIndex = ~0U; - for(uint32_t i = 0; i < m_GlobalState.constantBlocks.size(); ++i) - { - if(m_GlobalState.constantBlocks[i].name == cbufferVar.name) - { - cbufferIndex = i; - break; - } - } result.value.u32v[0] = 0; result.value.u32v[1] = 0; result.value.u32v[2] = 0; result.value.u32v[3] = 0; - if(cbufferIndex != ~0U) + auto constantBlockRefIt = m_ConstantBlockHandles.find(handleId); + if(constantBlockRefIt != m_ConstantBlockHandles.end()) { - const bytebuf &cbufferData = m_GlobalState.constantBlocksData[cbufferIndex]; - const uint32_t bufferSize = (uint32_t)cbufferData.size(); - const uint32_t maxIndex = AlignUp16(bufferSize) / 16; - RDCASSERTMSG("Out of bounds cbuffer load", regIndex < maxIndex, regIndex, maxIndex); - if(regIndex < maxIndex) + const ConstantBlockReference &constantBlockRef = constantBlockRefIt->second; + auto it = m_GlobalState.constantBlocksDatas.find(constantBlockRef); + if(it != m_GlobalState.constantBlocksDatas.end()) { - const uint32_t dataOffset = regIndex * 16; - const uint32_t byteWidth = 4; - const byte *data = cbufferData.data() + dataOffset; - const uint32_t numComps = RDCMIN(4U, (bufferSize - dataOffset) / byteWidth); - GlobalState::ViewFmt cbufferFmt; - cbufferFmt.byteWidth = byteWidth; - cbufferFmt.numComps = numComps; - cbufferFmt.compType = CompType::Float; - cbufferFmt.stride = 16; + const bytebuf &cbufferData = it->second; + const uint32_t bufferSize = (uint32_t)cbufferData.size(); + const uint32_t maxIndex = AlignUp16(bufferSize) / 16; + RDCASSERTMSG("Out of bounds cbuffer load", regIndex < maxIndex, regIndex, maxIndex); + if(regIndex < maxIndex) + { + const uint32_t dataOffset = regIndex * 16; + const uint32_t byteWidth = 4; + const byte *data = cbufferData.data() + dataOffset; + const uint32_t numComps = RDCMIN(4U, (bufferSize - dataOffset) / byteWidth); + GlobalState::ViewFmt cbufferFmt; + cbufferFmt.byteWidth = byteWidth; + cbufferFmt.numComps = numComps; + cbufferFmt.compType = CompType::Float; + cbufferFmt.stride = 16; - result.value = TypedUAVLoad(cbufferFmt, data); + result.value = TypedUAVLoad(cbufferFmt, data); + } + } + else + { + RDCERR("Failed to find data for constant block data for %s", + itVar->second.name.c_str()); } } else { - RDCERR("Failed to find data for cbuffer %s", cbufferVar.name.c_str()); + RDCERR("Failed to find data for cbuffer %s", itVar->second.name.c_str()); } // DXIL will create a vector of a single type with total size of 16-bytes @@ -6326,6 +6386,22 @@ Debugger::DebugInfo::~DebugInfo() scopedDebugDatas.clear(); } +// static helper function +rdcstr Debugger::GetResourceBaseName(const DXIL::Program *program, + const DXIL::ResourceReference *resRef) +{ + rdcstr resName = program->GetHandleAlias(resRef->handleID); + // Special case for cbuffer arrays + if((resRef->resourceBase.resClass == ResourceClass::CBuffer) && (resRef->resourceBase.regCount > 1)) + { + // Remove any array suffix that might have been appended to the resource name + int offs = resName.find('['); + if(offs > 0) + resName = resName.substr(0, offs); + } + return resName; +} + // static helper function rdcstr Debugger::GetResourceReferenceName(const DXIL::Program *program, DXIL::ResourceClass resClass, const BindingSlot &slot) @@ -6342,7 +6418,7 @@ rdcstr Debugger::GetResourceReferenceName(const DXIL::Program *program, if(resRef.resourceBase.regBase + resRef.resourceBase.regCount <= slot.shaderRegister) continue; - return program->GetHandleAlias(resRef.handleID); + return GetResourceBaseName(program, &resRef); } RDCERR("Failed to find DXIL %s Resource Space %d Register %d", ToStr(resClass).c_str(), slot.registerSpace, slot.shaderRegister); @@ -7592,7 +7668,6 @@ ShaderDebugTrace *Debugger::BeginDebug(uint32_t eventId, const DXBC::DXBCContain // The constant buffer data and details are filled in outside of this method size_t count = reflection.constantBlocks.size(); m_GlobalState.constantBlocks.resize(count); - m_GlobalState.constantBlocksData.resize(count); for(uint32_t i = 0; i < count; i++) { m_GlobalState.constantBlocks[i].type = VarType::ConstantBlock; diff --git a/renderdoc/driver/shaders/dxil/dxil_debug.h b/renderdoc/driver/shaders/dxil/dxil_debug.h index 265785c8c..6e45d083b 100644 --- a/renderdoc/driver/shaders/dxil/dxil_debug.h +++ b/renderdoc/driver/shaders/dxil/dxil_debug.h @@ -152,6 +152,19 @@ struct ResourceReferenceInfo }; }; +struct ConstantBlockReference +{ + size_t constantBlockIndex; + size_t arrayIndex; + + bool operator<(const ConstantBlockReference &other) const + { + if(constantBlockIndex != other.constantBlockIndex) + return constantBlockIndex < other.constantBlockIndex; + return arrayIndex < other.arrayIndex; + } +}; + class DebugAPIWrapper { public: @@ -317,6 +330,8 @@ struct ThreadState std::map m_AnnotatedProperties; // ResourceReferenceInfo for any direct heap access bindings created using createHandleFromHeap std::map m_DirectHeapAccessBindings; + // ConstantBlock information associated with a handle + std::map m_ConstantBlockHandles; const FunctionInfo *m_FunctionInfo = NULL; DXBC::ShaderType m_ShaderType; @@ -415,7 +430,7 @@ struct GlobalState // allocated storage for opaque uniform blocks, does not change over the course of debugging rdcarray constantBlocks; - rdcarray constantBlocksData; + std::map constantBlocksDatas; // resources may be read-write but the variable itself doesn't change rdcarray readOnlyResources; @@ -562,6 +577,8 @@ public: const rdcarray &GetLiveGlobals() { return m_LiveGlobals; } static rdcstr GetResourceReferenceName(const DXIL::Program *program, DXIL::ResourceClass resClass, const BindingSlot &slot); + static rdcstr GetResourceBaseName(const DXIL::Program *program, + const DXIL::ResourceReference *resRef); const DXIL::Program &GetProgram() const { return *m_Program; } uint32_t GetEventId() { return m_EventId; } const FunctionInfo *GetFunctionInfo(const DXIL::Function *function) const;