Как я могу сообщить Metal, что я избегаю конфликтов данных между GPU и CPU? - PullRequest
0 голосов
/ 27 декабря 2018

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

WWDC Diagram

Идея состоит в том, что вы буферизуете свои данные, которые обновляются каждый кадр, таким образом, что процессор всегда записывает в другой раздел буфера, чем считывает графический процессор.Затем вы ждете, пока кадры завершат рендеринг, прежде чем начинать запись в другой раздел буфера ЦП.

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

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

----- ----- ----- ----- ----- ----- -----
 n-3   n-2   n-1    n    n+1   n+2   n-4
----- ----- ----- ----- ----- ----- -----
                               ^CPU Write

В приведенном выше примере для данного кадра, где n представляет самую последнюю часть визуализации,ЦП будет записывать в место в буфере, помеченном как n + 2, а графический процессор будет за два вызова отрисовки отображать n-3 -> n и n-4.Хотя технически это позволило бы избежать ситуации, когда центральный процессор и графический процессор взаимодействуют с одним и тем же блоком данных в одно и то же время, я обеспокоен передачей этого.

По сути, мой вопрос: Как я могу сообщить Metal, что я гарантировал, что ЦП не будет записывать данные, пока ГП пытается их прочитать?Есть ли что-то, что мне нужно сделать с выравниванием?Они блокируют доступ к определенным размерам памяти или к чему-то еще?

Чтобы сделать этот вопрос немного более запутанным, представьте, что я хранил следы для 120 кадров движения для 1000 различных объектов внутри одного буфера.Есть несколько способов, которыми я мог бы добиться этого, по-разному размещая данные в буфере.Например, у меня могло бы быть это как это

-----  -----  -----
 p1      p2    p3
-----  -----  -----

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

Или я мог бы выложить их следующим образом:

----- ----- ----- ----- ----- ----- -----
 n-3   n-2   n-1    n    n+1   n+2   n-4
----- ----- ----- ----- ----- ----- -----
                               ^CPU Write

Где внутри каждого из n блоков данные для каждой частицы расположены рядом.

Чтобы сделать вещи еще более сложными, я мог бы вообще избежать нескольких вызовов отрисовки и открыть вещи для альфа-смешивания (сортировки порядка отрисовки треугольника), используя индексный буфер.Индексный буфер действительно может гарантировать, что CPU и GPU технически не должны ждать друг друга. Но узнают ли они?

Могу ли я даже добиться этой оптимизации, когда у меня происходят индексные буферы ?Или это делает доступ к памяти непредсказуемым?

Я понимаю, что это долгая запись!Основные вопросы выделены жирным шрифтом.По сути, мне просто интересно, как / когда графический процессор и процессор решают ждать при обмене данными.

1 Ответ

0 голосов
/ 28 декабря 2018

Как я могу сообщить Metal, что я гарантировал, что ЦП не будет записывать данные, пока ГП пытается их прочитать?Есть ли что-то, что мне нужно сделать с выравниванием?Блокируют ли они доступ к памяти определенного размера или к чему-то другому?

Вам не нужно передавать такую ​​информацию в Metal API.Metal возлагает бремя на программиста, гарантируя, что вы не измените данные, которые графический процессор еще не использовал.

Типичный подход в примерах (например, проект iOS Metal Game по умолчанию в XCode или в примере, описанном здесь ) - создать семафор и определить MaxBuffersInFlight.Семафор находится в ожидании перед заполнением буфера команд и сигнализирует об этом в обработчике завершения буфера команд фрейма.

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

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

...