VK_EXT_descriptor_indexing

在 Vulkan 1.2 中提升为核心

蒙特利尔开发者日的演示 (视频幻灯片)

此扩展旨在分解为几个不同的、较小的功能,以便实现可以在可能的情况下添加对每个功能的支持。

绑定后更新

如果没有此扩展,则不允许应用程序中的描述符在记录命令缓冲区和执行命令缓冲区之间进行更新。 使用此扩展,应用程序可以查询所使用描述符类型的 descriptorBinding*UpdateAfterBind 支持,这允许应用程序在记录和执行之间进行更新。

示例

如果应用程序具有 StorageBuffer 描述符,则它将查询 descriptorBindingStorageBufferUpdateAfterBind 支持。

在启用对绑定后更新的所需功能支持后,应用程序需要设置以下内容才能使用可以在绑定后更新的描述符

  • 从其中分配描述符的任何 VkDescriptorPoolVK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT 标志。

  • 来自该描述符的任何 VkDescriptorSetLayoutVK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT 标志。

  • 描述符将使用的 VkDescriptorSetLayout 中每个绑定的 VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT

以下代码示例说明了启用绑定后更新和不启用之间的区别

VK_EXT_descriptor_indexing_update_after_bind.png

部分绑定

使用 descriptorBindingPartiallyBound 功能并在 VkDescriptorSetLayoutBindingFlagsCreateInfo::pBindingFlags 中使用 VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT,应用程序开发人员不需要在使用时更新所有描述符。

例如,如果应用程序的 GLSL 具有

layout(set = 0, binding = 0) uniform sampler2D textureSampler[64];

但仅绑定数组中的前 32 个插槽。 这也依赖于应用程序知道它不会索引到数组中未绑定的插槽。

动态索引

通常,当应用程序索引到绑定描述符数组中时,索引需要在编译时已知。 使用 shader*ArrayDynamicIndexing 功能,可以通过“动态统一”整数索引某种类型的描述符。 这已经作为大多数描述符的 VkPhysicalDeviceFeatures 支持,但此扩展添加了 VkPhysicalDeviceDescriptorIndexingFeatures 结构,使实现可以公开对输入附件、统一纹理缓冲区和存储纹理缓冲区的动态统一索引的支持。

这里的关键词是“统一”,这意味着 SPIR-V 调用组中的所有调用都需要使用相同的动态索引。 这转换为 vkCmdDraw* 调用中的所有调用或 vkCmdDispatch* 调用的单个工作组。

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);
    // ...
}

此示例是“动态的”,因为它在运行时才知道 ubo.textureId 的值。 这也是“统一的”,因为所有调用都将在此着色器中使用 ubo.textureId

动态非统一索引

动态 非统一 意味着调用可能会以不同的方式索引到描述符数组中,但在运行时才会知道。 此扩展在 VkPhysicalDeviceDescriptorIndexingFeatures 中公开了一组 shader*ArrayNonUniformIndexing 功能位,以显示实现支持哪些描述符类型的动态非统一索引。 SPIR-V 扩展添加了一个 NonUniform 修饰符,可以使用添加的 nonuniformEXT 关键字在 GLSL 中设置该修饰符。

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);
    // ...
}

此示例是非统一的,因为一些调用索引 mySampler[0],而另一些调用索引 mySampler[1]。 在这种情况下需要 nonuniformEXT()