vulkan杂记-描述符池和描述符集
上一章我们介绍了用于描述可以绑定的描述符类型的描述符布局。
在这一章节,我们为每一个 vkBuffer 创建描述符集,将其和 uniform 缓冲
描述符进行绑定。
描述符池
描述符集不能被直接创建,需要通过描述符池来分配。我们添加一个
叫做 createDescriptorPool 的函数来进行描述符池的创建:描述符集不能被
直接创建,需要通过描述符池来分配。
我们通过 VkDescriptorPoolSize 结构体来对描述符池可以分配的描述
符集进行定义:
VkDescriptorPoolSize poolSize = {};
p o o l S i z e . type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
p o o l S i z e . d e s c r i p t o r C o u n t = s t a t i c _ c a s t <uint32_t >(
swapChainImages . s i z e ( ) ) ;
我们会在每一帧分配一个描述符。描述符池的大小需要通过 VkDe-
scriptorPoolCreateInfo 结构体定义:
VkDescriptorPoolCreateInfo poolInfo = {};
p o o l I n f o . sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
p o o l I n f o . poolSizeCount = 1 ;
p o o l I n f o . p P o o l S i z e s = &p o o l S i z e ;
除了可用的最大独立描述符个数外,我们还需要指定可以分配的最大
描述符集个数:
p o o l I n f o . maxSets = s t a t i c _ c a s t <uint32_t >(swapChainImages . s i z e ( )
);
VkDescriptorPoolCreateInfo 结构体有一个用于优化的标记,它决定了
独立的描述符集是否可以被清除掉:VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_S
由于我们在描述符集创建后,就不再对其进行操作,所以我们不需要使用
这一标记,将其设置为 0 来使用它的默认值。
描述符集
有了描述符池,现在我们可以开始创建描述符集对象了。添加一个叫
做 createDescriptorSets 的函数来完成描述符集对象的创建:
描述符集的创建需要我们填写 VkDescriptorSetAllocateInfo 结构体。
我们需要指定分配描述符集对象的描述符池,需要分配的描述符集数量,
以及它们使用的描述符布局:
s t d : : v e c t o r <VkDescriptorSetLayout>
l a y o u t s ( swapChainImages . s i z e ( ) , d e s c r i p t o r S e t L a y o u t ) ;
VkDescriptorSetAllocateInfo a l l o c I n f o = {};
a l l o c I n f o . sType =
allocInfo . descriptorPool = descriptorPool ;
a l l o c I n f o . d e s c r i p t o r S e t C o u n t = s t a t i c _ c a s t <uint32_t >(
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
swapChainImages . s i z e ( ) ) ;
a l l o c I n f o . pSetLayouts = l a y o u t s . data ( ) ;
在这里,我们为每一个交换链图像使用相同的描述符布局创建对应的
描述符集。
但由于描述符布局对象个数要匹配描述符集对象个数,所以,
我们还是需要使用多个相同的描述符布局对象。
添加类成员变量来存储使用 vkAllocateDescriptorSets 函数创建的描述
符集对象:
s t d : : v e c t o r <VkDescriptorSet> d e s c r i p t o r S e t s ;
描述符集对象会在描述符池对象清除时自动被清除,所以不需要我们
自己显式地清除描述符对象。
vkAllocateDescriptorSets 函数分配地描述符
集对象,每一个都带有一个 uniform 缓冲描述符。
描述符集对象创建后,还需要进行一定地配置。我们使用循环来遍历
描述符集对象,对它进行配置:
f o r ( s i z e _ t i = 0 ; i < swapChainImages . s i z e ( ) ; i ++) {
}
我们通过 VkDescriptorBufferInfo 结构体来配置描述符引用的缓冲对
象。VkDescriptorBufferInfo 结构体可以指定缓冲对象和可以访问的数据范
围:
f o r ( s i z e _ t i = 0 ; i < swapChainImages . s i z e ( ) ; i ++) {
VkDescriptorBufferInfo bufferInfo = {};
bufferInfo . buffer = uniformBuffers [ i ] ;
bufferInfo . offset = 0;
b u f f e r I n f o . range = s i z e o f ( UniformBufferObject ) ;
}
如 果 需 要 使 用 整 个 缓 冲, 可 以 将 range 成 员 变 量 的 值 设 置
为 VK_WHOLE_SIZE。
更新描述符的配置可以使用 vkUpdateDescrip-
torSets 函数进行,它以 VkWriteDescriptorSet 结构体数组作为参数:
VkWriteDescriptorSet d e s c r i p t o r W r i t e = { } ;
d e s c r i p t o r W r i t e . sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite . dstSet = descriptorSets [ i ] ;
d e s c r i p t o r W r i t e . dstBind in g = 0 ;
d e s c r i p t o r W r i t e . dstArrayElement = 0 ;
dstSet 和 dstBinding 成员变量用于指定要更新的描述符集对象以及缓
冲绑定。在这里,我们将 uniform 缓冲绑定到索引 0。
需要注意描述符可
以是数组,所以我们还需要指定数组的第一个元素的索引,在这里,我们
没有使用数组作为描述符,将索引指定为 0 即可。
descriptorWrite . descriptorType =
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
descriptorWrite . descriptorCount = 1;
可以通过设置 dstArrayElement 和
descriptorCount 成员变量一次更新多个描述符。
d e s c r i p t o r W r i t e . p B u f f e r I n f o = &b u f f e r I n f o ;
d e s c r i p t o r W r i t e . pImageInfo = n u l l p t r ; // Optional
d e s c r i p t o r W r i t e . pTexelBufferView = n u l l p t r ; // Optiona
pBufferInfo 成员变量用于指定描述符引用的缓冲数据。pImageInfo 成
员变量用于指定描述符引用的图像数据。pTexelBufferView 成员变量用于
指定描述符引用的缓冲视图。
这里,我们的描述符是用来访问缓冲的,所
以我们只使用 pBufferInfo 成员变量。
vkUpdateDescriptorSets 函数可以接受两个数组作为参数:VkWrit-
eDescriptorSet 结构体数组和 VkCopyDescriptorSet 结构体数组。后者被用
来复制描述符对象。
使用描述符集
现在修改 createCommandBuffers 函数为每个交换链图像绑定对应的
描述符集。这需要调用 cmdBindDescriptorSets 函数来完成,我们在调用
vkCmdDrawIndexed 函数之前调用这一函数:
vkCmdBindDescriptorSets ( commandBuffers [ i ] ,
VK_PIPELINE_BIND_POINT_GRAPHICS, p i p e l i n e L a y o u t , 0 , 1 , &
descriptorSets [ i ] , 0 , nullptr ) ;
vkCmdDrawIndexed ( commandBuffers [ i ] , s t a t i c _ c a s t <uint32_t >(
i n d i c e s . s i z e ( ) ) , 1 , 0 , 0 , 0) ;
和顶点缓冲、索引缓冲不同,描述符集并不是图形管线所独有的,所
以需要我们指定我们要绑定的是图形管线还是计算管线。
管线类型之后的参数是描述符所使用的布局。
接着三个参数用于指定描述符集的第一个元
素索引,需要绑定的描述符集个数,以及用于绑定的描述符集数组。
最后两个参数用于指定动态描述符的数组偏移。
更多推荐
所有评论(0)