Профилирование мобильных игр в Unity и Arm

MARK HARKNESS / UNITY TECHNOLOGIESSenior Software Engineer
Mar 11, 2021|11 Мин
Профилирование мобильных игр в Unity и Arm
Эта веб-страница была переведена с помощью машинного перевода для вашего удобства. Мы не можем гарантировать точность или надежность переведенного контента. Если у вас есть вопросы о точности переведенного контента, обращайтесь к официальной английской версии веб-страницы.

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

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

Чтобы выявить проблемы с производительностью игры, сначала протестируйте ее на разных устройствах. Лучший способ сделать это - снять профиль производительности на реальном устройстве. Такие инструменты, как Unity Profiler и Frame Debugger, помогут вам понять, на что тратят ресурсы элементы вашей игры. Кроме того, такие инструменты, как Arm Mobile Studio, позволяют собирать данные о производительности и активности устройства, чтобы точно видеть, как ваша игра использует ресурсы CPU и GPU. Хотя используемое нами устройство оснащено графическим процессором Mali, представленные здесь концепции применимы и к другим мобильным GPU.

Пример теста

Игра, которую мы тестируем, представляет собой экшен-РПГ, где игроку предстоит сражаться с волнами наступающих вражеских NPC с помощью атак ближнего боя и заклинаний. На мобильном устройстве игры такого типа могут быстро увязнуть в графическом процессоре, поскольку на экране появляется все больше врагов, а также множество визуальных эффектов с частицами и постобработкой.

Профилирование с помощью Unity Profiler и Frame Debugger

Мы прогнали игру через Unity Profiler, чтобы выявить любое замедление производительности. Мы нашли несколько высокоприоритетных подозреваемых, провели пост-обработку и исправили скачки Timestep и instantiation.

Post-Processing

Эффекты постобработки были главной причиной низкой производительности процессора в игре.

Рендер камеры занимает огромное количество времени и пересекает границу кадра
Рендер камеры занимает огромное количество времени и пересекает границу кадра

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

На скриншоте выше видно, что камера рендеринга занимает огромное количество времени и пересекает границу кадра. Затем главный поток ожидает завершения команд рендеринга перед подготовкой следующего кадра. Давайте посмотрим на отладчик Unity Frame, чтобы понять, что происходит.

Просмотр Frame Debugger с устройством в полноэкранном разрешении
Просмотр Frame Debugger с устройством в полноэкранном разрешении

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

Просмотр рисунков для пирамиды Блум
Просмотр рисунков для пирамиды Блум

Следующее наблюдение заключается в том, что эффект цветения проявляется в 25 розыгрышах пирамиды цветения. Каждый вызов draw представляет целевой буфер с размером, начинающимся с половины разрешения полноэкранного устройства. Затем это разрешение уменьшается вдвое с каждой итерацией. Снижение начального разрешения рендеринга - один из способов уменьшить потенциальное количество итераций. Другой альтернативой может быть модификация исходного кода эффекта bloom, чтобы уменьшить количество итераций и установить какое-либо разумное ограничение. Однако в данном случае лучше пока отключить эффекты постобработки, так как на их обработку уходит много времени. По крайней мере, до тех пор, пока остальную часть игры не удастся заставить плавно работать при 30 кадрах в секунду.

Фиксированный временной интервал

Еще одним улучшением для проекта стало бы уменьшение частоты фиксированного интервала Timestep. Мы видим, что в настоящее время он достаточно короткий, чтобы вызываться несколько раз за кадр; по умолчанию Unity устанавливает это значение на 0,02 или 50 Гц. Вы можете попробовать фиксированное значение Timestep 0,04 для мобильных игр, нацеленных на 30 кадров в секунду. Причина в том, что при 0,333, что соответствует 30 кадрам в секунду, есть вероятность того, что один кадр проскочит во времени и в следующем кадре окажется два вызова. Это означает, что он занимает больше времени - и вы никогда не сможете разорвать цикл, состоящий из чуть более длинных кадров. Пользователь также может установить максимальный допустимый временной интервал, чтобы не допустить, чтобы догоняющий процесс занял больше времени, чем требуется.

