Как чередовать Kernel / Vertex METAL шейдеры

Я сталкиваюсь с развертыванием цикла рендеринга Metal как цепочки из нескольких шейдеров KCS (ядро / вычисление) и шейдеров VFS (вершин / фрагментов):

texture -> [KCS -> VFS -> KCS -> VFS] --\
                                         --->[KCS -> KCS] --> presentable
texture -> [KCS -> VFS -> KCS -> VFS] --/

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

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

Я тоже не указал на это, но последний вызов Presentable также будет передавать подобласть его вывода в отдельный MTKView (через вершинный / фрагментный шейдер).

Мы будем благодарны за любые подсказки.


person zzyzy    schedule 01.09.2017    source источник


Ответы (1)


Вам нужны разные дескрипторы, только если они будут иметь разные значения. То есть, если какой-либо из шагов KCS, которые вы показываете, использует одну и ту же функцию вычисления шейдера, то они обычно могут иметь общий дескриптор. (Есть и другие свойства MTLComputePipelineDescriptor, но они используются реже.)

Для шагов VFS дескриптор более сложен, поэтому для совместного использования они должны быть одинаковыми для всех свойств.

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

Вы определенно не хотите использовать обработчики завершения для отправки следующего шага. Это приведет к ужасной остановке конвейера (заставит ЦП и ГП постоянно ждать друг друга). Просто закодируйте шаги по порядку в буфер команд. Любая отрисовка или отправка не будет продолжена до тех пор, пока не будет завершена предыдущая отрисовка / отправка, которая могла бы писать на его входы.

person Ken Thomases    schedule 01.09.2017
comment
И снова быстрый ответ, Кен! Если немного упростить это, у меня будет набор VFS MTLRenderPipelineDescriptors и набор KCS MTLRenderPipelineDescriptors и один MTLCommandBuffer? Я бы создал кодировщики на лету в буфере команд, и они будут выполняться по порядку - даже если они чередуются с KCS / VFS? Кроме того, можно ли использовать эти дескрипторы конвейера в нескольких MTKView? - person zzyzy; 01.09.2017
comment
Что ж, у вас будет набор объектов MTLRenderPipelineState и MTLComputePipelneState. Вы создадите дескрипторы во время создания этих объектов состояния, но вам не нужно их хранить. (Также обратите внимание: вы можете настроить дескриптор, создать из него объект состояния, перенастроить тот же дескриптор, создать на его основе другой объект состояния и т. Д. Таким образом, вам не обязательно нужен дескриптор для каждого объекта состояния.) требуется один командный буфер на каждую итерацию цикла рендеринга, кодировать его, фиксировать и отбрасывать ссылки на него. - person Ken Thomases; 01.09.2017
comment
Да, закодированные команды будут выполняться по порядку. Графический процессор может фактически распараллеливать команды, которые не зависят от результатов друг друга, но эффект такой, как если бы они выполнялись по порядку. И, да, вы можете делиться объектами состояния между целевыми объектами рендеринга и т. Д. В принципе, нет необходимости создавать избыточные объекты состояния (т.е. из эквивалентных дескрипторов). Объект состояния просто отражает значения в дескрипторе на момент его создания, с определенными предварительными вычислениями, выполняемыми во время этого создания. - person Ken Thomases; 01.09.2017
comment
У меня есть один вопрос ... допустим, у меня есть Compute Encoder (шейдер ядра), и я ожидаю от него выходной буфер / текстуру после выполнения dispatchThreadGroups. Я не вижу способа обойтись без фиксации в буфере команд, а затем добавить обработчик завершения (или просто waitUntilCompleted) перед планированием следующего пакета работы, используя вывод текстуры в качестве входных данных для следующего (скажем) вершинного шейдера. Или я слишком много обдумываю - вы, кажется, указываете, что кодировщик достаточно умен, чтобы приостановить работу вершинного шейдера, при этом outBuffer ref является ссылкой inBuffer на вершинный шейдер. - person zzyzy; 02.09.2017
comment
Команды, которые вы кодируете в командный буфер с помощью различных кодировщиков, семантически выполняются последовательно. Вот как вы должны думать о них. Возможно, что графический процессор может распараллелить их, но только если он поддерживает результат, который был бы результатом их последовательного выполнения. - person Ken Thomases; 02.09.2017
comment
Думать об этом как о приостановке операции рисования немного странно. Помните, что это команда рендеринга кодировщик. Вызов метода рисования - это просто кодирование команды рисования в буфер. Он не запускает операцию рисования напрямую. В конце концов, вы фиксируете буфер команд с целым набором закодированных в него команд. Затем эти команды выполняются последовательно. Таким образом, это естественное следствие командного буфера, что отрисовка не начинается, пока не завершится вычислительный шейдер. - person Ken Thomases; 02.09.2017