跳到主要内容

描述符动态偏移

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
);

缓冲区如下所示:

descriptor_dynamic_offset_example_a.png

接下来,在绑定时使用 8 字节的动态偏移量:

uint32_t offsets[1] = { 8 };
vkCmdBindDescriptorSets(
1, // descriptorSetCount,
&descriptorSet, // pDescriptorSets,
1, // dynamicOffsetCount
offsets // pDynamicOffsets
);

缓冲区变成:

descriptor_dynamic_offset_example_b.png

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
);

缓冲区如下所示:

descriptor_dynamic_offset_example_c.png

如果尝试使用动态偏移,将遇到未定义的行为,并且验证层会有报错信息

// Invalid
uint32_t offsets[1] = { 8 };
vkCmdBindDescriptorSets(
1, // descriptorSetCount,
&descriptorSet, // pDescriptorSets,
1, // dynamicOffsetCount
offsets // pDynamicOffsets
);

这是无效的动态偏移量:

descriptor_dynamic_offset_example_d.png

限制

检查minUniformBufferOffsetAlignmentminStorageBufferOffsetAlignment也很重要,因为 base offsetdynamic offset 都必须是这些限制的倍数。