描述符动态偏移
Vulkan 提供了两种类型的描述符,可以在绑定时调整偏移量,参阅:Vulkan Spec详细内容。
- 动态统一缓冲区 (
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
) - 动态存储缓冲区 (
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC
)
示例
此例有一个 32 字节的缓冲区,其中 16 个字节将在vkUpdateDescriptorSets
时设置,这时我们还没有添加任何动态偏移:
VkDescriptorSet descriptorSet; // allocated
VkBuffer buffer; // size of 32 bytes
VkDescriptorBufferInfo bufferInfo = {
buffer,
4, // offset
16 // range
};
VkWriteDescriptorSet writeInfo = {
.dstSet = descriptorSet,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
.pBufferInfo = bufferInfo
};
vkUpdateDescriptorSets(
1, // descriptorWriteCount,
&writeInfo // pDescriptorWrites,
);
// No dynamic offset
vkCmdBindDescriptorSets(
1, // descriptorSetCount,
&descriptorSet, // pDescriptorSets,
0, // dynamicOffsetCount
NULL // pDynamicOffsets
);
缓冲区如下所示:
接下来,在绑定时使用 8 字节的动态偏移量:
uint32_t offsets[1] = { 8 };
vkCmdBindDescriptorSets(
1, // descriptorSetCount,
&descriptorSet, // pDescriptorSets,
1, // dynamicOffsetCount
offsets // pDynamicOffsets
);
缓冲区变成:
VK_WHOLE_SIZE 示例
此例使用VK_WHOLE_SIZE
作为范围,除了VkDescriptorBufferInfo::range
,代码与上面的示例相同:
VkDescriptorSet descriptorSet; // allocated
VkBuffer buffer; // size of 32 bytes
VkDescriptorBufferInfo info = {
buffer,
4, // offset
VK_WHOLE_SIZE // range
};
VkWriteDescriptorSet writeInfo = {
.dstSet = descriptorSet,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC,
.pBufferInfo = bufferInfo
};
vkUpdateDescriptorSets(
1, // descriptorWriteCount,
&writeInfo // pDescriptorWrites,
);
// No dynamic offset
vkCmdBindDescriptorSets(
1, // descriptorSetCount,
&descriptorSet, // pDescriptorSets,
0, // dynamicOffsetCount
NULL // pDynamicOffsets
);
缓冲区如下所示:
如果尝试使用动态偏移,将遇到未定义的行为,并且验证层会有报错信息
// Invalid
uint32_t offsets[1] = { 8 };
vkCmdBindDescriptorSets(
1, // descriptorSetCount,
&descriptorSet, // pDescriptorSets,
1, // dynamicOffsetCount
offsets // pDynamicOffsets
);
这是无效的动态偏移量:
限制
检查minUniformBufferOffsetAlignment
和minStorageBufferOffsetAlignment
也很重要,因为 base offset
和 dynamic offset
都必须是这些限制的倍数。