tgoop.com/unity_cg/76092
Last Update:
Представим, что:
Есть шейдер, который делает простой бокс-блюр. Это фуллскрин шейдер и в нашем примере он будет выполнять только свою фрагментную часть.
Есть мобильный гпу. У него 4 ядра. Каждое ядро - маленькая фабрика, и поэтому на каждом ядре есть 32 юнита ALU (которые считают математику) и 1 юнит текстурных читок. Так же у нас есть регистровый файл на каждое ядро в размере 8192 байта.
Допустим, разрешение 1920x1080, это даст 2 073 600 пикселей.
Но мы же помним, что TBR работает по тайлам, представим что на этом устройстве у нас тайл это 32x32 пикселя, значит у нас будет 60x34 тайла.
Тогда в каждый тайлик у нас войдёт 32x32 = 1024 пикселя.
В реальной жизни пиксели обрабатываются в растер пайплайне пачками 2х2 ради дерривативов (ddx/ddy) и растеризации, но предположим, что растеризации в нашем мире не существует и каждый пиксель обрабатывается отдельно, для упрощения.
Итак, у нас есть шейдер, который делает бокс-фильтр. Что это такое?
Это набор инструкций, типа
1. Посчитай uv1: сложи это число и это.
2. Сделай сэмпл из текстуры
3. Сложи результат
4. Посчитай uv2
...
N.: раздели результат на число сэмплов
ret;
Инструкции зачитывает специальный отдельный модуль на ядре. Он один на ядро, в нашем примере (да и в реальности обычно тоже так).
Что такое тред?
Вот у тебя в шейдере во
frag
метод приходит структура vert2frag
. На каждый тред будут уникальные значения. Значит тредом можно назвать некий "контекст пикселя". Его уникальный UV, его уникальную позицию, тексель текстуры куда будет сохранён результат. Вот этот скоуп значений, информации - это тред. Можно условно представить, что пиксель = тред в нашем случае, но это не совсем так в реальности, ведь считаются 2х2 пикселя, помните? И это один тред, да. Но у нас для примера тред = пиксель, ладно.Итак, на ядро есть планировщик, шедулер. Объединяет треды в группы, обычно по 32 штуки на группу (ведь у нас 32 алу юнита). Такую группу мы назовём "варп". Варп - это термин Nvidia, но сам концепт варпа есть во всех современных архитектурах, в amd это wavefront в apple, видимо, просто "группа тредов".
Допустим, у нас может быть максимум 32 варпа на ядро. Тогда планировщик возьмёт все наши треды (а это сейчас 1024 штуки), разобьёт их по 32 штуки и получит 32 варпа.
Это как раз и есть "капасити" ядра - 32 варпа. И если у нас из 32 возможных варпов загружено 32 - то у нас 100% occupancy, т.е. 100% занятость ядра.
Это количество (32 варпа по 32 треда, на 32х32 пикселя) не случайно, для лучшей утилизации оптимальный размер тайлика будет равен максимальному числу варпов на ядро. НО размер тайла может меняться в зависимости от разных условий, например, от количества требуемой тайловой памяти. И если у тебя деферред пайплайн плохо написан (слишком много текстур в сабпассе), то можно по этой причине уменьшить размер тайла от чего перфа тоже может упасть: тредов на тайл будет меньше, чем доступно варпов.
Мы уже поняли, что алу юнит - это реальная маленькая электронка. Но варп - это "виртуальная единица", т.е. это просто группа лежащих рядом друг с другом, в регистровом файле, данных, которые объединены общим айдишником = оффсетом.
Работу работают только реальные юниты - алу и текстурный. А нафига тогда варпы? Зачем нам держать целых 32 варпа "на лету", если выполняется только один?
Вот прилетел дк на гпу, ядро взяло в работу первый варп.
У нас там по порядку идёт:
1. Посчитай uv1: сложи это число и это.
У нас 32 алу и 32 треда. Посчитали за один такт. Дальше.
2. Сделай сэмпл из текстуры
Оп. А у нас 1 текстурный юнит. А читок нужно 32.
В лучшем случае у нас данные текстуры по запрошенным UV лежат уже в L2 кэше. Тогда текстурный юнит дотянется и за такт заберёт данные, потом ещё за несколько тактов их интерполирует (если включена, например, билинейная фильтрация).
Но что в это время делать 32 алу юнитам?
Вот тут нам и пригодятся варпы "на лету", шедулер просто переключит алу на другой варп и посчитает их значения.
BY WellMOR in Unity CG Tech
Share with your friend now:
tgoop.com/unity_cg/76092