Promoted to core in Vulkan 1.2
This extension was designed to be broken down into a few different, smaller features to allow implementations to add support for the each feature when possible.
Without this extension, descriptors in an application are not allowed to update between recording the command buffer and the execution of the command buffers. With this extension an application can querying for descriptorBinding*UpdateAfterBind
support for the type of descriptor being used which allows an application to then update in between recording and execution.
For example, if an application has a
StorageBuffer
descriptor, then it will query fordescriptorBindingStorageBufferUpdateAfterBind
support.
After enabling the desired feature support for updating after bind, an application needs to setup the following in order to use a descriptor that can update after bind:
- The
VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT
flag for anyVkDescriptorPool
the descriptor is allocated from. - The
VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT
flag for anyVkDescriptorSetLayout
the descriptor is from. - The
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT
for each binding in theVkDescriptorSetLayout
that the descriptor will use.
The following code example gives an idea of the difference between enabling update after bind and without it:
With the descriptorBindingPartiallyBound
feature and using VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT
in the VkDescriptorSetLayoutBindingFlagsCreateInfo::pBindingFlags
an application developer isn't required to update all the descriptors at time of use.
An example would be if an application's GLSL has
layout(set = 0, binding = 0) uniform sampler2D textureSampler[64];
but only binds the first 32 slots in the array. This also relies on the the application knowing that it will not index into the unbound slots in the array.
Normally when an application indexes into an array of bound descriptors the index needs to be known at compile time. With the shader*ArrayDynamicIndexing
feature, a certain type of descriptor can be indexed by "dynamically uniform" integers. This was already supported as a VkPhysicalDeviceFeatures
for most descriptors, but this extension adds VkPhysicalDeviceDescriptorIndexingFeatures
struct that lets implementations expose support for dynamic uniform indexing of input attachments, uniform texel buffers, and storage texel buffers as well.
The key word here is "uniform" which means that all invocations in a SPIR-V Invocation Group need to all use the same dynamic index. This translates to either all invocations in a single vkCmdDraw*
call or a single workgroup of a vkCmdDispatch*
call.
An example of dynamic uniform indexing in GLSL
layout(set = 0, binding = 0) uniform sampler2D mySampler[64];
layout(set = 0, binding = 1) uniform UniformBufferObject {
int textureId;
} ubo;
// ...
void main() {
// ...
vec4 samplerColor = texture(mySampler[ubo.textureId], uvCoords);
// ...
}
This example is "dynamic" as it is will not be known until runtime what the value of ubo.textureId
is. This is also "uniform" as all invocations will use ubo.textureId
in this shader.
To be dynamically non-uniform means that it is possible that invocations might index differently into an array of descriptors, but it won't be known until runtime. This extension exposes in VkPhysicalDeviceDescriptorIndexingFeatures
a set of shader*ArrayNonUniformIndexing
feature bits to show which descriptor types an implementation supports dynamic non-uniform indexing for. The SPIR-V extension adds a NonUniform
decoration which can be set in GLSL with the help of the nonuniformEXT
keyword added.
An example of dynamic non-uniform indexing in GLSL
#version450
#extension GL_EXT_nonuniform_qualifier : enable
layout(set = 0, binding = 0) uniform sampler2D mySampler[64];
layout(set = 0, binding = 1) uniform UniformBufferObject {
int textureId;
} ubo;
// ...
void main() {
// ...
if (uvCoords.x > runtimeThreshold) {
index = 0;
} else {
index = 1;
}
vec4 samplerColor = texture(mySampler[nonuniformEXT(index)], uvCoords);
// ...
}
This example is non-uniform as some invocations index a mySampler[0]
and some at mySampler[1]
. The nonuniformEXT()
is needed in this case.