Советы по оптимизации ЦП и ГП

В этом документе показано, как оптимизировать производительность игр с помощью инструментов для выявления и устранения узких мест, связанных с процессором и видеокартой.

Оптимизация ЦП

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

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

инструменты трассировки времени игрового движка

В проведении этого анализа могут помочь следующие инструменты:

Невероятные открытия

В проектах Unreal Engine инструмент Unreal Insight Tool упрощает анализ информации о временных параметрах отдельных потоков, составляющих кадр.

В качестве примера, поток GameThread обычно использует наибольшую долю процессорного времени, в основном за счет времени тактов (Tick Time). Кроме того, значительная часть времени тактов расходуется на задачи, связанные с FActorComponentTickFunction .

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

График трассировки Unreal Insight, показывающий время выполнения потоков GameThread, RenderThread и RHIThread.
Трассировка Unreal Engine с использованием GameThread, RenderThread и RHIThread (нажмите для увеличения).

Профайлер Unity (Unity)

Анализ с помощью Unity Profiler показывает, что основной поток потребляет более 45 мс, при этом PostLateUpdate.FinishFrameRendering занимает 16,23 мс, что делает его наиболее ресурсоемкой операцией. При этом наблюдается множество вызовов Inl_RenderCameraStack. Рекомендуется определить необходимость включения камер и оптимизировать их соответствующим образом.

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

Инструменты профилирования на системном уровне

Используйте следующие инструменты профилирования:

Перфетто

С помощью Perfetto Trace можно определить назначение ядер ЦП и подробные сведения о выполнении каждого потока на устройстве под управлением Android. Это позволяет выявлять узкие места в производительности путем анализа данных о выполнении потоков.

корпус для размещения процессора

Трассировка показывает, что нагрузка на потоки GameThread и RenderThread вызывает задержки в отображении QueuePresent потока RHI, что приводит к ситуации, когда производительность процессора ограничена из-за VSync.

Трассировка Perfetto показывает время выполнения потоков GameThread, RenderThread и RHIThread.
Трассировка Perfetto с подробными сведениями о выполнении на ЦП (нажмите для увеличения).

Корпус для графического процессора

Трассировка показывает, что само завершение работы графического процессора занимает более 25 мс, что свидетельствует о ситуации, когда производительность графического процессора ограничена.

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

Simpleperf

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

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

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

Оптимизация графического процессора

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

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

В следующих разделах описаны методы и инструменты для оптимизации работы графического процессора.

Удалите ненужные RenderPasses

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

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

  1. Отсутствие вызовов отрисовки: Проверьте, содержит ли проход рендеринга какие-либо вызовы отрисовки. Если вызовов отрисовки нет, удалите проход.

  2. Неиспользуемый выходной сигнал: проверьте, обращаются ли последующие проходы к выходным данным прохода рендеринга или отображают их, например, цвет или глубину. Если нет, удалите проход.

  3. Объединяемые проходы: Определите проходы, которые можно объединить:

    • Тот же буфер кадров или вложения
    • Совместимые операции по погрузке или хранению.
    • Отсутствие барьеров зависимости между ними
В браузере событий RenderDoc отображаются проходы рендеринга и вызовы отрисовки Vulkan.
Последовательность команд RenderPass и GPU в RenderDoc (нажмите для увеличения).

Минимизируйте операции по загрузке или хранению.

Операции загрузки или сохранения данных требуют значительных ресурсов, поскольку используют большой объем памяти. Сведите к минимуму ненужные операции загрузки и сохранения. Выполняйте эти действия только тогда, когда требуются вложения внутри RenderPass . В противном случае замените их операциями Clear или Don't care чтобы уменьшить накладные расходы.

Как оптимизировать

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

  1. Загрузка: Если вложенный проход рендеринга не использует данные из предыдущего прохода или вложения, операция загрузки не требуется. В таких случаях использование параметров Don't care или Clear может уменьшить накладные расходы.

  2. Сохранение: Если после текущего прохода рендеринга не используется привязка прохода рендеринга, операция сохранения не требуется. В таких случаях используйте либо Don't care , либо Clear .

  3. Заменить: Определите, можно ли заменить текущие настройки загрузки или сохранения на Clear или Don't Care без влияния на итоговый кадр.

Браузер событий и инспектор ресурсов RenderDoc анализируют компоновку изображений и проходы рендеринга.
Анализ конвейера рендеринга RenderDoc (нажмите для увеличения).

Избегайте отбрасывания, чтобы включить Early-Z.

Технология Early-Z повышает производительность на мобильных платформах. Однако инструкция discard внутри шейдера автоматически отключает Early-Z. Если инструкция discard не является необходимой, удалите её.

Раннее Z-ускорение

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

Раннее тестирование глубины Z и трафарета

Таблица, сравнивающая показатели производительности ЦП и ГП при включенной и выключенной функции Early-Z.
Влияние ускорения Early-Z на производительность (нажмите для увеличения).

