在 renderPass 中更新 VkDescriptorSet

hid*_*yat 6 c++ graphics vulkan

假设我想用不同的材料渲染多个网格。我知道我可以push constants在这个例子中使用,但这个问题更多地是为了理解 vkDescriptorset 是如何工作的。

struct Material {
    vec4 color;
    vkDescriptorset descriptorSet;
    VkDescriptorBufferInfo descriptorBufferInfo;
};
Run Code Online (Sandbox Code Playgroud)

我只叫vkUpdateDescriptorSets_descriptorBufferInfo对数据的缓冲区创建后。一切正常。

我测试了另一个解决方案。我不是vkDescriptorset每种材料都有一个,而是所有材料都只有一个。而里面的rendepassI call vkUpdateDescriptorSetsfor each of the material VkDescriptorBufferInfo

vkDescriptorset globalDescriptorSet;
struct Material {
  vec4 color;
  VkDescriptorBufferInfo descriptorBufferInfo;
};

beginCommandBuffer
beginRenderPass
for (auto &mesh : meshes) {
    ...
    writeDescriptorSets.dstSet = globalDescriptorSet;
    writeDescriptorSets.pBufferInfo = &mesh.material.descriptorBufferInfo;
    ....
    vkUpdateDescriptorSets(device, 1, &writeDescriptorSets, 0, nullptr);
    renderMesh(mesh);
}
endRenderPass
endCommandBuffer
Run Code Online (Sandbox Code Playgroud)

但是当我这样做时,它不起作用。验证层表示您必须beginCommandBuffer在为我渲染的第二个网格调用任何命令vkCmdBindDescriptorSetsvkCmdBindPipeline等之前调用。

那么这里的问题是什么,我不能在多个 VkDescriptorBufferInfo 之间共享一个 vkDescriptorset,或者我不能在 renderPass 内更新它吗?

Nic*_*las 5

来自 Vulkan 规范:

通过调用 vkCmdBindDescriptorSets 绑定的描述符集内容可能会在命令的主机执行期间、结果绘制的着色器执行期间或两者之间的任何时间被消耗。因此,在记录命令和命令在队列上完成执行之间,内容不得更改(被更新命令覆盖或释放)。

(强调)

据推测,您的renderMesh调用将描述符集绑定到命令缓冲区。从那一刻起,在该命令缓冲区中的命令完成(或 CB 被破坏)之前,您不得以任何方式修改该描述符集。

这就是动态统一/存储缓冲区存在的原因。它们允许您更改统一/存储缓冲区的基本偏移量,而不会被视为对实际描述符集的修改。因此,您可以在具有不同缓冲区偏移量的多个位置使用相同的描述符集。