【发布时间】:2019-04-17 19:45:22
【问题描述】:
所以我想在 Vulkan 中渲染两个独立的网格。我正在涉足纹理,第一个网格使用 4 个,而第二个使用 5 个。我正在做索引绘制。
为简单起见,每个网格都有自己的统一缓冲区和采样器数组,它们被打包到单独的描述符集中,每个描述符集都有一个用于 UBO 的绑定和另一个用于采样器的绑定。以下代码针对每个网格运行,其中descriptorSet 是与单个网格关联的描述符集。 filepaths 是特定网格使用的图像路径向量。
std::vector<VkWriteDescriptorSet> descriptorWrites;
descriptorWrites.resize(2);
VkDescriptorBufferInfo bufferInfo = {};
bufferInfo.buffer = buffers[i];
bufferInfo.offset = 0;
bufferInfo.range = sizeof(UniformBufferObject);
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[0].dstSet = descriptorSet;
descriptorWrites[0].dstBinding = 0;
descriptorWrites[0].dstArrayElement = 0;
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC;
descriptorWrites[0].descriptorCount = 1;
descriptorWrites[0].pBufferInfo = &bufferInfo;
std::vector<VkDescriptorImageInfo> imageInfos;
imageInfos.resize(filepaths.size());
for (size_t j = 0; j < filepaths.size(); j++) {
imageInfos[j].imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageInfos[j].imageView = imageViews[j];
imageInfos[j].sampler = samplers[j];
}
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrites[1].dstSet = descriptorSet;
descriptorWrites[1].dstBinding = 1;
descriptorWrites[1].dstArrayElement = 0;
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
descriptorWrites[1].descriptorCount = imageInfos.size();
descriptorWrites[1].pImageInfo = imageInfos.data();
vkUpdateDescriptorSets(devicesHandler->device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr);
所以为了告诉 Vulkan 这些描述符集是如何布局的,我当然需要两个描述符集布局,即每个网格一个,由于filepaths 的大小不同,它们的采样器绑定不同:
// <Stuff for binding 0 for UBO here>
// ...
VkDescriptorSetLayoutBinding layoutBinding = {};
layoutBinding.binding = 1;
layoutBinding.descriptorCount = filepaths.size();
layoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
layoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
现在,当我创建管道时,我需要提供管道布局。我这样做如下,其中layouts 是填充到向量中的网格的描述符集布局。:
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = layouts.size();
pipelineLayoutInfo.pSetLayouts = layouts.data();
最后在渲染之前我绑定了合适的描述符集。
我天真地认为定义管道布局的方式是可行的(只需获取所有涉及的布局并将它们传递给pSetLayouts),但它不起作用。我得到的错误是:
descriptorSet #0 being bound is not compatible with overlapping descriptorSetLayout at index 0 of pipelineLayout 0x6e due to: DescriptorSetLayout 87 has 5 descriptors, but DescriptorSetLayout 88, which comes from pipelineLayout, has 6 descriptors.. The Vulkan spec states: Each element of pDescriptorSets must have been allocated with a VKDescriptorSetLayout that matches (is the same as, or identically defined as) the VkDescriptorSetLayout at set n in layout, where n is the sum of firstSet and the index into pDescriptorSets.
我还注意到,如果我将第二个网格中使用的纹理数量从 5 个减少到 4 个,以便它们与第一个网格中的 4 个匹配,那么它就可以工作。所以我想知道是否需要为布局的每个可能配置创建一个管道?也就是说,一条管道setLayoutCount设置为4,另一条设置为5,当我要绘制一个网格或另一个时绑定相应的?那是愚蠢的吗?我错过了什么吗?
值得注意的是,如果我单独渲染每个网格,一切都会顺利进行。当我把它们都放在场景中时,问题就出现了。
另外,我知道缓冲区应该连续分配并考虑对齐情况,而且我在那里做的事情是一种不好的做法 - 但我还没有处理这个问题。
【问题讨论】:
-
请不要将文字作为图片发布。引用的代码块使用大于后跟 6 个空格。