Vulkan 的描述符集布局和 `VkWriteDescriptorInfo` 有什么区别?

What's the difference between Vulkan's descriptor set layouts and `VkWriteDescriptorInfo`?

我正在关注 Vulkan tutorial about uniform buffers,但我很困惑为什么我们需要提供描述符集布局,其中它们提供的所有信息似乎已经在 VkWriteDescriptorSet 结构中并通过进入函数 vkUpdateDescriptorSets.

为什么 Vulkan 需要这两种信息,而不仅仅是我们通过 vkUpdateDescriptorSets 提供的信息?

来自tutorial's code

            VkWriteDescriptorSet descriptorWrite{};
            descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
            descriptorWrite.dstSet = descriptorSets[i];
            descriptorWrite.dstBinding = 0;
            descriptorWrite.dstArrayElement = 0;
            descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
            descriptorWrite.descriptorCount = 1;
            descriptorWrite.pBufferInfo = &bufferInfo;
    void createDescriptorSetLayout() {
        VkDescriptorSetLayoutBinding uboLayoutBinding{};
        uboLayoutBinding.binding = 0;
        uboLayoutBinding.descriptorCount = 1;
        uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
        uboLayoutBinding.pImmutableSamplers = nullptr;
        uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;

        VkDescriptorSetLayoutCreateInfo layoutInfo{};
        layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
        layoutInfo.bindingCount = 1;
        layoutInfo.pBindings = &uboLayoutBinding;

        if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) {
            throw std::runtime_error("failed to create descriptor set layout!");
        }
    }

在写入描述符集之前需要一个描述符集布局,原因与在 实例化 之前需要 class 相同。在定义 A 是什么之前,您不能对某些类型 A 执行 A a;VkWriteDescriptorSet 就像做 a.x = whatever;在您知道 a 是什么之前,它没有任何意义,这需要为 A.

定义 class

描述符集布局定义了描述符集的外观。它指定了所有的东西。 vkAllocateDescriptorSets 是创建描述符集布局实例的方式(在我们的类比中,它是 A a;,集合是 a)。 VkWriteDescriptorSet 是您提供进入描述符集的 数据 的方式(在我们的类比中,它就像 a.x = whatever;,仅可能用于多个成员)。

VkWriteDescrptorSet 有很多数据在描述符集合布局中冗余指定,因此实现不必 存储 集合布局作为原始数据。

假设描述符集中的绑定 2 是长度为 X 的 UBO。并且您想攻击该 UBO 描述符的缓冲区范围。为此,实现可能需要知道它是一个 UBO 描述符及其长度。如果它确实需要知道,那么它还需要将该信息存储在描述符集中。

这会强制实现存储仅对写入描述符有用的额外数据。如果该描述符仅设置一次且永远不会再次设置或不经常修改(描述符通常如此),则实现必须无缘无故地保留一堆信息。

所以 Vulkan 让 决定是否保留信息。