Vulkan 的描述符集布局和 `VkWriteDescriptorInfo` 有什么区别?
What's the difference between Vulkan's descriptor set layouts and `VkWriteDescriptorInfo`?
我正在关注 Vulkan tutorial about uniform buffers,但我很困惑为什么我们需要提供描述符集布局,其中它们提供的所有信息似乎已经在 VkWriteDescriptorSet
结构中并通过进入函数 vkUpdateDescriptorSets
.
为什么 Vulkan 需要这两种信息,而不仅仅是我们通过 vkUpdateDescriptorSets
提供的信息?
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 让 你 决定是否保留信息。
我正在关注 Vulkan tutorial about uniform buffers,但我很困惑为什么我们需要提供描述符集布局,其中它们提供的所有信息似乎已经在 VkWriteDescriptorSet
结构中并通过进入函数 vkUpdateDescriptorSets
.
为什么 Vulkan 需要这两种信息,而不仅仅是我们通过 vkUpdateDescriptorSets
提供的信息?
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
.
描述符集布局定义了描述符集的外观。它指定了所有的东西。 vkAllocateDescriptorSets
是创建描述符集布局实例的方式(在我们的类比中,它是 A a;
,集合是 a
)。 VkWriteDescriptorSet
是您提供进入描述符集的 数据 的方式(在我们的类比中,它就像 a.x = whatever;
,仅可能用于多个成员)。
VkWriteDescrptorSet
有很多数据在描述符集合布局中冗余指定,因此实现不必 存储 集合布局作为原始数据。
假设描述符集中的绑定 2 是长度为 X 的 UBO。并且您想攻击该 UBO 描述符的缓冲区范围。为此,实现可能需要知道它是一个 UBO 描述符及其长度。如果它确实需要知道,那么它还需要将该信息存储在描述符集中。
这会强制实现存储仅对写入描述符有用的额外数据。如果该描述符仅设置一次且永远不会再次设置或不经常修改(描述符通常如此),则实现必须无缘无故地保留一堆信息。
所以 Vulkan 让 你 决定是否保留信息。