From bbbfb5f3d2354c4cad8fae9d8cb0072011f3cfca Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 18 Mar 2024 12:55:33 +0000 Subject: [PATCH] Add fixed bindpoint information to shader reflection data * Previously this was provided by the ShaderBindpointMapping, but since we plan to remove that we add the information here. These will be purely for informational purposes and will not be used to look up bound resources etc. They exist for display only, or for API-specific interpretation if e.g. the bindpoint is known ahead of time it can be identified here without having to jump through hoops to get which descriptor a given bind accesses and get the register number for that descriptor. * On OpenGL this information will not be present because bindings are mutable (even if they are declared in the shader). The only way to identify a particular binding by register will be with those hoops --- renderdoc/api/replay/shader_types.h | 138 +++++++++++++++++- .../driver/shaders/dxbc/dxbc_reflect.cpp | 12 ++ .../driver/shaders/spirv/spirv_reflect.cpp | 20 +++ renderdoc/replay/renderdoc_serialise.inl | 17 ++- 4 files changed, 179 insertions(+), 8 deletions(-) diff --git a/renderdoc/api/replay/shader_types.h b/renderdoc/api/replay/shader_types.h index aac7062ad..b742061fc 100644 --- a/renderdoc/api/replay/shader_types.h +++ b/renderdoc/api/replay/shader_types.h @@ -1143,6 +1143,7 @@ struct ConstantBlock bool operator==(const ConstantBlock &o) const { return name == o.name && variables == o.variables && bindPoint == o.bindPoint && + fixedBindSetOrSpace == o.fixedBindSetOrSpace && bufferBacked == o.bufferBacked && byteSize == o.byteSize && bufferBacked == o.bufferBacked && inlineDataBytes == o.inlineDataBytes && compileConstants == o.compileConstants; } @@ -1150,10 +1151,12 @@ struct ConstantBlock { if(!(name == o.name)) return name < o.name; - if(!(variables == o.variables)) - return variables < o.variables; if(!(bindPoint == o.bindPoint)) return bindPoint < o.bindPoint; + if(!(fixedBindNumber == o.fixedBindNumber)) + return fixedBindNumber < o.fixedBindNumber; + if(!(fixedBindSetOrSpace == o.fixedBindSetOrSpace)) + return fixedBindSetOrSpace < o.fixedBindSetOrSpace; if(!(byteSize == o.byteSize)) return byteSize < o.byteSize; if(!(bufferBacked == o.bufferBacked)) @@ -1162,6 +1165,8 @@ struct ConstantBlock return inlineDataBytes < o.inlineDataBytes; if(!(compileConstants == o.compileConstants)) return compileConstants < o.compileConstants; + if(!(variables == o.variables)) + return variables < o.variables; return false; } DOCUMENT("The name of this constant block, may be empty on some APIs."); @@ -1175,6 +1180,48 @@ struct ConstantBlock :data:`ShaderBindpointMapping.constantBlocks` list. )"); int32_t bindPoint = 0; + + DOCUMENT(R"(The fixed binding number for this binding. The interpretation of this is API-specific +and it is provided purely for informational purposes and has no bearing on how data is accessed or +described. Similarly some bindings don't have a fixed bind number and the value here should not be +relied on. + +For OpenGL only, this value is not used as bindings are dynamic and cannot be determined by the +shader reflection. Bindings must be determined only by the descriptor mapped to. + +Generally speaking sorting by this number will give a reasonable ordering by binding if it exists. + +.. note:: + Because this number is API-specific, there is no guarantee that it will be unique across all + resources, though generally it will be unique within all binds of the same type. It should be used + only within contexts that can interpret it API-specifically, or else for purely + informational/non-semantic purposes like sorting. + +:type: int +)"); + uint32_t fixedBindNumber = 0; + + DOCUMENT(R"(The fixed binding set or space for this binding. This is API-specific, on Vulkan this +gives the set and on D3D12 this gives the register space. +It is provided purely for informational purposes and has no bearing on how data is accessed or +described. + +Generally speaking sorting by this number before :data:`fixedBindNumber` will give a reasonable +ordering by binding if it exists. + +:type: int +)"); + uint32_t fixedBindSetOrSpace = 0; + + DOCUMENT(R"(If this binding is natively arrayed, how large is the array size. If not arrayed, this +will be set to 1. + +This value may be set to a very large number if the array is unbounded in the shader. + +:type: int +)"); + uint32_t bindArraySize = 1; + DOCUMENT("The total number of bytes consumed by all of the constants contained in this block."); uint32_t byteSize = 0; DOCUMENT(R"(``True`` if the contents are stored in a buffer of memory. If not then they are set by @@ -1222,6 +1269,47 @@ struct ShaderSampler :data:`ShaderBindpointMapping.samplers` list. )"); int32_t bindPoint; + + DOCUMENT(R"(The fixed binding number for this binding. The interpretation of this is API-specific +and it is provided purely for informational purposes and has no bearing on how data is accessed or +described. Similarly some bindings don't have a fixed bind number and the value here should not be +relied on. + +For OpenGL only, this value is not used as bindings are dynamic and cannot be determined by the +shader reflection. Bindings must be determined only by the descriptor mapped to. + +Generally speaking sorting by this number will give a reasonable ordering by binding if it exists. + +.. note:: + Because this number is API-specific, there is no guarantee that it will be unique across all + resources, though generally it will be unique within all binds of the same type. It should be used + only within contexts that can interpret it API-specifically, or else for purely + informational/non-semantic purposes like sorting. + +:type: int +)"); + uint32_t fixedBindNumber = 0; + + DOCUMENT(R"(The fixed binding set or space for this binding. This is API-specific, on Vulkan this +gives the set and on D3D12 this gives the register space. +It is provided purely for informational purposes and has no bearing on how data is accessed or +described. + +Generally speaking sorting by this number before :data:`fixedBindNumber` will give a reasonable +ordering by binding if it exists. + +:type: int +)"); + uint32_t fixedBindSetOrSpace = 0; + + DOCUMENT(R"(If this binding is natively arrayed, how large is the array size. If not arrayed, this +will be set to 1. + +This value may be set to a very large number if the array is unbounded in the shader. + +:type: int +)"); + uint32_t bindArraySize = 1; }; DECLARE_REFLECTION_STRUCT(ShaderSampler); @@ -1242,6 +1330,7 @@ struct ShaderResource bool operator==(const ShaderResource &o) const { return resType == o.resType && name == o.name && variableType == o.variableType && + fixedBindNumber == o.fixedBindNumber && fixedBindSetOrSpace == o.fixedBindSetOrSpace && bindPoint == o.bindPoint && isTexture == o.isTexture && hasSampler == o.hasSampler && isInputAttachment == o.isInputAttachment && isReadOnly == o.isReadOnly; } @@ -1253,8 +1342,8 @@ struct ShaderResource return name < o.name; if(!(variableType == o.variableType)) return variableType < o.variableType; - if(!(bindPoint == o.bindPoint)) - return bindPoint < o.bindPoint; + if(!(fixedBindSetOrSpace == o.fixedBindSetOrSpace)) + return fixedBindSetOrSpace < o.fixedBindSetOrSpace; if(!(isTexture == o.isTexture)) return isTexture < o.isTexture; if(!(hasSampler == o.hasSampler)) @@ -1283,6 +1372,47 @@ struct ShaderResource )"); int32_t bindPoint; + DOCUMENT(R"(The fixed binding number for this binding. The interpretation of this is API-specific +and it is provided purely for informational purposes and has no bearing on how data is accessed or +described. Similarly some bindings don't have a fixed bind number and the value here should not be +relied on. + +For OpenGL only, this value is not used as bindings are dynamic and cannot be determined by the +shader reflection. Bindings must be determined only by the descriptor mapped to. + +Generally speaking sorting by this number will give a reasonable ordering by binding if it exists. + +.. note:: + Because this number is API-specific, there is no guarantee that it will be unique across all + resources, though generally it will be unique within all binds of the same type. It should be used + only within contexts that can interpret it API-specifically, or else for purely + informational/non-semantic purposes like sorting. + +:type: int +)"); + uint32_t fixedBindNumber = 0; + + DOCUMENT(R"(The fixed binding set or space for this binding. This is API-specific, on Vulkan this +gives the set and on D3D12 this gives the register space. +It is provided purely for informational purposes and has no bearing on how data is accessed or +described. + +Generally speaking sorting by this number before :data:`fixedBindNumber` will give a reasonable +ordering by binding if it exists. + +:type: int +)"); + uint32_t fixedBindSetOrSpace = 0; + + DOCUMENT(R"(If this binding is natively arrayed, how large is the array size. If not arrayed, this +will be set to 1. + +This value may be set to a very large number if the array is unbounded in the shader. + +:type: int +)"); + uint32_t bindArraySize = 1; + DOCUMENT("``True`` if this resource is a texture, otherwise it is a buffer."); bool isTexture; DOCUMENT("``True`` if this texture resource has a sampler as well."); diff --git a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp index f86afafd0..1869e05d9 100644 --- a/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp +++ b/renderdoc/driver/shaders/dxbc/dxbc_reflect.cpp @@ -252,6 +252,10 @@ static void MakeResourceList(bool srv, DXBC::DXBCContainer *dxbc, res.bindPoint = (int32_t)i; + res.fixedBindNumber = r.reg; + res.fixedBindSetOrSpace = r.space; + res.bindArraySize = r.bindCount == 0 ? ~0U : r.bindCount; + Bindpoint map; map.arraySize = r.bindCount == 0 ? ~0U : r.bindCount; map.bindset = r.space; @@ -398,6 +402,10 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl, cb.byteSize = dxbcRefl->CBuffers[i].descriptor.byteSize; cb.bindPoint = (int32_t)i; + cb.fixedBindNumber = dxbcRefl->CBuffers[i].reg; + cb.fixedBindSetOrSpace = dxbcRefl->CBuffers[i].space; + cb.bindArraySize = dxbcRefl->CBuffers[i].bindCount; + Bindpoint map; map.arraySize = dxbcRefl->CBuffers[i].bindCount; map.bindset = dxbcRefl->CBuffers[i].space; @@ -424,6 +432,10 @@ void MakeShaderReflection(DXBC::DXBCContainer *dxbc, ShaderReflection *refl, s.name = dxbcRefl->Samplers[i].name; s.bindPoint = (int32_t)i; + s.fixedBindNumber = dxbcRefl->Samplers[i].reg; + s.fixedBindSetOrSpace = dxbcRefl->Samplers[i].space; + s.bindArraySize = dxbcRefl->Samplers[i].bindCount; + Bindpoint map; map.arraySize = 1; map.bindset = dxbcRefl->Samplers[i].space; diff --git a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp index 3a2a86309..431ac2166 100644 --- a/renderdoc/driver/shaders/spirv/spirv_reflect.cpp +++ b/renderdoc/driver/shaders/spirv/spirv_reflect.cpp @@ -1407,6 +1407,10 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st bindmap.bindset = 0; bindmap.bind = GetBinding(decorations[global.id].binding); + res.fixedBindSetOrSpace = 0; + res.fixedBindNumber = GetBinding(decorations[global.id].binding); + res.bindArraySize = isArray ? arraySize : 1; + rwresources.push_back(shaderrespair(bindmap, res)); } else if(varType->IsOpaqueType()) @@ -1424,6 +1428,10 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st if(res.name.empty()) res.name = StringFormat::Fmt("res%u", global.id.value()); + res.fixedBindSetOrSpace = bindmap.bindset; + res.fixedBindNumber = bindmap.bind; + res.bindArraySize = isArray ? arraySize : 1; + if(varType->type == DataType::SamplerType) { res.resType = TextureType::Unknown; @@ -1544,6 +1552,10 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st res.name = StringFormat::Fmt("ssbo%u", global.id.value()); res.resType = TextureType::Buffer; + res.fixedBindNumber = bindmap.bind; + res.fixedBindSetOrSpace = bindmap.bindset; + res.bindArraySize = isArray ? arraySize : 1; + res.variableType.columns = 0; res.variableType.rows = 0; res.variableType.baseType = VarType::Float; @@ -1564,6 +1576,10 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st cblock.bufferBacked = !pushConst; cblock.inlineDataBytes = pushConst; + cblock.fixedBindNumber = bindmap.bind; + cblock.fixedBindSetOrSpace = bindmap.bindset; + cblock.bindArraySize = isArray ? arraySize : 1; + MakeConstantBlockVariables(effectiveStorage, *varType, 0, 0, cblock.variables, pointerTypes, specInfo); @@ -1616,6 +1632,8 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st specblock.inlineDataBytes = true; specblock.compileConstants = true; specblock.byteSize = 0; + // set the binding number to some huge value to try to sort it to the end + specblock.fixedBindNumber = 0x8000000; Bindpoint bindmap; @@ -1636,6 +1654,8 @@ void Reflector::MakeReflection(const GraphicsAPI sourceAPI, const ShaderStage st globalsblock.inlineDataBytes = false; globalsblock.byteSize = (uint32_t)globalsblock.variables.size(); globalsblock.bindPoint = (int)cblocks.size(); + // set the binding number to some huge value to try to sort it to the end + globalsblock.fixedBindNumber = 0x8000001; Bindpoint bindmap; bindmap.bindset = 0; diff --git a/renderdoc/replay/renderdoc_serialise.inl b/renderdoc/replay/renderdoc_serialise.inl index 561932d52..fe9ec5520 100644 --- a/renderdoc/replay/renderdoc_serialise.inl +++ b/renderdoc/replay/renderdoc_serialise.inl @@ -198,11 +198,14 @@ void DoSerialise(SerialiserType &ser, ConstantBlock &el) SERIALISE_MEMBER(name); SERIALISE_MEMBER(variables); SERIALISE_MEMBER(bindPoint); + SERIALISE_MEMBER(fixedBindNumber); + SERIALISE_MEMBER(fixedBindSetOrSpace); + SERIALISE_MEMBER(bindArraySize); SERIALISE_MEMBER(byteSize); SERIALISE_MEMBER(bufferBacked); SERIALISE_MEMBER(compileConstants); - SIZE_CHECK(64); + SIZE_CHECK(72); } template @@ -210,8 +213,11 @@ void DoSerialise(SerialiserType &ser, ShaderSampler &el) { SERIALISE_MEMBER(name); SERIALISE_MEMBER(bindPoint); + SERIALISE_MEMBER(fixedBindNumber); + SERIALISE_MEMBER(fixedBindSetOrSpace); + SERIALISE_MEMBER(bindArraySize); - SIZE_CHECK(32); + SIZE_CHECK(40); } template @@ -221,12 +227,15 @@ void DoSerialise(SerialiserType &ser, ShaderResource &el) SERIALISE_MEMBER(name); SERIALISE_MEMBER(variableType); SERIALISE_MEMBER(bindPoint); + SERIALISE_MEMBER(fixedBindNumber); + SERIALISE_MEMBER(fixedBindSetOrSpace); + SERIALISE_MEMBER(bindArraySize); SERIALISE_MEMBER(isTexture); SERIALISE_MEMBER(hasSampler); SERIALISE_MEMBER(isInputAttachment); SERIALISE_MEMBER(isReadOnly); - SIZE_CHECK(112); + SIZE_CHECK(128); } template @@ -312,7 +321,7 @@ void DoSerialise(SerialiserType &ser, ShaderReflection &el) SERIALISE_MEMBER(taskPayload); - SIZE_CHECK(480); + SIZE_CHECK(488); } template