资源描述符
描述符 是表示着色器资源(如缓冲区、缓冲区视图、图像视图、采样器或组合图像采样器)的不透明数据结构。描述符被组织成描述符集,这些描述符集在命令记录期间绑定,以便在后续的绘制命令中使用。每个描述符集中内容的排列由描述符集布局确定,该布局决定了可以在其中存储哪些描述符。管线可以使用的一系列描述符集布局在管线布局中指定。每个管线对象可以使用最多 maxBoundDescriptorSets
个描述符集(参见限制)。
如果启用了descriptorBuffer
功能,则实现支持将描述符放置到描述符缓冲区中,这些描述符缓冲区在命令记录期间以类似于描述符集的方式绑定。
着色器通过使用描述符集和绑定编号修饰的变量来访问资源,这些变量将它们链接到描述符集中的描述符。着色器接口映射到绑定的描述符集在着色器资源接口部分中描述。
着色器可以通过使用物理存储缓冲区访问通过 64 位地址访问缓冲区,而无需通过描述符。
描述符类型
Vulkan 支持多种不同类型的描述符,对应于不同的资源或用法。以下各节描述了每种描述符类型的 API 定义。每种类型到 SPIR-V 的映射列在着色器资源和描述符类型对应关系和着色器资源和存储类对应关系表,位于着色器接口章节中。
存储图像
对于其格式功能包含VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT
的图像视图,所有着色器阶段都支持存储图像加载。
对于其格式功能包含VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT
的图像视图,任务着色器、网格着色器和计算着色器都支持存储到存储图像。
对于其格式功能包含VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT
的图像视图,任务着色器、网格着色器和计算着色器都支持对存储图像的原子操作。
当启用fragmentStoresAndAtomics
功能时,片段着色器中的存储图像也支持存储和原子操作,其图像格式与计算着色器中支持的相同。当启用vertexPipelineStoresAndAtomics
功能时,顶点着色器、细分着色器和几何着色器也支持存储和原子操作,其图像格式与计算着色器中支持的相同。
为了在着色器中访问其数据,存储图像的图像子资源必须处于 VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
或 VK_IMAGE_LAYOUT_GENERAL
布局中。
采样图像
着色器将采样图像变量和采样器变量组合在一起以执行采样操作。
对于其格式功能包含VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT
的图像视图,所有着色器阶段都支持采样图像。
采样图像的图像子资源必须处于以下布局之一
-
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_GENERAL
-
VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
-
VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL
-
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR
-
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT
组合图像采样器
组合图像采样器的图像子资源必须采用以下布局之一
-
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_GENERAL
-
VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
-
VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL
-
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_STENCIL_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR
-
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT
在某些实现中,使用组合描述符中存储在一起的采样器和采样图像的组合来采样图像可能更有效。 |
统一纹素缓冲区
统一纹素缓冲区定义了一个紧密打包的 1 维线性纹素数组,当在着色器中读取时,纹素会像图像一样进行格式转换。
对于报告格式功能支持 VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT
的缓冲区视图格式,在所有着色器阶段都支持从统一纹素缓冲区加载操作。
存储纹素缓冲区
存储纹素缓冲区(VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
)是通过缓冲区视图与缓冲区资源关联的描述符类型,可以在其上执行图像加载、存储和原子操作。
对于报告格式功能支持 VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT
的纹素缓冲区视图格式,在所有着色器阶段都支持存储纹素缓冲区加载。
对于报告格式功能支持 VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT
的纹素缓冲区格式,在任务、网格和计算着色器中支持对存储纹素缓冲区进行存储。
对于报告格式功能支持 VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT
的纹素缓冲区格式,在任务、网格和计算着色器中支持对存储纹素缓冲区进行原子操作。
当启用fragmentStoresAndAtomics
功能时,片段着色器中也支持对存储纹素缓冲区进行存储和原子操作,其支持的纹素缓冲区格式与计算着色器中支持的相同。当启用vertexPipelineStoresAndAtomics
功能时,顶点、细分和几何着色器中也支持存储和原子操作,其支持的纹素缓冲区格式与计算着色器中支持的相同。
存储缓冲区
存储缓冲区 (VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
) 是与缓冲区资源直接关联的描述符类型,在着色器中描述为具有各种成员的结构,可以对其执行加载、存储和原子操作。
原子操作只能在SPIR-V 环境附录中定义的某些类型的成员上执行。 |
统一缓冲区
统一缓冲区(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
)是与缓冲区资源直接关联的描述符类型,在着色器中描述为具有各种成员的结构,可以对其执行加载操作。
动态统一缓冲区
动态统一缓冲区(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
)几乎与统一缓冲区相同,唯一的区别在于如何指定缓冲区中的偏移量。最初更新描述符集时通过VkDescriptorBufferInfo计算的基本偏移量,在绑定描述符集时会加上动态偏移量。
动态存储缓冲区
动态存储缓冲区(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC
)几乎与存储缓冲区相同,唯一的区别在于如何指定缓冲区中的偏移量。最初更新描述符集时通过VkDescriptorBufferInfo计算的基本偏移量,在绑定描述符集时会加上动态偏移量。
内联统一块
内联统一块 (VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
) 几乎与统一缓冲区相同,唯一的区别在于它的存储直接来自包含的描述符集,而不是由缓冲区内存支持。它通常用于访问少量常量数据,这些数据不需要使用统一缓冲区时启用的间接寻址所提供的额外灵活性,在统一缓冲区中,描述符和引用的缓冲区内存是分离的。与推送常量相比,它们允许在多个不相交的绘制和调度命令集中重复使用同一组常量数据。
内联统一块描述符不能聚合到数组中。相反,为内联统一块描述符绑定指定的数组大小指定绑定的容量(以字节为单位)。
采样权重图像
采样权重图像 (VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM
) 是一种通过图像视图与图像资源相关联的描述符类型,该描述符类型可以用于权重图像采样。图像视图必须使用VkImageViewSampleWeightCreateInfoQCOM创建。
着色器可以组合权重图像变量、采样图像变量和采样器变量来执行权重图像采样。
如果权重图像视图指定了支持格式功能 VK_FORMAT_FEATURE_2_WEIGHT_IMAGE_BIT_QCOM
的格式,并且采样图像视图指定了支持格式功能 VK_FORMAT_FEATURE_2_WEIGHT_SAMPLED_IMAGE_BIT_QCOM
的格式,则在所有着色器阶段都支持权重图像采样。
权重图像的图像子资源必须采用 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
或 VK_IMAGE_LAYOUT_GENERAL
布局,以便在着色器中访问其数据。
块匹配图像
着色器可以组合目标图像变量、参考图像变量和采样器变量来执行 块匹配。
如果目标视图和参考视图都指定了支持 格式特性 VK_FORMAT_FEATURE_2_BLOCK_MATCHING_BIT_QCOM
的格式,则所有着色器阶段都支持块匹配。
块匹配的图像子资源必须位于 VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
或 VK_IMAGE_LAYOUT_GENERAL
布局中,以便在着色器中访问其数据。
输入附件
对于给定图像平铺模式,所有支持颜色附件(VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT
或 VK_FORMAT_FEATURE_2_LINEAR_COLOR_ATTACHMENT_BIT_NV
)或深度/模板附件(VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT
)的图像格式也支持输入附件。
用作输入附件的图像视图必须位于以下布局之一:
-
VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_GENERAL
-
VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
-
VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL
-
VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL
-
VK_IMAGE_LAYOUT_READ_ONLY_OPTIMAL_KHR
-
VK_IMAGE_LAYOUT_ATTACHMENT_FEEDBACK_LOOP_OPTIMAL_EXT
-
VK_IMAGE_LAYOUT_RENDERING_LOCAL_READ
加速结构
加速结构 (VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR
或 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV
) 是一种描述符类型,用于从用于光线遍历的着色器中检索场景几何体。着色器具有对内存的只读访问权限。
可变
可变 (VK_DESCRIPTOR_TYPE_MUTABLE_EXT
) 类型的描述符表示此描述符可以变异为 VkMutableDescriptorTypeListEXT::pDescriptorTypes
描述符类型列表中给定的任何描述符类型,该列表位于此绑定的 VkDescriptorSetLayoutCreateInfo 的 pNext
链中。在任何时候,每个可变类型的单个描述符都具有活动描述符类型。活动描述符类型可以是 pDescriptorTypes
中声明的类型之一。此外,可变描述符的活动描述符类型可以是 VK_DESCRIPTOR_TYPE_MUTABLE_EXT
类型,这是初始活动描述符类型。当更新描述符时,活动描述符类型可以更改。当通过绑定描述符集来使用描述符时,会考虑活动描述符类型,而不是 VK_DESCRIPTOR_TYPE_MUTABLE_EXT
。
VK_DESCRIPTOR_TYPE_MUTABLE_EXT
的活动描述符类型被认为是未定义的描述符。如果使用的描述符的活动描述符类型与着色器期望的不匹配,则该描述符被认为是未定义的描述符。
要查找支持哪些描述符类型作为 |
可变描述符类型的意图是,实现为每个描述符分配 N 个字节,其中 N 由给定描述符绑定的最大描述符大小确定。实现不应跟踪活动描述符类型,它应该被视为类似 C 的联合类型。 与使用非可变描述符类型相比,可变描述符类型在运行时性能方面效率不高,不鼓励应用程序在 API 分层工作之外使用它们。如果替代方案是使用许多不同的描述符来模拟可变描述符类型,则可变描述符类型可能更有效。 |
描述符集
描述符被分组到描述符集对象中。描述符集对象是一个不透明的对象,其中包含一组描述符的存储,描述符的类型和数量由描述符集布局定义。布局对象可以用于定义每个描述符绑定与内存或其他实现资源的关联。布局既用于确定需要与描述符集关联的资源,也用于确定着色器阶段和着色器资源之间的接口。
描述符集布局
描述符集布局对象由零个或多个描述符绑定的数组定义。每个单独的描述符绑定由描述符类型、绑定中描述符的数量(数组大小)、可以访问该绑定的着色器阶段集合以及(如果使用不可变采样器)采样器描述符数组指定。
描述符集布局对象由 VkDescriptorSetLayout
句柄表示
// Provided by VK_VERSION_1_0
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSetLayout)
要创建描述符集布局对象,请调用
// Provided by VK_VERSION_1_0
VkResult vkCreateDescriptorSetLayout(
VkDevice device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorSetLayout* pSetLayout);
-
device
是创建描述符集布局的逻辑设备。 -
pCreateInfo
是指向 VkDescriptorSetLayoutCreateInfo 结构的指针,该结构指定描述符集布局对象的状态。 -
pAllocator
控制主机内存分配,如 内存分配 章节中所述。 -
pSetLayout
是指向 VkDescriptorSetLayout 句柄的指针,其中返回生成的描述符集布局对象。
关于描述符集布局的信息通过 VkDescriptorSetLayoutCreateInfo
结构传递。
// Provided by VK_VERSION_1_0
typedef struct VkDescriptorSetLayoutCreateInfo {
VkStructureType sType;
const void* pNext;
VkDescriptorSetLayoutCreateFlags flags;
uint32_t bindingCount;
const VkDescriptorSetLayoutBinding* pBindings;
} VkDescriptorSetLayoutCreateInfo;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
flags
是一个 VkDescriptorSetLayoutCreateFlagBits 的位掩码,用于指定描述符集布局创建的选项。 -
bindingCount
是pBindings
中元素的数量。 -
pBindings
是指向 VkDescriptorSetLayoutBinding 结构数组的指针。
如果 VkDescriptorSetLayoutCreateInfo 或 VkDescriptorPoolCreateInfo 结构的 pNext
链包含 VkMutableDescriptorTypeCreateInfoEXT 结构,则该结构指定有关可变描述符类型可能使用的描述符类型的信息。
VkMutableDescriptorTypeCreateInfoEXT
结构定义如下
// Provided by VK_EXT_mutable_descriptor_type
typedef struct VkMutableDescriptorTypeCreateInfoEXT {
VkStructureType sType;
const void* pNext;
uint32_t mutableDescriptorTypeListCount;
const VkMutableDescriptorTypeListEXT* pMutableDescriptorTypeLists;
} VkMutableDescriptorTypeCreateInfoEXT;
或等效结构
// Provided by VK_VALVE_mutable_descriptor_type
typedef VkMutableDescriptorTypeCreateInfoEXT VkMutableDescriptorTypeCreateInfoVALVE;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
mutableDescriptorTypeListCount
是pMutableDescriptorTypeLists
中的元素数量。 -
pMutableDescriptorTypeLists
是指向VkMutableDescriptorTypeListEXT
结构数组的指针。
如果 mutableDescriptorTypeListCount
为零,或者此结构未包含在 pNext
链中,则每个元素的 VkMutableDescriptorTypeListEXT 都被认为是零或每个成员都为 NULL
。 否则,VkDescriptorSetLayoutCreateInfo::pBindings
[i] 处的描述符集布局绑定使用 VkMutableDescriptorTypeCreateInfoEXT::pMutableDescriptorTypeLists
[i] 中的描述符类型列表。
给定可变描述符可以突变到的潜在描述符类型列表在 VkMutableDescriptorTypeListEXT
结构中传递。
VkMutableDescriptorTypeListEXT
结构定义如下
// Provided by VK_EXT_mutable_descriptor_type
typedef struct VkMutableDescriptorTypeListEXT {
uint32_t descriptorTypeCount;
const VkDescriptorType* pDescriptorTypes;
} VkMutableDescriptorTypeListEXT;
或等效结构
// Provided by VK_VALVE_mutable_descriptor_type
typedef VkMutableDescriptorTypeListEXT VkMutableDescriptorTypeListVALVE;
-
descriptorTypeCount
是pDescriptorTypes
中的元素数量。 -
pDescriptorTypes
为NULL
或指向descriptorTypeCount
个 VkDescriptorType 值的数组的指针,这些值定义给定绑定可能突变到的描述符类型。
可以在 VkDescriptorSetLayoutCreateInfo::flags
中设置的位,用于指定描述符集布局的选项,如下所示
// Provided by VK_VERSION_1_0
typedef enum VkDescriptorSetLayoutCreateFlagBits {
// Provided by VK_VERSION_1_2
VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT = 0x00000002,
// Provided by VK_VERSION_1_4
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT = 0x00000001,
// Provided by VK_EXT_descriptor_buffer
VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT = 0x00000010,
// Provided by VK_EXT_descriptor_buffer
VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT = 0x00000020,
// Provided by VK_NV_device_generated_commands_compute
VK_DESCRIPTOR_SET_LAYOUT_CREATE_INDIRECT_BINDABLE_BIT_NV = 0x00000080,
// Provided by VK_EXT_mutable_descriptor_type
VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT = 0x00000004,
// Provided by VK_NV_per_stage_descriptor_set
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PER_STAGE_BIT_NV = 0x00000040,
// Provided by VK_KHR_push_descriptor
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT,
// Provided by VK_EXT_descriptor_indexing
VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT,
// Provided by VK_VALVE_mutable_descriptor_type
VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_VALVE = VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT,
} VkDescriptorSetLayoutCreateFlagBits;
-
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT
指定必须不使用此布局分配描述符集,而是通过 vkCmdPushDescriptorSet 推送描述符。 -
VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT
指定使用此布局的描述符集必须从创建时设置了VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT
位的描述符池中分配。使用此位创建的描述符集布局对每个阶段和每个管线布局的最大描述符数量有备用限制。非 UpdateAfterBind 限制仅计算在没有此标志的情况下创建的集合中的描述符。UpdateAfterBind 限制计算所有描述符,但限制可能高于非 UpdateAfterBind 限制。 -
VK_DESCRIPTOR_SET_LAYOUT_CREATE_INDIRECT_BINDABLE_BIT_NV
指定使用此布局的描述符集允许它们与使用VK_PIPELINE_CREATE_INDIRECT_BINDABLE_BIT_NV
标志创建的计算管线绑定,以便在设备生成命令中使用。 -
VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT
指定此布局必须仅与描述符缓冲区一起使用。 -
VK_DESCRIPTOR_SET_LAYOUT_CREATE_EMBEDDED_IMMUTABLE_SAMPLERS_BIT_EXT
指定这是一个仅包含不可变采样器的布局,这些采样器可以通过 vkCmdBindDescriptorBufferEmbeddedSamplersEXT 绑定。与普通的不可变采样器不同,嵌入式不可变采样器不需要应用程序在描述符缓冲区中提供它们。 -
VK_DESCRIPTOR_SET_LAYOUT_CREATE_HOST_ONLY_POOL_BIT_EXT
指定使用此布局的描述符集必须从使用VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT
位设置创建的描述符池中分配。使用此位创建的描述符集布局对于每个阶段的最大描述符数量没有明确的限制。主机描述符集仅受可用主机内存的限制,但可能会因实现特定的原因而受到限制。实现可能会将支持的描述符数量限制为 UpdateAfterBind 限制或非 UpdateAfterBind 限制,以较大者为准。 -
VK_DESCRIPTOR_SET_LAYOUT_CREATE_PER_STAGE_BIT_NV
指定使用此布局的描述符集中的绑定编号可能表示每个阶段中不同的资源和/或资源类型。
// Provided by VK_VERSION_1_0
typedef VkFlags VkDescriptorSetLayoutCreateFlags;
VkDescriptorSetLayoutCreateFlags
是一种位掩码类型,用于设置零个或多个 VkDescriptorSetLayoutCreateFlagBits 的掩码。
VkDescriptorSetLayoutBinding
结构定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkDescriptorSetLayoutBinding {
uint32_t binding;
VkDescriptorType descriptorType;
uint32_t descriptorCount;
VkShaderStageFlags stageFlags;
const VkSampler* pImmutableSamplers;
} VkDescriptorSetLayoutBinding;
-
binding
是此条目的绑定编号,并对应于着色器阶段中具有相同绑定编号的资源。 -
descriptorType
是一个 VkDescriptorType,指定此绑定使用哪种类型的资源描述符。 -
descriptorCount
是绑定中包含的描述符数量,在着色器中以数组形式访问,除非descriptorType
是VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,在这种情况下,descriptorCount
是内联统一块的大小(以字节为单位)。如果descriptorCount
为零,则此绑定条目将被保留,并且必须不能在任何使用该集合布局的管线中通过此绑定从任何阶段访问该资源。 -
stageFlags
成员是 VkShaderStageFlagBits 的位掩码,指定哪些管线着色器阶段可以访问此绑定的资源。VK_SHADER_STAGE_ALL
是一种简写形式,指定所有定义的着色器阶段(包括扩展定义的任何其他阶段)可以访问该资源。如果着色器阶段未包含在
stageFlags
中,则必须不能在任何使用该集合布局的管线中通过此绑定从该阶段访问资源。除了仅限于片段着色器的输入附件外,对于哪些阶段的组合可以使用描述符绑定没有任何限制,特别是绑定可以被图形阶段和计算阶段使用。 -
pImmutableSamplers
影响采样器的初始化。如果descriptorType
指定VK_DESCRIPTOR_TYPE_SAMPLER
或VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
类型描述符,则pImmutableSamplers
可以用于初始化一组不可变采样器。不可变采样器永久绑定到集合布局中,并且必须不能更改;不允许使用不可变采样器更新VK_DESCRIPTOR_TYPE_SAMPLER
描述符,并且使用不可变采样器更新VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
描述符不会修改采样器(图像视图会更新,但采样器更新会被忽略)。如果pImmutableSamplers
不为NULL
,则它是一个指向采样器句柄数组的指针,这些句柄将复制到集合布局中并用于相应的绑定。仅复制采样器句柄;在最终使用集合布局以及使用它创建的任何描述符池和集合之前,必须不能销毁采样器对象。如果pImmutableSamplers
为NULL
,则采样器槽是动态的,并且必须将采样器句柄绑定到使用此布局的描述符集中。如果descriptorType
不是这些描述符类型之一,则忽略pImmutableSamplers
。
上面的布局定义允许稀疏地指定描述符绑定,因此不必在 pBindings
数组中指定 0 和最大绑定编号之间的所有绑定编号。未指定的绑定的 descriptorCount
和 stageFlags
为零,descriptorType
的值是未定义的。但是,即使并非所有描述符绑定都已使用,VkDescriptorSetLayoutCreateInfo::pBindings
数组中 0 和最大绑定编号之间的所有绑定编号可能会在描述符集布局中占用内存,尽管它应该不会从描述符池中消耗额外的内存。
指定的最大绑定编号应该尽可能紧凑,以避免浪费内存。 |
如果 VkDescriptorSetLayoutCreateInfo 结构的 pNext
链包含 VkDescriptorSetLayoutBindingFlagsCreateInfo 结构,则该结构包含一个标志数组,每个描述符集布局绑定对应一个标志。
// Provided by VK_VERSION_1_2
typedef struct VkDescriptorSetLayoutBindingFlagsCreateInfo {
VkStructureType sType;
const void* pNext;
uint32_t bindingCount;
const VkDescriptorBindingFlags* pBindingFlags;
} VkDescriptorSetLayoutBindingFlagsCreateInfo;
或等效结构
// Provided by VK_EXT_descriptor_indexing
typedef VkDescriptorSetLayoutBindingFlagsCreateInfo VkDescriptorSetLayoutBindingFlagsCreateInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
bindingCount
为零或pBindingFlags
中的元素数量。 -
pBindingFlags
是指向 VkDescriptorBindingFlags 位域数组的指针,每个描述符集布局绑定对应一个位域。
如果 bindingCount
为零,或者如果此结构不包含在 pNext
链中,则认为每个描述符集布局绑定的 VkDescriptorBindingFlags 为零。 否则,VkDescriptorSetLayoutCreateInfo::pBindings
[i] 处的描述符集布局绑定使用 pBindingFlags
[i] 中的标志。
可以在 VkDescriptorSetLayoutBindingFlagsCreateInfo::pBindingFlags
的每个元素中设置的位,用于指定相应描述符集布局绑定的选项,包括:
// Provided by VK_VERSION_1_2
typedef enum VkDescriptorBindingFlagBits {
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT = 0x00000001,
VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT = 0x00000002,
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT = 0x00000004,
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT = 0x00000008,
// Provided by VK_EXT_descriptor_indexing
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT,
// Provided by VK_EXT_descriptor_indexing
VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT,
// Provided by VK_EXT_descriptor_indexing
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT,
// Provided by VK_EXT_descriptor_indexing
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT,
} VkDescriptorBindingFlagBits;
或等效结构
// Provided by VK_EXT_descriptor_indexing
typedef VkDescriptorBindingFlagBits VkDescriptorBindingFlagBitsEXT;
-
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT
指定如果此绑定中的描述符在命令缓冲区中绑定描述符集和将该命令缓冲区提交到队列之间被更新,则提交将使用此绑定最近设置的描述符,并且更新不会使命令缓冲区失效。使用此标志创建的描述符绑定部分豁免 vkUpdateDescriptorSetWithTemplateKHR 和 vkUpdateDescriptorSets 中的外部同步要求。具有此标志设置的多个描述符可以在不同线程中并发更新,但同一个描述符必须不能被两个线程并发更新。具有此标志设置的描述符可以与在另一个线程中绑定到命令集的集合并发更新,但不能与集合的重置或释放并发更新。 -
VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT
指定此绑定中未动态使用的描述符在消耗描述符时不需要包含有效的描述符。如果任何着色器调用执行使用描述符执行任何内存访问的指令,则描述符将被动态使用。如果某个描述符没有被动态使用,则在命令执行期间,由该描述符引用的任何资源都不会被视为已引用。 -
VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT
指定在此描述符集被绑定后,或者在使用此描述符集的命令缓冲区等待执行时,此绑定中的描述符可以被更新,只要更新的描述符没有被那些命令缓冲区使用即可。使用此标志创建的描述符绑定部分豁免 vkUpdateDescriptorSetWithTemplateKHR 和 vkUpdateDescriptorSets 中的外部同步要求,与VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT
的方式相同。如果也设置了VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT
,那么只要描述符没有被任何着色器调用动态使用,就可以进行更新。如果没有设置VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT
,那么只要描述符没有被任何着色器调用静态使用,就可以进行更新。 -
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
指定这是一个可变大小的描述符绑定,其大小将在使用此布局分配描述符集时指定。descriptorCount
的值被视为绑定大小的上限。这必须仅用于描述符集布局中的最后一个绑定(即,binding
值最大的绑定)。为了计入诸如maxDescriptorSet
* 和maxPerStageDescriptor
* 之类的限制,会计算descriptorCount
的完整值,但描述符类型为VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
的描述符绑定除外,此时,VkDescriptorSetLayoutCreateInfo::flags
不包含VK_DESCRIPTOR_SET_LAYOUT_CREATE_DESCRIPTOR_BUFFER_BIT_EXT
。在这种情况下,descriptorCount
指定绑定字节大小的上限;因此,它会针对maxInlineUniformBlockSize
和maxInlineUniformTotalSize
限制进行计数。
请注意,虽然 |
// Provided by VK_VERSION_1_2
typedef VkFlags VkDescriptorBindingFlags;
或等效结构
// Provided by VK_EXT_descriptor_indexing
typedef VkDescriptorBindingFlags VkDescriptorBindingFlagsEXT;
VkDescriptorBindingFlags
是一个位掩码类型,用于设置零个或多个 VkDescriptorBindingFlagBits 的掩码。
要查询描述符集布局是否可以被创建的信息,请调用
// Provided by VK_VERSION_1_1
void vkGetDescriptorSetLayoutSupport(
VkDevice device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
VkDescriptorSetLayoutSupport* pSupport);
或等效命令
// Provided by VK_KHR_maintenance3
void vkGetDescriptorSetLayoutSupportKHR(
VkDevice device,
const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
VkDescriptorSetLayoutSupport* pSupport);
-
device
是将创建描述符集布局的逻辑设备。 -
pCreateInfo
是指向 VkDescriptorSetLayoutCreateInfo 结构的指针,该结构指定描述符集布局对象的状态。 -
pSupport
是指向 VkDescriptorSetLayoutSupport 结构的指针,其中返回有关描述符集布局对象支持的信息。
某些实现在描述符集中可以容纳的内容方面存在限制,这些限制不容易用现有的限制(例如 maxDescriptorSet
*)来表达,例如,如果所有描述符类型在内存中共享有限的空间,但每个描述符的大小或对齐方式都不同。此命令返回有关描述符集是否满足此限制的信息。如果描述符集布局满足 VkPhysicalDeviceMaintenance3Properties::maxPerSetDescriptors
限制,则此命令保证在 VkDescriptorSetLayoutSupport::supported
中返回 VK_TRUE
。如果描述符集布局超过 VkPhysicalDeviceMaintenance3Properties::maxPerSetDescriptors
限制,则是否支持描述符集布局取决于具体实现,并且可能取决于描述符的大小和对齐方式是否导致布局超出内部限制。
此命令不考虑其他限制,例如 maxPerStageDescriptor
*,因此根据此命令支持的描述符集布局必须仍然满足管道布局限制,例如 maxPerStageDescriptor
*,才能在管道布局中使用。
这是一个 |
有关描述符集布局支持的信息在 VkDescriptorSetLayoutSupport
结构中返回
// Provided by VK_VERSION_1_1
typedef struct VkDescriptorSetLayoutSupport {
VkStructureType sType;
void* pNext;
VkBool32 supported;
} VkDescriptorSetLayoutSupport;
或等效结构
// Provided by VK_KHR_maintenance3
typedef VkDescriptorSetLayoutSupport VkDescriptorSetLayoutSupportKHR;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
supported
指定描述符集布局是否可以被创建。
如果描述符集可以被创建,则 supported
将为 VK_TRUE
,否则为 VK_FALSE
。
如果 VkDescriptorSetLayoutSupport 结构的 pNext
链包含 VkDescriptorSetVariableDescriptorCountLayoutSupport
结构,则该结构会返回有关是否支持描述符集布局的附加信息。
// Provided by VK_VERSION_1_2
typedef struct VkDescriptorSetVariableDescriptorCountLayoutSupport {
VkStructureType sType;
void* pNext;
uint32_t maxVariableDescriptorCount;
} VkDescriptorSetVariableDescriptorCountLayoutSupport;
或等效结构
// Provided by VK_EXT_descriptor_indexing
typedef VkDescriptorSetVariableDescriptorCountLayoutSupport VkDescriptorSetVariableDescriptorCountLayoutSupportEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
maxVariableDescriptorCount
表示布局中编号最高的绑定(如果该绑定是可变大小的)支持的最大描述符数量。如果布局中编号最高的绑定的描述符类型为VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则maxVariableDescriptorCount
表示该绑定(如果该绑定是可变大小的)支持的最大字节大小。
如果在 vkGetDescriptorSetLayoutSupport::pCreateInfo
中指定的 VkDescriptorSetLayoutCreateInfo 结构包含可变大小的描述符,则假设请求的可变大小描述符的大小来确定 supported
,并且 maxVariableDescriptorCount
是可以成功创建的该描述符的最大大小(大于或等于传入的请求大小)。如果 VkDescriptorSetLayoutCreateInfo 结构不包含可变大小的描述符,或者如果 VkPhysicalDeviceDescriptorIndexingFeatures::descriptorBindingVariableDescriptorCount
功能未启用,则 maxVariableDescriptorCount
为零。为了此命令的目的,如果 descriptorType
是 VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则具有 descriptorCount
为零的可变大小描述符绑定将被视为具有 descriptorCount
为 4,否则为 1,因此不会忽略该绑定,并且将返回最大描述符计数。如果不支持该布局,则写入 maxVariableDescriptorCount
的值是未定义的。
以下示例显示了使用两个描述符集的着色器代码片段,以及创建相应描述符集布局的应用程序代码。
//
// binding to a single sampled image descriptor in set 0
//
layout (set=0, binding=0) uniform texture2D mySampledImage;
//
// binding to an array of sampled image descriptors in set 0
//
layout (set=0, binding=1) uniform texture2D myArrayOfSampledImages[12];
//
// binding to a single uniform buffer descriptor in set 1
//
layout (set=1, binding=0) uniform myUniformBuffer
{
vec4 myElement[32];
};
...
%1 = OpExtInstImport "GLSL.std.450"
...
OpName %9 "mySampledImage"
OpName %14 "myArrayOfSampledImages"
OpName %18 "myUniformBuffer"
OpMemberName %18 0 "myElement"
OpName %20 ""
OpDecorate %9 DescriptorSet 0
OpDecorate %9 Binding 0
OpDecorate %14 DescriptorSet 0
OpDecorate %14 Binding 1
OpDecorate %17 ArrayStride 16
OpMemberDecorate %18 0 Offset 0
OpDecorate %18 Block
OpDecorate %20 DescriptorSet 1
OpDecorate %20 Binding 0
%2 = OpTypeVoid
%3 = OpTypeFunction %2
%6 = OpTypeFloat 32
%7 = OpTypeImage %6 2D 0 0 0 1 Unknown
%8 = OpTypePointer UniformConstant %7
%9 = OpVariable %8 UniformConstant
%10 = OpTypeInt 32 0
%11 = OpConstant %10 12
%12 = OpTypeArray %7 %11
%13 = OpTypePointer UniformConstant %12
%14 = OpVariable %13 UniformConstant
%15 = OpTypeVector %6 4
%16 = OpConstant %10 32
%17 = OpTypeArray %15 %16
%18 = OpTypeStruct %17
%19 = OpTypePointer Uniform %18
%20 = OpVariable %19 Uniform
...
VkResult myResult;
const VkDescriptorSetLayoutBinding myDescriptorSetLayoutBinding[] =
{
// binding to a single image descriptor
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = NULL
},
// binding to an array of image descriptors
{
.binding = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE,
.descriptorCount = 12,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = NULL
},
// binding to a single uniform buffer descriptor
{
.binding = 0,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.pImmutableSamplers = NULL
}
};
const VkDescriptorSetLayoutCreateInfo myDescriptorSetLayoutCreateInfo[] =
{
// Information for first descriptor set with two descriptor bindings
{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.bindingCount = 2,
.pBindings = &myDescriptorSetLayoutBinding[0]
},
// Information for second descriptor set with one descriptor binding
{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.bindingCount = 1,
.pBindings = &myDescriptorSetLayoutBinding[2]
}
};
VkDescriptorSetLayout myDescriptorSetLayout[2];
//
// Create first descriptor set layout
//
myResult = vkCreateDescriptorSetLayout(
myDevice,
&myDescriptorSetLayoutCreateInfo[0],
NULL,
&myDescriptorSetLayout[0]);
//
// Create second descriptor set layout
//
myResult = vkCreateDescriptorSetLayout(
myDevice,
&myDescriptorSetLayoutCreateInfo[1],
NULL,
&myDescriptorSetLayout[1]);
要销毁描述符集布局,请调用
// Provided by VK_VERSION_1_0
void vkDestroyDescriptorSetLayout(
VkDevice device,
VkDescriptorSetLayout descriptorSetLayout,
const VkAllocationCallbacks* pAllocator);
-
device
是销毁描述符集布局的逻辑设备。 -
descriptorSetLayout
是要销毁的描述符集布局。 -
pAllocator
控制主机内存分配,如 内存分配 章节中所述。
管道布局
通过管线布局可以访问管线中的描述符集。零个或多个描述符集布局和零个或多个推送常量范围组合在一起,形成一个管线布局对象,描述管线可以访问的完整资源集。管线布局表示一系列描述符集,每个描述符集都有特定的布局。这一系列布局用于确定着色器阶段和着色器资源之间的接口。每个管线都使用管线布局创建。
管线布局对象由 VkPipelineLayout
句柄表示。
// Provided by VK_VERSION_1_0
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkPipelineLayout)
要创建管线布局,请调用
// Provided by VK_VERSION_1_0
VkResult vkCreatePipelineLayout(
VkDevice device,
const VkPipelineLayoutCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkPipelineLayout* pPipelineLayout);
-
device
是创建管线布局的逻辑设备。 -
pCreateInfo
是一个指向 VkPipelineLayoutCreateInfo 结构的指针,该结构指定管线布局对象的状态。 -
pAllocator
控制主机内存分配,如 内存分配 章节中所述。 -
pPipelineLayout
是一个指向 VkPipelineLayout 句柄的指针,创建的管线布局对象将返回到该句柄中。
VkPipelineLayoutCreateInfo 结构的定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkPipelineLayoutCreateInfo {
VkStructureType sType;
const void* pNext;
VkPipelineLayoutCreateFlags flags;
uint32_t setLayoutCount;
const VkDescriptorSetLayout* pSetLayouts;
uint32_t pushConstantRangeCount;
const VkPushConstantRange* pPushConstantRanges;
} VkPipelineLayoutCreateInfo;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
flags
是一个 VkPipelineLayoutCreateFlagBits 的位掩码,指定管线布局创建的选项。 -
setLayoutCount
是管线布局中包含的描述符集的数量。 -
pSetLayouts
是一个指向VkDescriptorSetLayout
对象数组的指针。 -
pushConstantRangeCount
是管线布局中包含的推送常量范围的数量。 -
pPushConstantRanges
是一个指向VkPushConstantRange
结构数组的指针,该数组定义了单个管线布局中使用的推送常量范围集。除了描述符集布局之外,管线布局还描述了管线的每个阶段可以访问多少个推送常量。推送常量表示一种高速路径,用于修改管线中的常量数据,预计其性能优于基于内存的资源更新。
// Provided by VK_EXT_graphics_pipeline_library
typedef enum VkPipelineLayoutCreateFlagBits {
// Provided by VK_EXT_graphics_pipeline_library
VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT = 0x00000002,
} VkPipelineLayoutCreateFlagBits;
-
VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT
指定实现必须确保特定描述符集的属性和/或缺失不会影响管道布局的任何其他属性。这允许创建链接时不带VK_PIPELINE_CREATE_LINK_TIME_OPTIMIZATION_BIT_EXT
的管道库,其中仅包含描述符集的子集。
// Provided by VK_VERSION_1_0
typedef VkFlags VkPipelineLayoutCreateFlags;
VkPipelineLayoutCreateFlags
是用于设置 VkPipelineLayoutCreateFlagBits 掩码的位掩码类型。
VkPushConstantRange
结构体的定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkPushConstantRange {
VkShaderStageFlags stageFlags;
uint32_t offset;
uint32_t size;
} VkPushConstantRange;
-
stageFlags
是一组阶段标志,描述将访问推送常量范围的着色器阶段。如果某个特定阶段未包含在该范围内,则从相应的着色器阶段访问该范围的推送常量成员将返回未定义的值。 -
offset
和size
分别是范围消耗的起始偏移量和大小。offset
和size
均以字节为单位,并且必须是 4 的倍数。推送常量变量的布局在着色器中指定。
一旦创建,管线布局将用作管线创建的一部分(请参阅管线),作为绑定描述符集的一部分(请参阅描述符集绑定),以及作为设置推送常量的一部分(请参阅推送常量更新)。管线创建接受一个管线布局作为输入,该布局可以用于将 (set, binding, arrayElement) 元组映射到描述符集内的实现资源或内存位置。实现资源的分配仅取决于构成管线布局的描述符集中定义的绑定,而不取决于任何着色器源代码。
管线中所有着色器中静态使用的所有资源变量必须使用 (set, binding, arrayElement) 进行声明,该 (set, binding, arrayElement) 存在于相应的描述符集布局中,并且是适当的描述符类型,并包含 stageFlags
中使用的着色器阶段集。管线布局可以包含特定管线未使用的条目。管线布局允许应用程序在多个管线编译中提供一组一致的绑定,这使得这些管线能够以一种方式编译,即实现可以在不重新编程绑定的情况下廉价地切换管线。
同样,每个着色器中声明的推送常量块(如果存在)必须仅将变量放置在每个包含在推送常量范围内的偏移量处,且该推送常量范围的 stageFlags
包括对应于使用它的着色器阶段的位。管线布局可以包含特定管线未使用的范围或范围的部分。
如管线布局资源限制所示,管线布局中所有描述符集布局的绑定中包含的每种类型的资源总数都有限制。“可用资源总数”列给出了管线布局中所有描述符集中可以包含的每种类型资源数量的限制。某些资源类型会影响多个限制。此外,如着色器资源限制中所述,任何管线阶段中可以使用的每种类型资源的总数也有限制。
可用资源总数 | 资源类型 |
---|---|
|
采样器 |
组合图像采样器 |
|
|
采样图像 |
组合图像采样器 |
|
统一纹理缓冲 |
|
|
存储图像 |
存储纹理缓冲 |
|
|
统一缓冲 |
动态统一缓冲 |
|
|
动态统一缓冲 |
|
存储缓冲 |
动态存储缓冲 |
|
|
动态存储缓冲 |
|
输入附件 |
|
内联统一块 |
|
加速结构 |
要销毁管线布局,请调用
// Provided by VK_VERSION_1_0
void vkDestroyPipelineLayout(
VkDevice device,
VkPipelineLayout pipelineLayout,
const VkAllocationCallbacks* pAllocator);
-
device
是销毁管线布局的逻辑设备。 -
pipelineLayout
是要销毁的管线布局。 -
pAllocator
控制主机内存分配,如 内存分配 章节中所述。
管线布局兼容性
如果两个管线布局在创建时具有相同的推送常量范围,则定义它们“对于推送常量兼容”。如果两个管线布局都使用 完全相同的定义描述符集布局创建了集零到 N,并且它们是否都使用 VK_PIPELINE_LAYOUT_CREATE_INDEPENDENT_SETS_BIT_EXT
创建,并且它们使用相同的推送常量范围创建,则定义它们“对于集合 N 兼容”。
当将描述符集(请参阅描述符集绑定)绑定到集编号 N 时,如果集 M 和 N 的管线布局对于集 M 不兼容,则会干扰先前绑定的索引低于 N 的描述符集。否则,M 中绑定的描述符集不会受到干扰。
此外,如果先前绑定的集 N 的描述符集是使用与集 N 不兼容的管线布局绑定的,则会干扰编号大于 N 的集中的所有绑定。
在绑定管线时,如果先前绑定的描述符集 N 是使用与集 N 兼容的管线布局绑定的,并且没有受到干扰,则管线可以正确访问它。
布局兼容性意味着描述符集可以绑定到命令缓冲区,供任何使用兼容的管线布局创建的管线使用,而无需首先绑定特定的管线。 这也意味着描述符集可以在管线更改后仍然有效,并且新绑定的管线将可以访问相同的资源。
当描述符集被绑定描述符集打断时,被打断的集合被认为包含与干扰描述符集具有相同管线布局的未定义描述符。
将更改频率最低的描述符集放置在管线布局的开头附近,并将表示更改频率最高的资源的描述符集放置在结尾附近。 当切换管线时,只需要更新已失效的描述符集绑定,其余的描述符集绑定将保持原位。 |
可以绑定到管线布局的描述符集的最大数量是从物理设备属性查询的(请参阅限制中的maxBoundDescriptorSets
)。
const VkDescriptorSetLayout layouts[] = { layout1, layout2 };
const VkPushConstantRange ranges[] =
{
{
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.offset = 0,
.size = 4
},
{
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.offset = 4,
.size = 4
},
};
const VkPipelineLayoutCreateInfo createInfo =
{
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.setLayoutCount = 2,
.pSetLayouts = layouts,
.pushConstantRangeCount = 2,
.pPushConstantRanges = ranges
};
VkPipelineLayout myPipelineLayout;
myResult = vkCreatePipelineLayout(
myDevice,
&createInfo,
NULL,
&myPipelineLayout);
描述符集的分配
描述符池维护一个描述符池,从中分配描述符集。描述符池是外部同步的,这意味着应用程序必须不能在多个线程中同时从同一个池中分配和/或释放描述符集。
描述符池由VkDescriptorPool
句柄表示
// Provided by VK_VERSION_1_0
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorPool)
要创建描述符池对象,请调用
// Provided by VK_VERSION_1_0
VkResult vkCreateDescriptorPool(
VkDevice device,
const VkDescriptorPoolCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorPool* pDescriptorPool);
-
device
是创建描述符池的逻辑设备。 -
pCreateInfo
是指向VkDescriptorPoolCreateInfo结构的指针,该结构指定描述符池对象的状态。 -
pAllocator
控制主机内存分配,如 内存分配 章节中所述。 -
pDescriptorPool
是指向VkDescriptorPool句柄的指针,将在其中返回结果描述符池对象。
创建的描述符池将在pDescriptorPool
中返回。
有关池的其他信息在VkDescriptorPoolCreateInfo
结构中传递
// Provided by VK_VERSION_1_0
typedef struct VkDescriptorPoolCreateInfo {
VkStructureType sType;
const void* pNext;
VkDescriptorPoolCreateFlags flags;
uint32_t maxSets;
uint32_t poolSizeCount;
const VkDescriptorPoolSize* pPoolSizes;
} VkDescriptorPoolCreateInfo;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
flags
是VkDescriptorPoolCreateFlagBits的位掩码,指定池上的某些受支持的操作。 -
maxSets
是可以从池中分配的最大描述符集数量。 -
poolSizeCount
是pPoolSizes
中的元素数量。 -
pPoolSizes
是指向VkDescriptorPoolSize结构数组的指针,每个结构包含一个描述符类型和要分配到池中的该类型描述符的数量。
如果多个包含相同描述符类型的VkDescriptorPoolSize
结构出现在pPoolSizes
数组中,则池将创建足够的存储空间,用于存储每种类型的描述符总数。
描述符池的碎片是可能的,并且可能导致描述符集分配失败。由于碎片导致的失败定义为:尽管池中所有未完成的描述符集分配的总和加上请求的分配不超过池创建时请求的描述符总数,但描述符集分配失败。如下所述,实现提供了某些保证,即何时碎片必须不会导致分配失败。
如果自创建或最近一次重置以来,描述符池没有释放任何描述符集,则碎片必须不会导致分配失败(请注意,对于创建时未设置VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT
位的池,始终如此)。此外,如果自创建或最近一次重置以来从池中分配的所有集合都使用相同数量的描述符(每种类型),并且请求的分配也使用相同数量的描述符(每种类型),则碎片必须不会导致分配失败。
如果由于碎片而发生分配失败,则应用程序可以创建额外的描述符池以执行进一步的描述符集分配。
如果flags
设置了VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT
位,则如果使用此位设置创建的所有池(包括此池)中的描述符总数超过maxUpdateAfterBindDescriptorsInAllPools
,或者发生底层硬件资源碎片,则描述符池创建可能会失败,并出现错误VK_ERROR_FRAGMENTATION
。
如果pPoolSizes
[i]::type
是VK_DESCRIPTOR_TYPE_MUTABLE_EXT
,则pNext
链中的VkMutableDescriptorTypeCreateInfoEXT结构可以用于指定可以从池中分配哪些可变描述符类型。 如果包含在pNext
链中,则VkMutableDescriptorTypeCreateInfoEXT::pMutableDescriptorTypeLists
[i]指定可以从该池条目分配哪种VK_DESCRIPTOR_TYPE_MUTABLE_EXT
描述符。 如果pNext
链中不存在VkMutableDescriptorTypeCreateInfoEXT,或者VkMutableDescriptorTypeCreateInfoEXT::pMutableDescriptorTypeLists
[i]超出范围,则描述符池会分配足够的内存,以便能够分配一个VK_DESCRIPTOR_TYPE_MUTABLE_EXT
描述符,并将任何受支持的VkDescriptorType作为可变描述符。 如果VkDescriptorSetLayoutCreateInfo中的类型列表是描述符池中声明的类型列表的子集,或者池条目是在没有描述符类型列表的情况下创建的,则可以从池条目中分配可变描述符。 可以声明多个具有VK_DESCRIPTOR_TYPE_MUTABLE_EXT
的pPoolSizes
条目。 当pPoolSizes
中存在多个此类池条目时,它们指定完全重叠、部分重叠或不相交的受支持描述符类型集。如果受支持的描述符类型集相等,则两个集合完全重叠。如果集合不相交,则它们部分重叠。 未分配VkMutableDescriptorTypeListEXT
的池条目被认为与分配了VkMutableDescriptorTypeListEXT
的任何其他池条目部分重叠。应用程序必须确保pPoolSizes
中不存在部分重叠。
不允许部分重叠的要求旨在解决验证的歧义,因为不会混淆将从哪个 |
为了能够分配具有内联统一缓冲区块绑定的描述符集,创建描述符池时,除了通过 descriptorType
值为 VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
的 VkDescriptorPoolSize 结构指定的总内联统一数据容量(以字节为单位)之外,还 **必须** 指定描述符池的内联统一缓冲区块绑定容量。可以通过将 VkDescriptorPoolInlineUniformBlockCreateInfo
结构添加到 VkDescriptorPoolCreateInfo 的 pNext
链来实现。
VkDescriptorPoolInlineUniformBlockCreateInfo
结构定义如下:
// Provided by VK_VERSION_1_3
typedef struct VkDescriptorPoolInlineUniformBlockCreateInfo {
VkStructureType sType;
const void* pNext;
uint32_t maxInlineUniformBlockBindings;
} VkDescriptorPoolInlineUniformBlockCreateInfo;
或等效结构
// Provided by VK_EXT_inline_uniform_block
typedef VkDescriptorPoolInlineUniformBlockCreateInfo VkDescriptorPoolInlineUniformBlockCreateInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
maxInlineUniformBlockBindings
是要分配的内联统一缓冲区块绑定的数量。
可以在 VkDescriptorPoolCreateInfo::flags
中设置的位,用于启用描述符池上的操作:
// Provided by VK_VERSION_1_0
typedef enum VkDescriptorPoolCreateFlagBits {
VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001,
// Provided by VK_VERSION_1_2
VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT = 0x00000002,
// Provided by VK_EXT_mutable_descriptor_type
VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT = 0x00000004,
// Provided by VK_NV_descriptor_pool_overallocation
VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_SETS_BIT_NV = 0x00000008,
// Provided by VK_NV_descriptor_pool_overallocation
VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_POOLS_BIT_NV = 0x00000010,
// Provided by VK_EXT_descriptor_indexing
VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT,
// Provided by VK_VALVE_mutable_descriptor_type
VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_VALVE = VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT,
} VkDescriptorPoolCreateFlagBits;
-
VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT
指定描述符集 **可以** 将其单独的分配返回到池,即允许所有 vkAllocateDescriptorSets、vkFreeDescriptorSets 和 vkResetDescriptorPool。否则,从池中分配的描述符集 **必须** 不能单独释放回池中,即只允许 vkAllocateDescriptorSets 和 vkResetDescriptorPool。 -
VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT
指定从此池分配的描述符集 **可以** 包括设置了VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT
位的绑定。可以从设置了VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT
的池中分配不设置VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT
位的绑定的描述符集。 -
VK_DESCRIPTOR_POOL_CREATE_HOST_ONLY_BIT_EXT
指定此描述符池以及从中分配的描述符集完全驻留在主机内存中,并且无法绑定。与未设置此标志分配的描述符集类似,应用程序 **可以** 从此描述符池分配的描述符集进行复制操作。从此池分配的描述符集部分免除 vkUpdateDescriptorSetWithTemplateKHR 和 vkUpdateDescriptorSets 中的外部同步要求。描述符集及其描述符可以在不同的线程中并发更新,但同一个描述符 **必须** 不能被两个线程并发更新。 -
VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_SETS_BIT_NV
指定实现应允许应用程序从描述符池中分配超过 VkDescriptorPoolCreateInfo::maxSets
个描述符集对象,只要可用资源允许。实现 **可以** 使用maxSets
值来分配初始可用集,但允许使用零。 -
VK_DESCRIPTOR_POOL_CREATE_ALLOW_OVERALLOCATION_POOLS_BIT_NV
指定实现应允许应用程序从池中分配比 VkDescriptorPoolSize::descriptorCount
为任何描述符类型指定的数量更多的描述符,如 VkDescriptorPoolCreateInfo::poolSizeCount
和 VkDescriptorPoolCreateInfo::pPoolSizes
指定的那样,只要可用资源允许。实现 **可以** 使用每个描述符类型的descriptorCount
来分配初始池,但允许应用程序将poolSizeCount
设置为零,或将pPoolSizes
数组中的任何descriptorCount
值设置为零。
// Provided by VK_VERSION_1_0
typedef VkFlags VkDescriptorPoolCreateFlags;
VkDescriptorPoolCreateFlags
是一种位掩码类型,用于设置零个或多个 VkDescriptorPoolCreateFlagBits 的掩码。
VkDescriptorPoolSize
结构定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkDescriptorPoolSize {
VkDescriptorType type;
uint32_t descriptorCount;
} VkDescriptorPoolSize;
-
type
是描述符的类型。 -
descriptorCount
是要分配的该类型描述符的数量。如果type
是VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则descriptorCount
是为此类型描述符分配的字节数。
当创建将包含多平面格式的组合图像采样器的描述符的描述符池时,应用程序在选择 为简单起见,应用程序 **可以** 使用 VkPhysicalDeviceMaintenance6Properties:: |
要销毁描述符池,请调用
// Provided by VK_VERSION_1_0
void vkDestroyDescriptorPool(
VkDevice device,
VkDescriptorPool descriptorPool,
const VkAllocationCallbacks* pAllocator);
-
device
是销毁描述符池的逻辑设备。 -
descriptorPool
是要销毁的描述符池。 -
pAllocator
控制主机内存分配,如 内存分配 章节中所述。
当一个池被销毁时,从该池分配的所有描述符集都会被隐式释放并变为无效。从给定池分配的描述符集在销毁该描述符池之前不需要被释放。
描述符集是从描述符池对象分配的,并由 VkDescriptorSet
句柄表示。
// Provided by VK_VERSION_1_0
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorSet)
要从描述符池分配描述符集,请调用
// Provided by VK_VERSION_1_0
VkResult vkAllocateDescriptorSets(
VkDevice device,
const VkDescriptorSetAllocateInfo* pAllocateInfo,
VkDescriptorSet* pDescriptorSets);
-
device
是拥有描述符池的逻辑设备。 -
pAllocateInfo
是指向 VkDescriptorSetAllocateInfo 结构的指针,该结构描述了分配的参数。 -
pDescriptorSets
是指向 VkDescriptorSet 句柄数组的指针,其中返回结果描述符集对象。
分配的描述符集在 pDescriptorSets
中返回。
当分配描述符集时,初始状态在很大程度上是未初始化的,并且所有描述符都是未定义的,但具有非空 pImmutableSamplers
的采样器在分配时会进行初始化。如果销毁了底层资源或视图对象,描述符也会变为未定义。包含未定义描述符的描述符集可以仍然被绑定和使用,但需满足以下条件:
如果对 vkAllocateDescriptorSets
的调用导致从池分配的描述符集总数超过用于创建 pAllocateInfo->descriptorPool
的 VkDescriptorPoolCreateInfo::maxSets
的值,则由于描述符池中缺少空间,分配可能会失败。同样,如果对 vkAllocateDescriptorSets
的调用导致任何给定描述符类型的数量超过 VkDescriptorPoolCreateInfo::pPoolSizes
的每个元素的 descriptorCount
成员的总和,且 type
等于该类型,则分配可能会因缺少空间而失败。
此外,如果对 vkAllocateDescriptorSets
的调用导致从池分配的内联统一块绑定总数超过用于创建描述符池的 VkDescriptorPoolInlineUniformBlockCreateInfo::maxInlineUniformBlockBindings
的值,则分配可能也会失败。
如果由于描述符池中没有更多空间而导致分配失败,而不是由于系统或设备内存耗尽,则必须返回 VK_ERROR_OUT_OF_POOL_MEMORY
。
vkAllocateDescriptorSets
可以用于创建多个描述符集。如果创建这些描述符集中的任何一个失败,则实现必须销毁此命令中所有成功创建的描述符集对象,将 pDescriptorSets
数组的所有条目设置为 VK_NULL_HANDLE 并返回错误。
VkDescriptorSetAllocateInfo
结构体的定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkDescriptorSetAllocateInfo {
VkStructureType sType;
const void* pNext;
VkDescriptorPool descriptorPool;
uint32_t descriptorSetCount;
const VkDescriptorSetLayout* pSetLayouts;
} VkDescriptorSetAllocateInfo;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
descriptorPool
是分配描述符集的池。 -
descriptorSetCount
决定了要从池中分配的描述符集的数量。 -
pSetLayouts
是一个指向描述符集布局数组的指针,每个成员指定了相应描述符集的分配方式。
如果 VkDescriptorSetAllocateInfo 结构的 pNext
链包含 VkDescriptorSetVariableDescriptorCountAllocateInfo
结构,则该结构包含一个用于可变大小描述符绑定的描述符计数数组,每个分配的描述符集一个。
VkDescriptorSetVariableDescriptorCountAllocateInfo
结构体的定义如下:
// Provided by VK_VERSION_1_2
typedef struct VkDescriptorSetVariableDescriptorCountAllocateInfo {
VkStructureType sType;
const void* pNext;
uint32_t descriptorSetCount;
const uint32_t* pDescriptorCounts;
} VkDescriptorSetVariableDescriptorCountAllocateInfo;
或等效结构
// Provided by VK_EXT_descriptor_indexing
typedef VkDescriptorSetVariableDescriptorCountAllocateInfo VkDescriptorSetVariableDescriptorCountAllocateInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
descriptorSetCount
为零或pDescriptorCounts
中的元素数量。 -
pDescriptorCounts
是一个指向描述符计数数组的指针,每个成员指定了正在分配的相应描述符集中可变大小描述符绑定中的描述符数量。
如果 descriptorSetCount
为零或此结构未包含在 pNext
链中,则可变长度被视为零。 否则,pDescriptorCounts
[i] 是相应描述符集布局中可变大小描述符绑定中的描述符数量。 如果相应描述符集布局中的可变大小描述符绑定的描述符类型为 VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则 pDescriptorCounts
[i] 指定绑定的容量(以字节为单位)。 如果 VkDescriptorSetAllocateInfo::pSetLayouts
[i] 不包含可变大小的描述符绑定,则忽略 pDescriptorCounts
[i]。
要释放已分配的描述符集,请调用:
// Provided by VK_VERSION_1_0
VkResult vkFreeDescriptorSets(
VkDevice device,
VkDescriptorPool descriptorPool,
uint32_t descriptorSetCount,
const VkDescriptorSet* pDescriptorSets);
-
device
是拥有描述符池的逻辑设备。 -
descriptorPool
是分配描述符集的描述符池。 -
descriptorSetCount
是pDescriptorSets
数组中的元素数量。 -
pDescriptorSets
是指向 VkDescriptorSet 对象句柄数组的指针。
在调用 vkFreeDescriptorSets
之后,pDescriptorSets
中的所有描述符集都将无效。
要将从给定池分配的所有描述符集返回到池,而不是释放单个描述符集,请调用
// Provided by VK_VERSION_1_0
VkResult vkResetDescriptorPool(
VkDevice device,
VkDescriptorPool descriptorPool,
VkDescriptorPoolResetFlags flags);
-
device
是拥有描述符池的逻辑设备。 -
descriptorPool
是要重置的描述符池。 -
flags
保留供将来使用。
重置描述符池会将从描述符池分配的所有描述符集的所有资源回收回描述符池,并且描述符集会被隐式释放。
// Provided by VK_VERSION_1_0
typedef VkFlags VkDescriptorPoolResetFlags;
VkDescriptorPoolResetFlags
是一种用于设置掩码的位掩码类型,但目前保留供将来使用。
描述符集更新
一旦分配,可以使用写入和复制操作的组合来更新描述符集。要更新描述符集,请调用
// Provided by VK_VERSION_1_0
void vkUpdateDescriptorSets(
VkDevice device,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites,
uint32_t descriptorCopyCount,
const VkCopyDescriptorSet* pDescriptorCopies);
-
device
是更新描述符集的逻辑设备。 -
descriptorWriteCount
是pDescriptorWrites
数组中的元素数量。 -
pDescriptorWrites
是指向 VkWriteDescriptorSet 结构数组的指针,该结构描述要写入的描述符集。 -
descriptorCopyCount
是pDescriptorCopies
数组中的元素数量。 -
pDescriptorCopies
是指向 VkCopyDescriptorSet 结构数组的指针,该结构描述要复制的描述符集。
首先执行 pDescriptorWrites
描述的操作,然后执行 pDescriptorCopies
描述的操作。在每个数组中,操作按照它们在数组中出现的顺序执行。
pDescriptorWrites
数组中的每个元素都描述了一个使用结构中指定的资源的描述符更新描述符集的操作。
pDescriptorCopies
数组中的每个元素都是一个 VkCopyDescriptorSet 结构,描述在集合之间复制描述符的操作。
VkWriteDescriptorSet
结构的定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkWriteDescriptorSet {
VkStructureType sType;
const void* pNext;
VkDescriptorSet dstSet;
uint32_t dstBinding;
uint32_t dstArrayElement;
uint32_t descriptorCount;
VkDescriptorType descriptorType;
const VkDescriptorImageInfo* pImageInfo;
const VkDescriptorBufferInfo* pBufferInfo;
const VkBufferView* pTexelBufferView;
} VkWriteDescriptorSet;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
dstSet
是要更新的目标描述符集。 -
dstBinding
是该集合内的描述符绑定。 -
dstArrayElement
是该数组中的起始元素。如果由dstSet
和dstBinding
标识的描述符绑定的描述符类型为VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则dstArrayElement
指定绑定内的起始字节偏移量。 -
descriptorCount
是要更新的描述符的数量。如果由dstSet
和dstBinding
标识的描述符绑定的描述符类型为VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则descriptorCount
指定要更新的字节数。否则,descriptorCount
是以下值之一:-
pImageInfo
中的元素数量 -
pBufferInfo
中的元素数量 -
pTexelBufferView
中的元素数量 -
与
pNext
链中的 VkWriteDescriptorSetInlineUniformBlock 结构的dataSize
成员匹配的值 -
与
pNext
链中的 VkWriteDescriptorSetAccelerationStructureKHR 或 VkWriteDescriptorSetAccelerationStructureNV 结构的accelerationStructureCount
匹配的值
-
-
descriptorType
是一个 VkDescriptorType,指定pImageInfo
、pBufferInfo
或pTexelBufferView
中每个描述符的类型,如下所述。如果dstSet
中dstBinding
的VkDescriptorSetLayoutBinding
不等于VK_DESCRIPTOR_TYPE_MUTABLE_EXT
,则descriptorType
必须与dstSet
中dstBinding
的VkDescriptorSetLayoutBinding
中指定的descriptorType
类型相同。描述符的类型还控制描述符来自哪个数组。 -
pImageInfo
是指向 VkDescriptorImageInfo 结构体数组的指针,或被忽略,如下所述。 -
pBufferInfo
是指向 VkDescriptorBufferInfo 结构体数组的指针,或被忽略,如下所述。 -
pTexelBufferView
是指向 VkBufferView 句柄数组的指针,如缓冲区视图部分所述,或被忽略,如下所述。
根据包含 VkWriteDescriptorSet
结构的 descriptorType
成员中指定的描述符类型,仅使用 pImageInfo
、pBufferInfo
或 pTexelBufferView
成员中的一个,或者如果 descriptorType
为 VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则不使用任何一个,在这种情况下,描述符写入的源数据取自 VkWriteDescriptorSet
的 pNext
链中包含的 VkWriteDescriptorSetInlineUniformBlock 结构体;或者如果 descriptorType
为 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR
,在这种情况下,描述符写入的源数据取自 VkWriteDescriptorSet
的 pNext
链中的 VkWriteDescriptorSetAccelerationStructureKHR 结构体;或者如果 descriptorType
为 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV
,在这种情况下,描述符写入的源数据取自 VkWriteDescriptorSet
的 pNext
链中的 VkWriteDescriptorSetAccelerationStructureNV 结构体,如下所述。
如果启用了 nullDescriptor
功能,则缓冲区、加速结构、imageView 或 bufferView 可以是 VK_NULL_HANDLE。从空描述符加载会返回零值,而存储和原子操作到空描述符会被丢弃。空加速结构描述符会导致调用 miss 着色器。
如果目标描述符是可变描述符,则目标描述符的活动描述符类型变为 descriptorType
。
如果 dstBinding
从 dstArrayElement
开始剩余的数组元素少于 descriptorCount
,则剩余部分将用于更新后续的绑定 - dstBinding
+1,从数组元素零开始。如果绑定的 descriptorCount
为零,则会跳过该绑定。此行为会递归应用,根据需要更新连续的绑定以更新所有 descriptorCount
个描述符。连续的绑定必须具有相同的 VkDescriptorType、VkShaderStageFlags、VkDescriptorBindingFlagBits 和不可变采样器引用。此外,如果 VkDescriptorType 是 VK_DESCRIPTOR_TYPE_MUTABLE_EXT
,则 VkMutableDescriptorTypeCreateInfoEXT 中支持的描述符类型必须定义相同。
对于描述符类型为 |
描述符集中描述符的类型由 VkWriteDescriptorSet::descriptorType
指定,它必须是以下值之一:
// Provided by VK_VERSION_1_0
typedef enum VkDescriptorType {
VK_DESCRIPTOR_TYPE_SAMPLER = 0,
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 1,
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 2,
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 3,
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 4,
VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 5,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 6,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 7,
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8,
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9,
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10,
// Provided by VK_VERSION_1_3
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK = 1000138000,
// Provided by VK_KHR_acceleration_structure
VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR = 1000150000,
// Provided by VK_NV_ray_tracing
VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
// Provided by VK_QCOM_image_processing
VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM = 1000440000,
// Provided by VK_QCOM_image_processing
VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM = 1000440001,
// Provided by VK_EXT_mutable_descriptor_type
VK_DESCRIPTOR_TYPE_MUTABLE_EXT = 1000351000,
// Provided by VK_EXT_inline_uniform_block
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK,
// Provided by VK_VALVE_mutable_descriptor_type
VK_DESCRIPTOR_TYPE_MUTABLE_VALVE = VK_DESCRIPTOR_TYPE_MUTABLE_EXT,
} VkDescriptorType;
-
VK_DESCRIPTOR_TYPE_SAMPLER
指定一个采样器描述符。 -
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
指定一个组合图像采样器描述符。 -
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
指定一个采样图像描述符。 -
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
指定一个存储图像描述符。 -
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
指定一个统一纹理缓冲区描述符。 -
VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
指定一个存储纹理缓冲区描述符。 -
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
指定一个统一缓冲区描述符。 -
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
指定一个存储缓冲区描述符。 -
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
指定一个动态统一缓冲区描述符。 -
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC
指定一个动态存储缓冲区描述符。 -
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
指定一个输入附件描述符。 -
VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
指定一个内联统一块。 -
VK_DESCRIPTOR_TYPE_MUTABLE_EXT
指定一个可变类型的描述符。 -
VK_DESCRIPTOR_TYPE_SAMPLE_WEIGHT_IMAGE_QCOM
指定一个采样权重图像描述符。 -
VK_DESCRIPTOR_TYPE_BLOCK_MATCH_IMAGE_QCOM
指定一个块匹配图像描述符。
当通过 VkWriteDescriptorSet 的元素更新描述符集时,只有当 pImageInfo
、pBufferInfo
和 pTexelBufferView
的成员对应于正在定义的描述符类型时,实现才会访问它们 - 否则将被忽略。对于每种描述符类型,访问的成员如下:
-
对于
VK_DESCRIPTOR_TYPE_SAMPLER
,仅访问 VkWriteDescriptorSet::pImageInfo
的每个元素的sampler
成员。 -
对于
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
、VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
或VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
,仅访问 VkWriteDescriptorSet::pImageInfo
的每个元素的imageView
和imageLayout
成员。 -
对于
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
,访问 VkWriteDescriptorSet::pImageInfo
的每个元素的所有成员。 -
对于
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
、VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
、VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
或VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC
,访问 VkWriteDescriptorSet::pBufferInfo
的每个元素的所有成员。 -
对于
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
或VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
,访问 VkWriteDescriptorSet::pTexelBufferView
的每个元素。
当使用 descriptorType
为 VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
的描述符更新时,不会访问 pImageInfo
、pBufferInfo
或 pTexelBufferView
成员中的任何一个,而是从 VkWriteDescriptorSet
的 pNext
链中的 VkWriteDescriptorSetInlineUniformBlock 结构中获取描述符更新操作的源数据。当使用 descriptorType
为 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR
的描述符更新时,不会访问 pImageInfo
、pBufferInfo
或 pTexelBufferView
成员中的任何一个,而是从 VkWriteDescriptorSet
的 pNext
链中的 VkWriteDescriptorSetAccelerationStructureKHR 结构中获取描述符更新操作的源数据。当使用 descriptorType
为 VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV
的描述符更新时,不会访问 pImageInfo
、pBufferInfo
或 pTexelBufferView
成员中的任何一个,而是从 VkWriteDescriptorSet
的 pNext
链中的 VkWriteDescriptorSetAccelerationStructureNV 结构中获取描述符更新操作的源数据。
VkDescriptorBufferInfo
结构定义为:
// Provided by VK_VERSION_1_0
typedef struct VkDescriptorBufferInfo {
VkBuffer buffer;
VkDeviceSize offset;
VkDeviceSize range;
} VkDescriptorBufferInfo;
-
buffer
是 VK_NULL_HANDLE 或缓冲区资源。 -
offset
是从buffer
开始的字节偏移量。通过此描述符访问缓冲区内存使用相对于此起始偏移量的寻址。 -
range
是用于此描述符更新的字节大小,或者使用VK_WHOLE_SIZE
来使用从offset
到缓冲区末尾的范围。当将
range
设置为VK_WHOLE_SIZE
时,有效范围 必须 不大于描述符类型的最大范围(maxUniformBufferRange
或maxStorageBufferRange
)。这意味着,在统一缓冲区描述符是从远大于maxUniformBufferRange
的缓冲区进行子分配的常见情况下,VK_WHOLE_SIZE
通常没有用处。
对于 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
和 VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC
描述符类型,offset
是应用动态偏移的基础偏移量,range
是用于所有动态偏移的静态大小。
当 range
为 VK_WHOLE_SIZE
时,有效范围是在 vkUpdateDescriptorSets 中通过取 buffer
的大小减去 offset
来计算的。
VkDescriptorImageInfo
结构的定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkDescriptorImageInfo {
VkSampler sampler;
VkImageView imageView;
VkImageLayout imageLayout;
} VkDescriptorImageInfo;
-
sampler
是采样器句柄,如果正在更新的绑定不使用不可变的采样器,则在VK_DESCRIPTOR_TYPE_SAMPLER
和VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
类型的描述符更新中使用。 -
imageView
是 VK_NULL_HANDLE 或图像视图句柄,用于VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
、VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
、VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
和VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
类型的描述符更新。 -
imageLayout
是在访问此描述符时,可从imageView
访问的图像子资源将处于的布局。imageLayout
用于VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
、VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
、VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
和VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
类型的描述符更新。
VkDescriptorImageInfo
中未在更新中使用的成员(如上所述)将被忽略。
如果 VkWriteDescriptorSet 的 descriptorType
成员是 VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则写入描述符集的数据通过包含在 VkWriteDescriptorSet
的 pNext
链中的 VkWriteDescriptorSetInlineUniformBlock
结构指定。
VkWriteDescriptorSetInlineUniformBlock
结构定义如下:
// Provided by VK_VERSION_1_3
typedef struct VkWriteDescriptorSetInlineUniformBlock {
VkStructureType sType;
const void* pNext;
uint32_t dataSize;
const void* pData;
} VkWriteDescriptorSetInlineUniformBlock;
或等效结构
// Provided by VK_EXT_inline_uniform_block
typedef VkWriteDescriptorSetInlineUniformBlock VkWriteDescriptorSetInlineUniformBlockEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
dataSize
是pData
指向的内联统一缓冲区数据的字节数。 -
pData
是一个指针,指向要写入内联统一缓冲区的dataSize
字节的数据。
VkWriteDescriptorSetAccelerationStructureKHR
结构定义如下:
// Provided by VK_KHR_acceleration_structure
typedef struct VkWriteDescriptorSetAccelerationStructureKHR {
VkStructureType sType;
const void* pNext;
uint32_t accelerationStructureCount;
const VkAccelerationStructureKHR* pAccelerationStructures;
} VkWriteDescriptorSetAccelerationStructureKHR;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
accelerationStructureCount
是pAccelerationStructures
中的元素数量。 -
pAccelerationStructures
是指向 VkAccelerationStructureKHR 结构数组的指针,指定要更新的加速结构。
VkWriteDescriptorSetAccelerationStructureNV
结构定义如下:
// Provided by VK_NV_ray_tracing
typedef struct VkWriteDescriptorSetAccelerationStructureNV {
VkStructureType sType;
const void* pNext;
uint32_t accelerationStructureCount;
const VkAccelerationStructureNV* pAccelerationStructures;
} VkWriteDescriptorSetAccelerationStructureNV;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
accelerationStructureCount
是pAccelerationStructures
中的元素数量。 -
pAccelerationStructures
是指向 VkAccelerationStructureNV 结构数组的指针,指定要更新的加速结构。
VkCopyDescriptorSet
结构定义如下:
// Provided by VK_VERSION_1_0
typedef struct VkCopyDescriptorSet {
VkStructureType sType;
const void* pNext;
VkDescriptorSet srcSet;
uint32_t srcBinding;
uint32_t srcArrayElement;
VkDescriptorSet dstSet;
uint32_t dstBinding;
uint32_t dstArrayElement;
uint32_t descriptorCount;
} VkCopyDescriptorSet;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
srcSet
、srcBinding
和srcArrayElement
分别是源集、绑定和数组元素。如果由srcSet
和srcBinding
标识的描述符绑定的描述符类型为VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则srcArrayElement
指定要从中复制的绑定内的起始字节偏移量。 -
dstSet
、dstBinding
和dstArrayElement
分别是目标集、绑定和数组元素。如果由dstSet
和dstBinding
标识的描述符绑定的描述符类型为VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则dstArrayElement
指定要复制到的绑定内的起始字节偏移量。 -
descriptorCount
是要从源复制到目标的描述符数量。如果descriptorCount
大于源或目标绑定中剩余的数组元素数量,则这些会以类似于上面的 VkWriteDescriptorSet 的方式影响连续的绑定。如果由srcSet
和srcBinding
标识的描述符绑定的描述符类型为VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则descriptorCount
指定要复制的字节数,并且源或目标绑定中的剩余数组元素指的是其中剩余的字节数。
如果 dstBinding
的 VkDescriptorSetLayoutBinding
为 VK_DESCRIPTOR_TYPE_MUTABLE_EXT
,而 srcBinding
不是 VK_DESCRIPTOR_TYPE_MUTABLE_EXT
,则新的活动描述符类型变为 srcBinding
的描述符类型。如果 srcBinding
和 dstBinding
的 VkDescriptorSetLayoutBinding
均为 VK_DESCRIPTOR_TYPE_MUTABLE_EXT
,则每个源描述符中的活动描述符类型将复制到相应的目标描述符中。每个源描述符的活动描述符类型可以不同。
这样做的目的是,可变描述符的复制操作是一个简单的 memcpy。在不可变描述符和可变描述符之间进行复制时,预计每个描述符需要一个 memcpy 来处理大小差异,但这种具有多个 |
描述符更新模板
描述符更新模板指定了主机内存中的描述符更新信息到描述符集中描述符的映射。它旨在避免在频繁更新描述符集中的同一组描述符时,向驱动程序传递冗余信息。
描述符更新模板对象由 VkDescriptorUpdateTemplate
句柄表示。
// Provided by VK_VERSION_1_1
VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDescriptorUpdateTemplate)
或等效结构
// Provided by VK_KHR_descriptor_update_template
typedef VkDescriptorUpdateTemplate VkDescriptorUpdateTemplateKHR;
使用模板更新描述符集
更新一个大的 VkDescriptorSet
数组可能是一个昂贵的操作,因为应用程序必须为每个要更新的描述符或描述符数组指定一个 VkWriteDescriptorSet 结构,当在多个描述符集中更新相同的描述符时,每个结构都重新指定相同的状态。对于应用程序希望在多个使用相同 VkDescriptorSetLayout
分配的描述符集中更新同一组描述符的情况,可以使用 vkUpdateDescriptorSetWithTemplate 来代替 vkUpdateDescriptorSets。
VkDescriptorUpdateTemplate
允许实现将对单个描述符集的一组描述符更新操作转换为内部格式。结合 vkCmdPushDescriptorSetWithTemplate 或 vkUpdateDescriptorSetWithTemplate,这可能比调用 vkCmdPushDescriptorSet 或 vkUpdateDescriptorSets 更高效。描述符本身并未在 VkDescriptorUpdateTemplate
中指定,而是指定了指向应用程序提供的主机内存指针的偏移量,这些偏移量与传递给 vkCmdPushDescriptorSetWithTemplate 或 vkUpdateDescriptorSetWithTemplate 的指针结合使用。这允许执行大批量的更新,而无需将应用程序数据结构转换为严格定义的 Vulkan 数据结构。
要创建描述符更新模板,请调用
// Provided by VK_VERSION_1_1
VkResult vkCreateDescriptorUpdateTemplate(
VkDevice device,
const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
或等效命令
// Provided by VK_KHR_descriptor_update_template
VkResult vkCreateDescriptorUpdateTemplateKHR(
VkDevice device,
const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
-
device
是创建描述符更新模板的逻辑设备。 -
pCreateInfo
是一个指向 VkDescriptorUpdateTemplateCreateInfo 结构的指针,该结构指定要通过一次调用 vkCmdPushDescriptorSetWithTemplate 或 vkUpdateDescriptorSetWithTemplate 更新的描述符集。 -
pAllocator
控制主机内存分配,如 内存分配 章节中所述。 -
pDescriptorUpdateTemplate
是一个指向VkDescriptorUpdateTemplate
句柄的指针,该句柄返回生成的描述符更新模板对象。
// Provided by VK_VERSION_1_1
typedef struct VkDescriptorUpdateTemplateCreateInfo {
VkStructureType sType;
const void* pNext;
VkDescriptorUpdateTemplateCreateFlags flags;
uint32_t descriptorUpdateEntryCount;
const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries;
VkDescriptorUpdateTemplateType templateType;
VkDescriptorSetLayout descriptorSetLayout;
VkPipelineBindPoint pipelineBindPoint;
VkPipelineLayout pipelineLayout;
uint32_t set;
} VkDescriptorUpdateTemplateCreateInfo;
或等效结构
// Provided by VK_KHR_descriptor_update_template
typedef VkDescriptorUpdateTemplateCreateInfo VkDescriptorUpdateTemplateCreateInfoKHR;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
flags
保留供将来使用。 -
descriptorUpdateEntryCount
是pDescriptorUpdateEntries
数组中的元素数量。 -
pDescriptorUpdateEntries
是一个指向 VkDescriptorUpdateTemplateEntry 结构数组的指针,这些结构描述了要由描述符更新模板更新的描述符。 -
templateType
指定描述符更新模板的类型。如果设置为VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET
,则它只能用于更新具有固定descriptorSetLayout
的描述符集。如果设置为VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS
,则它只能用于使用提供的pipelineBindPoint
、pipelineLayout
和set
编号来推送描述符集。 -
descriptorSetLayout
是用于构建描述符更新模板的描述符集布局。所有将通过新创建的描述符更新模板更新的描述符集必须使用与此布局匹配(与此布局相同或定义相同的布局)的布局创建。如果templateType
不是VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET
,则忽略此参数。 -
pipelineBindPoint
是一个 VkPipelineBindPoint,指示将使用描述符的管道类型。如果templateType
不是VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS
,则忽略此参数。 -
pipelineLayout
是用于编程绑定的 VkPipelineLayout 对象。如果templateType
不是VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS
,则忽略此参数。 -
set
是管道布局中将更新的描述符集的集合编号。如果templateType
不是VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS
,则忽略此参数。
// Provided by VK_VERSION_1_1
typedef VkFlags VkDescriptorUpdateTemplateCreateFlags;
或等效结构
// Provided by VK_KHR_descriptor_update_template
typedef VkDescriptorUpdateTemplateCreateFlags VkDescriptorUpdateTemplateCreateFlagsKHR;
VkDescriptorUpdateTemplateCreateFlags
是一个用于设置掩码的位掩码类型,但目前保留供将来使用。
描述符更新模板类型由 VkDescriptorUpdateTemplateCreateInfo::templateType
属性确定,它接受以下值:
// Provided by VK_VERSION_1_1
typedef enum VkDescriptorUpdateTemplateType {
VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0,
// Provided by VK_VERSION_1_4
VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS = 1,
// Provided by VK_KHR_descriptor_update_template with VK_KHR_push_descriptor, VK_KHR_push_descriptor with VK_VERSION_1_1 or VK_KHR_descriptor_update_template
VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS,
// Provided by VK_KHR_descriptor_update_template
VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
} VkDescriptorUpdateTemplateType;
或等效结构
// Provided by VK_KHR_descriptor_update_template
typedef VkDescriptorUpdateTemplateType VkDescriptorUpdateTemplateTypeKHR;
-
VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET
指定描述符更新模板仅用于描述符集更新。 -
VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS
指定描述符更新模板仅用于推送描述符更新。
VkDescriptorUpdateTemplateEntry
结构定义如下:
// Provided by VK_VERSION_1_1
typedef struct VkDescriptorUpdateTemplateEntry {
uint32_t dstBinding;
uint32_t dstArrayElement;
uint32_t descriptorCount;
VkDescriptorType descriptorType;
size_t offset;
size_t stride;
} VkDescriptorUpdateTemplateEntry;
或等效结构
// Provided by VK_KHR_descriptor_update_template
typedef VkDescriptorUpdateTemplateEntry VkDescriptorUpdateTemplateEntryKHR;
-
dstBinding
是使用此描述符更新模板时要更新的描述符绑定。 -
dstArrayElement
是属于dstBinding
的数组中的起始元素。如果由dstBinding
标识的描述符绑定的描述符类型为VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则dstArrayElement
指定要更新的起始字节偏移量。 -
descriptorCount
是要更新的描述符的数量。如果descriptorCount
大于目标绑定中剩余的数组元素数量,则会像上面的 VkWriteDescriptorSet 一样影响连续的绑定。如果由dstBinding
标识的描述符绑定的描述符类型为VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则descriptorCount
指定要更新的字节数,并且目标绑定中剩余的数组元素指的是其中的剩余字节数。 -
descriptorType
是一个 VkDescriptorType,指定描述符的类型。 -
offset
是原始数据结构中第一个绑定的字节偏移量。 -
stride
是原始数据结构中描述符更新信息的两个连续数组元素之间的字节步幅。每个更新条目 i 的每个数组元素 j 的实际指针 ptr 使用以下公式计算:const char *ptr = (const char *)pData + pDescriptorUpdateEntries[i].offset + j * pDescriptorUpdateEntries[i].stride
如果绑定与其它数据一起存储在结构体中,则步幅非常有用。如果
descriptorType
为VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,则会忽略stride
的值,并且假定步幅为1
,即它们的描述符更新信息始终指定为连续范围。
要销毁描述符更新模板,请调用:
// Provided by VK_VERSION_1_1
void vkDestroyDescriptorUpdateTemplate(
VkDevice device,
VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const VkAllocationCallbacks* pAllocator);
或等效命令
// Provided by VK_KHR_descriptor_update_template
void vkDestroyDescriptorUpdateTemplateKHR(
VkDevice device,
VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const VkAllocationCallbacks* pAllocator);
-
device
是用于创建描述符更新模板的逻辑设备。 -
descriptorUpdateTemplate
是要销毁的描述符更新模板。 -
pAllocator
控制主机内存分配,如 内存分配 章节中所述。
一旦创建了 VkDescriptorUpdateTemplate
,可以通过调用以下命令来更新描述符集:
// Provided by VK_VERSION_1_1
void vkUpdateDescriptorSetWithTemplate(
VkDevice device,
VkDescriptorSet descriptorSet,
VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const void* pData);
或等效命令
// Provided by VK_KHR_descriptor_update_template
void vkUpdateDescriptorSetWithTemplateKHR(
VkDevice device,
VkDescriptorSet descriptorSet,
VkDescriptorUpdateTemplate descriptorUpdateTemplate,
const void* pData);
-
device
是更新描述符集的逻辑设备。 -
descriptorSet
是要更新的描述符集。 -
descriptorUpdateTemplate
是一个 VkDescriptorUpdateTemplate 对象,指定pData
和要更新的描述符集之间的更新映射。 -
pData
是指向包含一个或多个 VkDescriptorImageInfo、VkDescriptorBufferInfo 或 VkBufferView 结构体或 VkAccelerationStructureKHR 或 VkAccelerationStructureNV 句柄的内存的指针,这些句柄用于写入描述符。
struct AppBufferView {
VkBufferView bufferView;
uint32_t applicationRelatedInformation;
};
struct AppDataStructure
{
VkDescriptorImageInfo imageInfo; // a single image info
VkDescriptorBufferInfo bufferInfoArray[3]; // 3 buffer infos in an array
AppBufferView bufferView[2]; // An application-defined structure containing a bufferView
// ... some more application-related data
};
const VkDescriptorUpdateTemplateEntry descriptorUpdateTemplateEntries[] =
{
// binding to a single image descriptor
{
.binding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.offset = offsetof(AppDataStructure, imageInfo),
.stride = 0 // stride not required if descriptorCount is 1
},
// binding to an array of buffer descriptors
{
.binding = 1,
.dstArrayElement = 0,
.descriptorCount = 3,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.offset = offsetof(AppDataStructure, bufferInfoArray),
.stride = sizeof(VkDescriptorBufferInfo) // descriptor buffer infos are compact
},
// binding to an array of buffer views
{
.binding = 2,
.dstArrayElement = 0,
.descriptorCount = 2,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER,
.offset = offsetof(AppDataStructure, bufferView) +
offsetof(AppBufferView, bufferView),
.stride = sizeof(AppBufferView) // bufferViews do not have to be compact
},
};
// create a descriptor update template for descriptor set updates
const VkDescriptorUpdateTemplateCreateInfo createInfo =
{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.descriptorUpdateEntryCount = 3,
.pDescriptorUpdateEntries = descriptorUpdateTemplateEntries,
.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
.descriptorSetLayout = myLayout,
.pipelineBindPoint = 0, // ignored by given templateType
.pipelineLayout = 0, // ignored by given templateType
.set = 0, // ignored by given templateType
};
VkDescriptorUpdateTemplate myDescriptorUpdateTemplate;
myResult = vkCreateDescriptorUpdateTemplate(
myDevice,
&createInfo,
NULL,
&myDescriptorUpdateTemplate);
AppDataStructure appData;
// fill appData here or cache it in your engine
vkUpdateDescriptorSetWithTemplate(myDevice, myDescriptorSet, myDescriptorUpdateTemplate, &appData);
描述符集绑定
要将一个或多个描述符集绑定到命令缓冲区,请调用
// Provided by VK_VERSION_1_0
void vkCmdBindDescriptorSets(
VkCommandBuffer commandBuffer,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t firstSet,
uint32_t descriptorSetCount,
const VkDescriptorSet* pDescriptorSets,
uint32_t dynamicOffsetCount,
const uint32_t* pDynamicOffsets);
-
commandBuffer
是描述符集将要绑定到的命令缓冲区。 -
pipelineBindPoint
是一个 VkPipelineBindPoint,指示将使用描述符的管线类型。每个管线类型都有一组单独的绑定点,因此绑定一个不会干扰其他绑定点。 -
layout
是一个 VkPipelineLayout 对象,用于编程绑定。 -
firstSet
是要绑定的第一个描述符集的集合编号。 -
descriptorSetCount
是pDescriptorSets
数组中的元素数量。 -
pDescriptorSets
是一个指向 VkDescriptorSet 对象句柄数组的指针,这些对象描述要绑定的描述符集。 -
dynamicOffsetCount
是pDynamicOffsets
数组中动态偏移的数量。 -
pDynamicOffsets
是一个指向uint32_t
值数组的指针,指定动态偏移。
vkCmdBindDescriptorSets
将描述符集 pDescriptorSets
[0..descriptorSetCount
-1] 绑定到集合编号 [firstSet
..firstSet
+descriptorSetCount
-1],用于后续由 pipelineBindPoint
设置的绑定的管线命令。之前通过这些集合或对 vkCmdSetDescriptorBufferOffsetsEXT 或 vkCmdBindDescriptorBufferEmbeddedSamplersEXT 的调用应用的任何绑定都不再有效。
一旦绑定,描述符集会影响命令缓冲区中与给定管线类型交互的后续命令的渲染,直到不同的集合绑定到同一集合编号,或者该集合如管线布局兼容性中所述受到干扰。
在记录使用该管线执行绘制或调度命令时,必须为管线中任何着色器访问的所有集合编号绑定一个兼容的描述符集。但是,如果管线中的任何着色器都没有静态使用任何具有特定集合编号的绑定,则无需为该集合编号绑定描述符集,即使管线布局包含该集合编号的非平凡描述符集布局也是如此。
当使用描述符时,如果描述符不是 描述符集分配中所述的未定义,则该描述符被视为有效。如果启用了 nullDescriptor
功能,则空描述符也被视为有效。被管线布局兼容性干扰或从未被 vkCmdBindDescriptorSets
绑定的描述符不被视为有效。如果管线根据 VkDescriptorBindingFlagBits 静态或动态地访问描述符,则管线中的消耗描述符类型必须与 VkDescriptorSetLayoutCreateInfo 中的 VkDescriptorType 匹配,以便该描述符被视为有效。如果描述符是可变描述符,则管线中的消耗描述符类型必须与描述符的活动描述符类型匹配,以便该描述符被视为有效。
可能会执行超越描述符类型验证的进一步验证,例如 纹素输入验证。 |
如果正在绑定的任何集合包含动态统一或存储缓冲区,则 pDynamicOffsets
包含每个集合中每个动态描述符类型绑定中的每个数组元素的一个元素。从 pDynamicOffsets
中提取值的顺序是,集合 N 的所有条目都位于集合 N+1 之前;在一个集合内,条目按照描述符集布局中的绑定编号排序;并且在绑定数组中,元素按顺序排列。dynamicOffsetCount
必须等于正在绑定的集合中动态描述符的总数。
用于动态统一和存储缓冲区绑定的有效偏移量是从 pDynamicOffsets
中提取的相对偏移量与描述符集中缓冲区的基地址加上基偏移量之和。动态统一和存储缓冲区绑定的范围是描述符集中指定的缓冲区范围。
通过调用 vkCmdBindDescriptorSets
绑定的描述符集内容可以在以下时间使用
-
对于使用设置的
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT
位创建的描述符绑定,当命令缓冲区提交到队列时,或者在生成的绘制和调度的着色器执行期间,或在两者之间的任何时间,可以使用内容。否则, -
在命令的主机执行期间,或者在生成的绘制和调度的着色器执行期间,或在两者之间的任何时间使用。
因此,描述符集绑定的内容必须在它可能被使用的第一个时间点到命令在队列中完成执行之间不得更改(被更新命令覆盖或释放)。
pDynamicOffsets
的内容在执行 vkCmdBindDescriptorSets
期间立即使用。一旦所有挂起的使用完成,更新和重用描述符集是合法的。
或者,要将一个或多个描述符集绑定到命令缓冲区,请调用
// Provided by VK_VERSION_1_4
void vkCmdBindDescriptorSets2(
VkCommandBuffer commandBuffer,
const VkBindDescriptorSetsInfo* pBindDescriptorSetsInfo);
或等效命令
// Provided by VK_KHR_maintenance6
void vkCmdBindDescriptorSets2KHR(
VkCommandBuffer commandBuffer,
const VkBindDescriptorSetsInfo* pBindDescriptorSetsInfo);
-
commandBuffer
是描述符集将要绑定到的命令缓冲区。 -
pBindDescriptorSetsInfo
是指向VkBindDescriptorSetsInfo
结构的指针。
VkBindDescriptorSetsInfo
结构定义如下:
// Provided by VK_VERSION_1_4
typedef struct VkBindDescriptorSetsInfo {
VkStructureType sType;
const void* pNext;
VkShaderStageFlags stageFlags;
VkPipelineLayout layout;
uint32_t firstSet;
uint32_t descriptorSetCount;
const VkDescriptorSet* pDescriptorSets;
uint32_t dynamicOffsetCount;
const uint32_t* pDynamicOffsets;
} VkBindDescriptorSetsInfo;
或等效结构
// Provided by VK_KHR_maintenance6
typedef VkBindDescriptorSetsInfo VkBindDescriptorSetsInfoKHR;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
stageFlags
是一个 VkShaderStageFlagBits 的位掩码,指定描述符集将绑定到的着色器阶段。 -
layout
是用于编程绑定的 VkPipelineLayout 对象。如果启用了dynamicPipelineLayout
功能,则layout
可以 为 VK_NULL_HANDLE,并且布局必须通过将 VkPipelineLayoutCreateInfo 结构链接到pNext
来指定。 -
firstSet
是要绑定的第一个描述符集的集合编号。 -
descriptorSetCount
是pDescriptorSets
数组中的元素数量。 -
pDescriptorSets
是一个指向 VkDescriptorSet 对象句柄数组的指针,这些对象描述要绑定的描述符集。 -
dynamicOffsetCount
是pDynamicOffsets
数组中动态偏移的数量。 -
pDynamicOffsets
是一个指向uint32_t
值数组的指针,指定动态偏移。
如果 stageFlags
指定一个或多个对应于管线绑定点的所有阶段的子集,则绑定操作仍然影响对应于给定管线绑定点的所有阶段,就好像使用相同的参数调用了此命令的等效原始版本一样。例如,指定一个 stageFlags
值为 VK_SHADER_STAGE_VERTEX_BIT
| VK_SHADER_STAGE_FRAGMENT_BIT
| VK_SHADER_STAGE_COMPUTE_BIT
等效于使用 VK_PIPELINE_BIND_POINT_GRAPHICS
调用原始版本的此命令一次,并使用 VK_PIPELINE_BIND_POINT_COMPUTE
调用一次。
推送描述符更新
除了分配描述符集并将它们绑定到命令缓冲区之外,应用程序可以将描述符更新记录到命令缓冲区中。
要将描述符更新推送到命令缓冲区,请调用
// Provided by VK_VERSION_1_4
void vkCmdPushDescriptorSet(
VkCommandBuffer commandBuffer,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t set,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites);
或等效命令
// Provided by VK_KHR_push_descriptor
void vkCmdPushDescriptorSetKHR(
VkCommandBuffer commandBuffer,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t set,
uint32_t descriptorWriteCount,
const VkWriteDescriptorSet* pDescriptorWrites);
-
commandBuffer
是将记录描述符的命令缓冲区。 -
pipelineBindPoint
是一个 VkPipelineBindPoint,指示将使用描述符的管线的类型。每种管线类型都有一组单独的推送描述符绑定,因此绑定一个不会干扰其他绑定。 -
layout
是一个 VkPipelineLayout 对象,用于编程绑定。 -
set
是将要更新的管线布局中描述符集的集号。 -
descriptorWriteCount
是pDescriptorWrites
数组中的元素数量。 -
pDescriptorWrites
是指向描述要更新的描述符的 VkWriteDescriptorSet 结构数组的指针。
推送描述符是一小块描述符,其存储由命令缓冲区内部管理,而不是写入描述符集并稍后绑定到命令缓冲区。推送描述符允许增量更新描述符,而无需管理描述符集的生命周期。
当命令缓冲区开始记录时,所有推送描述符都是未定义的。推送描述符可以增量更新,并使着色器在后续的绑定的管线命令中使用更新后的描述符,直到描述符被覆盖,或者直到集合被管线布局兼容性中所述的方式干扰。当集合被干扰或设置了具有不同描述符集布局的推送描述符时,所有推送描述符都是未定义的。
管线静态使用的推送描述符在记录使用该管线执行的绘制或调度命令时,必须不是未定义的。这包括不可变的采样器描述符,它们必须在被管线访问之前推送(推送的是不可变的采样器,而不是pDescriptorWrites
中的采样器)。未被静态使用的推送描述符可以保持未定义状态。
推送描述符不使用动态偏移。相反,可以使用相应的非动态描述符类型,并且每次写入描述符时,都可以更改VkDescriptorBufferInfo的offset
成员。
pDescriptorWrites
的每个元素都按照 VkWriteDescriptorSet 中的方式解释,只是忽略 dstSet
成员。
要推送一个不可变的采样器,请使用一个 VkWriteDescriptorSet,其中 dstBinding
和 dstArrayElement
选择不可变采样器的绑定。如果描述符类型为 VK_DESCRIPTOR_TYPE_SAMPLER
,则忽略 pImageInfo
参数,并且不可变采样器取自管线布局中的推送描述符集布局。如果描述符类型为 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
,则忽略 pImageInfo
参数的 sampler
成员,并且不可变采样器取自管线布局中的推送描述符集布局。
或者,要将描述符更新推送到命令缓冲区中,请调用
// Provided by VK_VERSION_1_4
void vkCmdPushDescriptorSet2(
VkCommandBuffer commandBuffer,
const VkPushDescriptorSetInfo* pPushDescriptorSetInfo);
或等效命令
// Provided by VK_KHR_maintenance6 with VK_KHR_push_descriptor
void vkCmdPushDescriptorSet2KHR(
VkCommandBuffer commandBuffer,
const VkPushDescriptorSetInfo* pPushDescriptorSetInfo);
-
commandBuffer
是将记录描述符的命令缓冲区。 -
pPushDescriptorSetInfo
是指向VkPushDescriptorSetInfo
结构的指针。
VkPushDescriptorSetInfo
结构的定义如下
// Provided by VK_VERSION_1_4
typedef struct VkPushDescriptorSetInfo {
VkStructureType sType;
const void* pNext;
VkShaderStageFlags stageFlags;
VkPipelineLayout layout;
uint32_t set;
uint32_t descriptorWriteCount;
const VkWriteDescriptorSet* pDescriptorWrites;
} VkPushDescriptorSetInfo;
或等效结构
// Provided by VK_KHR_maintenance6 with VK_KHR_push_descriptor
typedef VkPushDescriptorSetInfo VkPushDescriptorSetInfoKHR;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
stageFlags
是 VkShaderStageFlagBits 的位掩码,指定将使用描述符的着色器阶段。 -
layout
是用于编程绑定的 VkPipelineLayout 对象。如果启用了dynamicPipelineLayout
功能,则layout
可以是 VK_NULL_HANDLE,并且布局必须通过链接pNext
的 VkPipelineLayoutCreateInfo 结构来指定 -
set
是将要更新的管线布局中描述符集的集号。 -
descriptorWriteCount
是pDescriptorWrites
数组中的元素数量。 -
pDescriptorWrites
是指向描述要更新的描述符的 VkWriteDescriptorSet 结构数组的指针。
如果 stageFlags
指定一个或多个对应于管线绑定点的所有阶段的子集,则绑定操作仍然影响对应于给定管线绑定点的所有阶段,就好像使用相同的参数调用了此命令的等效原始版本一样。例如,指定一个 stageFlags
值为 VK_SHADER_STAGE_VERTEX_BIT
| VK_SHADER_STAGE_FRAGMENT_BIT
| VK_SHADER_STAGE_COMPUTE_BIT
等效于使用 VK_PIPELINE_BIND_POINT_GRAPHICS
调用原始版本的此命令一次,并使用 VK_PIPELINE_BIND_POINT_COMPUTE
调用一次。
使用描述符更新模板进行 Push 描述符更新
也可以使用描述符更新模板来指定要更新的 push 描述符。为此,请调用
// Provided by VK_VERSION_1_4
void vkCmdPushDescriptorSetWithTemplate(
VkCommandBuffer commandBuffer,
VkDescriptorUpdateTemplate descriptorUpdateTemplate,
VkPipelineLayout layout,
uint32_t set,
const void* pData);
或等效命令
// Provided by VK_KHR_descriptor_update_template with VK_KHR_push_descriptor, VK_KHR_push_descriptor with VK_VERSION_1_1 or VK_KHR_descriptor_update_template
void vkCmdPushDescriptorSetWithTemplateKHR(
VkCommandBuffer commandBuffer,
VkDescriptorUpdateTemplate descriptorUpdateTemplate,
VkPipelineLayout layout,
uint32_t set,
const void* pData);
-
commandBuffer
是将记录描述符的命令缓冲区。 -
descriptorUpdateTemplate
是一个描述符更新模板,定义了如何解释pData
中的描述符信息。 -
layout
是一个 VkPipelineLayout 对象,用于编程绑定。它必须与用于创建descriptorUpdateTemplate
句柄的布局兼容。 -
set
是管道布局中将被更新的描述符集的集合号。此值必须与用于创建descriptorUpdateTemplate
句柄的值相同。 -
pData
是一个指向内存的指针,该内存包含模板化更新的描述符。
struct AppDataStructure
{
VkDescriptorImageInfo imageInfo; // a single image info
// ... some more application-related data
};
const VkDescriptorUpdateTemplateEntry descriptorUpdateTemplateEntries[] =
{
// binding to a single image descriptor
{
.binding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.offset = offsetof(AppDataStructure, imageInfo),
.stride = 0 // not required if descriptorCount is 1
}
};
// create a descriptor update template for push descriptor set updates
const VkDescriptorUpdateTemplateCreateInfo createInfo =
{
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO,
.pNext = NULL,
.flags = 0,
.descriptorUpdateEntryCount = 1,
.pDescriptorUpdateEntries = descriptorUpdateTemplateEntries,
.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS,
.descriptorSetLayout = 0, // ignored by given templateType
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
.pipelineLayout = myPipelineLayout,
.set = 0,
};
VkDescriptorUpdateTemplate myDescriptorUpdateTemplate;
myResult = vkCreateDescriptorUpdateTemplate(
myDevice,
&createInfo,
NULL,
&myDescriptorUpdateTemplate);
AppDataStructure appData;
// fill appData here or cache it in your engine
vkCmdPushDescriptorSetWithTemplate(myCmdBuffer, myDescriptorUpdateTemplate, myPipelineLayout, 0,&appData);
或者,要使用描述符更新模板来指定要更新的 push 描述符,请调用
// Provided by VK_VERSION_1_4
void vkCmdPushDescriptorSetWithTemplate2(
VkCommandBuffer commandBuffer,
const VkPushDescriptorSetWithTemplateInfo* pPushDescriptorSetWithTemplateInfo);
或等效命令
// Provided by VK_KHR_maintenance6 with VK_KHR_push_descriptor
void vkCmdPushDescriptorSetWithTemplate2KHR(
VkCommandBuffer commandBuffer,
const VkPushDescriptorSetWithTemplateInfo* pPushDescriptorSetWithTemplateInfo);
-
commandBuffer
是将记录描述符的命令缓冲区。 -
pPushDescriptorSetWithTemplateInfo
是指向VkPushDescriptorSetWithTemplateInfo
结构的指针。
VkPushDescriptorSetWithTemplateInfo
结构定义如下
// Provided by VK_VERSION_1_4
typedef struct VkPushDescriptorSetWithTemplateInfo {
VkStructureType sType;
const void* pNext;
VkDescriptorUpdateTemplate descriptorUpdateTemplate;
VkPipelineLayout layout;
uint32_t set;
const void* pData;
} VkPushDescriptorSetWithTemplateInfo;
或等效结构
// Provided by VK_KHR_maintenance6 with VK_KHR_push_descriptor
typedef VkPushDescriptorSetWithTemplateInfo VkPushDescriptorSetWithTemplateInfoKHR;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
descriptorUpdateTemplate
是一个描述符更新模板,定义了如何解释pData
中的描述符信息。 -
layout
是一个 VkPipelineLayout 对象,用于编程绑定。它必须与用于创建descriptorUpdateTemplate
句柄的布局兼容。如果启用了dynamicPipelineLayout
功能,则layout
可以为 VK_NULL_HANDLE,并且布局必须通过链接pNext
的 VkPipelineLayoutCreateInfo 结构来指定。 -
set
是管道布局中将被更新的描述符集的集合号。此值必须与用于创建descriptorUpdateTemplate
句柄的值相同。 -
pData
是一个指向内存的指针,该内存包含模板化更新的描述符。
推送常量更新
如上文 管线布局 一节所述,管线布局定义了着色器推送常量,这些常量通过 Vulkan 命令而不是通过写入内存或复制命令来更新。
推送常量表示一种高速路径,用于修改管线中的常量数据,预计其性能优于基于内存的资源更新。 |
要更新推送常量,请调用
// Provided by VK_VERSION_1_0
void vkCmdPushConstants(
VkCommandBuffer commandBuffer,
VkPipelineLayout layout,
VkShaderStageFlags stageFlags,
uint32_t offset,
uint32_t size,
const void* pValues);
-
commandBuffer
是记录推送常量更新的命令缓冲区。 -
layout
是用于编程推送常量更新的管线布局。 -
stageFlags
是一个 VkShaderStageFlagBits 的位掩码,指定将在更新范围内使用推送常量的着色器阶段。 -
offset
是要更新的推送常量范围的起始偏移量,以字节为单位。 -
size
是要更新的推送常量范围的大小,以字节为单位。 -
pValues
是指向包含新的推送常量值的size
字节数组的指针。
当命令缓冲区开始记录时,所有推送常量值都是未定义的。执行着色器读取未定义的推送常量值将返回未定义的值。
推送常量值可以递增更新,导致 stageFlags
中的着色器阶段从 pValues
中读取此命令修改的推送常量的新数据,同时仍然读取此命令未修改的推送常量的先前数据。当发出绑定的管线命令时,绑定的管线的布局必须与用于设置管线布局的推送常量范围中所有推送常量值的布局兼容,如管线布局兼容性中所述。绑定与推送常量布局不兼容的布局的管线不会干扰推送常量值。
由于 |
或者,要更新推送常量,请调用
// Provided by VK_VERSION_1_4
void vkCmdPushConstants2(
VkCommandBuffer commandBuffer,
const VkPushConstantsInfo* pPushConstantsInfo);
或等效命令
// Provided by VK_KHR_maintenance6
void vkCmdPushConstants2KHR(
VkCommandBuffer commandBuffer,
const VkPushConstantsInfo* pPushConstantsInfo);
-
commandBuffer
是记录推送常量更新的命令缓冲区。 -
pPushConstantsInfo
是指向VkPushConstantsInfo
结构的指针。
VkPushConstantsInfo
结构定义如下
// Provided by VK_VERSION_1_4
typedef struct VkPushConstantsInfo {
VkStructureType sType;
const void* pNext;
VkPipelineLayout layout;
VkShaderStageFlags stageFlags;
uint32_t offset;
uint32_t size;
const void* pValues;
} VkPushConstantsInfo;
或等效结构
// Provided by VK_KHR_maintenance6
typedef VkPushConstantsInfo VkPushConstantsInfoKHR;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
layout
是用于编程推送常量更新的管线布局。 如果启用dynamicPipelineLayout
功能,则layout
可以为VK_NULL_HANDLE,并且必须通过链接pNext
上的 VkPipelineLayoutCreateInfo 结构来指定布局。 -
stageFlags
是一个 VkShaderStageFlagBits 的位掩码,指定将在更新范围内使用推送常量的着色器阶段。 -
offset
是要更新的推送常量范围的起始偏移量,以字节为单位。 -
size
是要更新的推送常量范围的大小,以字节为单位。 -
pValues
是指向包含新的推送常量值的size
字节数组的指针。
物理存储缓冲区访问
要查询可以通过着色器访问缓冲区内存的 64 位缓冲区设备地址值,请调用
// Provided by VK_VERSION_1_2
VkDeviceAddress vkGetBufferDeviceAddress(
VkDevice device,
const VkBufferDeviceAddressInfo* pInfo);
或等效命令
// Provided by VK_KHR_buffer_device_address
VkDeviceAddress vkGetBufferDeviceAddressKHR(
VkDevice device,
const VkBufferDeviceAddressInfo* pInfo);
或等效命令
// Provided by VK_EXT_buffer_device_address
VkDeviceAddress vkGetBufferDeviceAddressEXT(
VkDevice device,
const VkBufferDeviceAddressInfo* pInfo);
-
device
是创建缓冲区的逻辑设备。 -
pInfo
是指向 VkBufferDeviceAddressInfo 结构的指针,该结构指定要检索地址的缓冲区。
64 位返回值是 pInfo->buffer
的起始地址。从该值开始且大小为缓冲区大小的地址范围可以在着色器中使用,以使用 SPV_KHR_physical_storage_buffer
扩展或等效的 SPV_EXT_physical_storage_buffer
扩展以及 PhysicalStorageBuffer
存储类来访问绑定到该缓冲区的内存。例如,此值可以存储在统一缓冲区中,并且着色器可以从统一缓冲区读取该值并使用它来对该缓冲区进行依赖读取/写入。零值保留为“空”指针,并且必须不作为有效的缓冲区设备地址返回。着色器中通过 PhysicalStorageBuffer
指针进行的所有加载、存储和原子操作必须访问某些缓冲区的地址范围内的地址。
如果缓冲区是使用非零值 VkBufferOpaqueCaptureAddressCreateInfo::opaqueCaptureAddress
或 VkBufferDeviceAddressCreateInfoEXT::deviceAddress
创建的,则返回值将是在捕获时返回的相同地址。
返回的地址必须满足 VkMemoryRequirements::alignment
为 VkBufferDeviceAddressInfo::buffer
中的缓冲区指定的对齐要求。
如果多个 VkBuffer 对象绑定到 VkDeviceMemory 的重叠范围,则实现可以返回重叠的地址范围。在这种情况下,哪个 VkBuffer 与任何给定的设备地址相关联是模棱两可的。为了有效使用的目的,如果多个 VkBuffer 对象可以归因于设备地址,则会选择一个 VkBuffer 以便通过有效的使用,如果存在的话。
VkBufferDeviceAddressInfo
结构定义为
// Provided by VK_VERSION_1_2
typedef struct VkBufferDeviceAddressInfo {
VkStructureType sType;
const void* pNext;
VkBuffer buffer;
} VkBufferDeviceAddressInfo;
或等效结构
// Provided by VK_KHR_buffer_device_address
typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoKHR;
或等效结构
// Provided by VK_EXT_buffer_device_address
typedef VkBufferDeviceAddressInfo VkBufferDeviceAddressInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
buffer
指定正在查询其地址的缓冲区。
要查询 64 位缓冲区不透明捕获地址,请调用
// Provided by VK_VERSION_1_2
uint64_t vkGetBufferOpaqueCaptureAddress(
VkDevice device,
const VkBufferDeviceAddressInfo* pInfo);
或等效命令
// Provided by VK_KHR_buffer_device_address
uint64_t vkGetBufferOpaqueCaptureAddressKHR(
VkDevice device,
const VkBufferDeviceAddressInfo* pInfo);
-
device
是创建缓冲区的逻辑设备。 -
pInfo
是指向 VkBufferDeviceAddressInfo 结构的指针,该结构指定要检索地址的缓冲区。
64 位返回值是 pInfo->buffer
起始处的不透明捕获地址。
如果缓冲区是使用非零值 VkBufferOpaqueCaptureAddressCreateInfo::opaqueCaptureAddress
创建的,则返回值必须是相同的地址。
VkStridedDeviceAddressRegionKHR
结构定义为
// Provided by VK_KHR_ray_tracing_pipeline
typedef struct VkStridedDeviceAddressRegionKHR {
VkDeviceAddress deviceAddress;
VkDeviceSize stride;
VkDeviceSize size;
} VkStridedDeviceAddressRegionKHR;
-
deviceAddress
是区域开始处的设备地址(由 vkGetBufferDeviceAddress 命令返回),如果区域未使用,则为零。 -
stride
是连续元素之间的字节步幅。 -
size
是从deviceAddress
开始的区域的大小(以字节为单位)。
描述符缓冲区
如果启用了descriptorBuffer
特性,则可以通过缓冲区而不是描述符集对象来指定描述符集。
将描述符放入内存
提供了命令来检索描述符数据,以及确定数据必须写入内存中的哪个位置以匹配给定的描述符集布局。
要确定存储具有给定布局的所有描述符所需的内存量,请调用
// Provided by VK_EXT_descriptor_buffer
void vkGetDescriptorSetLayoutSizeEXT(
VkDevice device,
VkDescriptorSetLayout layout,
VkDeviceSize* pLayoutSizeInBytes);
-
device
是获取大小的逻辑设备。 -
layout
是正在查询的描述符集布局。 -
pLayoutSizeInBytes
是一个指向VkDeviceSize
的指针,其中将写入以字节为单位的大小。
描述符集布局的大小至少应等于布局中所有描述符的总大小之和,并且可能更大。 此大小表示当根据通过 vkGetDescriptorSetLayoutBindingOffsetEXT 获取的布局偏移量放置时,在内存中存储此布局的所有描述符所需的内存量。
如果 layout
中的任何 binding
具有 VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
,则返回的大小包括为该 binding
声明的最大 descriptorCount
描述符的空间。 要计算具有 VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
的描述符集所需的大小
-
大小 = 偏移量 + 描述符大小 × 可变描述符计数
其中 偏移量 通过 vkGetDescriptorSetLayoutBindingOffsetEXT 获得,描述符大小 是从 VkPhysicalDeviceDescriptorBufferPropertiesEXT 获得的相应描述符的大小,可变描述符计数 等同于 VkDescriptorSetVariableDescriptorCountAllocateInfo::pDescriptorCounts
。 对于 VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK
,可变描述符计数 是内联统一块的字节大小,描述符大小 为 1。
如果 VkPhysicalDeviceDescriptorBufferPropertiesEXT::combinedImageSamplerDescriptorSingleArray
为 VK_FALSE
且可变描述符类型为 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
,则始终认为 可变描述符计数 为上限。
要获取内存中描述符集布局中绑定的偏移量,请调用
// Provided by VK_EXT_descriptor_buffer
void vkGetDescriptorSetLayoutBindingOffsetEXT(
VkDevice device,
VkDescriptorSetLayout layout,
uint32_t binding,
VkDeviceSize* pOffset);
-
device
是获取偏移量的逻辑设备。 -
layout
是正在查询的描述符集布局。 -
binding
是正在查询的绑定编号。 -
pOffset
是一个指向VkDeviceSize
的指针,其中将写入绑定的字节偏移量。
描述符集布局中的每个绑定都由实现分配一个内存偏移量。 当着色器使用该绑定访问资源时,它将从该偏移量访问绑定的描述符缓冲区以查找其描述符。 此命令为应用程序提供该偏移量,以便可以将描述符放置在正确的位置。 着色器针对给定描述符访问的精确位置如下所示
-
位置 = 缓冲区地址 + 集偏移量 + 描述符偏移量 + (数组元素 × 描述符大小)
其中 缓冲区地址 和 集偏移量 是由 vkCmdBindDescriptorBuffersEXT 和 vkCmdSetDescriptorBufferOffsetsEXT 指定的已标识描述符集的基地址和偏移量,描述符偏移量 是此命令返回的绑定的偏移量,数组元素 是着色器中指定的数组索引,描述符大小 是从 VkPhysicalDeviceDescriptorBufferPropertiesEXT 获得的相应描述符的大小。 应用程序负责将有效描述符放置在预期位置,以便着色器可以访问它。 添加到 缓冲区地址 以计算 位置 的总偏移量必须小于采样器的 VkPhysicalDeviceDescriptorBufferPropertiesEXT::maxSamplerDescriptorBufferRange
和资源的 VkPhysicalDeviceDescriptorBufferPropertiesEXT::maxResourceDescriptorBufferRange
。
如果 layout
中的任何 binding
具有 VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
,则该 binding
必须具有任何 binding
的最大偏移量。
可以使用类型为 VK_DESCRIPTOR_TYPE_MUTABLE_VALVE
的描述符 binding
。 VkMutableDescriptorTypeCreateInfoVALVE::pDescriptorTypes
中 binding
的任何潜在类型都共享相同的偏移量。 如果 可变描述符 的大小大于正在访问的具体描述符类型的大小,则实现会忽略填充区域。
要获取要放入缓冲区中的描述符数据,请调用
// Provided by VK_EXT_descriptor_buffer
void vkGetDescriptorEXT(
VkDevice device,
const VkDescriptorGetInfoEXT* pDescriptorInfo,
size_t dataSize,
void* pDescriptor);
-
device
是获取描述符的逻辑设备。 -
pDescriptorInfo
是一个指向 VkDescriptorGetInfoEXT 结构的指针,该结构指定要获取的描述符的参数。 -
dataSize
是要获取的描述符数据的大小,以字节为单位。 -
pDescriptor
是一个指向应用程序分配的缓冲区的指针,描述符将被写入该缓冲区。
每种描述符类型的数据大小由 VkPhysicalDeviceDescriptorBufferPropertiesEXT 中的值确定。此值还定义了该描述符类型数组的步长(以字节为单位)。
如果 VkPhysicalDeviceDescriptorBufferPropertiesEXT::combinedImageSamplerDescriptorSingleArray
属性为 VK_FALSE
,则实现要求将 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
描述符数组写入描述符缓冲区,作为图像描述符数组,紧接着是采样器描述符数组。应用程序必须将通过 pDescriptor
返回的数据的前 VkPhysicalDeviceDescriptorBufferPropertiesEXT::sampledImageDescriptorSize
字节写入第一个数组,并将剩余的 VkPhysicalDeviceDescriptorBufferPropertiesEXT::samplerDescriptorSize
字节写入第二个数组。对于 VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
描述符的可变大小描述符绑定,这两个数组的大小都等于该绑定的上限 descriptorCount
。
通过此命令获取的描述符引用底层的 VkImageView 或 VkSampler,并且这些对象在最后一次动态访问描述符之前不得销毁。对于使用地址而不是对象的描述符类型,则引用底层的 VkBuffer。
要获取的描述符的信息在 VkDescriptorGetInfoEXT
结构中传递。
// Provided by VK_EXT_descriptor_buffer
typedef struct VkDescriptorGetInfoEXT {
VkStructureType sType;
const void* pNext;
VkDescriptorType type;
VkDescriptorDataEXT data;
} VkDescriptorGetInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
type
是要获取的描述符的类型。 -
data
是一个包含获取描述符所需信息的结构。
描述符的数据在 VkDescriptorDataEXT
结构中传递
// Provided by VK_EXT_descriptor_buffer
typedef union VkDescriptorDataEXT {
const VkSampler* pSampler;
const VkDescriptorImageInfo* pCombinedImageSampler;
const VkDescriptorImageInfo* pInputAttachmentImage;
const VkDescriptorImageInfo* pSampledImage;
const VkDescriptorImageInfo* pStorageImage;
const VkDescriptorAddressInfoEXT* pUniformTexelBuffer;
const VkDescriptorAddressInfoEXT* pStorageTexelBuffer;
const VkDescriptorAddressInfoEXT* pUniformBuffer;
const VkDescriptorAddressInfoEXT* pStorageBuffer;
VkDeviceAddress accelerationStructure;
} VkDescriptorDataEXT;
-
pSampler
是指向 VkSampler 句柄的指针,该句柄指定VK_DESCRIPTOR_TYPE_SAMPLER
描述符的参数。 -
pCombinedImageSampler
是指向 VkDescriptorImageInfo 结构的指针,该结构指定VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
描述符的参数。 -
pInputAttachmentImage
是指向 VkDescriptorImageInfo 结构的指针,该结构指定VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
描述符的参数。 -
pSampledImage
是指向 VkDescriptorImageInfo 结构的指针,该结构指定VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
描述符的参数。 -
pStorageImage
是指向 VkDescriptorImageInfo 结构的指针,该结构指定VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
描述符的参数。 -
pUniformTexelBuffer
是指向 VkDescriptorAddressInfoEXT 结构的指针,该结构指定VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
描述符的参数。 -
pStorageTexelBuffer
是指向 VkDescriptorAddressInfoEXT 结构的指针,该结构指定VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
描述符的参数。 -
pUniformBuffer
是指向 VkDescriptorAddressInfoEXT 结构的指针,该结构指定VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
描述符的参数。 -
pStorageBuffer
是指向 VkDescriptorAddressInfoEXT 结构的指针,该结构指定VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
描述符的参数。 -
accelerationStructure
是 VkAccelerationStructureKHR 的地址,该地址指定VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR
描述符的参数,或者是 VkAccelerationStructureNV 句柄,该句柄指定VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV
描述符的参数。
如果启用了 nullDescriptor
功能,则 pSampledImage
、pStorageImage
、pUniformTexelBuffer
、pStorageTexelBuffer
、pUniformBuffer
和 pStorageBuffer
每个都**可以**为 NULL
。从空描述符加载会返回零值,并且对空描述符的存储和原子操作会被丢弃。
如果启用了 nullDescriptor
功能,accelerationStructure
**可以**为 0
。空加速结构描述符会导致调用缺失着色器。
描述 VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
、VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
、VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
或 VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
描述符的数据在 VkDescriptorAddressInfoEXT
结构中传递。
// Provided by VK_EXT_descriptor_buffer
typedef struct VkDescriptorAddressInfoEXT {
VkStructureType sType;
void* pNext;
VkDeviceAddress address;
VkDeviceSize range;
VkFormat format;
} VkDescriptorAddressInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
address
要么是0
,要么是缓冲区中偏移量的设备地址,其中基本地址可以从 vkGetBufferDeviceAddress 查询。 -
range
是描述符使用的缓冲区或缓冲区视图的大小(以字节为单位)。 -
format
是缓冲区视图中数据元素的格式,对于缓冲区会被忽略。
如果启用了 nullDescriptor
功能,则 address
可以 为零。 从空描述符加载返回零值,对空描述符的存储和原子操作会被丢弃。
通过 pImmutableSamplers
在描述符集布局中指定的不可变采样器,在获取描述符数据时,必须 由应用程序提供。 在描述符缓冲区中写入的不可变采样器,必须 与使用该采样器的描述符集布局中的不可变采样器具有相同的参数。
如果描述符集布局是使用 |
由于描述符现在位于常规内存中,因此驱动程序无法隐藏最终进入描述符集的不可变采样器的副本。 因此,要求应用程序提供这些采样器,就像它们不是不可变地提供的一样。 |
绑定描述符缓冲区
描述符缓冲区在命令缓冲区上具有自己独立的绑定点,使用 vkCmdBindDescriptorBuffersEXT 绑定缓冲区。 vkCmdSetDescriptorBufferOffsetsEXT 将缓冲区绑定索引和缓冲区偏移量对分配到与 vkCmdBindDescriptorSets 相同的命令缓冲区绑定点,允许后续的绑定的管道命令 使用指定的描述符缓冲区。 通过 vkCmdBindDescriptorSets 应用的绑定不能与通过调用 vkCmdSetDescriptorBufferOffsetsEXT 或 vkCmdBindDescriptorBufferEmbeddedSamplersEXT 应用的绑定同时存在,因为调用 vkCmdSetDescriptorBufferOffsetsEXT 或 vkCmdBindDescriptorBufferEmbeddedSamplersEXT 会使之前调用 vkCmdBindDescriptorSets 所做的任何绑定失效,反之亦然。
要将描述符缓冲区绑定到命令缓冲区,请调用
// Provided by VK_EXT_descriptor_buffer
void vkCmdBindDescriptorBuffersEXT(
VkCommandBuffer commandBuffer,
uint32_t bufferCount,
const VkDescriptorBufferBindingInfoEXT* pBindingInfos);
-
commandBuffer
是将要绑定描述符缓冲区的命令缓冲区。 -
bufferCount
是pBindingInfos
数组中的元素数量。 -
pBindingInfos
是指向 VkDescriptorBufferBindingInfoEXT 结构数组的指针。
vkCmdBindDescriptorBuffersEXT
会导致之前通过 vkCmdSetDescriptorBufferOffsetsEXT 设置的使用绑定编号 [0
.. bufferCount
-1] 的任何偏移量对于后续绑定的管道命令不再有效。 任何绑定点大于或等于 bufferCount
的先前绑定的缓冲区都会被解除绑定。
描述符缓冲区绑定的数据在 VkDescriptorBufferBindingInfoEXT
结构中传递
// Provided by VK_EXT_descriptor_buffer
typedef struct VkDescriptorBufferBindingInfoEXT {
VkStructureType sType;
const void* pNext;
VkDeviceAddress address;
VkBufferUsageFlags usage;
} VkDescriptorBufferBindingInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
address
是一个VkDeviceAddress
,指定要绑定的描述符缓冲区的设备地址。 -
usage
是一个 VkBufferUsageFlagBits 的位掩码,指定从中查询address
的缓冲区的 VkBufferCreateInfo::usage
。
如果 pNext
链包含 VkBufferUsageFlags2CreateInfo 结构,则使用该结构中的 VkBufferUsageFlags2CreateInfo::usage
,而不是此结构中的 usage
。
当 VkPhysicalDeviceDescriptorBufferPropertiesEXT
::bufferlessPushDescriptors
属性为 VK_FALSE
时,推送描述符的缓冲区的 VkBuffer
句柄在 VkDescriptorBufferBindingPushDescriptorBufferHandleEXT
结构中传递
// Provided by VK_EXT_descriptor_buffer
typedef struct VkDescriptorBufferBindingPushDescriptorBufferHandleEXT {
VkStructureType sType;
const void* pNext;
VkBuffer buffer;
} VkDescriptorBufferBindingPushDescriptorBufferHandleEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
buffer
是用于推送描述符的缓冲区的VkBuffer
句柄。
要在命令缓冲区中设置描述符缓冲区偏移量,请调用
// Provided by VK_EXT_descriptor_buffer
void vkCmdSetDescriptorBufferOffsetsEXT(
VkCommandBuffer commandBuffer,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t firstSet,
uint32_t setCount,
const uint32_t* pBufferIndices,
const VkDeviceSize* pOffsets);
-
commandBuffer
是将在其中设置描述符缓冲区偏移量的命令缓冲区。 -
pipelineBindPoint
是一个 VkPipelineBindPoint,指示将使用描述符的管道类型。 -
layout
是一个 VkPipelineLayout 对象,用于编程绑定。 -
firstSet
是要绑定的第一个集合的编号。 -
setCount
是pBufferIndices
和pOffsets
数组中的元素数量。 -
pBufferIndices
是一个指向索引数组的指针,该索引数组指向由 vkCmdBindDescriptorBuffersEXT 设置的描述符缓冲区绑定点。 -
pOffsets
是一个指向VkDeviceSize
偏移量数组的指针,该偏移量将应用于绑定的描述符缓冲区。
vkCmdSetDescriptorBufferOffsetsEXT
绑定 setCount
对描述符缓冲区,这些缓冲区由使用 vkCmdBindDescriptorBuffersEXT 绑定的绑定点索引指定,以及缓冲区偏移量,以设置后续 绑定管线命令 由 pipelineBindPoint
设置的集合编号 [firstSet
..firstSet
+descriptorSetCount
-1]。集合 [firstSet
+ i] 绑定到绑定 pBufferIndices
[i] 处,偏移量为 pOffsets
[i] 的描述符缓冲区。任何先前通过这些集合或调用 vkCmdBindDescriptorSets 应用的绑定都将失效。如果 layout
与用于绑定其他集合的管线布局不同,则在调用此命令时,其他集合也将失效,如 管线布局兼容性 中所述。
在绑定描述符之后,应用程序可以通过在主机上执行写入或使用设备命令来修改描述符内存。当使用设备命令更新描述符内存时,访问描述符的着色器阶段的可见性通过 VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT
访问标志来确保。除非着色器动态访问,否则实现必须不访问这些描述符引用的资源。如果着色器未动态访问,则使用此调用绑定的描述符可以是未定义的。
如果 layout
中的 binding
没有使用 VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
标志声明,则实现可以读取任何静态访问的描述符的描述符数据。如果 layout
中的 binding
使用 VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT
声明,则实现必须不读取未动态访问的描述符数据。
应用程序必须确保实现可以读取的任何描述符都在底层描述符缓冲区绑定的范围内。
应用程序可以自由决定可变描述符缓冲区绑定的大小,因此静态读取此类描述符有效负载可能不安全。这些规则的目的是允许实现尽可能推测性地预取描述符有效负载。 |
通过 稀疏部分驻留缓冲区的未绑定区域的描述符数据动态访问资源将导致读取无效的描述符数据,因此行为未定义。
对于主机写入的描述符,可见性通过队列提交时的自动可见性操作来隐含,无需考虑 |
上述要求意味着所有描述符绑定都已使用等效于 |
或者,要在命令缓冲区中设置描述符缓冲区偏移量,请调用
// Provided by VK_KHR_maintenance6 with VK_EXT_descriptor_buffer
void vkCmdSetDescriptorBufferOffsets2EXT(
VkCommandBuffer commandBuffer,
const VkSetDescriptorBufferOffsetsInfoEXT* pSetDescriptorBufferOffsetsInfo);
-
commandBuffer
是将在其中设置描述符缓冲区偏移量的命令缓冲区。 -
pSetDescriptorBufferOffsetsInfo
是指向VkSetDescriptorBufferOffsetsInfoEXT
结构的指针。
VkSetDescriptorBufferOffsetsInfoEXT
结构定义如下:
// Provided by VK_KHR_maintenance6 with VK_EXT_descriptor_buffer
typedef struct VkSetDescriptorBufferOffsetsInfoEXT {
VkStructureType sType;
const void* pNext;
VkShaderStageFlags stageFlags;
VkPipelineLayout layout;
uint32_t firstSet;
uint32_t setCount;
const uint32_t* pBufferIndices;
const VkDeviceSize* pOffsets;
} VkSetDescriptorBufferOffsetsInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
stageFlags
是 VkShaderStageFlagBits 的位掩码,指定描述符集将绑定到的着色器阶段。 -
layout
是用于编程绑定的 VkPipelineLayout 对象。如果启用了dynamicPipelineLayout
功能,则layout
可以是 VK_NULL_HANDLE,并且布局必须通过链接pNext
的 VkPipelineLayoutCreateInfo 结构来指定 -
firstSet
是要绑定的第一个集合的编号。 -
setCount
是pBufferIndices
和pOffsets
数组中的元素数量。 -
pBufferIndices
是一个指向索引数组的指针,该索引数组指向由 vkCmdBindDescriptorBuffersEXT 设置的描述符缓冲区绑定点。 -
pOffsets
是一个指向VkDeviceSize
偏移量数组的指针,该偏移量将应用于绑定的描述符缓冲区。
如果 stageFlags
指定一个或多个对应于管线绑定点的所有阶段的子集,则绑定操作仍然影响对应于给定管线绑定点的所有阶段,就好像使用相同的参数调用了此命令的等效原始版本一样。例如,指定一个 stageFlags
值为 VK_SHADER_STAGE_VERTEX_BIT
| VK_SHADER_STAGE_FRAGMENT_BIT
| VK_SHADER_STAGE_COMPUTE_BIT
等效于使用 VK_PIPELINE_BIND_POINT_GRAPHICS
调用原始版本的此命令一次,并使用 VK_PIPELINE_BIND_POINT_COMPUTE
调用一次。
要将嵌入式不可变采样器集绑定到命令缓冲区,请调用:
// Provided by VK_EXT_descriptor_buffer
void vkCmdBindDescriptorBufferEmbeddedSamplersEXT(
VkCommandBuffer commandBuffer,
VkPipelineBindPoint pipelineBindPoint,
VkPipelineLayout layout,
uint32_t set);
-
commandBuffer
是将绑定嵌入式不可变采样器的命令缓冲区。 -
pipelineBindPoint
是一个 VkPipelineBindPoint,指示将使用嵌入式不可变采样器的管线类型。 -
layout
是一个 VkPipelineLayout 对象,用于编程绑定。 -
set
是要绑定的集合的编号。
vkCmdBindDescriptorBufferEmbeddedSamplersEXT
将 layout
的 set
中的嵌入式不可变采样器绑定到命令缓冲区的 set
,以供随后由 pipelineBindPoint
设置的 绑定的管线命令使用。对该集合的任何先前绑定(通过 vkCmdSetDescriptorBufferOffsetsEXT 或此命令)都会被覆盖。调用此命令时,上次通过调用 vkCmdBindDescriptorSets 绑定的任何集合都将失效。如果 layout
与用于绑定其他集合的管线布局不同,如 管线布局兼容性中所述,则调用此命令时,其他集合也会失效。
或者,要将嵌入式不可变采样器集绑定到命令缓冲区,请调用:
// Provided by VK_KHR_maintenance6 with VK_EXT_descriptor_buffer
void vkCmdBindDescriptorBufferEmbeddedSamplers2EXT(
VkCommandBuffer commandBuffer,
const VkBindDescriptorBufferEmbeddedSamplersInfoEXT* pBindDescriptorBufferEmbeddedSamplersInfo);
-
commandBuffer
是将绑定嵌入式不可变采样器的命令缓冲区。 -
pBindDescriptorBufferEmbeddedSamplersInfo
是指向VkBindDescriptorBufferEmbeddedSamplersInfoEXT
结构的指针。
VkBindDescriptorBufferEmbeddedSamplersInfoEXT
结构的定义如下:
// Provided by VK_KHR_maintenance6 with VK_EXT_descriptor_buffer
typedef struct VkBindDescriptorBufferEmbeddedSamplersInfoEXT {
VkStructureType sType;
const void* pNext;
VkShaderStageFlags stageFlags;
VkPipelineLayout layout;
uint32_t set;
} VkBindDescriptorBufferEmbeddedSamplersInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
stageFlags
是 VkShaderStageFlagBits 的位掩码,指定将使用嵌入式不可变采样器的着色器阶段。 -
layout
是用于编程绑定的 VkPipelineLayout 对象。如果启用了dynamicPipelineLayout
功能,则layout
可以是 VK_NULL_HANDLE,并且布局必须通过链接pNext
的 VkPipelineLayoutCreateInfo 结构来指定 -
set
是要绑定的集合的编号。
如果 stageFlags
指定一个或多个对应于管线绑定点的所有阶段的子集,则绑定操作仍然影响对应于给定管线绑定点的所有阶段,就好像使用相同的参数调用了此命令的等效原始版本一样。例如,指定一个 stageFlags
值为 VK_SHADER_STAGE_VERTEX_BIT
| VK_SHADER_STAGE_FRAGMENT_BIT
| VK_SHADER_STAGE_COMPUTE_BIT
等效于使用 VK_PIPELINE_BIND_POINT_GRAPHICS
调用原始版本的此命令一次,并使用 VK_PIPELINE_BIND_POINT_COMPUTE
调用一次。
更新描述符缓冲区
可以通过主机或设备上任何可以访问内存的操作来执行缓冲区中描述符数据的更新。
可以使用相关着色器阶段中的 VK_ACCESS_2_DESCRIPTOR_BUFFER_READ_BIT_EXT
来同步描述符缓冲区读取。
使用描述符缓冲区的推送描述符
如果启用了 descriptorBufferPushDescriptors
功能,则可以将推送描述符与描述符缓冲区一起使用,方式与使用描述符集相同。
VkPhysicalDeviceDescriptorBufferPropertiesEXT
::bufferlessPushDescriptors
属性指示实现是否需要缓冲区来支持推送描述符。如果该属性为 VK_FALSE
,则在记录任何推送描述符之前,应用程序必须绑定恰好 1
个使用 VK_BUFFER_USAGE_PUSH_DESCRIPTORS_DESCRIPTOR_BUFFER_BIT_EXT
位设置创建的描述符缓冲区。当绑定此缓冲区时,必须再次记录后续命令所需的任何先前记录的推送描述符。
捕获和重放
与 bufferDeviceAddressCaptureReplay
类似,descriptorBufferCaptureReplay
功能允许在捕获时为对象创建不透明句柄,这些句柄可以在将来的重放中传递到对象创建调用中,从而使描述符使用相同的数据创建。这些资源使用的任何内存的不透明内存地址必须已使用 vkGetDeviceMemoryOpaqueCaptureAddress 捕获,并使用 VkMemoryOpaqueCaptureAddressAllocateInfo 重放。
要获取缓冲区的不透明描述符数据,请调用:
// Provided by VK_EXT_descriptor_buffer
VkResult vkGetBufferOpaqueCaptureDescriptorDataEXT(
VkDevice device,
const VkBufferCaptureDescriptorDataInfoEXT* pInfo,
void* pData);
-
device
是获取数据的逻辑设备。 -
pInfo
是指向 VkBufferCaptureDescriptorDataInfoEXT 结构的指针,该结构指定缓冲区。 -
pData
是指向应用程序分配的缓冲区的指针,数据将写入到该缓冲区。
用于获取描述符缓冲区捕获数据的缓冲区的相关信息在 VkBufferCaptureDescriptorDataInfoEXT
结构中传递。
// Provided by VK_EXT_descriptor_buffer
typedef struct VkBufferCaptureDescriptorDataInfoEXT {
VkStructureType sType;
const void* pNext;
VkBuffer buffer;
} VkBufferCaptureDescriptorDataInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
buffer
是用于获取不透明捕获数据的缓冲区的VkBuffer
句柄。
要获取图像的不透明捕获描述符数据,请调用:
// Provided by VK_EXT_descriptor_buffer
VkResult vkGetImageOpaqueCaptureDescriptorDataEXT(
VkDevice device,
const VkImageCaptureDescriptorDataInfoEXT* pInfo,
void* pData);
-
device
是获取数据的逻辑设备。 -
pInfo
是指向 VkImageCaptureDescriptorDataInfoEXT 结构的指针,该结构指定图像。 -
pData
是指向应用程序分配的缓冲区的指针,数据将写入到该缓冲区。
要获取描述符缓冲区捕获数据的图像信息在 VkImageCaptureDescriptorDataInfoEXT
结构中传递
// Provided by VK_EXT_descriptor_buffer
typedef struct VkImageCaptureDescriptorDataInfoEXT {
VkStructureType sType;
const void* pNext;
VkImage image;
} VkImageCaptureDescriptorDataInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
image
是要获取不透明捕获数据的图像的VkImage
句柄。
要获取图像视图的不透明捕获描述符数据,请调用
// Provided by VK_EXT_descriptor_buffer
VkResult vkGetImageViewOpaqueCaptureDescriptorDataEXT(
VkDevice device,
const VkImageViewCaptureDescriptorDataInfoEXT* pInfo,
void* pData);
-
device
是获取数据的逻辑设备。 -
pInfo
是指向 VkImageViewCaptureDescriptorDataInfoEXT 结构的指针,该结构指定图像视图。 -
pData
是指向应用程序分配的缓冲区的指针,数据将写入到该缓冲区。
要获取描述符缓冲区捕获数据的图像视图信息在 VkImageViewCaptureDescriptorDataInfoEXT
结构中传递
// Provided by VK_EXT_descriptor_buffer
typedef struct VkImageViewCaptureDescriptorDataInfoEXT {
VkStructureType sType;
const void* pNext;
VkImageView imageView;
} VkImageViewCaptureDescriptorDataInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
imageView
是要获取不透明捕获数据的图像视图的VkImageView
句柄。
要获取采样器的不透明捕获描述符数据,请调用
// Provided by VK_EXT_descriptor_buffer
VkResult vkGetSamplerOpaqueCaptureDescriptorDataEXT(
VkDevice device,
const VkSamplerCaptureDescriptorDataInfoEXT* pInfo,
void* pData);
-
device
是获取数据的逻辑设备。 -
pInfo
是指向 VkSamplerCaptureDescriptorDataInfoEXT 结构的指针,该结构指定采样器。 -
pData
是指向应用程序分配的缓冲区的指针,数据将写入到该缓冲区。
要获取描述符缓冲区捕获数据的采样器信息在 VkSamplerCaptureDescriptorDataInfoEXT
结构中传递
// Provided by VK_EXT_descriptor_buffer
typedef struct VkSamplerCaptureDescriptorDataInfoEXT {
VkStructureType sType;
const void* pNext;
VkSampler sampler;
} VkSamplerCaptureDescriptorDataInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
sampler
是要获取不透明捕获数据的采样器的VkSampler
句柄。
要获取加速结构的不透明捕获描述符数据,请调用
// Provided by VK_EXT_descriptor_buffer with VK_KHR_acceleration_structure or VK_NV_ray_tracing
VkResult vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT(
VkDevice device,
const VkAccelerationStructureCaptureDescriptorDataInfoEXT* pInfo,
void* pData);
-
device
是获取数据的逻辑设备。 -
pInfo
是指向 VkAccelerationStructureCaptureDescriptorDataInfoEXT 结构的指针,该结构指定加速结构。 -
pData
是指向应用程序分配的缓冲区的指针,数据将写入到该缓冲区。
要获取描述符缓冲区捕获数据的加速结构信息,需要通过 VkAccelerationStructureCaptureDescriptorDataInfoEXT
结构传递
// Provided by VK_EXT_descriptor_buffer with VK_KHR_acceleration_structure or VK_NV_ray_tracing
typedef struct VkAccelerationStructureCaptureDescriptorDataInfoEXT {
VkStructureType sType;
const void* pNext;
VkAccelerationStructureKHR accelerationStructure;
VkAccelerationStructureNV accelerationStructureNV;
} VkAccelerationStructureCaptureDescriptorDataInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
accelerationStructure
是要获取不透明捕获数据的加速结构的VkAccelerationStructureKHR
句柄。 -
accelerationStructureNV
是要获取不透明捕获数据的加速结构的VkAccelerationStructureNV
句柄。
VkOpaqueCaptureDescriptorDataCreateInfoEXT
结构定义如下:
// Provided by VK_EXT_descriptor_buffer
typedef struct VkOpaqueCaptureDescriptorDataCreateInfoEXT {
VkStructureType sType;
const void* pNext;
const void* opaqueCaptureDescriptorData;
} VkOpaqueCaptureDescriptorDataCreateInfoEXT;
-
sType
是一个 VkStructureType 值,用于标识此结构。 -
pNext
是NULL
或指向扩展此结构的结构的指针。 -
opaqueCaptureDescriptorData
是指向应用程序分配的缓冲区的指针,该缓冲区包含使用 vkGetBufferOpaqueCaptureDescriptorDataEXT、vkGetImageOpaqueCaptureDescriptorDataEXT、vkGetImageViewOpaqueCaptureDescriptorDataEXT、vkGetSamplerOpaqueCaptureDescriptorDataEXT 或 vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT 检索到的不透明捕获数据。
在重放期间,可以通过将 VkOpaqueCaptureDescriptorDataCreateInfoEXT
结构添加到 VkBufferCreateInfo、VkImageCreateInfo、VkImageViewCreateInfo、VkSamplerCreateInfo、VkAccelerationStructureCreateInfoNV 或 VkAccelerationStructureCreateInfoKHR 结构的相关 pNext
链中,来指定不透明的描述符捕获数据。