Эта длительность Timestep влияет на скрипты, использующие функцию FixedUpdate, и любые внутренние системы Unity, которые обновляются с фиксированным интервалом обновления, например, физика и анимация.

Timeline с фиксированным временным интервалом
Timeline с фиксированным временным интервалом

Для целей данного проекта только физика и Cinemachine вносили значительный вклад в затрачиваемое время - около 3 мс на вызов; вызов означает, что система полностью обновляется (хотя вызов еще 5 раз означает, что это может добавить 15 мс на кадр потерянного времени).

FixedUpdate.PhysicsFixedUpdate замедляется эффектами постобработки
FixedUpdate.PhysicsFixedUpdate замедляется эффектами постобработки

Это происходит из-за медленной работы эффектов постобработки. Их отключение уменьшает затрачиваемое время, однако прежняя рекомендация уменьшить фиксированную частоту Timestep, чтобы избежать лишней работы для процессора, остается в силе.

Шипы инстанций

Во время профилирования можно было заметить скачки во времени кадра. Отслеживание их в иерархическом представлении CPU profiler показывает, что они возникают из-за инстанцирования NPC.

Отслеживание всплесков инстанций в иерархии профилировщика ЦП
Отслеживание всплесков инстанций в иерархии профилировщика ЦП

Наиболее распространенное решение для этого - инстанцировать персонажей заранее и держать их в незанятом состоянии, в некоем пуле объектов. Эти NPC могут быть взяты из пула без затрат на инстанс. Если понадобится больше, то бассейн можно расширить по мере необходимости.

Та же проблема наблюдается и при использовании способностей, поскольку они также инстанцируют объекты.

Скачки инстанций процессора
Скачки инстанций процессора

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

Профилирование с помощью Arm Mobile Studio

Мы также использовали Arm Mobile Studio, чтобы получить больше информации о поведении игры. С помощью инструментов Mobile Studio мы можем получить данные о противодействии производительности CPU и GPU, чтобы точно увидеть, как игра использует ресурсы устройства.

Вы можете бесплатно скачать Arm Mobile Studio здесь. В комплект входят 4 инструмента:

  • Performance Advisor - для создания удобных отчетов и получения рекомендаций по оптимизации
  • Streamline - комплексный профилировщик производительности, позволяющий фиксировать всю активность счетчиков
  • Mali Offline Compiler - для проверки того, как шейдерная программа будет работать на GPU Mali.
  • Графический анализатор - для отладки вызовов графического API и анализа отображения содержимого
Советник по производительности

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

Советник по производительности - Резюме по захвату
Советник по производительности - Резюме по захвату

В течение первых 2 минут игры Performance Advisor сообщает нам, что в среднем мы делаем всего 17 кадров в секунду. Зеленый участок в начале графика анализа частоты кадров указывает на то, что игра загружается, а затем внезапно график становится синим, указывая на то, что игра стала привязана к фрагментам, и остается таким на протяжении всего времени. Это означает, что графический процессор устройства с трудом справляется с обработкой фрагментов, что говорит о том, что игра либо запрашивает слишком много работы, либо неэффективно обрабатывает пиксели.

Поскольку мы добавили в игру аннотации к регионам, на графике анализа частоты кадров отображаются наши собственные названия регионов. Там, где на графике есть маркер с надписью "S", Performance Advisor сделал скриншот игры, чтобы помочь нам определить, что происходит на экране в этот момент. Вы можете настроить захват экрана, когда частота кадров в секунду падает ниже указанного значения. Здесь, поскольку FPS остается низким на протяжении всего времени, Performance Advisor делает снимок экрана с интервалом по умолчанию - каждые 200 кадров.

