Синхронизации в Vulkan (комментарии)
Это сообщение сгенерировано автоматически.
Кто может заревьюить все это?
/A\
Первая страница — очень сумбурно. Если не знать, о чём идёт речь, то будет очень сложно разобраться из-за слабой структуризации.
иногда я так и не понял, что ты хотел сказать:
> Все команды на стороне Device начинают выполняются в том же порядке, в котором они были вызваны на стороне Host. Закончить выполнение они могут в любом порядке, для контроля за порядком выполнения следует использовать примитивы синхронизации.
что значит "все команды"? все команды внутри одного буфера? все команды внутри одного сабмита? вообще все команды API? например, команды, возвращающие значения (вроде CreateInstance()) гарантированно заканчивают выполнение после возвращения значения, то есть они каким-то образом не входят в множество "всех команд".
если ты говоришь, что команды начинают выполнение в том же порядке, в каком были вызваны, но заканчивают выполнение как попало, то какая вообще разница, в каком порядке они были вызваны и что мешает считать, что они начинают выполняться в случайном порядке?
в барьерах, мне кажется, имеет более подробно рассмотреть взаимодействие параметров access mask/stage mask. не любые комбинации являются валидными по стандарту, поэтому имеет смысл обсудить, какие именно комбинации имеют смысл. что если указать stage mask и не указать access mask? что если наоборот?
много предложений сформулированы странно/двусмысленно:
> Если семафор передан для операции сигнала (параметр pSignalSemaphores), то он сразу переводится в не сигнальное состояние, как только команда завершает выполнение на Device семафор переходит в сигнальное состояние
тут то ли что-то с пунктуацией, то ли что, но можно прочитать так:
Если семафор передан <...>, то он сразу переводится в не сигнальное состояние, как только команда завершает выполнение на Device <...>
что, очевидно, неверно. попробуй сам перечитай, таких мест много.
вообще мне кажется, что имеет смысл более подробно поговорить о гарантиях, что по умолчанию синхронизируется неявно и вокруг чего не надо городить огород.
> GPU может параллельно выполнять сразу несколько команд рисования.
тебе некоторые вещи могут показаться очевидными в твоих обозначениях, а читателю — нет. например, ты подразумеваешь в диаграммах синхронизации, что один столбец = один дроколл, хотя это вообще не очевидно, если честно. также имеет смысл привести очень примерные величины, сколько именно дроколлов могут типично обрабатываться одновременно — это 4 или 4000000.
> Здесь все 4 рисования доходят до этапа фрагментного шейдера, команды до барьера продолжают выполнение, а команды, вызванные после барьера, ожидают следующего этапа с фрагментным шейдером и пропускают все этапы до него.
на этой диаграмме вообще не очевидно, что вертикально друг под другом расположены проходы конвеера. вообще не очевидно, что в твоей интерпретации одни и те же команды отрисовки проходят через конвеер несколько раз. ещё я не понял, почему ты мыслишь в терминах нескольких проходов, а не в терминах ожидания. я правильно понимаю, что вертикаль, идущая вниз на диаграмме — время? об этом тоже имеет смысл сказать, так как в итоге всё сводится к его минимизации.
> Второй командный буфер (cmd2) не может начать рисование до того как произойдет синхронизация в первом командном буфере (cmd1).
не понял. почему? как вообще второй командный буфер узнает о барьере в первом?
последняя страница — более-менее норм. по крайней мере читатель, занимающийся передачей ownership'а уже, скорее всего, понимает, о чём идёт речь.
мне кажется, для упрощения восприятия имеет смысл к каждому абзацу на первой странице тоже добавить небольшую иллюстрацию. мне последующие страницы было проще читать, чем первую.
ещё ты даёшь ссылки обёртки вокруг вулкана. мне кажется, имеет смысл хотя бы в двух словах сказать, по какому пути пошла каждая из них. например, "ez-vulkan", вопреки своему названию, внутри себя вовсе даже не "ez", он записывает все api-вызовы в свой внутренни буффер, потом строит что-то вроде фреймграфа из него, короче, является гораздо более инвазивной библиотекой, чем хочет показаться. твоя обёртка осуществляет синхронизацию на уровне зависимостей между тасками, granite — между ресурсами. diligent абстрагирует dx12 и vulkan в один api. имеет смысл хотя бы одно предложение о каждой обёртке дать, я считаю.
если тебе лень (будет) работать над статьёй дальше, я могу просто опубликовать, как есть. но мне кажется, что она может оказаться полезнее, если над ней ещё поработать и потом опубликовать.
Suslik
Спасибо! Пойду допиливать.
Suslik
> если ты говоришь, что команды начинают выполнение в том же порядке, в каком
> были вызваны, но заканчивают выполнение как попало, то какая вообще разница, в
> каком порядке они были вызваны и что мешает считать, что они начинают
> выполняться в случайном порядке?
Если у тебя 2 командных буфера в батче и в них нет барьеров, то они могут выполняться параллельно, насколько это возможно.
Если в первом командном буфере стоит глобальный барьер, то он влияет на все следующие команды и на второй командный буфер тоже. Я это разобрал в одном из примеров.
> имеет смысл хотя бы в двух словах сказать, по какому пути пошла каждая из них
Если есть автоматическая расстановка барьеров, то в любом случае внутри будут накапливаться команды.
Я не хочу углубляться в детали их реализаций, а то начну все критиковать)) По ссылкам и так все подробно расписано.
> в барьерах, мне кажется, имеет более подробно рассмотреть взаимодействие
> параметров access mask/stage mask. не любые комбинации являются валидными по
> стандарту, поэтому имеет смысл обсудить, какие именно комбинации имеют смысл.
> что если указать stage mask и не указать access mask? что если наоборот?
Это все написано в документации, я бы хотел пропустить ненужную копипасту, лучше в примерах некоторые случаи разберу.
> вообще мне кажется, что имеет смысл более подробно поговорить о гарантиях, что
> по умолчанию синхронизируется неявно и вокруг чего не надо городить огород.
Неочевидные случаи я разобрал, а остальные в документации хорошо расписаны.
> также имеет смысл привести очень примерные величины, сколько именно дроколлов
> могут типично обрабатываться одновременно — это 4 или 4000000.
Единственная информация, что у меня есть, это 7 context rolls на АМД, но там не только дроуколы но и смены пайплайнов. По другим вендорам информации нет.
> ещё я не понял, почему ты мыслишь в терминах нескольких проходов, а не в терминах ожидания.
Потому что так описаны барьеры в вулкане - при ожидании пропускаются pipeline stages.
> я правильно понимаю, что вертикаль, идущая вниз на диаграмме — время?
да
> не понял. почему? как вообще второй командный буфер узнает о барьере в первом?
"Submission order for any given set of commands is based on the order in which they were recorded to command buffers and then submitted."
Только submission это не execution, это именно операция чтения команды, а на выполнение отправляется тогда, когда решит command processor, который знает о всех барьерах (которые прочитал). В том примере указаны VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT значит ни один этап рисования не начнет выполнение пока не завершатся все предыдущие.
/A\
я тебе вопросы написал в первую очередь как пример вопросов, которые могут возникнуть у абстрактного читателя. сам я на многие из них ответы либо знаю, либо могу потратить время и найти. но статьи пишутся для того, чтобы читатели не тратили время на поиск необходимой информации. вот я и думал, что вопросы эти лучше покрыть в статье, а не в посте в ответ мне.
Suslik
> но статьи пишутся для того, чтобы читатели не тратили время на поиск необходимой информации
Ну если я всю информацию из документации запихну в статью, то это будет очень длинная статья...
У меня больше цель кратко описать как оно работает и дать ссылки на документацию, там ведь все хорошо расписано, просто не всегда нужна настолько подробная информация.
Ох, надо будет вечерком почитать, мерсибо!
0r@ngE
Ранова-то, я еще пимеры с барьерами хочу подправить.
А вот заревьюить можно)
6 страниц, ох щи...
Great V.
> 6 страниц, ох щи...
Зато с цветными картинками)
Ну вроде готово, а то так можно до бесконечности допиливать)
Подправил то, в чем не был уверен, может потом сделаю тесты и напишу о результатах отдельно.
/A\
ещё пара непоняток. ты по умолчанию подразумеваешь, что если указан srcStageMask, то это execution dependency, а если srcAccessMask, то memory dependency. наверное, стоит пояснить, почему так.
> Все параметры в vkCmdPipelineBarrier это больше рекомендация драйверу, чем требование
очень неудачная формулировка, я считаю. параметры барьера — это требования, которые драйверу необходимо выполнить. ты, вероятно, имел в виду, что многие из них могут выполняться драйвером просто by design и без явного ожидания барьера, но проигнорировать то, что ты от него потребовал, он, вроде как, не может. или я что-то не знаю.
> Порядок, в котором выполняются команды, определяется только через зависимости, созданные барьерами и событиями
нипонил. например, если отрисовать несколько полупрозрачных объектов, то результат будет зависеть от порядка их отрисовки и даже от порядка отрисовки треугольников внутри каждого из них. этот порядок всегда гарантируется быть одним и тем же. как это согласуется с тем, что у тебя написано?
в главе, где ты рассказываешь про синхронизацию буфера с юниформами, имеет смысл рассказать про работу с HOST_COHERENT буфером.
на этой картинке:
справа compute shader(3) должен быть зелёненький. и на следующей тоже.
Suslik
> справа compute shader(3) должен быть зелёненький. и на следующей тоже.
Тут показано, что на эту команду тоже действует барьер, он проверил что барьер уже прошел и продолжил выполняться без ожидания. Но видимо это не очень понятно)
> например, если отрисовать несколько полупрозрачных объектов, то результат будет
> зависеть от порядка их отрисовки и даже от порядка отрисовки треугольников внутри каждого из них
Я тут решил не усложнять все, на самом деле там дополнительно описано как работают команды внутри рендер пасса и снаружи, в каком порядке рисуются примитивы и в каком порядке проходят этапы растеризации.
> очень неудачная формулировка,
ок, перефразирую
> ещё пара непоняток. ты по умолчанию подразумеваешь, что если указан
> srcStageMask, то это execution dependency, а если srcAccessMask, то memory
> dependency. наверное, стоит пояснить, почему так.
это же написано сразу под первой картинкой
> в главе, где ты рассказываешь про синхронизацию буфера с юниформами, имеет смысл рассказать про работу с HOST_COHERENT буфером.
думаю я достаточно про это написал на первой странице, там же все достаточно просто - в большинстве случаев все само отправится на девайс даже без когерентности, об этом не стоит беспокоиться)
окей, статью я опубликовал
Тема в архиве.