Как ведут себя перекрывающиеся барьеры изображений?

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

begin( commandBuffer );
1: write( image );
2: imageBarrier(
     image,
     src=STAGE_FRAGMENT(from the write at 1:),
     dst=STAGE_FRAGMENT(intended for read in FS of read at 4:),
     appropriate src and dst access flags,
     newLayout=A
   );
3: imageBarrier(
     image,
     src=STAGE_FRAGMENT(from the write at 1:),
     dst=STAGE_TRANSFER(intended for read by transfer of readT at 5:),
     appropriate src and dst access flags,
     newLayout=B
   );
4: read( image ); // through vkCmdDraw -- expects layout A
5: readT( image ); // different kind of read through Transfer -- expects layout B
end( commandBuffer );
  1. Это вообще законно? (можете ли вы подтвердить это цитатой из спецификации?)
  2. Какова компоновка изображения в каждой точке программы?
  3. Для полноты, как правильно/наилучший способ написать это (ситуация с одним производителем, двумя потребителями)? (Поменять местами строки 3: и 4: и сделать это зависимостью чтения-чтения?)

person krOoze    schedule 30.07.2016    source источник


Ответы (1)


Изображение не может принимать несколько макетов одновременно. В случае с кодом, который вы предложили выше, поскольку два барьера не зависят друг от друга, один будет происходить раньше другого, но порядок не указан. Таким образом, макет изображения впоследствии будет одним или другим. Это означает, что одна из двух операций чтения завершится ошибкой.

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

1: write( image );
2: imageBarrier( image, src=COLOR_ATTACHMENT_OUT, dst=FRAGMENT_SHADER, newLayout=A );
3: read( image ); // e.g. through vkCmdDraw -- expects layout A
4: imageBarrier( image, src=FRAGMENT_SHADER, dst=TRANSFER, newLayout=B );
5: readT( image ); // different kind of read e.g. Transfer -- expects layout B

Зависимость в № 4 говорит, что переход макета и последующие команды TRANSFER не будут выполняться до тех пор, пока не будут завершены все предыдущие операции FRAGMENT_SHADER.

сделать его зависимым от чтения-чтения

Это не зависимость «Чтение-Чтение». Переход макета изменяет изображение (теоретически, во всяком случае), точно так же, как если бы вы записывали значения непосредственно в изображение. Логично, что у вас есть следующее: «Мне нужно прочитать его в FS. После этого мне нужно перевести его на новый макет. После этого мне нужно прочитать его в операции передачи».

Это зависимость «Чтение-Запись-Чтение». Средняя часть должна дождаться завершения первого чтения, но второе чтение не может произойти, пока не будет завершена средняя часть. Вам нужна зависимость выполнения со связанным барьером памяти изображения и переходом макета.

person Nicol Bolas    schedule 30.07.2016
comment
Хорошо, это была моя интуиция (как всегда, это ответственность приложений). Мне просто интересно, нужно ли мне выполнять определенный порядок двух функций чтения. (Для этого есть какой-то трюк с подпроходами, но тогда, я думаю, не встроенный). - person krOoze; 31.07.2016
comment
@krOoze: у вас не может быть двух независимых подпроходов, считывающих одно и то же изображение с разными макетами. Один должен зависеть от другого, поскольку реализации разрешено чередовать подпроходы, если один не зависит от другого. - person Nicol Bolas; 31.07.2016
comment
Я имел в виду это (специфическая цитата): если два подпрохода используют одно и то же вложение в разных макетах, но оба использования доступны только для чтения [...], приложению не нужно выражать зависимость между двумя подпроходами. [...] - person krOoze; 31.07.2016
comment
@krOoze: Достаточно справедливо, хотя это относится только к вложениям, характеристики памяти которых уже странные. - person Nicol Bolas; 31.07.2016
comment
Обратите внимание, что вам следует избегать зависимостей между операциями только для чтения, подобными этим, вместо этого указывая биты FRAGMENT_SHADER и TRANSFER в dstStageMask первого барьера изображения. Затем можно удалить второй барьер изображения, что в целом улучшит производительность. - person Quinchilion; 04.08.2016
comment
@Quinchilion: вы не можете этого сделать из-за разных макетов операций чтения. - person Nicol Bolas; 04.08.2016
comment
@NicolBolas Ах, ты прав. Это ставит вопрос о том, стоит ли использовать здесь общую компоновку, чтобы избавиться от второго барьера. По крайней мере, это должно быть победой на оборудовании Nvidia, учитывая, что они полностью игнорируют макеты изображений. Ура аппаратно-зависимому коду! - person Quinchilion; 04.08.2016
comment
@krOoze: На самом деле, Квинчилион указал мне на интересную проблему. Вторая операция чтения в вашей гипотезе — это операция передачи. Итак... какую операцию передачи можно использовать в экземпляре прохода рендеринга? Потому что все команды передачи могут выполняться только вне RPI. А подпроходы разрешения используют макет LAYOUT_COLOR_ATTACHMENT_OPTIMAL. Поэтому мне интересно, как можно выполнить перенос из вложения. - person Nicol Bolas; 04.08.2016
comment
Ну, вы можете завершить рендерпас перед чтением. Хотя и не так показательно. Мне просто нужна была любая операция чтения с другим макетом (или, по крайней мере, этапом) для примера. - person krOoze; 04.08.2016
comment
Кстати, мне сказали, что барьеры имеют зависимость между собой, если они написаны таким образом (dst stage=src следующего барьера), так что это начинает казаться мне чем-то вроде кроличьей дыры, чтобы понять достоверно. Просто хотел интерполировать 2 вещи из этого вопроса: 1) Если перекрывающиеся барьеры одного и того же ресурса всегда злые (что может сделать для относительно легкого взлома слоя). 2) Если я могу легко разветвиться на два чтения с разным макетом (что может означать лучшую производительность, если макеты одинаковы в драйвере, или даже если нет, он может сначала выбрать любой путь, что создает хорошее место для скрыть задержку) - person krOoze; 04.08.2016
comment
@krOoze: Ну, вы можете завершить рендерпас перед чтением. Тогда finalLayout вашего рендерпасса должно быть тем, что ожидает следующая операция. Так что нет необходимости в дополнительной зависимости от этого. - person Nicol Bolas; 04.08.2016