Библиотека Frame Pacing. Часть комплекта разработки игр для Android .

Библиотека Android Frame Pacing, также известная как Swappy, входит в состав библиотек AGDK . Она обеспечивает плавный рендеринг и корректный темп кадров в играх 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 в вашу игру, ознакомьтесь с одним из следующих руководств:

Дополнительные ресурсы