javascript

Анализ производительности WebGL приложений

  • среда, 2 октября 2019 г. в 00:31:32
https://habr.com/ru/post/469145/
  • Высокая производительность
  • JavaScript
  • Разработка игр
  • WebGL


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

профилирование webgl


Понимание узких горлышек в рендере


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

  • Уменьшение количества полигонов при узком горлышке в фрагментном шейдере
    Единственное к чему данное действие приведет, это увеличение угловатости сцены и ухудшение ее качества. На самом деле, если угловатые модельки после этого станут занимать большее место на экране, то это может даже ухудшить производительность.
  • Уменьшение devicePixelRatio (разрешения) с мешем сцены чудовищного размера
    В этом случае, уменьшение разрешения в приложении только размылит картинку. К похожему результату приведет упрощение модели затенения и уменьшение текстур, когда проблема была с слишком большим количеством вершин в меше.
  • Переписывание на WASM при отсутствии нагрузки на цпу
    Если вы не производите никаких расчетов на js, а только скармливаете сцену видеокарте, то никакого ускорения от AssemblyScript/C++/Rust ждать не стоит. Все запросы на видеокарту выполняются асинхронно и она живет своей жизнью, за исключением нескольких синхронных команд readPixels(), finish(), getError(). Если у вас уже есть готовый рендер на js, о WASM стоит задумываться только когда фпс падает именно из-за цпу, например когда у вас нагруженный расчет физики, скининга, частиц или рейтрейсинга. В этих кейсах возможно изначально стоит писать на нем.

В общем случае, нужно находить операции с максимально большим вкладом, так как выигрыш от оптимизации операции которая занимает 1% всего времени несоизмеримо мал, чем от таковой с 60% вкладом. Так же нагрузку на CPU и GPU нужно профилировать отдельно, так как и то и другое не зависимо может приводить к тому, что FPS рендера в браузере будет снижен. Когда не хватает RAM, весь браузер начинает периодически дико тормозить из-за свопа, но при этом рендер работает шустро.

Циклическая оптимизация приложения


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

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


Что бы измерять CPU/GPU отдельно, я написал небольшой профайлер gl‑bench, который можно встраивать на страницу. Он независимо измеряет нагрузку в процентах и использует GPU таймеры из расширения EXT_disjoint_timer_query. Судя по тестам браузер снижает FPS, если какой то из параметров оказывается нагружен больше 60-80%, оставляя ресурсы для ОС. (Поддержите опенсорс лукасами).

По умолчанию FPS ограничено 60-ю кадрами в секунду, но можно отключить ограничение и получать 120+. Для этого надо зайти в NVIDIA Control Panel / Catalyst Control Center и отключить vsync, и запускать хром c флагом 'chrome.exe --disable-gpu-vsync --disable-frame-rate-limit', тут подробная инструкция по запуску флага на всех ос.

Для профилирования количества дравколов и состояния рендербуферов удобно использовать Spector.js. Для памяти на devtools. А для WASM есть свои инструменты.


Общий алгоритм по нахождению узких мест


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


Определение оптимального девайса для проверок


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


Статистика по поддержке WebGL расширений лучше учитывать отдельно, и она достаточно точная что бы ей можно доверять. Далее я рассчитал оптимальные устройства по статистике за 2019 на топ 10 айфонов и топ 10 андроидов, у меня получилась такая прикидка:


Оптимизация узких мест


Тут могли бы быть конкретные рекомендации как оптимизировать что либо, но статья была бы длиннее в 6-10 раз, если погружаться на должный уровень, поэтому я отправлю на соседнюю статью по оптимизации ассетов. Если коротко по шейдерам, то следует использовать оптимальную сложность геометрии, формат данных, точность вычислений, переиспользование данных, сложность текстур, их сжатие, mipmaping, фильтрации, вебжл дополнения, необходимые режимы, количество обращений к видеокарте, их сортировку, переключения состояний, количество компиляций, лучшую трансформацию систем координат, отсечения ненужных вычислений на различных этапах, убер-шейдеры, ветвление, обращение к текстурам, запаковки, константы, автоматические оптимизаторы и соответствующие алгоритмы для света, теней, материалов, msaa, ssao, ssr.