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
This commit is contained in:
baldurk
2024-03-18 12:55:33 +00:00
parent d88aad8fc2
commit bbbfb5f3d2
4 changed files with 179 additions and 8 deletions
+134 -4
View File
@@ -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.");
@@ -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;
@@ -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;
+13 -4
View File
@@ -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 <typename SerialiserType>
@@ -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 <typename SerialiserType>
@@ -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 <typename SerialiserType>
@@ -312,7 +321,7 @@ void DoSerialise(SerialiserType &ser, ShaderReflection &el)
SERIALISE_MEMBER(taskPayload);
SIZE_CHECK(480);
SIZE_CHECK(488);
}
template <typename SerialiserType>