Найти тему
Григорий Дядиченко

Draw Call

Draw Call

Все кто не особо вникал в работу графики обычно опираются в оптимизации на 3 метрики. Draw Call, Vertices и Triangles в профайлере. (Ну и на фпс конечно) Юнити придумали относительно неплохую систему "универсальных метрик", которые легко собирать и просто объяснить. Но тут есть свои нюансы. В целом я рекомендую прочитать Render Hell, чтобы иметь общее представление, как работает гпу. Хотя и конечно с упрощениями, но там отлично всё объясняется)

В сущности Draw Call — это вызов отрисовки. То есть CPU готовит для ГПУ команду с параметрами что отрисовать и как, и кладёт её в CommandBuffer. (Именно параметрами, сами текстуры, вертекс буфферы и т.п. уже находятся в VRAM) И вот тут начинают играть роль некоторые нюансы, которые профайлер не показывает, но о которых надо помнить. Основное это видеопамять (VRAM) и шина, о чём часто забывают.

Чтобы что-то отрисовать нужно загрузить информацию из VRAM в ГПУ

Современные ГПУ конечно устроены сложнее, там есть даже L1 и L2 кеш, и всё это зависит от гпу к гпу. Иногда бывает полезно почитать мануалы, особенно если вы разрабатываете под конкретное железо. Упрощённо, так как процессоры не имеют своей огромной памяти, нужно загружать всю информацию для отрисовки через шину. Шина гпу — это канал соединяющий VRAM и GPU. И у него есть ширина — параметр который отвечает за то, какое количество информации шина может обработать за единицу времени.

В контексте Unity количество Vertices вам конечно скажет сколько вы грузите из VRAM в GPU вертексов. Но обычно пропускная способность шины исчисляется всё же в байтах, поэтому это не полное представление. Очень важным является число параметров, которые вы храните в вертексе. Каждый float допустим — это 2 байта. То есть скажем вы не пользуетесь нормалями, но зачем-то храните их в вертексных параметрах, А это 12 байт (float32 x 3) информации на каждый вертекс, что при большом числе вертексов может сказываться на перфомансе. Для примера при 60 фпс и рендере модели в 500к вертексов у вас будет шина загружаться ещё на 360 мб в секунду дополнительно информацией, которая никак не используется. Даже если 3д моделеры зачем-то рассчитали нормали, то лучше в настройках импорта поставить None, если вам они не нужны)

Батчнутый меш пойдёт на гпу целиком

Я даже сам так когда-то делал, объединяя всю сцену в одну модель и один материал. Или же многие ассетом для батчинга мешей так пользовались, но у этого есть проблема. Если обратить внимание на даже на статс Unity (но это абсолютно логично) Если вы видите в камере даже 1 вертекс меша, то но гпу пойдёт весь его вертекс буффер. И зачем вам грузить лишнюю информацию, которую вы даже не видите. Чтобы снизить Draw Call, но при этом возможно даже негативно сыграть на производительность?

В одном проекте давным давно я так делал и не понимал: "А что не так?" В одной модели в 3д игре была вся комната. Батчить и разбивать меши на группы лучше осознано, понимая как это работает. Чтобы опять таки шина GPU вывозила то, что вы от неё хотите. Комбинировать меши по логике геймплея, тому как игрок перемещается и смотрит на 3д объекты и так далее.

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