diff --git a/renderdoc/driver/d3d12/d3d12_common.cpp b/renderdoc/driver/d3d12/d3d12_common.cpp index 1dd080547..c2bfc92d6 100644 --- a/renderdoc/driver/d3d12/d3d12_common.cpp +++ b/renderdoc/driver/d3d12/d3d12_common.cpp @@ -158,9 +158,9 @@ void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl, create_array_uninit(mapping->ConstantBlocks, numCbuffers); create_array_uninit(refl->ConstantBlocks, numCbuffers); - for(size_t i = 0, c = 0; i < dxbc->m_CBuffers.size(); i++) + for(size_t i = 0; i < dxbc->m_CBuffers.size(); i++) { - ConstantBlock &cb = refl->ConstantBlocks[c]; + ConstantBlock &cb = refl->ConstantBlocks[i]; if(dxbc->m_CBuffers[i].descriptor.type != DXBC::CBuffer::Descriptor::TYPE_CBUFFER) continue; @@ -176,7 +176,7 @@ void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl, map.bind = dxbc->m_CBuffers[i].reg; map.used = true; - mapping->ConstantBlocks[c] = map; + mapping->ConstantBlocks[i] = map; create_array_uninit(cb.variables, dxbc->m_CBuffers[i].variables.size()); for(size_t v = 0; v < dxbc->m_CBuffers[i].variables.size(); v++) @@ -307,7 +307,7 @@ void MakeShaderReflection(DXBC::DXBCFile *dxbc, ShaderReflection *refl, res.bindPoint = IsReadWrite ? rwidx : roidx; BindpointMap map; - map.arraySize = 1; + map.arraySize = r.bindCount == 0 ? ~0U : r.bindCount; map.bindset = r.space; map.bind = r.reg; map.used = true; diff --git a/renderdoc/driver/d3d12/d3d12_debug.cpp b/renderdoc/driver/d3d12/d3d12_debug.cpp index 8d6fdc2a0..62f2a2488 100644 --- a/renderdoc/driver/d3d12/d3d12_debug.cpp +++ b/renderdoc/driver/d3d12/d3d12_debug.cpp @@ -93,6 +93,8 @@ D3D12DebugManager::D3D12DebugManager(WrappedID3D12Device *wrapper) m_WrappedDevice = wrapper; m_WrappedDevice->InternalRef(); + m_TexResource = NULL; + m_width = m_height = 1; m_BBFmtIdx = BGRA8_BACKBUFFER; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp index c2a0abdb5..f55eb814e 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.cpp @@ -25,7 +25,8 @@ #include "dxbc_disassemble.h" #include -#include "common/common.h" // only dependencies are RDCASSERT, so this code is easy to detach from RenderDoc +#include "common/common.h" +#include "serialise/serialiser.h" #include "serialise/string_utils.h" #include "dxbc_inspect.h" @@ -136,6 +137,7 @@ static MaskedElement SkipOptimisation; static MaskedElement EnableMinPrecision; static MaskedElement EnableD3D11_1DoubleExtensions; static MaskedElement EnableD3D11_1ShaderExtensions; +static MaskedElement EnableD3D12AllResourcesBound; // OPCODE_DCL_CONSTANT_BUFFER static MaskedElement AccessPattern; @@ -175,7 +177,8 @@ static MaskedElement OutputPrimitiveTopology; static MaskedElement OutputPrimitive; // OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED -static MaskedElement GloballyCoherant; +static MaskedElement GloballyCoherent; +static MaskedElement RasterizerOrderedAccess; // OPCODE_DCL_INTERFACE static MaskedElement TableLength; @@ -241,6 +244,7 @@ static MaskedElement Extended; // EXTENDED_OPERAND_MODIFIER static MaskedElement Modifier; static MaskedElement MinPrecision; +static MaskedElement NonUniform; }; string toString(const uint32_t values[], uint32_t numComps); @@ -304,7 +308,8 @@ void DXBCFile::DisassembleHexDump() uint32_t *end = &m_HexDump.back(); // check supported types - if(!(m_Version.Major == 0x5 && m_Version.Minor == 0x0) && + if(!(m_Version.Major == 0x5 && m_Version.Minor == 0x1) && + !(m_Version.Major == 0x5 && m_Version.Minor == 0x0) && !(m_Version.Major == 0x4 && m_Version.Minor == 0x1) && !(m_Version.Major == 0x4 && m_Version.Minor == 0x0)) { @@ -316,6 +321,24 @@ void DXBCFile::DisassembleHexDump() cur += 2; + // count how many declarations are so we can get the vector statically sized + size_t numDecls = 0; + uint32_t *tmp = cur; + + while(tmp < end) + { + uint32_t OpcodeToken0 = tmp[0]; + + OpcodeType op = Opcode::Type.Get(OpcodeToken0); + + if(IsDeclaration(op)) + numDecls++; + + tmp += Opcode::Length.Get(OpcodeToken0); + } + + m_Declarations.reserve(numDecls); + while(cur < end) { ASMOperation op; @@ -344,6 +367,8 @@ void DXBCFile::DisassembleHexDump() } } + RDCASSERT(m_Declarations.size() <= numDecls); + ASMOperation implicitRet; implicitRet.length = 1; implicitRet.offset = (end - begin) * sizeof(uint32_t); @@ -840,6 +865,23 @@ bool DXBCFile::ExtractOperand(uint32_t *&tokenStream, ASMOperand &retOper) RDCASSERT(retOper.indices[idx].relative || retOper.indices[idx].absolute); } + if(retOper.type == TYPE_RESOURCE || retOper.type == TYPE_SAMPLER || + retOper.type == TYPE_UNORDERED_ACCESS_VIEW || retOper.type == TYPE_CONSTANT_BUFFER) + { + // try and find a declaration with a matching ID + RDCASSERT(retOper.indices.size() > 0 && retOper.indices[0].absolute); + for(size_t i = 0; i < m_Declarations.size(); i++) + { + // does the ID match, if so, it's our declaration + if(m_Declarations[i].operand.type == retOper.type && + m_Declarations[i].operand.indices[0] == retOper.indices[0]) + { + retOper.declaration = &m_Declarations[i]; + break; + } + } + } + return true; } @@ -877,40 +919,176 @@ string ASMOperand::toString(bool swizzle) const StringFormat::snprintf(buf, 63, "[%u]", funcNum); str += buf; } - else if(type == TYPE_TEMP || type == TYPE_RESOURCE || type == TYPE_SAMPLER || - type == TYPE_OUTPUT || type == TYPE_STREAM || type == TYPE_THREAD_GROUP_SHARED_MEMORY || - type == TYPE_UNORDERED_ACCESS_VIEW || type == TYPE_FUNCTION_BODY) + else if(type == TYPE_RESOURCE || type == TYPE_SAMPLER || type == TYPE_UNORDERED_ACCESS_VIEW) + { + // pre-DX11, just an index + if(indices.size() == 1) + { + if(type == TYPE_RESOURCE) + str = "t"; + if(type == TYPE_SAMPLER) + str = "s"; + if(type == TYPE_UNORDERED_ACCESS_VIEW) + str = "u"; + + str += indices[0].str; + } + else if(indices.size() == 3) + { + if(type == TYPE_RESOURCE) + str = "T"; + if(type == TYPE_SAMPLER) + str = "S"; + if(type == TYPE_UNORDERED_ACCESS_VIEW) + str = "U"; + + // DX12 declaration + + // if declaration pointer is NULL we're printing inside the declaration itself. + // Upper/lower bounds are printed with the space too, but print them here as + // operand indices refer relative to those bounds. + + // detect common case of non-arrayed resources and simplify + RDCASSERT(indices[1].absolute && indices[2].absolute); + if(indices[1].index == indices[2].index) + { + str += indices[0].str; + } + else + { + if(indices[2].index == 0xffffffff) + str += StringFormat::Fmt("%s[%s:unbound]", indices[0].str.c_str(), indices[1].str.c_str()); + else + str += StringFormat::Fmt("%s[%s:%s]", indices[0].str.c_str(), indices[1].str.c_str(), + indices[2].str.c_str()); + } + } + else if(indices.size() == 2) + { + if(type == TYPE_RESOURCE) + str = "T"; + if(type == TYPE_SAMPLER) + str = "S"; + if(type == TYPE_UNORDERED_ACCESS_VIEW) + str = "U"; + + // DX12 lookup + + // if we have a declaration, see if it's non-arrayed + if(declaration && declaration->operand.indices[1].index == declaration->operand.indices[2].index) + { + // resource index should be equal to the bound + RDCASSERT(indices[1].absolute && indices[1].index == declaration->operand.indices[1].index); + + // just include ID + str += indices[0].str; + } + else + { + if(indices[1].relative) + str += StringFormat::Fmt("%s%s", indices[0].str.c_str(), indices[1].str.c_str()); + else + str += StringFormat::Fmt("%s[%s]", indices[0].str.c_str(), indices[1].str.c_str()); + } + } + else + { + RDCERR("Unexpected dimensions for resource-type operand: %x, %u", type, + (uint32_t)indices.size()); + } + } + else if(type == TYPE_CONSTANT_BUFFER) + { + if(indices.size() == 3) + { + str = "CB"; + + if(declaration) + { + // see if the declaration was non-arrayed + if(declaration->operand.indices[1].index == declaration->operand.indices[2].index) + { + // resource index should be equal to the bound + RDCASSERT(indices[1].absolute && indices[1].index == declaration->operand.indices[1].index); + + // just include ID and vector index + if(indices[2].relative) + str += StringFormat::Fmt("%s%s", indices[0].str.c_str(), indices[2].str.c_str()); + else + str += StringFormat::Fmt("%s[%s]", indices[0].str.c_str(), indices[2].str.c_str()); + } + else + { + str += indices[0].str; + + if(indices[1].relative) + str += indices[1].str; + else + str += "[" + indices[1].str + "]"; + + if(indices[2].relative) + str += indices[1].str; + else + str += "[" + indices[2].str + "]"; + } + } + else + { + // if declaration pointer is NULL we're printing inside the declaration itself. + // Because of the operand format, the size of the constant buffer is also in a + // separate DWORD printed elsewhere. + // Upper/lower bounds are printed with the space too, but print them here as + // operand indices refer relative to those bounds. + + // detect common case of non-arrayed resources and simplify + RDCASSERT(indices[1].absolute && indices[2].absolute); + if(indices[1].index == indices[2].index) + { + str += indices[0].str; + } + else + { + if(indices[2].index == 0xffffffff) + str += + StringFormat::Fmt("%s[%s:unbound]", indices[0].str.c_str(), indices[1].str.c_str()); + else + str += StringFormat::Fmt("%s[%s:%s]", indices[0].str.c_str(), indices[1].str.c_str(), + indices[2].str.c_str()); + } + } + } + else + { + str = "cb"; + + str += StringFormat::Fmt("%s[%s]", indices[0].str.c_str(), indices[1].str.c_str()); + } + } + else if(type == TYPE_TEMP || type == TYPE_OUTPUT || type == TYPE_STREAM || + type == TYPE_THREAD_GROUP_SHARED_MEMORY || type == TYPE_FUNCTION_BODY) { if(type == TYPE_TEMP) str = "r"; - if(type == TYPE_RESOURCE) - str = "t"; - if(type == TYPE_SAMPLER) - str = "s"; if(type == TYPE_OUTPUT) str = "o"; if(type == TYPE_STREAM) str = "m"; if(type == TYPE_THREAD_GROUP_SHARED_MEMORY) str = "g"; - if(type == TYPE_UNORDERED_ACCESS_VIEW) - str = "u"; if(type == TYPE_FUNCTION_BODY) str = "fb"; - RDCASSERT(indices.size() == 1); + RDCASSERTEQUAL(indices.size(), 1); str += indices[0].str; } - else if(type == TYPE_CONSTANT_BUFFER || type == TYPE_IMMEDIATE_CONSTANT_BUFFER || - type == TYPE_INDEXABLE_TEMP || type == TYPE_INPUT || type == TYPE_INPUT_CONTROL_POINT || + else if(type == TYPE_IMMEDIATE_CONSTANT_BUFFER || type == TYPE_INDEXABLE_TEMP || + type == TYPE_INPUT || type == TYPE_INPUT_CONTROL_POINT || type == TYPE_INPUT_PATCH_CONSTANT || type == TYPE_THIS_POINTER || type == TYPE_OUTPUT_CONTROL_POINT) { if(type == TYPE_IMMEDIATE_CONSTANT_BUFFER) str = "icb"; - if(type == TYPE_CONSTANT_BUFFER) - str = "cb"; if(type == TYPE_INDEXABLE_TEMP) str = "x"; if(type == TYPE_INPUT) @@ -1028,6 +1206,8 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) uint32_t *begin = tokenStream; uint32_t OpcodeToken0 = tokenStream[0]; + const bool sm51 = (m_Version.Major == 0x5 && m_Version.Minor == 0x1); + OpcodeType op = Opcode::Type.Get(OpcodeToken0); RDCASSERT(op < NUM_OPCODES); @@ -1130,6 +1310,8 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) Declaration::EnableD3D11_1DoubleExtensions.Get(OpcodeToken0); retDecl.enableD3D11_1ShaderExtensions = Declaration::EnableD3D11_1ShaderExtensions.Get(OpcodeToken0); + retDecl.enableD3D12AllResourcesBound = + Declaration::EnableD3D12AllResourcesBound.Get(OpcodeToken0); retDecl.str += " "; @@ -1161,6 +1343,41 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) retDecl.str += "enableRawAndStructuredBuffers"; added = true; } + if(retDecl.skipOptimisation) + { + if(added) + retDecl.str += ", "; + retDecl.str += "skipOptimisation"; + added = true; + } + if(retDecl.enableMinPrecision) + { + if(added) + retDecl.str += ", "; + retDecl.str += "enableMinPrecision"; + added = true; + } + if(retDecl.enableD3D11_1DoubleExtensions) + { + if(added) + retDecl.str += ", "; + retDecl.str += "doubleExtensions"; + added = true; + } + if(retDecl.enableD3D11_1ShaderExtensions) + { + if(added) + retDecl.str += ", "; + retDecl.str += "shaderExtensions"; + added = true; + } + if(retDecl.enableD3D12AllResourcesBound) + { + if(added) + retDecl.str += ", "; + retDecl.str += "d3d12AllResourcesBound"; + added = true; + } } else if(op == OPCODE_DCL_CONSTANT_BUFFER) { @@ -1171,6 +1388,14 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) retDecl.str += " "; retDecl.str += retDecl.operand.toString(false); + if(sm51) + { + uint32_t float4size = tokenStream[0]; + tokenStream++; + + retDecl.str += StringFormat::Fmt("[%u]", float4size); + } + retDecl.str += ", "; if(accessPattern == ACCESS_IMMEDIATE_INDEXED) @@ -1179,6 +1404,23 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) retDecl.str += "dynamicIndexed"; else RDCERR("Unexpected cbuffer access pattern"); + + retDecl.space = 0; + + if(sm51) + { + retDecl.space = tokenStream[0]; + tokenStream++; + retDecl.str += StringFormat::Fmt(" space=%u", retDecl.space); + + if(retDecl.operand.indices[1].index == retDecl.operand.indices[2].index) + retDecl.str += StringFormat::Fmt(",reg=%u", retDecl.operand.indices[1].index); + else if(retDecl.operand.indices[2].index == 0xffffffff) + retDecl.str += StringFormat::Fmt(",regs=%u:unbound", retDecl.operand.indices[1].index); + else + retDecl.str += StringFormat::Fmt(",regs=%u:%u", retDecl.operand.indices[1].index, + retDecl.operand.indices[2].index); + } } else if(op == OPCODE_DCL_INPUT) { @@ -1281,6 +1523,21 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) retDecl.str += "mode_comparison"; if(retDecl.samplerMode == SAMPLER_MODE_MONO) retDecl.str += "mode_mono"; + + retDecl.space = 0; + + if(sm51) + { + retDecl.space = tokenStream[0]; + tokenStream++; + retDecl.str += StringFormat::Fmt(" space=%u", retDecl.space); + + if(retDecl.operand.indices[1].index == retDecl.operand.indices[2].index) + retDecl.str += StringFormat::Fmt(",reg=%u", retDecl.operand.indices[1].index); + else + retDecl.str += StringFormat::Fmt(",regs=%u:%u", retDecl.operand.indices[1].index, + retDecl.operand.indices[2].index); + } } else if(op == OPCODE_DCL_RESOURCE) { @@ -1319,6 +1576,21 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) retDecl.str += ")"; retDecl.str += " " + retDecl.operand.toString(false); + + retDecl.space = 0; + + if(sm51) + { + retDecl.space = tokenStream[0]; + tokenStream++; + retDecl.str += StringFormat::Fmt(" space=%u", retDecl.space); + + if(retDecl.operand.indices[1].index == retDecl.operand.indices[2].index) + retDecl.str += StringFormat::Fmt(",reg=%u", retDecl.operand.indices[1].index); + else + retDecl.str += StringFormat::Fmt(",regs=%u:%u", retDecl.operand.indices[1].index, + retDecl.operand.indices[2].index); + } } else if(op == OPCODE_DCL_INPUT_PS) { @@ -1530,18 +1802,51 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) } else if(op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW || op == OPCODE_DCL_RESOURCE_RAW) { + retDecl.rov = (op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW) && + Declaration::RasterizerOrderedAccess.Get(OpcodeToken0); + + retDecl.globallyCoherant = (op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW) & + Declaration::GloballyCoherent.Get(OpcodeToken0); + retDecl.str += " "; bool ret = ExtractOperand(tokenStream, retDecl.operand); RDCASSERT(ret); retDecl.str += retDecl.operand.toString(false); + + if(retDecl.globallyCoherant) + retDecl.str += ", globallyCoherant"; + + if(retDecl.rov) + retDecl.str += ", rasterizerOrderedAccess"; + + retDecl.space = 0; + + if(sm51) + { + retDecl.space = tokenStream[0]; + tokenStream++; + retDecl.str += StringFormat::Fmt(" space=%u", retDecl.space); + + if(retDecl.operand.indices[1].index == retDecl.operand.indices[2].index) + retDecl.str += StringFormat::Fmt(",reg=%u", retDecl.operand.indices[1].index); + else + retDecl.str += StringFormat::Fmt(",regs=%u:%u", retDecl.operand.indices[1].index, + retDecl.operand.indices[2].index); + } } else if(op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED || op == OPCODE_DCL_RESOURCE_STRUCTURED) { retDecl.hasCounter = (op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED) && Opcode::HasOrderPreservingCounter.Get(OpcodeToken0); + retDecl.rov = (op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED) && + Declaration::RasterizerOrderedAccess.Get(OpcodeToken0); + + retDecl.globallyCoherant = (op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED) & + Declaration::GloballyCoherent.Get(OpcodeToken0); + retDecl.str += " "; bool ret = ExtractOperand(tokenStream, retDecl.operand); @@ -1559,12 +1864,35 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) if(retDecl.hasCounter) retDecl.str += ", hasOrderPreservingCounter"; + + if(retDecl.globallyCoherant) + retDecl.str += ", globallyCoherant"; + + if(retDecl.rov) + retDecl.str += ", rasterizerOrderedAccess"; + + retDecl.space = 0; + + if(sm51) + { + retDecl.space = tokenStream[0]; + tokenStream++; + retDecl.str += StringFormat::Fmt(" space=%u", retDecl.space); + + if(retDecl.operand.indices[1].index == retDecl.operand.indices[2].index) + retDecl.str += StringFormat::Fmt(",reg=%u", retDecl.operand.indices[1].index); + else + retDecl.str += StringFormat::Fmt(",regs=%u:%u", retDecl.operand.indices[1].index, + retDecl.operand.indices[2].index); + } } else if(op == OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED) { retDecl.dim = Declaration::ResourceDim.Get(OpcodeToken0); - retDecl.globallyCoherant = Declaration::GloballyCoherant.Get(OpcodeToken0); + retDecl.globallyCoherant = Declaration::GloballyCoherent.Get(OpcodeToken0); + + retDecl.rov = Declaration::RasterizerOrderedAccess.Get(OpcodeToken0); retDecl.str += "_"; retDecl.str += toString(retDecl.dim); @@ -1598,6 +1926,24 @@ bool DXBCFile::ExtractDecl(uint32_t *&tokenStream, ASMDecl &retDecl) retDecl.str += " "; retDecl.str += retDecl.operand.toString(false); + + if(retDecl.rov) + retDecl.str += ", rasterizerOrderedAccess"; + + retDecl.space = 0; + + if(sm51) + { + retDecl.space = tokenStream[0]; + tokenStream++; + retDecl.str += StringFormat::Fmt(" space=%u", retDecl.space); + + if(retDecl.operand.indices[1].index == retDecl.operand.indices[2].index) + retDecl.str += StringFormat::Fmt(",reg=%u", retDecl.operand.indices[1].index); + else + retDecl.str += StringFormat::Fmt(",regs=%u:%u", retDecl.operand.indices[1].index, + retDecl.operand.indices[2].index); + } } else if(op == OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT || op == OPCODE_DCL_HS_JOIN_PHASE_INSTANCE_COUNT || op == OPCODE_DCL_GS_INSTANCE_COUNT) diff --git a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.h b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.h index 84a0ec0be..c0bab83f3 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_disassemble.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_disassemble.h @@ -407,6 +407,8 @@ enum OperandType TYPE_OUTPUT_DEPTH_GREATER_EQUAL, TYPE_OUTPUT_DEPTH_LESS_EQUAL, TYPE_CYCLE_COUNTER, + TYPE_OUTPUT_STENCIL_REF, + TYPE_INNER_COVERAGE, NUM_OPERAND_TYPES, }; @@ -652,6 +654,7 @@ enum ComponentType ///////////////////////////////////////////////////////////////////////// struct ASMIndex; +struct ASMDecl; struct ASMOperand { @@ -664,6 +667,7 @@ struct ASMOperand modifier = OPERAND_MODIFIER_NONE; precision = PRECISION_DEFAULT; funcNum = 0; + declaration = NULL; } bool operator==(const ASMOperand &o) const; @@ -691,6 +695,9 @@ struct ASMOperand // cbuffer member // 3 is rare but follows the above pattern + // the declaration of the resource in this operand (not always present) + ASMDecl *declaration; + uint32_t values[4]; // if this operand is immediate, the values are here OperandModifier modifier; // modifier, neg, abs(), -abs() etc. Could potentially be multiple @@ -808,10 +815,12 @@ struct ASMDecl bool enableMinPrecision; bool enableD3D11_1DoubleExtensions; bool enableD3D11_1ShaderExtensions; + bool enableD3D12AllResourcesBound; // OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED uint32_t stride; bool hasCounter; + bool rov; // OPCODE_DCL_TEMPS, OPCODE_DCL_INDEXABLE_TEMP uint32_t numTemps; @@ -827,6 +836,7 @@ struct ASMDecl uint32_t groupSize[3]; // OPCODE_DCL_RESOURCE + uint32_t space; ResourceRetType resType[4]; ResourceDimension dim; uint32_t sampleCount; diff --git a/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp b/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp index f45f020b2..a8e1a67cd 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_inspect.cpp @@ -601,7 +601,12 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) m_Resources.reserve(h->resources.count); - map > cbufferslots; + struct CBufferBind + { + uint32_t reg, space, bindCount; + }; + + map cbufferbinds; uint32_t resourceStride = sizeof(RDEFResource); @@ -643,10 +648,14 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) { string cname = desc.name; - while(cbufferslots.find(cname) != cbufferslots.end()) + while(cbufferbinds.find(cname) != cbufferbinds.end()) cname += "_"; - cbufferslots[cname] = std::make_pair(desc.space, desc.reg); + CBufferBind cb; + cb.space = desc.space; + cb.reg = desc.reg; + cb.bindCount = desc.bindCount; + cbufferbinds[cname] = cb; } m_Resources.push_back(desc); @@ -658,31 +667,36 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) // The reason for this is that an array element could refer to an un-used alias in a bind // point, and an individual non-array resoruce will always refer to the used alias (an // un-used individual resource will be omitted entirely from the reflection - for(size_t i = 0; i < m_Resources.size();) + // + // Note we preserve the arrays in SM5.1 + if(h->targetVersion < 0x501) { - if(m_Resources[i].bindCount > 1) + for(size_t i = 0; i < m_Resources.size();) { - ShaderInputBind desc = m_Resources[i]; - m_Resources.erase(m_Resources.begin() + i); - - string rname = desc.name; - uint32_t arraySize = desc.bindCount; - - desc.bindCount = 1; - - for(uint32_t a = 0; a < arraySize; a++) + if(m_Resources[i].bindCount > 1) { - desc.name = StringFormat::Fmt("%s[%u]", rname.c_str(), a); - m_Resources.push_back(desc); - desc.reg++; + ShaderInputBind desc = m_Resources[i]; + m_Resources.erase(m_Resources.begin() + i); + + string rname = desc.name; + uint32_t arraySize = desc.bindCount; + + desc.bindCount = 1; + + for(uint32_t a = 0; a < arraySize; a++) + { + desc.name = StringFormat::Fmt("%s[%u]", rname.c_str(), a); + m_Resources.push_back(desc); + desc.reg++; + } + + // continue from the i'th element again since + // we just removed it. + continue; } - // continue from the i'th element again since - // we just removed it. - continue; + i++; } - - i++; } set cbuffernames; @@ -773,8 +787,9 @@ DXBCFile::DXBCFile(const void *ByteCode, size_t ByteCodeLength) cbuffernames.insert(cname); - cb.space = cbufferslots[cname].first; - cb.reg = cbufferslots[cname].second; + cb.space = cbufferbinds[cname].space; + cb.reg = cbufferbinds[cname].reg; + cb.bindCount = cbufferbinds[cname].bindCount; if(cb.descriptor.type == CBuffer::Descriptor::TYPE_CBUFFER) { @@ -1021,7 +1036,7 @@ void DXBCFile::GuessResources() ShaderInputBind desc; RDCASSERT(dcl.operand.type == TYPE_SAMPLER); - RDCASSERT(dcl.operand.indices.size() == 1); + RDCASSERT(dcl.operand.indices.size() == 1 || dcl.operand.indices.size() == 3); RDCASSERT(dcl.operand.indices[0].absolute); uint32_t idx = (uint32_t)dcl.operand.indices[0].index; @@ -1030,7 +1045,7 @@ void DXBCFile::GuessResources() desc.name = buf; desc.type = ShaderInputBind::TYPE_SAMPLER; - desc.space = 0; + desc.space = dcl.space; desc.reg = idx; desc.bindCount = 1; desc.flags = dcl.samplerMode == SAMPLER_MODE_COMPARISON ? 2 : 0; @@ -1038,6 +1053,13 @@ void DXBCFile::GuessResources() desc.dimension = ShaderInputBind::DIM_UNKNOWN; desc.numSamples = 0; + if(dcl.operand.indices.size() == 3) + { + desc.bindCount = uint32_t(dcl.operand.indices[2].index - dcl.operand.indices[1].index); + if(dcl.operand.indices[2].index == 0xffffffff) + desc.bindCount = 0; + } + m_Resources.push_back(desc); break; @@ -1056,39 +1078,41 @@ void DXBCFile::GuessResources() desc.name = buf; desc.type = ShaderInputBind::TYPE_TEXTURE; - desc.space = 0; + desc.space = dcl.space; desc.reg = idx; desc.bindCount = 1; desc.flags = 0; desc.retType = (ShaderInputBind::RetType)dcl.resType[0]; - desc.dimension = - dcl.dim == RESOURCE_DIMENSION_BUFFER - ? ShaderInputBind::DIM_BUFFER - : dcl.dim == RESOURCE_DIMENSION_TEXTURE1D - ? ShaderInputBind::DIM_TEXTURE1D - : dcl.dim == RESOURCE_DIMENSION_TEXTURE2D - ? ShaderInputBind::DIM_TEXTURE2D - : dcl.dim == RESOURCE_DIMENSION_TEXTURE3D - ? ShaderInputBind::DIM_TEXTURE3D - : dcl.dim == RESOURCE_DIMENSION_TEXTURECUBE - ? ShaderInputBind::DIM_TEXTURECUBE - : dcl.dim == RESOURCE_DIMENSION_TEXTURE1DARRAY - ? ShaderInputBind::DIM_TEXTURE1DARRAY - : dcl.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY - ? ShaderInputBind::DIM_TEXTURE2DARRAY - : dcl.dim == RESOURCE_DIMENSION_TEXTURECUBEARRAY - ? ShaderInputBind::DIM_TEXTURECUBEARRAY - : dcl.dim == RESOURCE_DIMENSION_TEXTURE2DMS - ? ShaderInputBind::DIM_TEXTURE2DMS - : dcl.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY - ? ShaderInputBind::DIM_TEXTURE2DARRAY - : dcl.dim == RESOURCE_DIMENSION_TEXTURE2DMSARRAY - ? ShaderInputBind::DIM_TEXTURE2DMSARRAY - : ShaderInputBind::DIM_UNKNOWN; + + switch(dcl.dim) + { + case RESOURCE_DIMENSION_BUFFER: desc.dimension = ShaderInputBind::DIM_BUFFER; + case RESOURCE_DIMENSION_TEXTURE1D: desc.dimension = ShaderInputBind::DIM_TEXTURE1D; + case RESOURCE_DIMENSION_TEXTURE2D: desc.dimension = ShaderInputBind::DIM_TEXTURE2D; + case RESOURCE_DIMENSION_TEXTURE3D: desc.dimension = ShaderInputBind::DIM_TEXTURE3D; + case RESOURCE_DIMENSION_TEXTURECUBE: desc.dimension = ShaderInputBind::DIM_TEXTURECUBE; + case RESOURCE_DIMENSION_TEXTURE1DARRAY: + desc.dimension = ShaderInputBind::DIM_TEXTURE1DARRAY; + case RESOURCE_DIMENSION_TEXTURE2DARRAY: + desc.dimension = ShaderInputBind::DIM_TEXTURE2DARRAY; + case RESOURCE_DIMENSION_TEXTURECUBEARRAY: + desc.dimension = ShaderInputBind::DIM_TEXTURECUBEARRAY; + case RESOURCE_DIMENSION_TEXTURE2DMS: desc.dimension = ShaderInputBind::DIM_TEXTURE2DMS; + case RESOURCE_DIMENSION_TEXTURE2DMSARRAY: + desc.dimension = ShaderInputBind::DIM_TEXTURE2DMSARRAY; + default: desc.dimension = ShaderInputBind::DIM_UNKNOWN; break; + } desc.numSamples = dcl.sampleCount; RDCASSERT(desc.dimension != ShaderInputBind::DIM_UNKNOWN); + if(dcl.operand.indices.size() == 3) + { + desc.bindCount = uint32_t(dcl.operand.indices[2].index - dcl.operand.indices[1].index); + if(dcl.operand.indices[2].index == 0xffffffff) + desc.bindCount = 0; + } + m_Resources.push_back(desc); break; @@ -1111,7 +1135,7 @@ void DXBCFile::GuessResources() desc.name = buf; desc.type = dcl.operand.type == TYPE_RESOURCE ? ShaderInputBind::TYPE_BYTEADDRESS : ShaderInputBind::TYPE_UAV_RWBYTEADDRESS; - desc.space = 0; + desc.space = dcl.space; desc.reg = idx; desc.bindCount = 1; desc.flags = 0; @@ -1119,6 +1143,13 @@ void DXBCFile::GuessResources() desc.dimension = ShaderInputBind::DIM_BUFFER; desc.numSamples = 0; + if(dcl.operand.indices.size() == 3) + { + desc.bindCount = uint32_t(dcl.operand.indices[2].index - dcl.operand.indices[1].index); + if(dcl.operand.indices[2].index == 0xffffffff) + desc.bindCount = 0; + } + m_Resources.push_back(desc); break; @@ -1137,7 +1168,7 @@ void DXBCFile::GuessResources() desc.name = buf; desc.type = ShaderInputBind::TYPE_STRUCTURED; - desc.space = 0; + desc.space = dcl.space; desc.reg = idx; desc.bindCount = 1; desc.flags = 0; @@ -1145,6 +1176,13 @@ void DXBCFile::GuessResources() desc.dimension = ShaderInputBind::DIM_BUFFER; desc.numSamples = dcl.stride; + if(dcl.operand.indices.size() == 3) + { + desc.bindCount = uint32_t(dcl.operand.indices[2].index - dcl.operand.indices[1].index); + if(dcl.operand.indices[2].index == 0xffffffff) + desc.bindCount = 0; + } + m_Resources.push_back(desc); break; @@ -1167,7 +1205,7 @@ void DXBCFile::GuessResources() // rwstructured if(dcl.hasCounter) desc.type = ShaderInputBind::TYPE_UAV_RWSTRUCTURED_WITH_COUNTER; - desc.space = 0; + desc.space = dcl.space; desc.reg = idx; desc.bindCount = 1; desc.flags = 0; @@ -1175,6 +1213,13 @@ void DXBCFile::GuessResources() desc.dimension = ShaderInputBind::DIM_BUFFER; desc.numSamples = dcl.stride; + if(dcl.operand.indices.size() == 3) + { + desc.bindCount = uint32_t(dcl.operand.indices[2].index - dcl.operand.indices[1].index); + if(dcl.operand.indices[2].index == 0xffffffff) + desc.bindCount = 0; + } + m_Resources.push_back(desc); break; @@ -1193,33 +1238,39 @@ void DXBCFile::GuessResources() desc.name = buf; desc.type = ShaderInputBind::TYPE_UAV_RWTYPED; - desc.space = 0; + desc.space = dcl.space; desc.reg = idx; desc.bindCount = 1; desc.flags = 0; desc.retType = (ShaderInputBind::RetType) int(dcl.resType[0]); // enums match - desc.dimension = - dcl.dim == RESOURCE_DIMENSION_TEXTURE1D - ? ShaderInputBind::DIM_TEXTURE1D - : dcl.dim == RESOURCE_DIMENSION_TEXTURE2D - ? ShaderInputBind::DIM_TEXTURE2D - : dcl.dim == RESOURCE_DIMENSION_TEXTURE3D - ? ShaderInputBind::DIM_TEXTURE3D - : dcl.dim == RESOURCE_DIMENSION_TEXTURECUBE - ? ShaderInputBind::DIM_TEXTURECUBE - : dcl.dim == RESOURCE_DIMENSION_TEXTURE1DARRAY - ? ShaderInputBind::DIM_TEXTURE1DARRAY - : dcl.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY - ? ShaderInputBind::DIM_TEXTURE2DARRAY - : dcl.dim == RESOURCE_DIMENSION_TEXTURECUBEARRAY - ? ShaderInputBind::DIM_TEXTURECUBEARRAY - : dcl.dim == RESOURCE_DIMENSION_TEXTURE2DMS - ? ShaderInputBind::DIM_TEXTURE2DMS - : dcl.dim == RESOURCE_DIMENSION_TEXTURE2DARRAY - ? ShaderInputBind::DIM_TEXTURE2DARRAY - : ShaderInputBind::DIM_UNKNOWN; + + switch(dcl.dim) + { + case RESOURCE_DIMENSION_BUFFER: desc.dimension = ShaderInputBind::DIM_BUFFER; + case RESOURCE_DIMENSION_TEXTURE1D: desc.dimension = ShaderInputBind::DIM_TEXTURE1D; + case RESOURCE_DIMENSION_TEXTURE2D: desc.dimension = ShaderInputBind::DIM_TEXTURE2D; + case RESOURCE_DIMENSION_TEXTURE3D: desc.dimension = ShaderInputBind::DIM_TEXTURE3D; + case RESOURCE_DIMENSION_TEXTURECUBE: desc.dimension = ShaderInputBind::DIM_TEXTURECUBE; + case RESOURCE_DIMENSION_TEXTURE1DARRAY: + desc.dimension = ShaderInputBind::DIM_TEXTURE1DARRAY; + case RESOURCE_DIMENSION_TEXTURE2DARRAY: + desc.dimension = ShaderInputBind::DIM_TEXTURE2DARRAY; + case RESOURCE_DIMENSION_TEXTURECUBEARRAY: + desc.dimension = ShaderInputBind::DIM_TEXTURECUBEARRAY; + case RESOURCE_DIMENSION_TEXTURE2DMS: desc.dimension = ShaderInputBind::DIM_TEXTURE2DMS; + case RESOURCE_DIMENSION_TEXTURE2DMSARRAY: + desc.dimension = ShaderInputBind::DIM_TEXTURE2DMSARRAY; + default: desc.dimension = ShaderInputBind::DIM_UNKNOWN; break; + } desc.numSamples = (uint32_t)-1; + if(dcl.operand.indices.size() == 3) + { + desc.bindCount = uint32_t(dcl.operand.indices[2].index - dcl.operand.indices[1].index); + if(dcl.operand.indices[2].index == 0xffffffff) + desc.bindCount = 0; + } + m_Resources.push_back(desc); break; @@ -1239,7 +1290,7 @@ void DXBCFile::GuessResources() desc.name = buf; desc.type = ShaderInputBind::TYPE_CBUFFER; - desc.space = 0; + desc.space = dcl.space; desc.reg = idx; desc.bindCount = 1; desc.flags = 1; @@ -1247,14 +1298,22 @@ void DXBCFile::GuessResources() desc.dimension = ShaderInputBind::DIM_UNKNOWN; desc.numSamples = 0; - m_Resources.push_back(desc); + if(dcl.operand.indices.size() == 3) + { + desc.bindCount = uint32_t(dcl.operand.indices[2].index - dcl.operand.indices[1].index); + if(dcl.operand.indices[2].index == 0xffffffff) + desc.bindCount = 0; + } CBuffer cb; + m_Resources.push_back(desc); + cb.name = desc.name; - cb.space = 0; + cb.space = dcl.space; cb.reg = idx; + cb.bindCount = desc.bindCount; cb.descriptor.name = cb.name; cb.descriptor.byteSize = numVecs * 4 * sizeof(float); diff --git a/renderdoc/driver/shaders/dxbc/dxbc_inspect.h b/renderdoc/driver/shaders/dxbc/dxbc_inspect.h index 2f399d1e1..e106dc734 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_inspect.h +++ b/renderdoc/driver/shaders/dxbc/dxbc_inspect.h @@ -286,6 +286,7 @@ struct CBuffer uint32_t space; uint32_t reg; + uint32_t bindCount; struct Descriptor { diff --git a/renderdocui/Windows/PipelineState/D3D12PipelineStateViewer.cs b/renderdocui/Windows/PipelineState/D3D12PipelineStateViewer.cs index 9a5b9c196..1e13c3b7b 100644 --- a/renderdocui/Windows/PipelineState/D3D12PipelineStateViewer.cs +++ b/renderdocui/Windows/PipelineState/D3D12PipelineStateViewer.cs @@ -342,7 +342,14 @@ namespace renderdocui.Windows.PipelineState var b = binds[i]; var res = resources[i]; - if (b.bindset == space && b.bind == reg && !res.IsSampler) + bool regMatch = b.bind == reg; + + // handle unbounded arrays specially. It's illegal to have an unbounded array with + // anything after it + if (b.bind <= reg) + regMatch = (b.arraySize == UInt32.MaxValue) || (b.bind + b.arraySize > reg); + + if (b.bindset == space && regMatch && !res.IsSampler) { bind = b; shaderInput = res; @@ -351,6 +358,8 @@ namespace renderdocui.Windows.PipelineState } } + TreelistView.NodeCollection parent = list.Nodes; + string rootel = r.Immediate ? String.Format("#{0} Direct", r.RootElement) : rootel = String.Format("#{0} Table[{1}]", r.RootElement, r.TableIndex); bool filledSlot = r.Resource != ResourceId.Null; @@ -426,21 +435,22 @@ namespace renderdocui.Windows.PipelineState if (bufs[t].ID == r.Resource) { w = bufs[t].length; - h = 0; - d = 0; - a = 0; + h = 1; + d = 1; + a = 1; format = ""; name = bufs[t].name; - typename = "RWBuffer"; + typename = uav ? "RWBuffer" : "Buffer"; if (r.BufferFlags.HasFlag(D3DBufferViewFlags.Raw)) { - typename = "RWByteAddressBuffer"; + typename = uav ? "RWByteAddressBuffer" : "ByteAddressBuffer"; } else if (r.ElementSize > 0) { // for structured buffers, display how many 'elements' there are in the buffer - typename = "RWStructuredBuffer[" + (bufs[t].length / r.ElementSize) + "]"; + typename = (uav ? "RWStructuredBuffer" : "StructuredBuffer"); + a = (uint)(bufs[t].length / r.ElementSize); } if (r.CounterResource != ResourceId.Null) @@ -451,17 +461,12 @@ namespace renderdocui.Windows.PipelineState // get the buffer type, whether it's just a basic type or a complex struct if (shaderInput != null && !shaderInput.IsTexture) { - if (r.Format.compType == FormatComponentType.None) - { - if (shaderInput.variableType.members.Length > 0) - format = "struct " + shaderInput.variableType.Name; - else - format = shaderInput.variableType.Name; - } + if (shaderInput.variableType.members.Length > 0) + format = "struct " + shaderInput.variableType.Name; + else if (r.Format.compType == FormatComponentType.None) + format = shaderInput.variableType.Name; else - { format = r.Format.ToString(); - } } tag = new ViewBufTag(r, bufs[t], true, shaderInput); @@ -472,7 +477,7 @@ namespace renderdocui.Windows.PipelineState } } - var node = list.Nodes.Add(new object[] { rootel, space, regname, name, typename, w, h, d, a, format }); + var node = parent.Add(new object[] { rootel, space, regname, name, typename, w, h, d, a, format }); node.Image = global::renderdocui.Properties.Resources.action; node.HoverImage = global::renderdocui.Properties.Resources.action_hover; @@ -573,7 +578,14 @@ namespace renderdocui.Windows.PipelineState var b = stage.BindpointMapping.ReadOnlyResources[i]; var res = stage.ShaderDetails.ReadOnlyResources[i]; - if (b.bindset == space && b.bind == reg && res.IsSampler) + bool regMatch = b.bind == reg; + + // handle unbounded arrays specially. It's illegal to have an unbounded array with + // anything after it + if (b.bind <= reg) + regMatch = (b.arraySize == UInt32.MaxValue) || (b.bind + b.arraySize > reg); + + if (b.bindset == space && regMatch && res.IsSampler) { bind = b; shaderInput = res; @@ -702,7 +714,14 @@ namespace renderdocui.Windows.PipelineState var bd = stage.BindpointMapping.ConstantBlocks[i]; var res = stage.ShaderDetails.ConstantBlocks[i]; - if (bd.bindset == space && bd.bind == reg) + bool regMatch = bd.bind == reg; + + // handle unbounded arrays specially. It's illegal to have an unbounded array with + // anything after it + if (bd.bind <= reg) + regMatch = (bd.arraySize == UInt32.MaxValue) || (bd.bind + bd.arraySize > reg); + + if (bd.bindset == space && regMatch) { bind = bd; shaderCBuf = res;