Взгляните на график циклов GPU на кадр, где мы добавили бюджет в 28 миллионов циклов на кадр для этого устройства. Мы подсчитали, что это максимальное количество циклов, которое может выдержать данное устройство, при этом обеспечивая частоту кадров 30 fps. Здесь мы видим, что количество циклов GPU значительно превышает этот бюджет, и что количество циклов увеличивается со временем.

Performance Advisor - циклы GPU на кадр
Performance Advisor - циклы GPU на кадр

Performance Advisor дает рекомендации по оптимизации, когда обнаруживает проблему. Если мы посмотрим на график циклов шейдера на кадр, то увидим, что количество циклов движка исполнения велико. Внутри шейдерного ядра Mali механизм выполнения отвечает за обработку арифметических операций. Performance Advisor отметил это как проблему и советует нам уменьшить вычисления в шейдерах.

Performance Advisor - циклы шейдеров на кадр
Performance Advisor - циклы шейдеров на кадр

Для этого есть простое решение. Вы можете снизить точность шейдерных переменных до среднего уровня (mediump), а не высокого (highp), без заметных изменений на экране. Это позволит значительно снизить стоимость шейдеров. Информацию о том, как это сделать, можно найти в разделе Типы данных шейдеров и точность в нашей документации. Кроме того, как мы выяснили ранее с помощью отладчика кадров Unity, игра в настоящее время рендерится в полноэкранном разрешении устройства. Любые изменения, которые мы сделаем для уменьшения разрешения рендеринга игры (до 1080p или 720p), также уменьшат стоимость затенения фрагментов.

Метрики контента

Мы установили для этого устройства бюджет в 500 000 вершин на кадр. Бюджет превышен примерно на 45-й секунде, и с течением времени его количество неуклонно растет.

Performance Advisor - Вершины на кадр
Performance Advisor - Вершины на кадр

Глядя на график примитивов на кадр, мы замечаем, что общее количество обрабатываемых примитивов со временем увеличивается, хотя количество видимых примитивов остается относительно постоянным. В первые 2 минуты игры единственные новые объекты, которые создаются, - это вражеские NPC, которые затем уничтожаются взрывом молнии нашим героем. Это говорит о том, что когда враги уничтожены, их геометрия все еще присутствует, хотя и не видна.

Performance Advisor - Примитивы на кадр
Performance Advisor - Примитивы на кадр

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

Оптимизация анализа

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

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

Графические процессоры на базе Mali, обрабатывающие графические нагрузки
Графические процессоры на базе Mali, обрабатывающие графические нагрузки

Мы уже знаем, что GPU в устройстве максимально загружен работой с фрагментами, поэтому нам нужно искать способы снизить нагрузку на этап обработки пикселей.

Один из способов снизить нагрузку на обработку пикселей - уменьшить сложность геометрии, которая отправляется на обработку пикселей в первую очередь. Геометрия, которая полностью выходит за пределы экрана или обращена назад, уничтожается перед обработкой пикселей, но маленькие треугольники, которые лишь частично покрывают квадраты 2×2 пикселя, могут снижать эффективность фрагментов и иметь высокую стоимость полосы пропускания на один выходной пиксель.

Графики Mali Geometry Usage и Mali Geometry Culling Rate в Streamline показывают, насколько эффективно GPU обрабатывает геометрию. Мы видим, сколько примитивов отправляется на GPU и сколько из них отсеивается в процессе обработки геометрии. Работы, отсеянные на этом этапе, не попадут в пиксельную обработку. Это хорошая новость, но мы могли бы организовать содержимое более эффективно, чтобы невидимые примитивы вообще не передавались.

Графики использования геометрии Мали и коэффициента выбраковки геометрии Мали в Streamline
Графики использования геометрии Мали и коэффициента выбраковки геометрии Мали в Streamline

На графике Mali Geometry Usage мы видим, что 1,07 миллиона примитивов поступают на обработку геометрии (оранжевая линия) в выбранном временном интервале (около 0,05 секунды), но 700 000 примитивов отсеиваются на этом этапе (красная линия).

