Вулкан - когда мне создавать новый трубопровод? - PullRequest
0 голосов
/ 14 ноября 2018

Итак, я хочу сделать две независимые сетки в 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, и связать соответствующий, когда я собираюсь нарисовать одну сетку или другую?Это глупо?Я что-то упустил?

Стоит отметить, что если я рендерил каждую сетку в одиночку, все работает гладко.Проблема возникает, когда я помещаю их обоих в сцену.

Кроме того, я знаю, что буферы должны распределяться последовательно и с учетом выравнивания, и что то, что я делаю, это плохая практика - но я простопока не имею дело с этим.

1 Ответ

0 голосов
/ 16 ноября 2018

Передача нескольких компоновок наборов в конвейер означает, что вы хотите, чтобы конвейер имел возможность одновременно обращаться ко всем привязкам в обоих наборах, например, шейдеры имеют доступ к двум UBO в (set = 0, binding = 0) и (set= 1, привязка = 0), четыре текстуры в (набор = 0, привязка = 1) и пять текстур в качестве (набор = 1, привязка = 1).

Затем, когда вы связываете набор для второгоСетка как единственный набор, вы получаете несовместимость, потому что она имеет разную компоновку (5 текстур), чем конвейер ожидает для набора 0 (4 текстуры).

Так что да, когда у вас есть разные макеты дескрипторов, вынужны разные трубопроводы.Если вы используете конвейерный кеш, большая часть компиляции может фактически использоваться повторно между двумя конвейерами.

Если вы пытаетесь использовать один и тот же конвейер для обеих сеток, то, вероятно, код в вашем шейдере, который обращается кпятая текстура условная, на основе униформы что ли?Альтернативой является привязка фиктивной текстуры при рисовании сетки с 4 текстурами;поскольку к нему не будет никакого доступа, не имеет значения, какое у него содержимое, это может быть 1x1 и т. д. Затем вы можете использовать одинаковую компоновку набора из 5 текстур и один и тот же конвейер для обеих сеток.

...