Вот настройка визуализации Vulkan:
- Submit CB1 - содержит проход рендеринга A с X вызовами отрисовки.
- Submit CB2 - содержит проход рендеринга B с Y вызовами отрисовки, где один из рисования вызывает образцы из изображения, которое является целью рендеринга прохода рендеринга A.
- Во время передачи CB2, семафор, который используется совместно с некоторым внешним API GPU, вставляет сигнализацию, чтобы убедиться, что выполнение CB2 выполнено до цель визуализации прохода рендеринга B используется далее (в данном случае CUDA). Этот шаг установлен правильно, и мне ясно, как он работает.
Все это происходит в одной и той же очереди и в вышеуказанный порядок. Проходы рендеринга A и B совместно используют образ MSAA, но у каждого есть свое уникальное цветовое вложение, в котором разрешается MSAA.
Мой вопрос заключается в том, каков наилучший способ синхронизации между завершающей записью CB1 для рендеринга прохода A RT и одним или больше вызовов отрисовки в выборке CB2 из этой RT в шейдере во время выполнения прохода рендеринга B?
На основании некоторого предложения, которое я получил в группе Khronos Vulkan Slack, я попытался выполнить синхронизацию через зависимости subpass.
Проход рендеринга Настройка зависимости:
VkSubpassDependency dependencies[2] = {};
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkAttachmentReference colorReferences[2] = {};
colorReferences[0] = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; //this one for MSAA attachment
colorReferences[1] = { 1, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL };
Настройка рендеринга прохода B:
VkSubpassDependency dependencies[2] = {};
dependencies[0].srcSubpass = VK_SUBPASS_EXTERNAL;
dependencies[0].dstSubpass = 0;
dependencies[0].srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependencies[0].srcAccessMask = VK_ACCESS_MEMORY_READ_BIT;
dependencies[0].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
dependencies[0].dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkAttachmentReference colorReferences[2] = {};
colorReferences[0] = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
colorReferences[1] = { 1, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL };
Представленное выше решение, похоже, работает. Но я не уверен, что у меня есть гарантия неявной синхронизации об этом. В этом обсуждении один из ответов состояния
Единственные изображения, где это не так, - это зависимости для целей рендеринга. И те, и другие обрабатываются специально в любом случае. Каждый подпроцесс говорит, что он пишет и куда, поэтому у системы есть информация для явного построения этих зависимостей памяти.
Также в этой статье автор пишет:
ПРИМЕЧАНИЕ: Операции с буфером кадра внутри прохода рендеринга, конечно, выполняются в порядке API. Это специальное исключение, которое вызывает spe c.
Но в этом SO вопросе ответ заключается в том, что необходимо выполнить синхронизацию c между буферами команд , с событиями в этом случае.
Так что другой вариант, который я попробовал, состоял в том, чтобы вставить барьер памяти конвейера во время записи CB2 для изображений, которые являются целями рендеринга в ранее представленном CB (проход рендеринга A), до начала прохода рендеринга B запись:
запись CB2 :
BeginCommandBuffer(commandBuffer);
...
if (vulkanTex->isRenderTarget)//for each sampler in this pass
{
VkImageMemoryBarrier imageMemoryBarrier = CreateImageBarrier();
imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
imageMemoryBarrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
imageMemoryBarrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
imageMemoryBarrier.image = vulkanTex->image;
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
imageMemoryBarrier.subresourceRange = range;
vkCmdPipelineBarrier(
commandBuffer,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
0,
0, nullptr,
0, nullptr,
1, &imageMemoryBarrier);
}
VkRenderPassBeginInfo renderPassBeginInfo = {};
...
.....
Конечно, в этом сценарии я могу установить одинаковые зависимости для всех проходов рендеринга, чтобы они были аналогичны настройке зависимости прохода рендеринга B .Это тоже работает. Но это требует от меня записи большего количества команд в CB. Итак, какой путь является правильным (данная опция зависимостей подпроцесса действительна) и наиболее оптимальным с точки зрения эффективности аппаратного обеспечения?