Диаграмма Mali Geometry Culling Rate показывает, почему они выбраковываются. Около половины из них отсеиваются тестом "лицом к лицу" (оранжевая линия), что вполне ожидаемо, так как это треугольники, обращенные к спине наших 3D-объектов. Что еще более тревожно, так это то, что 31,9 % примитивов отсеиваются выборочным тестом (фиолетовая линия) - в идеале это число должно составлять менее 5 %. Тест образца показывает, что эти примитивы были слишком малы для растеризации, не попав ни в одну точку образца, и поэтому считаются невидимыми. Это может произойти, когда объекты со сложной сеткой расположены далеко от камеры, а треугольники в сетке слишком малы, чтобы быть видимыми. Более высокие цифры могут указывать на то, что сетки игровых объектов слишком сложны для их расположения на экране.

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

Крошечные треугольники, попадающие в подмножество пикселей внутри квадрата
Крошечные треугольники, попадающие в подмножество пикселей внутри квадрата

Чтобы проверить, есть ли у нас проблема с микротреугольниками, мы можем использовать график Mali Core Workload Property в Streamline для мониторинга эффективности покрытия. В идеале этот показатель должен составлять менее 10%. Мы видим, что в некоторых разделах уровень частичного покрытия (зеленая линия) очень высок, более 70 %. Это значение говорит о высокой плотности микротреугольников в контенте, что подтверждает проблему, отмеченную ранее высоким уровнем отсеивания образцов.

Mali Core Workload Property chart
Mali Core Workload Property chart

Геометрия, которая попадает на экран, должна иметь соответствующий размер для своего положения. Сложный пейзаж, расположенный вдали, не нужно очень детализировать, так как он не вносит особого вклада в сцену. Мы можем использовать сетки LOD (Level Of Detail)для объектов, находящихся на большом расстоянии от камеры, чтобы уменьшить сложность и сэкономить вычислительную мощность и пропускную способность DRAM. Или, вместо геометрии, мы можем использовать текстуры и карты нормалей для создания деталей поверхности объектов.

Анализ шейдеров

Благодаря отчету Performance Advisor мы обнаружили, что наши шейдеры могут быть слишком дорогими, и что мы могли бы выиграть от снижения их точности. В Streamline мы можем использовать график использования Mali varing usage, чтобы увидеть количество циклов, в которых активна 32-битная (высокой точности) или 16-битная (средней точности) интерполяция. Здесь мы видим, что в большинстве циклов используется 32-битная интерполяция. 16-битные переменные интерполируют в два раза быстрее, чем 32-битные, и используют вдвое меньше места в регистрах шейдера для хранения результатов интерполяции, поэтому рекомендуется по возможности использовать средние (16-битные) изменяющиеся входы во фрагментных шейдерах.

Мали Различная диаграмма использования
Мали Различная диаграмма использования
Анализ шейдеров с помощью Mali Offline Compiler

Для изучения шейдеров мы можем использовать инструмент статического автономного компилятора ARM Mobile Studio, чтобы быстро проанализировать шейдерную программу.

Для этого вам нужно взять код шейдера из скомпилированного файла, который Unity предоставляет вам, а затем запустить Mali Offline Compiler на этом файле:

1. В Unity выберите шейдер, который вы хотите проанализировать, либо непосредственно из папки assets, либо выбрав материал, нажав на значок шестеренки и выбрав Select shader.

2. Выберите Compile и отобразите код в Инспекторе. Скомпилированный код шейдера откроется в вашем стандартном редакторе кода. Этот файл содержит несколько вариантов кода шейдера.

3. Скопируйте вариант вершинного или фрагментного шейдера из этого файла в новый файл, присвоив ему расширение.vert или .frag. Вершинные шейдеры начинаются с #ifdef VERTEX, а фрагментные - с #ifdef FRAGMENT. Они заканчиваются соответствующими #endif. (Не включайте в новый файл операторы #ifdef и #endif).