Как оптимизировать

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

  1. Использование ключевого слова discard во фрагментных шейдерах: ключевое слово discard предотвращает выполнение графическим процессором предварительных проверок глубины, поскольку видимость фрагмента заранее неизвестна.

  2. Изменение параметра gl_FragDepth : Динамическое изменение gl_FragDepth изменяет глубину фрагмента, что отключает оптимизацию Early-Z, поскольку конечная глубина неизвестна до обработки фрагмента.

  3. Включение альфа-канала для покрытия фрагментов: Когда включен альфа-канал для покрытия фрагментов (часто используется в рендеринге MSAA), покрытие фрагментов зависит от значений альфа-канала. Это может замедлить проверку глубины и отключить функцию Early-Z.

Сравнение количества фрагментов на пиксель с использованием и без использования ключевого слова шейдера discard.
Отладчик RenderDoc для графического процессора для анализа (нажмите для увеличения).

Оптимизировать формат текстур

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

Как оптимизировать

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

  1. Используйте D24S8 вместо D32S8 для буферов глубины и трафарета: использование D24S8 для буферов глубины и трафарета снижает потребление памяти на 20% по сравнению с D32S8 , при этом практически не наблюдается заметной разницы в качестве изображения в большинстве приложений.
  2. Используйте сжатие ASTC для цветных текстур: сжатие ASTC значительно сокращает объем памяти, используемой для текстур, — до 8 раз по сравнению с несжатыми форматами — при сохранении высокого визуального качества.
  3. Используйте форматы с половинной плавающей запятой вместо форматов с полной плавающей запятой: используйте R16F или RG16F для уменьшения пропускной способности памяти и потребления памяти. Эти форматы хорошо подходят для буферов постобработки.

Оптимизация сложности геометрии

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

Как оптимизировать

Используйте инструменты профилирования и отладчики графического процессора, такие как RenderDoc , Android GPU Inspector или другие анализаторы производительности, чтобы выявить узкие места в производительности, связанные с геометрией.

  1. Уменьшите количество треугольников: сведите к минимуму использование полигонов, особенно для небольших или удаленных объектов.

  2. Используйте уровень детализации (LOD): в зависимости от расстояния до камеры автоматически используются более простые сетки.

  3. Объединение небольших сеток: консолидация статических объектов для уменьшения количества вызовов отрисовки и нагрузки на процессор.

  4. Отсечение по пирамиде видимости и окклюзии: Избегайте отрисовки объектов, находящихся за пределами поля зрения или заслоненных другими элементами.

Удалите ненужные вложения

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

Как оптимизировать

Используйте инструменты профилирования и отладчики графического процессора, такие как RenderDoc , Android GPU Inspector или другие анализаторы производительности, чтобы выявить узкие места в производительности, связанные с геометрией.

  1. Проверьте фактическое использование: есть ли какие-либо вызовы отрисовки или шейдеры, которые записывают или считывают данные из прикрепленного файла?
  2. Проанализируйте выходные данные кадра: используйте RenderDoc или аналогичные утилиты, чтобы определить, вносит ли прикрепленный файл вклад в итоговое изображение.
  3. Рассмотрите возможность использования временных или фиктивных подключений: для временных данных, не требующих постоянного хранения, следует использовать временные подключения или операцию сохранения "Don't Care".

Оптимизация точности шейдеров

Использование чрезмерно высокой точности (например, highp вместо mediump или lowp ) в шейдерах увеличивает нагрузку на графический процессор, энергопотребление и нагрузку на регистры, особенно на мобильных графических процессорах. Использование минимально необходимой точности для переменных (например, позиций, цветов, UV-координат) позволяет повысить производительность без заметного визуального эффекта.

Таблица, сравнивающая показатели производительности ЦП и ГП при использовании точности шейдеров mediump и highp.
Влияние точности шейдеров на производительность (нажмите для увеличения).

Как оптимизировать

Используйте инструменты профилирования и отладчики графического процессора, такие как RenderDoc, Android GPU Inspector или другие анализаторы производительности, чтобы выявить узкие места в производительности, связанные с геометрией.

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

  2. Используйте отладчики графического процессора: диагностические утилиты, такие как RenderDoc или мобильные профилировщики графических процессоров (например, AGI, Mali/GPU Inspector), выявляют повышенное использование регистров или задержки шейдеров, связанные с проблемами точности.

Профилировщик Mali Varying Usage отображает 16-битную интерполяцию вместе с кодом шейдера, используя mediump.
Пример инструментов профилирования и отладчиков графического процессора (нажмите для увеличения).

Включить отсечение задних граней

Для твердых объектов часто нет необходимости отображать треугольники, обращенные от камеры (задние грани).

Как оптимизировать

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

В логе команд Vulkan отображается значение vkCmdSetCullMode, равное VK_CULL_MODE_NONE.
Журналы отладки с отсечением задних граней (нажмите для увеличения).

Свести к минимуму избыточное отображение в сценах пользовательского интерфейса.

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

Как оптимизировать

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

  1. Проверьте отсутствие излишнего перерисовывания. В контексте пользовательского интерфейса, где может отображаться весь экран, убедитесь, что предыдущие проходы рендеринга не перерисовываются без необходимости.
  2. Включите проверку глубины и отсечение для оптимизации производительности.
  3. Рассмотрите возможность отображения в порядке от переднего плана к заднему.
Браузер событий RenderDoc и средство просмотра текстур выявляют ненужный проход рендеринга с избыточным отображением.
Пример устранения лишних вызовов отрисовки и проходов рендеринга (нажмите для увеличения).