tgoop.com/unity_cg/57772
Last Update:
Ладно, настало время затронуть эту тему).
Большинство ПК рендерят IMR - Immediate Mode Rendering.
Что и как подали на вход - так и отрендерили, в том же порядке. Стандартный графический апи - примитив, растеризация, шейдинг фрагмента.
В рендере примитивов важно соблюсти порядок - какой примитив отрисовать, какой примитив был перекрыт и его можно вообще не шейдить. Для этого, изначально, есть разные варианты - например - алгоритм художника или сортировка.
Но наиболее эффективный - это использовать хардварный Z-Buffer, он же буфер глубины.
Нюанс IMR в том, что при каждой отрисовке фрагмента, ты должен взять и подать из глобальной памяти (VRAM) глубину и стенсиль для этого фрагмента.
VRAM хоть и быстра, но это не кэш, фетч из неё, по ритму жизни обычных инструкций (типа сложения-умножения на гпу) может занимать месяцы если не годы.
Любой чих-пых на шине (это мостик между памятью и кэшем на гпу) стоит энергии, сиречь электричества. Где электричество, там теплопотери, нагрев и необходимость всю эту радость охлаждать.
При разработке гпу для мобильных девайсов, инженеры не захотели решать вопрос с креплением вентилятора и весом аккумуляторных батарей и пошли странным, но весьма эффективным путём - родили TBDR.
TBDR - Tile-Based Deferred Rendering.
Все инструкции что ведут до SV_Position + разбиение по примитивам выделяются в отдельную часть шейдера и выполняются здесь и сейчас.
А затем нужно выполнить для позиций примитивов биннинг (Qualcomm) или же тайлинг (Mali, PowerVR). Разница между ними не так уж велика.
Весь бэкбуфер разделен, хардварно, на небольшие участки. Ты мог иногда видеть артефакты биннинга, когда у тебя на экране есть крупные (относительно) прямоугольники, в которых изображение норм, а есть прямоугольники, где не норм, так вот это оно.
Работу эту выполняется отдельный хардварный модуль - тайлер. У него тоже есть предел нагрузки и если у тебя много геометрии, или она распределена так, чтобы покрывать множество бинов - ты вполне можешь достичь предела его способностей (у меня были такие кейсы в практике).
Вся геометрия после геометрического этапа распределяется по этим участкам-бинам и отправляется в системную память. И только потом по каждому отдельному бину/тайлу начинаются операции по растеризации-интерполяции-фрагментному-шейдингу.
Вся геометрия - в смысле вообще вся. Т.е. у тебя сначала все вертексные шейдеры ВСЕХ твоих дроуколлов выполняются (точнее, позиционная часть вертексных шейдеров) и только потом все остальные вычисления, в т.ч. шейдинг фрагментов
Интерполяционная часть вертексного шейдера, сама интерполяция и шейдинг идут уже по бинам. Будто твой бин - это отдельная, маленькая рендертекстура. Для каждого бина мы подтягиваем геометрические данные (позиции как минимум) из системной памяти, выполняем интерполяционную часть и переходим к дальнейшим шагам гпу пайплайна.
Синхронизация - смена рендертаргета. Т.е. в рамках одного таргета - всё так. Меняем таргет - всё по новой.
Цель сих манипуляций в том, что на гпу есть специальный кэш - тайловая память, где обычно и лежат данные глубины и стенсиля. Кэш маленький, зато свой. Размером под тайлик.
Когда мы растеризацию-интерполяцию делаем, мы в кэш этот глубину и стенсиль per-fragment и складываем, и с ней же сравниваем. И там же цвет пикселя лежит для операций блендинга.
После резолва текстуры - результат (т.е. те данные что ты в начале пометил как нужные для резолва, как правило - цвет, реже - глубина + стенсиль) отправляются в системную память. Если резолв не требуется - едут в бэкбуфер и далее - на экран девайса.
На этот же принцип (бины/тайлы, кэш на гпу) опирается рендерпасс апи в вулкане, чтобы делать деферред рендеринг и не гонять промежуточные данные между гпу и шареной мобильной памятью.
p.s. подробнее тут:
https://developer.samsung.com/galaxy-gamedev/resources/articles/gpu-framebuffer.html
https://developer.apple.com/documentation/metal/tailor_your_apps_for_apple_gpus_and_tile-based_deferred_rendering
BY WellMOR in Unity CG Tech
Share with your friend now:
tgoop.com/unity_cg/57772