4. В командном терминале запустите Mali Offline Compiler на этом файле, указав GPU, который вы хотите протестировать. Например: malioc -c Mali-G72 myshader.frag Дополнительные инструкции см. в разделе Начало работы с Mali Offline Compiler.

Мы решили проанализировать фрагментный шейдер, отвечающий за эффект растворения, который возникает при смерти вражеских NPC. Вот отчет Mali Offline Compiler с выделенными разделами, представляющими интерес:

Отчет о работе автономного компилятора Mali

Мы видим, что только 2% арифметических вычислений эффективно выполняются с 16-битной точностью. Шейдер будет работать эффективнее, если мы снизим точность с highp до mediump. Это снижает потребление энергии и давление в регистре, а также позволяет удвоить производительность. Есть ситуации, в которых всегда требуется высокая точность, например, при расчете положения и глубины, но во многих случаях при снижении точности до средней разницы на экране практически не заметно.

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

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

Мы также видим, что шейдер может изменять маску покрытия фрагмента, определяющую, какие точки выборки в каждом пикселе покрываются фрагментом, и использовать оператор discard для отбрасывания фрагментов ниже альфа-порога. Шейдеры с изменяемым покрытием должны использовать позднее обновление ZS, что может снизить эффективность раннего тестирования ZS и планирования фрагментов для последующих фрагментов в той же координате. По возможности следует свести к минимуму использование операторов отбрасывания и альфа-охвата во фрагментных шейдерах. Обратитесь к руководству Arm Mali Best Practices для получения рекомендаций по использованию утверждений об отбрасывании.

Анализ вызовов графического API с помощью Graphics Analyzer

В графическом анализаторе ARM Mobile Studio вы можете увидеть все вызовы графического API, которые совершило приложение, и пройтись по ним один за другим, чтобы увидеть, как строится сцена. Это помогает выявить объекты, которые слишком сложны для их экранного размера и расстояния до камеры. Вот несколько примеров, которые мы нашли в этой игре:

Кирпичная кладка в дальнем углу сцены построена с помощью геометрии и использует 2064 вершины. Детали не очень заметны в конечном результате, так что это напрасная обработка.

Образец кирпичной кладки в 2064 вершинах
Образец кирпичной кладки в 2064 вершинах

Мы обнаружили ту же проблему для напольных плиток - каждая из них имеет 1170 вершин, но, несмотря на то, что объект находится близко к камере, сцена не очень выигрывает от такой сложности. Было бы эффективнее использовать здесь карту нормалей для отображения неровностей и угловых граней, а не строить ее из треугольников. Кроме того, мы видим, что эти объекты рисуются с помощью отдельных вызовов draw. Сокращение количества вызовов рисования за счет пакетной обработки объектов или использования инстанцирования объектов может повысить производительность.

Образец напольной плитки в 1170 вершинах
Образец напольной плитки в 1170 вершинах

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

Образец статуи в 6966 вершинах
Образец статуи в 6966 вершинах

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

Оптимизация игры

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

Фиксированный временной интервал

Fixed Timestep - это интервал, не зависящий от частоты кадров, который управляет выполнением расчетов физики и событий FixedUpdate(). По умолчанию он настроен на 50 кадров в секунду. Если на мобильных устройствах высокого класса 50 или даже 60 fps вполне приемлемы, то на более распространенных устройствах они составляют 30 fps, на которые и ориентирована эта игра. Зайдите в Edit > Project Settings, а затем в категорию Time, чтобы установить для свойства Fixed Timestep значение 0.04. Это обеспечит синхронизацию расчетов физики, функции FixedUpdate() и обновлений.

Установка фиксированного временного интервала на 0,04 в настройках проекта
Установка фиксированного временного интервала на 0,04 в настройках проекта

После внесения изменений в фиксированный Timestep в Unity часть основного цикла игры с фиксированным обновлением вызывалась только один раз за кадр, в среднем 1,5 мс. Это огромное улучшение по сравнению с 12 мс, которые требовались ранее, и простое решение распространенной проблемы производительности.

Папка с ресурсами

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

