Библиотека кадровой синхронизации . Часть комплекта разработки игр для Android .

Библиотека Android Frame Pacing, также известная как Swappy, является частью AGDK Libraries . Это помогает играм OpenGL и Vulkan добиться плавного рендеринга и правильной частоты кадров на Android. В этом документе определяется синхронизация кадров, описываются ситуации, когда необходима синхронизация кадров, и показано, как библиотека решает эти ситуации. Если вы хотите сразу перейти к реализации синхронизации кадров в вашей игре, см. Следующий шаг .

Фон

Скорость кадров — это синхронизация логики игры и цикла рендеринга с подсистемой отображения ОС и базовым аппаратным обеспечением дисплея. Подсистема отображения Android была разработана так, чтобы избежать визуальных артефактов (известных как разрывы ), которые могут возникнуть, когда аппаратное обеспечение дисплея переключается на новый кадр во время обновления. Чтобы избежать этих артефактов, подсистема отображения делает следующее:

  • Внутренне буферизует прошлые кадры
  • Обнаруживает позднюю отправку кадров
  • Повторяет отображение прошлых кадров при обнаружении поздних кадров.

Игра сообщает SurfaceFlinger , компоновщику в подсистеме отображения, что она отправила все вызовы отрисовки, необходимые для кадра (путем вызова eglSwapBuffers или vkQueuePresentKHR ). SurfaceFlinger сигнализирует о доступности кадра аппаратному обеспечению дисплея с помощью защелки. Затем аппаратное обеспечение дисплея отображает данный кадр. Аппаратное обеспечение дисплея тикает с постоянной частотой, например 60 Гц, и если нет нового кадра, когда он необходим оборудованию, оборудование снова отображает предыдущий кадр.

Несогласованное время кадра часто возникает, когда цикл рендеринга игры выполняется с частотой, отличной от скорости родного оборудования дисплея. Если игра, работающая со скоростью 30 кадров в секунду, пытается выполнить рендеринг на устройстве, которое изначально поддерживает 60 кадров в секунду, цикл рендеринга игры не учитывает, что повторяющийся кадр остается на экране еще 16 миллисекунд. Это отключение обычно приводит к существенной несогласованности времени кадра, например: 49 миллисекунд, 16 миллисекунд, 33 миллисекунды. Чрезмерно сложные сцены еще больше усугубляют эту проблему, поскольку приводят к пропущенным кадрам.

Неоптимальные решения

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

Отправляйте кадры так быстро, как позволяет API рендеринга.

Этот подход связывает игру с переменной активностью SurfaceFlinger и вводит дополнительный кадр задержки. Конвейер отображения содержит очередь кадров, обычно размером 2, которая заполняется, если игра пытается отображать кадры слишком быстро. Когда в очереди больше нет места, игровой цикл (или, по крайней мере, поток рендеринга) блокируется вызовом OpenGL или Vulkan. Затем игра вынуждена ждать, пока аппаратное обеспечение дисплея покажет кадр, и это противодавление синхронизирует два компонента. Эта ситуация известна как заполнение буфера или заполнение очереди . Процесс рендеринга не понимает, что происходит, поэтому несоответствие частоты кадров ухудшается. Если игра производит выборку входных данных до кадра, задержка ввода увеличивается.

Используйте Android Choreographer отдельно

Игры также используют Android Choreographer для синхронизации. Этот компонент, доступный в Java из API 16 и в C++ из API 24, обеспечивает регулярные тики с той же частотой, что и подсистема отображения. Все еще существуют тонкости относительно того, когда этот тик доставляется относительно фактического аппаратного VSYNC, и эти смещения различаются в зависимости от устройства. Заполнение буфера все еще может происходить для длинных кадров.

Преимущества библиотеки Frame Pacing

Библиотека Frame Pacing использует Android Choreographer для синхронизации и обеспечивает вариативность доставки тиков за вас. Он использует временные метки представления, чтобы гарантировать, что кадры представлены в нужное время, и ограничивает синхронизацию, чтобы избежать переполнения буфера. Библиотека использует NDK Choreographer , если он доступен, и обращается к Java Choreographer, если его нет.

Библиотека поддерживает несколько частот обновления, если они поддерживаются устройством, что дает игре большую гибкость при представлении кадра. Например, для устройства, которое поддерживает частоту обновления 60 Гц, а также 90 Гц, игра, которая не может воспроизводить 60 кадров в секунду, может снизить частоту кадров до 45 кадров в секунду вместо 30 кадров в секунду, чтобы оставаться плавной. Библиотека определяет ожидаемую частоту кадров в игре и соответствующим образом автоматически корректирует время представления кадров. Библиотека Frame Pacing также увеличивает время автономной работы, поскольку позволяет избежать ненужных обновлений дисплея. Например, если игра рендерится со скоростью 60 кадров в секунду, но дисплей обновляется с частотой 120 Гц, экран обновляется дважды для каждого кадра. Библиотека Frame Pacing позволяет избежать этого, устанавливая частоту обновления на значение, поддерживаемое устройством, которое наиболее близко к целевой частоте кадров.

