Синхронизация командных буферов в Vulkan

Существует несколько способов обработки синхронизации в Vulkan. Вот как я это понимаю:

  • Заборы - это GPU для синхронизации процессора.
  • Семафоры - это графические процессоры GPU, они используются для синхронизации очереди (в тех же или разных очередях).
  • События более общие, reset и отмечены как на CPU, так и на GPU.
  • Барьеры используются для синхронизации внутри командного буфера.

В моем случае у меня есть два командных буфера. И я хочу, чтобы второй буфер команды выполнялся после первого.

submitInfo.pCommandBuffers = &firstCommandBuffer;
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);

// wait for first command buffer to finish
submitInfo.pCommandBuffers = &secondCommandBuffer;
vkQueueSubmit(queue, 1, &submitInfo, VK_NULL_HANDLE);

Какая синхронизация лучше всего подходит для этого? Если я использую vkQueueWaitIdle(queue)),, это то же самое, что использовать забор, или я должен использовать для этого события или семафоры?

Если я посылаю несколько командных буферов в очередь в одно и то же время:

std::vector<VkCommandBuffer> submitCmdBuffers = {
        firstCommandBuffer,
        secondCommandBuffer
    };
    submitInfo.commandBufferCount = submitCmdBuffers.size();
    submitInfo.pCommandBuffers = submitCmdBuffers.data();

Есть ли способ синхронизации между первым и вторым?

Ответы

Ответ 1

Первый командный буфер - это объект рендеринга с включенным тестом на глубину. Второй командный буфер - это рендеринг контуров сеток с выключенным тестом глубины. Потому что он должен быть поверх других объектов.

В этом случае то, что вам нужно, зависит от того, что эти буферы команд.

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

Поскольку раздел 2.2.1 Заказ API защищает вас. Глубокое тестирование и запись глубины в экземпляре render-pass всегда будут выполняться в порядке API. Поэтому более поздние команды, будь то в одном CB или другом, будут упорядочены в отношении тестирования/записи глубины.

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

В этом случае маска сцены для команды vkCmdSetEvent должна быть этапом, записывающим значение глубины. Это может быть EARLY_FRAGMENT_TESTS_BIT или LATE_FRAGMENT_TESTS_BIT. Чтобы быть в безопасности, используйте оба варианта. Однако, поскольку вы, вероятно, обновляете один и тот же колоритный буфер, вам также нужен этап COLOR_ATTACHMENT_OUTPUT_BIT. Вставьте эту команду в конец первого командного буфера (или после завершения записи глубины).

Для vkCmdWaitEvent вы хотите подождать на этапах конвейера, которые в этом нуждаются. В вашем случае это опять-таки тесты фрагмента и привязка цвета. Но если этап шейдера будет читать глубину, вам также понадобится эта команда в команде wait.

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

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

Ответ 2

Для вашего сценария вы должны использовать события. Это должны быть самые легкие объекты синхронизации для синхронизации выполнения двух командных буферов в заданном порядке, даже если вы отправляете их сразу. Но обратите внимание, что события не работают в разных очередях. Если вы используете только один, используйте события и попытайтесь сохранить маски масок src и dst как можно более узкими.

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