Как упорядочиваются командные буферы для барьеров в одном вызове vkQueueSubmit?

В спецификации Vulkan (1.0.27) говорится (в разделе 6.5. Трубопроводные барьеры):

Каждый элемент массивов pMemoryBarriers, pBufferMemoryBarriers и pImageMemoryBarriers определяет две половины зависимости от памяти, как определено выше. [...]

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

(Формулировка забавная; если интерпретировать буквально, кажется, что барьер упорядочивает команды только в одном командном буфере, оставляя, возможно, переданные в очередь части избыточными; но если интерпретировать немного более расплывчато, похоже, что цель состоит в том, чтобы сказать, что команды барьерных заказов как в своем буфере команд, так и в очереди. Другие страницы переполнения стека указывают мне на следующее, которое, кажется, подтверждает последнюю интерпретацию: https://github.com/KhronosGroup/Vulkan-Docs/issues/300)

Тогда мой вопрос. Предположим, у вас есть четыре командных буфера, отправляемых двумя пакетами по два, все в одной vkQueueSubmit команде:

VkSubmitInfo nextSubmitInfo;
nextSubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
nextSubmitInfo.pNext = nullptr;
nextSubmitInfo.waitSemaphoreCount = 0;
nextSubmitInfo.pWaitDstStageMask = nullptr;
nextSubmitInfo.pWaitSemaphores = nullptr;
nextSubmitInfo.signalSemaphoreCount = 0;
nextSubmitInfo.pSignalSemaphores = nullptr;

std::vector<VkCommandBuffer> commandBuffersAB{commandBufferA, commandBufferB};
std::vector<VkCommandBuffer> commandBuffersCD{commandBufferC, commandBufferD};

std::vector<VkSubmitInfo> submitInfo;

nextSubmitInfo.commandBufferCount = commandBuffersAB.size();
nextSubmitInfo.pCommandBuffers = commandBuffersAB.data();
submitInfo.emplace_back(nextSubmitInfo);

nextSubmitInfo.commandBufferCount = commandBuffersCD.size();
nextSubmitInfo.pCommandBuffers = commandBuffersCD.data();
submitInfo.emplace_back(nextSubmitInfo);

df.vkQueueSubmit(queue, submitInfo.size(), submitInfo.data(), VK_NULL_HANDLE);

Предположим, что каждый из четырех буферов команд включает в себя барьер и несколько команд действий (которые в соответствии со спецификацией являются командами, выполняющими действия (например, рисование / отправка)). Поэтому я склонен наивно ожидать, что барьеры будут воспринимать командные буферы как отправленные в алфавитном порядке, так что их первая и вторая половины будут включать (возможно, среди прочего) следующее:

| barrier             | first half                 | second half                |
|---------------------|----------------------------|----------------------------|
| barrier in buffer A | A0                         | A1, B0, B1, C0, C1, D0, D1 |
| barrier in buffer B | A0, A1, B0                 | B1, C0, C1, D0, D1         |
| barrier in buffer C | A0, A1, B0, B1, C0         | C1, D0, D1                 |
| barrier in buffer D | A0, A1, B0, B1, C0, C1, D0 | D1                         |

где для буфера X, X0 - это набор команд действия, записанных в X до барьера, а X1 - это набор, записанный после барьера; и что в результате наборы команд будут выглядеть следующим образом:

A0; then
A1 and B0; then
B1 and C0; then
C1 and D0; then
D1

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

Так ли это? Или это применимо только тогда, когда командные буферы A – D представлены четырьмя разными vkQueueSubmit командами? (Или тогда это вообще не применимо?)


person mjwach    schedule 18.09.2016    source источник


Ответы (1)


В соответствии с версией 1.0.35 спецификации Vulkan, границы буфера команд не влияют на порядок между операциями:

Границы буфера команд, как между первичными буферами команд одного и того же или разных пакетов или представлений, так и между первичными и вторичными буферами команд, не вводят никаких неявных ограничений упорядочения. Другими словами, отправка набора командных буферов (которые могут включать выполнение вторичных командных буферов) между любыми семафорными или ограничительными операциями выполняет записанные команды, как если бы они все были записаны в один первичный командный буфер, за исключением того, что текущее состояние сбрасывается. на каждой границе. Явные ограничения порядка могут быть выражены с помощью событий и конвейерных барьеров.

Таким образом, не имеет значения, являются ли CB первичными / вторичными, в одинаковых / разных пакетах или в одинаковых / разных командах отправки. Все они действуют так, как если бы они были одним действительно большим первичным командным буфером.

Следовательно, синхронизация работает между всеми этими границами.

vkQueueSubmit сообщает нам:

Пакеты начинают выполнение в том порядке, в котором они указаны в pSubmit, но могут завершиться не по порядку.

И VkSubmitInfo говорит в пакете:

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

Акцент добавлен.

Учитывая все это, мы знаем, что не имеет значения, как вы отправляете эти партии. Независимо от того, делаете ли вы это за 1 vkQueueSubmit или за 4. Независимо от того, делаете ли вы это 1 пакетом из 4 CB или 4 пакетами по 1 CB каждый. Единственное, что имеет значение, - это порядок, в котором представлены эти CB.

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

person Nicol Bolas    schedule 18.09.2016
comment
Я думаю, что в какой-то момент я увидел этот бит о том, что буферы начинают выполнение в том порядке, в котором они появляются в массиве их командных буферов, но я не смог надежно связать это с утверждением, которое я хотел подтвердить, а именно, что любые препятствия внутри этих буферов будет вести себя так, как если бы были упорядочены все буферы. В частности, может быть, два буфера команд в пакете могут начинаться по порядку, но после этого каким-то образом продолжаться параллельно ?? Я не знаю. Может быть, где-то есть еще что-то, что этого не может быть. - person mjwach; 18.09.2016
comment
@mjwach: Суть решения проблемы № 300 состоит в том, что после отправки в очередь не существует буферов команд. Есть только записанные в них команды. Барьеры синхронизируют группы команд, выполняемые в очереди. Для барьера есть только команды в очереди перед ним и команды в очереди после него. Вот что означает решение проблемы № 300: буферы команд не имеют значения для целей синхронизации. Только выполнение команд в очереди. - person Nicol Bolas; 18.09.2016
comment
@mjwach: спецификация Vulkan была обновлена, чтобы полностью указать все это, поэтому теперь очень ясно, каким должно быть поведение. - person Nicol Bolas; 28.11.2016
comment
Я до сих пор не вижу, где они на 100% полностью исключают возможность непредсказуемого чередования команд из двух буферов, даже включая команды барьера. Но это упоминание о сбросе состояния на границах, похоже, указывает на то, что они намерены запретить это, поскольку чередование сделало бы границу между двумя командными буферами сложной (или несуществующей, в зависимости от точки зрения). Но, тем не менее, каждый раз, когда я перечитываю это, как будто все они были записаны в один бит первичного командного буфера, я думаю: «Записано в каком порядке?» - person mjwach; 30.11.2016
comment
Я имею в виду, что я думаю, что вы правы ... Я просто придираюсь к формулировке спецификации, не возражаю с этим ответом. - person mjwach; 30.11.2016
comment
@mjwach: каждый раз, когда я перечитываю это, как будто все они были записаны в один первичный бит буфера команд, я думаю, записано в каком порядке ?? В том же порядке они были записаны в соответствующие CB, < b> как явно указано в командных операторах vkQueueSubmit. Я не знаю, как вы могли бы получить более четкое представление, чем в том порядке, в котором они появляются. - person Nicol Bolas; 30.11.2016
comment
@mjwach: Я до сих пор не понимаю, где они на 100% полностью исключают возможность непредсказуемого чередования команд из двух буферов, даже включая команды барьера. Я не вижу части где говорится, что можно было бы чередовать команды с разных сторон барьера. Опять же, все как если бы все они были записаны в один первичный командный буфер. - person Nicol Bolas; 30.11.2016
comment
Они только начинают выполнение в порядке появления в массивах, и после этого порядок их частей может измениться от порядка записи; отсюда явное утверждение, что они могут закончиться не по порядку. В другом месте сказано, что в командном буфере такое переупорядочение не может нарушать барьеры. Здесь говорится, что несколько буферов команд объединяются в очередь, как если бы они были в одном буфере с самого начала, поэтому ПОСЛЕ того, как это сочетание будет выполнено, переупорядочение времени выполнения также не может нарушить барьеры. - person mjwach; 30.11.2016
comment
Но что происходит ВО ВРЕМЯ этой концептуальной комбинации буферов? Я не вижу полного ответа в этих цитатах из спецификации. Барьеры не обязательно имеют значение во время этой воображаемой операции, потому что барьер разделяет один поток поставленных в очередь команд, и здесь мы говорим о двух или более потоках команд, которые еще не были поставлены в очередь. Каждый из них должен быть упорядочен внутри, и все они должны иметь свои начала в порядке буфера, но более поздняя команда из одного буфера может все же пересечь барьер из другого буфера - не во время выполнения, а во время комбинации. - person mjwach; 30.11.2016
comment
... В другом месте, однако, я вижу, что объяснения половин (теперь называемых областями синхронизации) команд синхронизации были обновлены, чтобы упомянуть пакеты отправки: если vkCmdPipelineBarrier был записан вне экземпляра прохода рендеринга, первая область синхронизации включает все команды переданы в ту же очередь, в том числе в том же буфере команд и в том же пакете. Это помогает прикрыть дыру, которую я вижу. - person mjwach; 30.11.2016
comment
@mjwach: но более поздняя команда из одного буфера может по-прежнему пересекать барьер из другого буфера - не во время выполнения, а во время комбинации. Нет, не может. Невозможно прочитать, как если бы все они были записаны в один первичный командный буфер таким образом, чтобы любая команда могла внезапно переместиться в новое место в потоке команд, которые должны быть выполнены. Для любой последовательности буферов, пакетов и отправок вы можете преобразовать ее в один основной CB, содержащий все эти команды в одном порядке, и вы получите тот же результат. Вот что как бы значит. - person Nicol Bolas; 30.11.2016
comment
Конечно, программист может свободно менять порядок команд во время программирования. Vulkan может изменять порядок, как если бы он был программистом, в очень ограниченной степени. Это чтение мне достаточно ясно; но я подниму его с Хроносом, если захочу продолжить решение. - person mjwach; 30.11.2016