Рекомендуемый метод работы с активами и ресурсами для улучшения потребления памяти - это система Addressables Asset System, которая обеспечивает эффективный способ выгрузки из памяти содержимого, которое больше не нужно.

Инстансирование GPU

В нашем окружении есть множество объектов, которые появляются несколько раз. Стены, напольная плитка и другие реквизиты окружения дублируются, чтобы создать эту сцену. Мы можем сэкономить вызовы рисования, включив инстансирование GPU для материала объектов. Инстансирование на GPU позволяет отрисовывать идентичные сетки с помощью небольшого количества вызовов рисования и позволяет каждому экземпляру иметь различные параметры, такие как цвет или масштаб. Эта модификация может увеличить производительность процессора. Ниже показаны данные Performance Advisor до включения инсталлирования GPU.

Данные до включения инстансинга GPU
Данные до включения инстансинга GPU

А здесь вы видите ту же часть приложения, но с включенным GPU-инстансом - небольшой, но ощутимый прирост к нашей цели в 30 кадров в секунду.

Данные с включенной инстанцией GPU
Данные с включенной инстанцией GPU
Рендеринг текстур

Рендерные текстуры - это способ добавить 3D-элементы в пользовательский интерфейс, а также множество других вариантов использования. Если камера рендерится в текстуру рендера, не забудьте отключить ее, когда она не на экране. Нет необходимости отображать то, что пользователь не увидит. Используйте Graphics Analyzer или Frame Debugger в Unity, чтобы убедиться, что эти текстуры не обновляются за пределами экрана.

Объединение объектов в пул

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

Благодаря переходу на объединение объектов, волны врагов, появляющиеся на экране, не стали шипами, что можно определить по снимкам Unity Profiler, а также не оказали заметного влияния на частоту кадров.

Сетки с уровнем детализации (LOD)

Когда сетка находится на экране, GPU тратит время на рендеринг всех треугольников сетки, независимо от того, насколько они малы. В играх, где камера или объекты могут двигаться, это часто создает ситуацию, когда вы можете потратить много ресурсов GPU на рендеринг треугольников сетки, которые слишком малы, чтобы их можно было увидеть в кадре. Чтобы решить эту проблему, используйте сетки с уровнем детализации (LOD). Это позволяет вашей игре использовать менее сложные сетки по мере удаления камеры от объектов, что снижает сложность сетки, которую должен отрисовывать GPU, и уменьшает количество вершин в кадре, предоставляя больше треугольников для обработки пикселей. Это не только повышает эффективность, но и сохраняет художественную целостность сцены.

LOD Meshes
LOD Meshes

Другие советы по оптимизации активов можно найти в руководствах для гейм-художников от Arm.

Атласы текстур

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

Плавающая и половинная точность шейдера

При написании собственных шейдеров или использовании Shader Graph вы можете выбрать, какую точность использовать: float или half. Выбор половины, где это возможно, сделает шейдеры более производительными - но помните, что вам, скорее всего, придется использовать float для всего, что имеет дело с позициями в мировом пространстве или вычислениями глубины!

Установка точности в половину в графике шейдеров
Установка точности в половину в графике шейдеров
Интегрированный набор функций по сравнению с Post Processing V2

Когда вы начинаете планировать эффекты постобработки для своего проекта, у вас есть два варианта на выбор: старый набор функций Integrated или новый набор функций Post Processing v2. Ниже вы можете увидеть игру с использованием интегрированного набора функций.

GPU Profiler без Post Processing v2
GPU Profiler без Post Processing v2

Каждые 3-4 кадра мы видим всплеск V-Sync, когда система ожидает кадр для рендеринга. В результате игра постоянно падает ниже 30 FPS и расходует энергию устройства. Здесь вы можете увидеть данные профилировщика игры с использованием тех же эффектов, но с набором функций Post Processing v2.

GPU Profiler with Post Processing v2
GPU Profiler with Post Processing v2

