在 renderPass 中更新 VkDescriptorSet

Update an VkDescriptorSet inside a renderPass

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

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

我只在创建数据缓冲区后为 _descriptorBufferInfo 调用 vkUpdateDescriptorSets。一切正常。

我测试了另一种解决方案。我不是每个 material 一个 vkDescriptorset,而是每个人只有一个。在 rendepass 中,我为每个 material VkDescriptorBufferInfo.

调用 vkUpdateDescriptorSets
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

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

那么这里有什么问题,我可以不在多个VkDescriptorBufferInfo之间共享一个vkDescriptorset吗,或者我可以不在renderPass中更新它吗?

来自 Vulkan 规范:

The descriptor set contents bound by a call to vkCmdBindDescriptorSets may be consumed during host execution of the command, or during shader execution of the resulting draws, or any time in between. Thus, the contents must not be altered (overwritten by an update command, or freed) between when the command is recorded and when the command completes executing on the queue.

(强调)

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

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