mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-09-13 09:15:36 +00:00
Pass bindless feedback data to UI through vulkan pipeline state
* Each binding element within an arrayed descriptor has a bool indicating if it's dynamically used or not (which will be set to true if the feedback isn't available). Each descriptor has a uint32_t indicating how many elements are dynamically used - which is useful for the UI to hide the root of an array that has no used elements, or to heuristically decide whether to expand or elide the contents.
This commit is contained in:
@@ -232,6 +232,7 @@ struct BoundResource
|
||||
BoundResource()
|
||||
{
|
||||
resourceId = ResourceId();
|
||||
dynamicallyUsed = true;
|
||||
firstMip = -1;
|
||||
firstSlice = -1;
|
||||
typeHint = CompType::Typeless;
|
||||
@@ -239,6 +240,7 @@ struct BoundResource
|
||||
BoundResource(ResourceId id)
|
||||
{
|
||||
resourceId = id;
|
||||
dynamicallyUsed = true;
|
||||
firstMip = -1;
|
||||
firstSlice = -1;
|
||||
typeHint = CompType::Typeless;
|
||||
@@ -264,6 +266,12 @@ struct BoundResource
|
||||
}
|
||||
DOCUMENT("A :class:`~renderdoc.ResourceId` identifying the bound resource.");
|
||||
ResourceId resourceId;
|
||||
DOCUMENT(R"(``True`` if this binding element is dynamically used.
|
||||
|
||||
Some APIs provide fine-grained usage based on dynamic shader feedback, to support 'bindless'
|
||||
scenarios where only a small sparse subset of bound resources are actually used.
|
||||
)");
|
||||
bool dynamicallyUsed = true;
|
||||
DOCUMENT("For textures, the highest mip level available on this binding, or -1 for all mips");
|
||||
int firstMip;
|
||||
DOCUMENT("For textures, the first array slice available on this binding. or -1 for all slices.");
|
||||
@@ -285,7 +293,10 @@ struct BoundResourceArray
|
||||
BoundResourceArray() = default;
|
||||
BoundResourceArray(const BoundResourceArray &) = default;
|
||||
BoundResourceArray(Bindpoint b) : bindPoint(b) {}
|
||||
BoundResourceArray(Bindpoint b, const rdcarray<BoundResource> &r) : bindPoint(b), resources(r) {}
|
||||
BoundResourceArray(Bindpoint b, const rdcarray<BoundResource> &r) : bindPoint(b), resources(r)
|
||||
{
|
||||
dynamicallyUsedCount = (uint32_t)r.size();
|
||||
}
|
||||
// for convenience for searching the array, we compare only using the BindPoint
|
||||
bool operator==(const BoundResourceArray &o) const { return bindPoint == o.bindPoint; }
|
||||
bool operator!=(const BoundResourceArray &o) const { return !(bindPoint == o.bindPoint); }
|
||||
@@ -295,6 +306,13 @@ struct BoundResourceArray
|
||||
|
||||
DOCUMENT("The resources at this bind point");
|
||||
rdcarray<BoundResource> resources;
|
||||
|
||||
DOCUMENT(R"(Lists how many bindings in :data:`resources` are dynamically used.
|
||||
|
||||
Some APIs provide fine-grained usage based on dynamic shader feedback, to support 'bindless'
|
||||
scenarios where only a small sparse subset of bound resources are actually used.
|
||||
)");
|
||||
uint32_t dynamicallyUsedCount = 0;
|
||||
};
|
||||
|
||||
DECLARE_REFLECTION_STRUCT(BoundResourceArray);
|
||||
|
||||
@@ -1115,9 +1115,12 @@ rdcarray<BoundResourceArray> PipeState::GetReadOnlyResources(ShaderStage stage)
|
||||
rdcarray<BoundResource> &val = ret.back().resources;
|
||||
val.resize(bind.descriptorCount);
|
||||
|
||||
ret.back().dynamicallyUsedCount = bind.dynamicallyUsedCount;
|
||||
|
||||
for(uint32_t i = 0; i < bind.descriptorCount; i++)
|
||||
{
|
||||
val[i].resourceId = bind.binds[i].resourceResourceId;
|
||||
val[i].dynamicallyUsed = bind.binds[i].dynamicallyUsed;
|
||||
val[i].firstMip = (int)bind.binds[i].firstMip;
|
||||
val[i].firstSlice = (int)bind.binds[i].firstSlice;
|
||||
val[i].typeHint = bind.binds[i].viewFormat.compType;
|
||||
@@ -1266,9 +1269,12 @@ rdcarray<BoundResourceArray> PipeState::GetReadWriteResources(ShaderStage stage)
|
||||
rdcarray<BoundResource> &val = ret.back().resources;
|
||||
val.resize(bind.descriptorCount);
|
||||
|
||||
ret.back().dynamicallyUsedCount = bind.dynamicallyUsedCount;
|
||||
|
||||
for(uint32_t i = 0; i < bind.descriptorCount; i++)
|
||||
{
|
||||
val[i].resourceId = bind.binds[i].resourceResourceId;
|
||||
val[i].dynamicallyUsed = bind.binds[i].dynamicallyUsed;
|
||||
val[i].firstMip = (int)bind.binds[i].firstMip;
|
||||
val[i].firstSlice = (int)bind.binds[i].firstSlice;
|
||||
val[i].typeHint = bind.binds[i].viewFormat.compType;
|
||||
|
||||
@@ -37,21 +37,23 @@ struct BindingElement
|
||||
|
||||
bool operator==(const BindingElement &o) const
|
||||
{
|
||||
return viewResourceId == o.viewResourceId && resourceResourceId == o.resourceResourceId &&
|
||||
samplerResourceId == o.samplerResourceId && immutableSampler == o.immutableSampler &&
|
||||
viewFormat == o.viewFormat && swizzle[0] == o.swizzle[0] && swizzle[1] == o.swizzle[1] &&
|
||||
swizzle[2] == o.swizzle[2] && swizzle[3] == o.swizzle[3] && firstMip == o.firstMip &&
|
||||
firstSlice == o.firstSlice && numMips == o.numMips && numSlices == o.numSlices &&
|
||||
byteOffset == o.byteOffset && byteSize == o.byteSize && filter == o.filter &&
|
||||
addressU == o.addressU && addressV == o.addressV && addressW == o.addressW &&
|
||||
mipBias == o.mipBias && maxAnisotropy == o.maxAnisotropy &&
|
||||
compareFunction == o.compareFunction && minLOD == o.minLOD && maxLOD == o.maxLOD &&
|
||||
borderColor[0] == o.borderColor[0] && borderColor[1] == o.borderColor[1] &&
|
||||
borderColor[2] == o.borderColor[2] && borderColor[3] == o.borderColor[3] &&
|
||||
unnormalized == o.unnormalized;
|
||||
return dynamicallyUsed == o.dynamicallyUsed && viewResourceId == o.viewResourceId &&
|
||||
resourceResourceId == o.resourceResourceId && samplerResourceId == o.samplerResourceId &&
|
||||
immutableSampler == o.immutableSampler && viewFormat == o.viewFormat &&
|
||||
swizzle[0] == o.swizzle[0] && swizzle[1] == o.swizzle[1] && swizzle[2] == o.swizzle[2] &&
|
||||
swizzle[3] == o.swizzle[3] && firstMip == o.firstMip && firstSlice == o.firstSlice &&
|
||||
numMips == o.numMips && numSlices == o.numSlices && byteOffset == o.byteOffset &&
|
||||
byteSize == o.byteSize && filter == o.filter && addressU == o.addressU &&
|
||||
addressV == o.addressV && addressW == o.addressW && mipBias == o.mipBias &&
|
||||
maxAnisotropy == o.maxAnisotropy && compareFunction == o.compareFunction &&
|
||||
minLOD == o.minLOD && maxLOD == o.maxLOD && borderColor[0] == o.borderColor[0] &&
|
||||
borderColor[1] == o.borderColor[1] && borderColor[2] == o.borderColor[2] &&
|
||||
borderColor[3] == o.borderColor[3] && unnormalized == o.unnormalized;
|
||||
}
|
||||
bool operator<(const BindingElement &o) const
|
||||
{
|
||||
if(!(dynamicallyUsed == o.dynamicallyUsed))
|
||||
return dynamicallyUsed < o.dynamicallyUsed;
|
||||
if(!(viewResourceId == o.viewResourceId))
|
||||
return viewResourceId < o.viewResourceId;
|
||||
if(!(resourceResourceId == o.resourceResourceId))
|
||||
@@ -121,6 +123,15 @@ struct BindingElement
|
||||
ResourceId samplerResourceId;
|
||||
DOCUMENT("``True`` if this is an immutable sampler binding.");
|
||||
bool immutableSampler = false;
|
||||
DOCUMENT(R"(``True`` if this binding element is dynamically used.
|
||||
|
||||
If set to ``False`` this means that the binding was available to the shader but during execution it
|
||||
was not referenced. The data gathered for setting this variable is conservative, meaning that only
|
||||
accesses through arrays will have this calculated to reduce the required feedback bandwidth - single
|
||||
non-arrayed descriptors may have this value set to ``True`` even if the shader did not use them,
|
||||
since single descriptors may only be dynamically skipped by control flow.
|
||||
)");
|
||||
bool dynamicallyUsed = true;
|
||||
|
||||
DOCUMENT("The :class:`ResourceFormat` that the view uses.");
|
||||
ResourceFormat viewFormat;
|
||||
@@ -209,13 +220,15 @@ struct DescriptorBinding
|
||||
|
||||
bool operator==(const DescriptorBinding &o) const
|
||||
{
|
||||
return descriptorCount == o.descriptorCount && type == o.type && stageFlags == o.stageFlags &&
|
||||
binds == o.binds;
|
||||
return descriptorCount == o.descriptorCount && dynamicallyUsedCount == o.dynamicallyUsedCount &&
|
||||
type == o.type && stageFlags == o.stageFlags && binds == o.binds;
|
||||
}
|
||||
bool operator<(const DescriptorBinding &o) const
|
||||
{
|
||||
if(!(descriptorCount == o.descriptorCount))
|
||||
return descriptorCount < o.descriptorCount;
|
||||
if(!(dynamicallyUsedCount == o.dynamicallyUsedCount))
|
||||
return dynamicallyUsedCount < o.dynamicallyUsedCount;
|
||||
if(!(type == o.type))
|
||||
return type < o.type;
|
||||
if(!(stageFlags == o.stageFlags))
|
||||
@@ -228,6 +241,12 @@ struct DescriptorBinding
|
||||
If this binding is empty/non-existant this value will be ``0``.
|
||||
)");
|
||||
uint32_t descriptorCount = 0;
|
||||
DOCUMENT(R"(Lists how many bindings in :data:`binds` are dynamically used. Useful to avoid
|
||||
redundant iteration to determine whether any bindings are present.
|
||||
|
||||
For more information see :data:`VKBindingElement.dynamicallyUsed`.
|
||||
)");
|
||||
uint32_t dynamicallyUsedCount = 0;
|
||||
DOCUMENT("The :class:`BindType` of this binding.");
|
||||
BindType type = BindType::Unknown;
|
||||
DOCUMENT("The :class:`ShaderStageMask` where this binding is visible.");
|
||||
|
||||
Reference in New Issue
Block a user