По причинам, связанным с пользовательской инфраструктурой, я не могу расширить команду, которая выполняет переходы макета изображения с помощью барьеров памяти (т.е. я не могу указать флаги доступа). Код перехода макета изображения фиксируется следующим образом:
void perform_image_layout_transition(VkImage theImage, VkImageLayout oldLayout, VkImageLayout newLayout, ...)
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = 0;
barrier.image = theImage;
vkCmdPipelineBarrier(..., VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, ... , 1, &barrier);
}
Если я хочу / должен создать барьеры памяти, я бы создал цепочку зависимостей выполнения следующим образом:
// 1. Synchronize with whatever comes before
VkMemoryBarrier memBarrBefore = {};
memBarrBefore.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
memBarrBefore.srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT; // Make previous writes available
memBarrBefore.dstAccessMask = 0; // No need to make memory visible; if it is available, that's fine.
vkCmdPipelineBarrier(...,
previousStageToSynchronizeWith,
VK_PIPELINE_STAGE_TRANSFER_BIT,
0,
1, &memBarrBefore,
...
);
// 2. Layout transition
perform_image_layout_transition(...);
// 3. Synchronize with whatever comes after
VkMemoryBarrier memBarrAfter = {};
memBarrAfter.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
memBarrAfter.srcAccessMask = 0; // Memory is already available. Hence, no need to specify an access mask.
memBarrAfter.dstAccessMask = VK_ACCESS_MEMORY_READ_BIT; // Make memory visible to the subsequent command
vkCmdPipelineBarrier(...,
VK_PIPELINE_STAGE_TRANSFER_BIT,
subsequentStageToSynchronizeWith,
0,
1, &memBarrAfter,
...
);
Мой вопрос: это жизнеспособный подход для синхронизации стадии previousStageToSynchronizeWith
с subsequentStageToSynchronizeWith
, делающей всю память из первой доступной и видимой для всех кэшей последнего?
Я не уверен, что выполнение цепочка зависимостей над VK_PIPELINE_STAGE_TRANSFER_BIT
- это правильный подход / выбор. Могу ли я также использовать другой этап конвейера для создания такой зависимости выполнения? Или VK_PIPELINE_STAGE_TRANSFER_BIT
единственный возможный выбор? Или это даже неправильно, может быть?
Дополнительный вопрос, основанный на ответе krOoze:
Давайте предположим, что обновленная версия perform_layout_transition
использует VK_PIPELINE_STAGE_BOTTOM_OF_PIPE
в соответствии с предложением:
void perform_image_layout_transition(VkImage theImage, VkImageLayout oldLayout, VkImageLayout newLayout, ...)
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.oldLayout = oldLayout;
barrier.newLayout = newLayout;
barrier.srcAccessMask = 0;
barrier.dstAccessMask = 0;
barrier.image = theImage;
vkCmdPipelineBarrier(..., VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ... , 1, &barrier);
}
Действительно ли это правильно синхронизируется с последующими TRANSFER
операциями - т.е., например, с двумя последующими vkCmdCopy*
операциями с переходом макета между ними? В исходной версии цепочка зависимостей выполнения от
before -> TRANSFER -> TRANSFER -> TRANSFER -> TRANSFER -> after
очевидна.
Но в обновленной версии это будет
before -> TRANSFER -> BOTTOM -> BOTTOM -> TRANSFER -> after
.
Действительно ли vkCmdPipelineBarrier(..., VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, ... , 1, &barrier);
гарантирует, что - в примере двух последующих операций vkCmdCopy*
- вторая vkCmdCopy*
ждет, пока не будет выполнен переход макета?
Что я не могу осознать, в частности, это следующее (т.е. это моя личная ментальная модель, которая в какой-то момент должна быть неверной):
- Первая передача команда проходит через этапы:
TOP -> TRANSFER -> BOTTOM
. - Между ними идет НЕТ команды (?) только переход макета, который не проходит через какие-либо этапы (?)
- Вторая команда передачи выполняется через этапы:
TOP -> TRANSFER -> BOTTOM
.
Теперь, если я использую обновленную версию, которая создает цепочку зависимостей выполнения между BOTTOM
и BOTTOM
, не может ли быть так, что переход макета изображения еще не завершился до второй команды передачи TRANSFER
этап начинается? Синхронизация BOTTOM -> BOTTOM
будет означать только, что переход макета выполняется после BOTTOM
первой команды передачи и до BOTTOM
второй команды передачи, или это так? Где я не прав?
Уточняющий вопрос:
В своем исходном вопросе (самый верхний) я рассматривал следующую ситуацию:
vkCmdCopy*(...);
vkCmdPipelineBarrier(..., TRANSFER, TRANSFER, /* memory barrier to make memory available, but no layout transition */);
perform_image_layout_transition(TRANSFER, TRANSFER, ...);
vkCmdPipelineBarrier(..., TRANSFER, TRANSFER, /* memory barrier to make memory visible, but no layout transition */);
vkCmdCopy*(...);
Затем было предложено использовать BOTTOM_OF_PIPE
stage для перехода к макету изображения, который сводится к следующему:
vkCmdCopy*(...);
vkCmdPipelineBarrier(..., TRANSFER, TRANSFER, /* memory barrier to make memory available, but no layout transition */);
perform_image_layout_transition(BOTTOM_OF_PIPE, BOTTOM_OF_PIPE, ...);
vkCmdPipelineBarrier(..., TRANSFER, TRANSFER, /* memory barrier to make memory visible, but no layout transition */);
vkCmdCopy*(...);
И после отличного описания ментальной модели по этапам конвейера, Я все еще не вижу, чтобы две vkCmdCopy*
команды были правильно синхронизированы с переходом макета между ними.
spe c говорит:
Цепочка зависимостей выполнения последовательность зависимостей выполнения, которые формируют отношение «до и после» между первой зависимостью A 'и конечной зависимостью B'. Для каждой последовательной пары зависимостей выполнения существует цепочка, если пересечение B в первой зависимости и As во второй зависимости не является пустым набором.
Не означает ли это, что vkCmdPipelineBarrier(..., TRANSFER, TRANSFER, ...)
и perform_image_layout_transition(BOTTOM_OF_PIPE, BOTTOM_OF_PIPE, ...)
не сможет создать цепочку зависимостей выполнения, поскольку пересечение их флагов этапа является пустым набором? Кроме того, первый vkCmdPipelineBarrier
не будет образовывать цепочку зависимостей выполнения со вторым vkCmdPipelineBarrier
, поскольку они не являются «последовательной парой»?!
Может быть, возможно / будет работать следующая версия:
vkCmdCopy*(...);
vkCmdPipelineBarrier(..., TRANSFER, BOTTOM_OF_PIPE, /* memory barrier to make memory available, but no layout transition */);
perform_image_layout_transition(BOTTOM_OF_PIPE, BOTTOM_OF_PIPE, ...);
vkCmdPipelineBarrier(..., BOTTOM_OF_PIPE, TRANSFER, /* memory barrier to make memory visible, but no layout transition */);
vkCmdCopy*(...);
Может быть, однако, эта версия все время имела в виду krOoze?