Этот график профилирования намного лучше, поскольку Post Processing v2 оптимизирован для работы на мобильном оборудовании. Используйте его в своем проекте, чтобы добиться максимальной производительности при постобработке.

Эффекты постобработки

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

После того как были проведены другие оптимизации, в некоторых областях мы по-прежнему наблюдали скачки. Используя двоичный поиск, включая и выключая разные вещи, мы в конце концов обнаружили две вещи: Одним из них был используемый стек постобработки. Это помогло сократить общее время, но частота кадров в итоге выровнялась, как только мы отключили сглаживание - настолько, что часть постобработки смогла остаться включенной даже на самых низкопрофильных устройствах, которые мы использовали для тестирования.

GPU Profiler - оптимизированный пример
GPU Profiler - оптимизированный пример

Оптимизировав игру, мы снова прогнали ее через Arm Mobile Studio, чтобы найти отличия. Отчет Performance Advisor теперь показывает, что мы достигли среднего fps 28,9 (ранее 17) и уменьшили общую ограниченность фрагментов. Активность фрагментов в некоторых разделах игры все еще высока, так что нам еще есть над чем работать, но с хорошими данными, направляющими наше исследование, мы сможем оптимизировать эти разделы для дальнейшего повышения производительности.

Arm Mobile Studio - краткое описание захвата
Arm Mobile Studio - краткое описание захвата

Количество вершин на кадр теперь значительно ниже нашего бюджета в 500 000, и вы можете видеть регулярные провалы, когда вражеские NPC уничтожаются.

Arm Mobile Studio - Вершины на кадр
Arm Mobile Studio - Вершины на кадр

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

Использование геометрии Мали и коэффициент очистки
Использование геометрии Мали и коэффициент очистки
В итоге

Используя профилировщик Unity и отладчик кадров, а также Arm Mobile Studio, мы смогли найти множество способов повысить производительность и снизить нагрузку на CPU и GPU мобильного устройства. Некоторых из выявленных нами проблем можно избежать в будущих изданиях, если придерживаться лучших практик работы с контентом.

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

Проактивное тестирование производительности

Тестирование производительности часто происходит на поздних этапах разработки. Это здорово - найти дополнительные возможности для оптимизации, но что делать, если нет времени исправить проблемы до окончания срока выпуска? Гораздо практичнее изначально разрабатывать контент оптимальным образом. Может быть полезно установить бюджеты на содержание в зависимости от сложности сетки, сложности шейдеров и сжатия текстур, чтобы дать вашей команде больше шансов на эффективный дизайн для мобильных устройств. Вот несколько ресурсов, которые могут помочь вашей команде:

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

Команды, использующие систему непрерывной интеграции, могут воспользоваться преимуществами автоматизированного тестирования производительности, доступного в профессиональной версии Arm Mobile Studio. Эта версия может работать на нескольких устройствах в ферме устройств и избавляет от необходимости вручную выполнять профилирование. Полученные данные могут быть переданы в любую JSON-совместимую базу данных, чтобы вы могли создавать визуальные панели и оповещения для отслеживания изменений производительности с течением времени и более раннего выявления проблем.

Никогда не пробовали инструменты для профилирования?

Встроенный в Unity профилировщик - отличное место для начала. О том , как создать профиль приложения, читайте в документации Unity. Или изучите отладчик фреймов, который позволяет исследовать, как строится отдельный фрейм.

Загрузите Arm Mobile Studio бесплатно с сайта Arm Developer и ознакомьтесь со стартовыми руководствами для Performance Advisor, Streamline, Mali Offline Compiler и Graphics Analyzer, чтобы быстро приступить к работе.

Свяжитесь с нами

Для получения дополнительной помощи по профилированию с помощью профилировщика Unity и отладчика кадров, пожалуйста, задавайте вопросы на нашем форуме.

За дополнительной поддержкой при работе с устройствами Mali или Arm Mobile Studio обращайтесь на форум Arm's Graphics and Gaming Forum, где вы можете задавать вопросы, и Arm будет рада помочь.