From 99e10f24c70edb2d955d2886d07edcd97534bac9 Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Mon, 29 Apr 2024 10:56:31 +0100 Subject: [PATCH] RD DXIL Disassembly: decode "dx.op.cbufferLoad*" to show members CBuffer[0] blah Space: 0 Reg: 0 Count: 1 { int4 mult; }; Example Output _dx.types.CBufRet.i32 %1 = CBufferLoadLegacy(%blah_cbuffer, 0); becomes _dx.types.CBufRet.i32 _1 = {blah.mult}; --- renderdoc/driver/shaders/dxil/dxil_bytecode.h | 1 + .../driver/shaders/dxil/dxil_disassemble.cpp | 157 +++++++++++++++--- .../driver/shaders/dxil/dxil_reflect.cpp | 1 + 3 files changed, 139 insertions(+), 20 deletions(-) diff --git a/renderdoc/driver/shaders/dxil/dxil_bytecode.h b/renderdoc/driver/shaders/dxil/dxil_bytecode.h index 96c38b36a..aea1cfbef 100644 --- a/renderdoc/driver/shaders/dxil/dxil_bytecode.h +++ b/renderdoc/driver/shaders/dxil/dxil_bytecode.h @@ -1198,6 +1198,7 @@ struct EntryPointInterface CBuffer(const Metadata *cbuffer); uint32_t sizeInBytes; bool isTBuffer; + const DXBC::CBuffer *cbufferRefl; }; struct Sampler : ResourceBase diff --git a/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp b/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp index 73212b3d6..66a6d78cc 100644 --- a/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_disassemble.cpp @@ -78,9 +78,15 @@ rdcstr escapeStringIfNeeded(const rdcstr &name) template T getival(const Value *v) { - const Constant *c = cast(v); - if(c && c->isLiteral()) - return T(c->getU32()); + if(const Constant *c = cast(v)) + { + if(c->isLiteral()) + return T(c->getU64()); + } + else if(const Literal *lit = cast(v)) + { + return T(lit->literal); + } return T(); } @@ -2176,6 +2182,94 @@ void Program::MakeDXCDisassemblyString() m_Disassembly += "\n"; } +static const DXBC::CBufferVariable *FindCBufferVar(const uint32_t minOffset, const uint32_t maxOffset, + const rdcarray &variables, + uint32_t &byteOffset, rdcstr &prefix) +{ + for(const DXBC::CBufferVariable &v : variables) + { + // absolute byte offset of this variable in the cbuffer + const uint32_t voffs = byteOffset + v.offset; + + // does minOffset-maxOffset reside in this variable? We don't handle the case where the range + // crosses a variable (and I don't think FXC emits that anyway). + if(voffs <= minOffset && voffs + v.type.bytesize > maxOffset) + { + byteOffset = voffs; + + // if it is a struct with members, recurse to find a closer match + if(!v.type.members.empty()) + { + prefix += v.name + "."; + return FindCBufferVar(minOffset, maxOffset, v.type.members, byteOffset, prefix); + } + + // otherwise return this variable. + return &v; + } + } + + return NULL; +} + +static rdcstr MakeCBufferRegisterStr(uint32_t reg, DXIL::EntryPointInterface::CBuffer cbuffer) +{ + rdcstr ret = "{"; + uint32_t offset = 0; + uint32_t regOffset = reg * 16; + while(offset < 16) + { + if(offset > 0) + ret += ", "; + + uint32_t baseOffset = 0; + uint32_t minOffset = regOffset + offset; + uint32_t maxOffset = minOffset + 1; + rdcstr prefix; + const DXBC::CBufferVariable *var = + FindCBufferVar(minOffset, maxOffset, cbuffer.cbufferRefl->variables, baseOffset, prefix); + if(var) + { + ret += cbuffer.name + "." + prefix + var->name; + uint32_t varOffset = regOffset - baseOffset; + + // if it's an array, add the index based on the relative index to the base offset + if(var->type.elements > 1) + { + uint32_t byteSize = var->type.bytesize; + + // round up the byte size to a the nearest vec4 in case it's not quite a multiple + byteSize = AlignUp16(byteSize); + + const uint32_t elementSize = byteSize / var->type.elements; + const uint32_t elementIndex = varOffset / elementSize; + + ret += StringFormat::Fmt("[%u]", elementIndex); + + // subtract off so that if there's any further offset, it can be processed + varOffset -= elementIndex; + } + + // or if it's a matrix + if((var->type.varClass == DXBC::CLASS_MATRIX_ROWS && var->type.cols > 1) || + (var->type.varClass == DXBC::CLASS_MATRIX_COLUMNS && var->type.rows > 1)) + { + ret += StringFormat::Fmt("[%u]", varOffset / 16); + } + + offset = var->offset + var->type.bytesize; + offset -= regOffset; + } + else + { + ret += ""; + offset += 4; + } + } + ret += "}"; + return ret; +} + void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection) { DXIL::dxcStyleFormatting = false; @@ -2310,7 +2404,6 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection) for(size_t i = 0; i < entryPoint.cbuffers.size(); ++i) { EntryPointInterface::CBuffer &cbuffer = entryPoint.cbuffers[i]; - const DXBC::CBuffer *cbufferRefl = NULL; if(reflection) { for(size_t cbIdx = 0; cbIdx < reflection->CBuffers.size(); ++cbIdx) @@ -2321,7 +2414,8 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection) { if(cbuffer.name.empty()) cbuffer.name = cb.name; - cbufferRefl = &reflection->CBuffers[cbIdx]; + if(!cbuffer.cbufferRefl) + cbuffer.cbufferRefl = &reflection->CBuffers[cbIdx]; } } } @@ -2330,28 +2424,29 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection) m_Disassembly += " Space: " + ToStr(cbuffer.space); m_Disassembly += " Reg: " + ToStr(cbuffer.regBase); m_Disassembly += " Count: " + ToStr(cbuffer.regCount); - if(cbufferRefl) + if(cbuffer.cbufferRefl) { - if(!cbufferRefl->variables.empty()) + if(!cbuffer.cbufferRefl->variables.empty()) { DisassemblyAddNewLine(); m_Disassembly += " {"; DisassemblyAddNewLine(); - for(size_t m = 0; m < cbufferRefl->variables.size(); ++m) + + for(const DXBC::CBufferVariable &cbVar : cbuffer.cbufferRefl->variables) { - const DXBC::CBufferVariableType &cbType = cbufferRefl->variables[m].type; + const DXBC::CBufferVariableType &cbType = cbVar.type; m_Disassembly += " "; m_Disassembly += cbType.name; + m_Disassembly += " " + cbVar.name; if(cbType.elements > 1) m_Disassembly += "[" + ToStr(cbType.elements) + "]"; - m_Disassembly += " " + cbufferRefl->variables[m].name; m_Disassembly += ";"; DisassemblyAddNewLine(); } - m_Disassembly += " }"; + m_Disassembly += " };"; + DisassemblyAddNewLine(); } } - m_Disassembly += ";"; DisassemblyAddNewLine(); } @@ -2426,7 +2521,7 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection) m_Disassembly += "{"; DisassemblyAddNewLine(); - std::map handleNames; + std::map> resHandles; size_t curBlock = 0; @@ -2451,11 +2546,13 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection) } rdcstr resultIdStr; if(!inst.getName().empty()) - resultIdStr = escapeStringIfNeeded(inst.getName()); + resultIdStr = StringFormat::Fmt("%c%s", DXIL::dxilIdentifier, + escapeStringIfNeeded(inst.getName()).c_str()); else if(inst.slot != ~0U) - resultIdStr = ToStr(inst.slot); + resultIdStr = StringFormat::Fmt("%c%s", DXIL::dxilIdentifier, ToStr(inst.slot).c_str()); - lineStr += StringFormat::Fmt("%c%s = ", DXIL::dxilIdentifier, resultIdStr.c_str()); + if(!resultIdStr.empty()) + lineStr += resultIdStr + " = "; bool showDxFuncName = false; rdcstr commentStr; @@ -2516,14 +2613,34 @@ void Program::MakeRDDisassemblyString(const DXBC::Reflection *reflection) case ResourceClass::Sampler: resName = entryPoint.samplers[resIndex].name; break; default: resName = "INVALID RESOURCE CLASS"; break; }; - handleNames[resultIdStr] = resName; + resHandles[resName] = make_rdcpair(resClass, resIndex); lineStr += resName; - lineStr += ";"; - if(resLowerBound != resIndex) - commentStr += " lowerBound = " + ToStr(resLowerBound); + if(index != resIndex) + commentStr += " index = " + ToStr(index); if(nonUniformIndex) commentStr += " nonUniformIndex = " + ToStr(nonUniformIndex); } + else if(showDxFuncName && funcCallName.beginsWith("dx.op.cbufferLoad")) + { + showDxFuncName = false; + uint32_t dxopCode = getival(inst.args[0]); + RDCASSERTEQUAL(dxopCode, 59); + rdcstr handleStr = ArgToString(inst.args[1], false); + rdcpair resInfo = resHandles[handleStr]; + uint32_t regIndex; + if(funcCallName.beginsWith("dx.op.cbufferLoadLegacy")) + { + regIndex = getival(inst.args[2]); + } + else + { + // TODO: handle non 16-byte aligned offsets + uint32_t byteOffset = getival(inst.args[2]); + regIndex = byteOffset / 16; + // uint32_t alignment = getival(inst.args[3]); + } + lineStr += MakeCBufferRegisterStr(regIndex, entryPoint.cbuffers[resInfo.second]); + } else if(funcCallName.beginsWith("llvm.dbg.")) { } diff --git a/renderdoc/driver/shaders/dxil/dxil_reflect.cpp b/renderdoc/driver/shaders/dxil/dxil_reflect.cpp index 7470471c5..0a687bd0c 100644 --- a/renderdoc/driver/shaders/dxil/dxil_reflect.cpp +++ b/renderdoc/driver/shaders/dxil/dxil_reflect.cpp @@ -360,6 +360,7 @@ EntryPointInterface::CBuffer::CBuffer(const Metadata *cbuffer) : ResourceBase(cb if(tag == ResourcesTag::IsTBufferTag) isTBuffer = (getival(tags->children[t + 1]) == 1); } + cbufferRefl = NULL; } EntryPointInterface::Sampler::Sampler(const Metadata *sampler) : ResourceBase(sampler)