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