Как это работает

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

Правильная частота кадров при 30 Гц

При рендеринге с частотой 30 Гц на устройстве с частотой 60 Гц идеальная ситуация на Android показана на рисунке 1. SurfaceFlinger фиксирует новые графические буферы, если они есть (обратите внимание, что на диаграмме указано «нет буфера», а предыдущий повторяется).

Идеальная частота кадров при частоте 30 Гц на устройстве с частотой 60 Гц

Рисунок 1. Идеальная частота кадров при частоте 30 Гц на устройстве с частотой 60 Гц.

Короткие игровые кадры приводят к заиканию

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

Короткие игровые кадры

Рисунок 2. Кадр C короткой игры приводит к тому, что кадр B представляет только один кадр, за которым следуют несколько кадров C.

Библиотека Frame Pacing решает эту проблему, используя временные метки представления. Библиотека использует расширения меток времени презентации EGL_ANDROID_presentation_time и VK_GOOGLE_display_timing , чтобы кадры не представлялись раньше, как показано на рисунке 3.

Временные метки презентации

Рис. 3. Игровой кадр B представлен дважды для более плавного отображения.

Длинные кадры приводят к заиканию и задержкам

Если рабочая нагрузка дисплея превышает рабочую нагрузку приложения, в очередь добавляются дополнительные кадры. Это снова приводит к заиканию, а также может привести к задержке дополнительного кадра из-за заполнения буфера (см. рисунок 4). Библиотека устраняет как заикание, так и дополнительный кадр задержки.

Длинные игровые фреймы

Рисунок 4. Длинный кадр B дает неправильный темп для двух кадров — A и B.

Библиотека решает эту проблему, используя ограничения синхронизации ( EGL_KHR_fence_sync и VkFence ) для внедрения в приложение ожиданий, которые позволяют конвейеру отображения подстраиваться, а не позволяют создавать противодавление. Кадр A по-прежнему представляет дополнительный кадр, но кадр B теперь отображается правильно, как показано на рисунке 5.

Ожидания добавлены на уровень приложения

Рисунок 5. Кадры C и D ожидают представления

Поддерживаемые режимы работы

Вы можете настроить библиотеку Frame Pacing для работы в одном из трех следующих режимов:

  • Автоматический режим выключен + Конвейер
  • Автоматический режим включен + Конвейер
  • Автоматический режим включен + Автоматический режим конвейера (конвейерный/неконвейерный)

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

  swappyAutoSwapInterval(false);
  swappyAutoPipelineMode(false);
  swappyEnableStats(false);
  swappySwapIntervalNS(1000000000L/yourPreferredFrameRateInHz);

Конвейерный режим

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

Конвейерный режим

Рисунок 6. Конвейерный режим

Неконвейерный режим

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

Неконвейерный режим

Рисунок 7. Неконвейерный режим

Автоматический режим

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

  • Автоматически выбирать интервалы переключения : игры, которые обеспечивают 30 Гц в некоторых сценах и 60 Гц в других, могут позволить библиотеке динамически регулировать этот интервал.
  • Отключить конвейерную обработку для сверхбыстрых кадров : обеспечивает оптимальную задержку экрана ввода во всех случаях.

Несколько частот обновления

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

  • На устройствах с частотой 60 Гц : 60 кадров в секунду/30 кадров в секунду/20 кадров в секунду.
  • На устройствах с частотой 60 Гц + 90 Гц : 90 кадров в секунду/60 кадров в секунду/45 кадров в секунду/30 кадров в секунду.
  • На устройствах с частотой 60 Гц + 90 Гц + 120 Гц : 120 кадров в секунду/90 кадров в секунду/60 кадров в секунду/45 кадров в секунду/40 кадров в секунду/30 кадров в секунду

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

Дополнительные сведения о синхронизации кадров с несколькими частотами обновления см. в публикации блога «Рендеринг с высокой частотой обновления» в Android .

Статистика кадров

Библиотека Frame Pacing предлагает следующую статистику для целей отладки и профилирования:

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

Следующий шаг

Ознакомьтесь с одним из следующих руководств по интеграции библиотеки Android Frame Pacing в вашу игру: