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

В Android 11 добавлена поддержка устройств с несколькими частотами обновления. Эта функция состоит из трех основных компонентов:

  • Новые HAL API, представленные в android.hardware.graphics.composer@2.4.
  • Код платформы для анализа конфигураций устройств с разной частотой обновления и установки нужной частоты обновления
  • Новые API SDK и NDK, позволяющие приложениям задавать желаемую частоту кадров

Реализация

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

Группы конфигурации

В IComposerClient::Attribute добавлен новый атрибут CONFIG_GROUP, который можно запросить с помощью getDisplayAttribute_2_4 API. Этот атрибут позволяет поставщикам группировать конфигурации дисплеев. В большинстве случаев между конфигурациями из одной группы можно легко переключаться. Платформа использует группу конфигурации, чтобы различать, какие конфигурации можно переключать, чтобы изменить частоту обновления, а не другие атрибуты конфигурации.

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

  • 1080p, 60 Гц
  • 1080p при 90 Гц
  • 1080i (72 Гц)
  • 1080i при 48 Гц

Хотя устройство поддерживает частоту обновления 48, 60, 72 и 90 Гц, экран работает в другом режиме, и переключение с 60 на 72 Гц меняет конфигурацию экрана с 1080p на 1080i, что может быть нежелательно. Группы конфигурации решают эту проблему. Если объединить 60 и 90 Гц в одну группу, а 48 и 72 Гц – в другую, платформа будет знать, что она может переключаться между 60 и 90 Гц, а также между 48 и 72 Гц, но не между 60 и 72 Гц, поскольку это приведет к изменению конфигурации, а не просто частоты обновления.

Обновления Composer API

getDisplayVsyncPeriod
Для более удобного управления частотой обновления и предсказуемости при ее изменении был добавлен параметр getDisplayVsyncPeriod. getDisplayVsyncPeriod возвращает текущую частоту обновления экрана (в периодах вертикальной синхронизации). Это особенно полезно при переходе между частотами обновления, когда платформе нужна текущая частота обновления, чтобы решить, когда начать следующий кадр.
setActiveConfigWithConstraints
Метод setActiveConfigWithConstraints – это новое расширение существующего метода setActiveConfig, которое предоставляет больше информации об изменении конфигурации. Ограничения задаются в параметрах vsyncPeriodChangeConstraints и содержат следующие параметры:
    desiredTimeNanos
    Время в CLOCK_MONOTONIC, после которого может измениться период вертикальной синхронизации (то есть до этого времени период вертикальной синхронизации меняться не должен). Это полезно, когда платформа хочет заранее запланировать изменение частоты обновления, но в очереди уже есть буферы для показа. Платформа устанавливает это время с учетом буферов, чтобы переход на другую частоту обновления был как можно более плавным.
    seamlessRequired
    Если задано значение true, изменение периода вертикальной синхронизации должно происходить без заметных визуальных артефактов. Платформа использует этот флаг, когда необходимо изменить частоту обновления в результате изменения контента (например, устройство находится в режиме ожидания и начинается анимация). Это позволяет поставщику запретить определенные изменения конфигурации, если они могут привести к заметному визуальному артефакту. Если конфигурации нельзя изменить без проблем и для параметра seamlessRequired задано значение true, то реализация должна возвращать код SEAMLESS_NOT_POSSIBLE и вызывать новый обратный вызов onSeamlessPossible, когда то же изменение конфигурации можно будет выполнить без проблем.

В случае успеха реализация возвращает значение VsyncPeriodChangeTimeline, которое указывает платформе, когда ожидать изменения частоты обновления. Параметры newVsyncAppliedTimeNanos должны быть установлены на время в CLOCK_MONOTONIC, когда новый дисплей начнет обновляться с новым периодом вертикальной синхронизации. Это, вместе с desiredTimeNanos, позволяет платформе заранее планировать переключение частоты обновления и начинать тикинг приложений для новой частоты обновления заранее. Это позволяет плавно менять частоту обновления.

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

onVsyncPeriodTimingChanged [callback]
Новая функция обратного вызова, которую HAL может использовать, чтобы сообщить платформе об изменении параметра временной шкалы и необходимости ее скорректировать. Этот обратный вызов должен выполняться, если по какой-то причине старая временная шкала была пропущена из-за длительного времени обработки на уровне HAL или позднего обновления кадра.

Как платформа решает, когда нужно изменить частоту обновления?

Частота обновления выбирается в следующих двух системных сервисах:

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

Менеджер дисплея выполняет следующие действия, чтобы определить правила:

  • Находит идентификатор конфигурации по умолчанию, запрашивая активную конфигурацию из SurfaceFlinger.
  • Ограничение диапазона минимальных и максимальных значений путем итерации по системным условиям.
    • Частота обновления по умолчанию. Значение частоты обновления по умолчанию задается в оверлее конфигурации R.integer.config_defaultRefreshRate. Это значение используется для определения стандартной частоты обновления экрана устройства для анимации и сенсорного взаимодействия.
    • Настройка максимальной частоты обновления. Значение максимальной частоты обновления считывается из Settings.System.PEAK_REFRESH_RATE. Это значение изменяется во время выполнения, чтобы отразить текущие настройки устройства (например, выбранные в меню). Значение по умолчанию задано в наложении конфигурации R.integer.config_defaultPeakRefreshRate.
    • Минимальная частота обновления. Минимальная частота обновления считывается из Settings.System.MIN_REFRESH_RATE. Это значение можно изменить во время выполнения, чтобы отразить текущие настройки устройства (например, выбранные в меню). Значение по умолчанию – 0, то есть минимальное значение по умолчанию не задано.
    • Запрошенный приложением ModeId. Приложения могут задавать WindowManager.LayoutParams.preferredDisplayModeId, чтобы указать предпочтительную конфигурацию, в которой должен работать дисплей. В большинстве случаев DisplayManager задает идентификатор конфигурации по умолчанию и устанавливает минимальную и максимальную частоту обновления в соответствии с частотой обновления конфигурации.
    • Режим экономии энергии. Частота обновления экрана ограничивается 60 Гц или более низким значением, когда устройство находится в режиме экономии энергии, о чем свидетельствует значок Settings.Global.LOW_POWER_MODE..

После того как DisplayManager задаст политику, SurfaceFlinger установит частоту обновления на основе активных слоев (слоев, которые ставят в очередь обновления кадров). Если владелец слоя задает частоту кадров, SurfaceFlinger пытается установить частоту обновления, которая является множителем этой частоты. Например, если два активных слоя задают частоту кадров 24 и 60, SurfaceFlinger выберет 120 Гц, если она доступна. Если SurfaceFlinger не может использовать такую частоту обновления, он попытается выбрать частоту, при которой ошибка частоты кадров будет минимальной. Дополнительную информацию можно найти в документации для разработчиков на сайте developer.android.com.

SurfaceFlinger поддерживает следующие флаги, чтобы контролировать, как определяется частота обновления:

  • ro.surface_flinger.use_content_detection_for_refresh_rate: Если задано, частота обновления определяется на основе активных слоев, даже если частота кадров не задана. SurfaceFlinger использует эвристический метод, чтобы определить среднюю частоту кадров в секунду, с которой слой публикует буферы, анализируя временные метки, прикрепленные к буферу.
  • ro.surface_flinger.set_touch_timer_ms: если значение больше 0, частота обновления по умолчанию будет использоваться, когда пользователь касается экрана в течение заданного времени ожидания. Эвристический анализ выполняется, чтобы подготовить частоту обновления по умолчанию для анимации.
  • ro.surface_flinger.set_idle_timer_ms: если значение больше 0, минимальная частота обновления будет использоваться, когда экран не обновляется в течение заданного времени ожидания.
  • ro.surface_flinger.set_display_power_timer_ms: если значение больше 0, при включении экрана (или выходе из режима AOD) будет использоваться частота обновления по умолчанию в течение заданного времени ожидания.

Frame Rate API

Frame Rate API позволяет приложениям сообщать платформе Android о желаемой частоте кадров. Этот API доступен в приложениях, предназначенных для Android 11. Дополнительную информацию об API частоты кадров можно найти в документации для разработчиков на сайте developer.android.com.

Для разработчиков

В меню "Для разработчиков" добавлен новый параметр, который позволяет включить оверлей с текущей частотой обновления экрана. Новый параметр находится в разделе Настройки > Система > Для разработчиков > Показывать частоту обновления.