Vulkan - какие этапы существуют вне прохода рендеринга для настройки в команде vkCmdPipelineBarrier

Какие этапы могут быть установлены для srcStageMask/dstStageMask при отправке vkCmdPipelineBarrier из прохода рендеринга, потому что в этом случае нет точки привязки подпрохода к графическому конвейеру?

Тот же вопрос при отправке vkCmdPipelineBarrier в подпроходе, который имеет точку привязки к вычислительному конвейеру, который, как я полагаю, не имеет таких этапов, как VK_PIPELINE_STAGE_VERTEX_SHADER_BIT и, возможно, многих других.

Спасибо

Изменить

Во-первых, благодаря комментарию @Nicol Bolas, вычислительный шейдер не может быть отправлен в середине подпрохода.

И я хотел бы уточнить свой вопрос:

Скажем, у меня есть изображение, которое после рендеринга будет иметь макет VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.

После прохождения рендеринга я хочу обновить изображение новыми данными и изменить его макет на VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL.

Таким образом, после записи vkCmdEndRenderPass я записываю команду vkCmdPipelineBarrier следующим образом:

const VkImageMemoryBarrier imageMemoryBarrier =
{
    VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,     
    nullptr,                                    
    VK_ACCESS_SHADER_READ_BIT,                  // srcAccessMask
    VK_ACCESS_TRANSFER_WRITE_BIT,               // dstAccessMask
    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,   // oldLayout
    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,       // newLayout
    VK_QUEUE_FAMILY_IGNORED,                    
    VK_QUEUE_FAMILY_IGNORED,                    
    image,                                      
    {                                           // subresourceRange
        VK_IMAGE_ASPECT_COLOR_BIT,              // aspectMask
        0,                                      // baseMipLevel
        VK_REMAINING_MIP_LEVELS,                // levelCount
        0,                                      // baseArrayLayer
        VK_REMAINING_ARRAY_LAYERS               // layerCount
    }
};

vkCmdPipelineBarrier(currentCommandBuffer,
                     VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
                     VK_PIPELINE_STAGE_TRANSFER_BIT,
                     0,
                     0, nullptr,
                     0, nullptr,
                     1, &imageMemoryBarrier);

Это гарантирует ожидание перехода до тех пор, пока предыдущая команда в renderpass не пересекла этап фрагментного шейдера.

Но что, если vulkan выполнит vkCmdPipelineBarrier после того, как выполнение renderpass уже завершено? теперь нет связанного конвейера, нет этапов - означает ли это, что барьер перейдет в бесконечное ожидание, пока не начнется новый проход рендеринга и не произойдет этап фрагментного шейдера?


person audi02    schedule 12.06.2021    source источник
comment
Вы не можете отправить вычислительный шейдер в середине подпрохода. Так что вопрос спорный. Кроме того, то, какие этапы использовать, зависит от того, какую синхронизацию вы выполняете. Что такое пишущие и потребляющие операции.   -  person Nicol Bolas    schedule 13.06.2021
comment
Спасибо @NicolBolas, отредактировал и прояснил вопрос. Я кое-что скучаю.   -  person audi02    schedule 13.06.2021


Ответы (2)


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

Для этого вы установили барьеры, которые синхронизируют

Execution:   FRAGMENT_SHADER            ->   TRANSFER
Memory:      SHADER_READ                ->   TRANSFER_WRITE
Layout:      SHADER_READ_ONLY_OPTIMAL   ->   TRANSFER_DST_OPTIMAL

Хотя эти параметры синхронизации обеспечивают правильность, на самом деле их немного больше, чем необходимо. srcAccessMask используется для памяти, которую необходимо сделать доступной, что означает ~ передачу в память L2, чтобы к ней можно было получить доступ впоследствии.

Это часть, которая не нужна в вашем барьере, потому что память уже доступна (в памяти L2), иначе она не могла быть прочитана должным образом.

Т.е. оптимальный барьер будет следующим:

Execution:   FRAGMENT_SHADER            ->   TRANSFER
Memory:      0                          ->   TRANSFER_WRITE
Layout:      SHADER_READ_ONLY_OPTIMAL   ->   TRANSFER_DST_OPTIMAL

Теперь к вопросу о

Но что, если vulkan выполнит vkCmdPipelineBarrier после того, как выполнение renderpass уже завершено?

Что записанный барьер, подобный приведенным выше, говорит вашему графическому процессору, следующее:

  • В текущей очереди дождитесь, пока все предыдущие команды, которые имеют этап FRAGMENT_SHADER, завершат свои FRAGMENT_SHADER этапы, прежде чем переходить к последующим командам на своих TRANSFER этапах.

Это также означает:

  • Если в очереди нет предыдущих команд, требование барьера уже выполнено, и выполнение дальнейших команд может продолжаться немедленно.
  • Если в очереди есть команды, которые потенциально не проходят FRAGMENT_SHADER этапов, мы их не ждем.
  • Барьер применяется ко всем командам, которые когда-либо были отправлены в очередь. (Но большинство команд больше не будут выполняться, а уже будут удалены, потому что они завершили выполнение.) src зависимости барьера никогда относятся к чему-то, что может быть отправлено в будущем, только для вещи, которые были отправлены ранее.

Если у вас возникают трудности с этими вещами, вы можете прочитать лекцию Введение в Vulkan, в которой рассматриваются такие темы синхронизации начиная с 22:28 и далее.

person j00hi    schedule 13.06.2021
comment
Что делает ваш барьер более оптимальным? Звучит просто вопрос стиля кода ... - person krOoze; 13.06.2021
comment
Спасибо @joohi, видео тоже очень информативное. Это действительно не интуитивный предмет! - person audi02; 13.06.2021
comment
@krOoze Можно утверждать, что мой барьер более оптимален по двум причинам: 1) Не может быть никаких сомнений для компилятора w.r.t. доступ src, т.е. ясно, что в этом случае память не должна быть доступна. Теперь, если вы возразите, что ни один компилятор не будет действовать так глупо и предоставлять доступную память в этом случае, я полностью согласен. Но все же: 2) Он имеет дидактический эффект, указывая на то, что никакие READ флаги доступа не имеют смысла с srcAccessMask параметрами. - person j00hi; 14.06.2021

Просто проверьте Допустимое использование.

Все они разрешены, за исключением тех, у которых функция отключена на всем устройстве (например, геометрический шейдер), или тех, которые семейство очередей не поддерживает.

Для зависимостей подпрохода разрешены только те, которые поддерживаются pipelineBindPoint конвейером (т.е. в настоящее время только графика).


Я думаю, что основная проблема, которая вас глубоко сбивает с толку, заключается в том, что вы думаете, что pipeline - это конечный автомат. Но конвейер - это не конечный автомат, это конвейер (как следует из названия). Он существует всегда (как и все его этапы), даже если в данный момент ничего не проходит по конвейеру.

В частности, на английском языке ваш барьер просто говорит: Прежде чем любые команды, записанные после меня, начнут копировать в это изображение, убедитесь, что все команды, записанные до меня, закончили считывать это изображение как текстуру.

Когда существуют этапы, не является допустимым вопросом (как объяснено выше); существование и небытие на самом деле не является их собственностью. И, как видно из семантики барьера, даже не имеет значения изменить его значение.

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

person krOoze    schedule 12.06.2021
comment
@krOooze - Спасибо, отредактировал и прояснил вопрос. Есть кое-что, что я скучаю - person audi02; 13.06.2021
comment
@ audi02 Пытался решить некоторые из этих проблем в обновлении. - person krOoze; 13.06.2021