Сначала рассмотрим ненужную информацию. Когда говорят о высокой частоте обновления экрана, нельзя не упомянуть два термина: ProMotion и LTPO. ProMotion — это технология динамического изменения частоты обновления экрана, введенная Apple после поддержки 120 Гц, которая позволяет использовать различные частоты обновления в зависимости от сценария использования, что повышает качество восприятия и снижает потребление батареи.
LTPO (low-temperature polycrystalline oxide) позволяет дисплею динамически менять частоту обновления. Эта технология была внедрена в устройствах Samsung S20 Ultra, OPPO Find X3 серии, OnePlus 9 Pro и других продуктах. Однако производители используют эту технологию по-разному, что приводит к различным проблемам.
Например, в эпоху LTPO 1.0 большинство реализаций просто жестко ограничивали частоту обновления экрана на 60 Гц или 120 Гц в зависимости от сценария использования. В эпоху LTPO 2.0 производители начали применять адаптивные стратегии, такие как изменение частоты при скролле:
Конечно, помимо скролла, производители могут также применять различные стратегии изменения частоты обновления экрана для анимаций, видео, ввода текста, переключения между приложениями и так далее. Причины этого следуют ниже:- Apple ProMotion основана на единой официальной реализации;
Данные выше взяты из статьи «[LTPO действительно экономит энергию? — Опыт использования OnePlus LTPO 2.0]»(https://mobile.it168.com/a2022/0121/6612/000006612347.shtml).
Именно поэтому Flutter требует отдельной настройки для Android и iOS.
Ранее было упомянуто реализация OnePlus LTPO 2.0 по причине того, что адаптивная частота обновления экрана является самостоятельной настройкой производителей оборудования, то есть теоретически приложение не должно требовать какой-либо настройки, поскольку следует за Android, который использует Skia для рендера.
Однако часто реальность отличается от ожиданий. Проблема высокой частоты обновления экрана в Flutter была впервые упомянута в связи с OnePlus, когда большинство ссылалось на статью «The OnePlus 7 Pro’s 90Hz Refresh Rate Doesn’t Support Every App». > Поддержка режима 90 Гц на OnePlus 7 Pro может снижаться до 60 Гц в некоторых приложениях. Чтобы заставить устройство работать строго на 90 Гц во всех приложениях, следует выполнить команду adb shell settings put global oneplus_screen_refresh_rate 0
. В отличие от этого, Pixel 4 поддерживает отрисовку Flutter-приложений со скоростью 90 Гц без каких-либо изменений.Проблема заключалась в том, что некоторые приложения не поддерживают 90 fps на OnePlus 7 Pro. Обсуждение этой проблемы в сообществе привело к тому, что компания OnePlus предоставила следующую информацию:
Для балансировки производительности и энергопотребления OnePlus 7 Pro использует собственный механизм управления частотой кадров, основанный на Android. Экран обычно работает с высокой частотой кадров, но в некоторых случаях система переходит на низкую частоту кадров. Из-за этого механизма могут возникать ситуации, когда приложение пытается использовать высокую частоту кадров, но система ограничивает её низкой частотой.
Как можно установить желаемую частоту кадров через приложение? Если приложению требуется установить частоту кадров, то сначала следует получить список поддерживаемых режимов экрана с помощью метода getSupportedModes()
, затем перебрать этот список и найти подходящий режим с нужной разрешением и частотой кадров (modeId
). Этот modeId
следует назначить свойству preferredDisplayModeId
окна.
Поэтому для решения данной проблемы был создан плагин flutter_displaymode, который предоставляет возможность получения объекта Display.Mode
и установки значения preferredDisplayModeId
.
/// На OnePlus 7 Pro:
/// #1 1080x2340 @ 60 Гц
/// #2 1080x2340 @ 90 Гц
/// #3 1440x3120 @ 90 Гц
/// #4 1440x3120 @ 60 Гц
/// На OnePlus 8 Pro:
/// #1 1080x2376 @ 60 Гц
/// #2 1440x3168 @ 120 Гц
/// #3 1440x3168 @ 60 Гц
/// #4 1080x2376 @ 120 Гц
```Что такое `preferredDisplayModeId`? Официальная статья ["setframerate-vs-preferreddisplaymodeid"](https://developer.android.com/guide/topics/media/frame-rate#setframerate-vs-preferreddisplaymodeid) объясняет это подробнее:
> `WindowManager.LayoutParams.preferredDisplayModeId` — это способ, которым приложение может указать платформе требуемый идентификатор режима отображения. Иногда приложение хочет изменить только частоту кадров, а не другие параметры отображения, такие как разрешение. Аналогичный метод `setFrameRate()` позволяет более простым образом менять частоту кадров, так как он автоматически выбирает подходящий режим из списка доступных режимов.
**Почему же не использовать `setFrameRate` напрямую? Одной из причин является то, что этот метод имеет высокий уровень API**.
> PS: **Хочу представить вам известного специалиста по Flutter, Алекса V525. Он как глобального директора экосистемы (GDE) следил за этим вопросом очень долго, а также участвует в поддержке этого плагина. Также хочу поздравить его с победой в программе Google Open Source Peer Bonus Winners в 2022 году**.Однако спустя некоторое время стабильной работы, [OnePlus 9 Pro получил LTPO и ColorOS](https://github.com/ajinasokan/flutter_displaymode/issues/10), и старые команды ADB перестали работать на новом ColorOS. Но не стоит беспокоиться, так как было выявлено, что это был баг в ColorOS, который был исправлен начиная с версии `11_A.06`. Таким образом, плагин продолжает работать корректно.Прошло уже почти два года, но проблема до сих пор решается временным использованием плагина, поскольку официальная поддержка такого подхода не является приоритетной:
- Flutter следует передать управление частотой обновления операционной системе, а не жестко закодировать её;
- Лучше решать проблемы отдельных производителей через плагины, а не через движок Flutter;
> Этот подход кажется отличным от того, что используется в iOS, возможно, из-за ограничений платформы.
На самом деле, реализация LTPO различна у разных производителей. Например, OnePlus 10 Pro выбирает между сжатием или игнорированием некоторых избыточных команд при рендере LTPO.

Мы знаем, что Flutter рендерит `Widget` на `Surface`, что аналогично тому, как работает `SurfaceView` и `OpenGL` в Google Maps. После тестирования стало очевидно, что Google Maps на этих устройствах может рендериться только со скоростью 60 Гц без специальных настроек.
> Производители устройств имеют право решать, будут ли они позволять приложениям использовать более высокую частоту обновления экрана, даже если приложение требует её. Это снова "белый список" режим?Поэтому, чтобы сделать `Surface` способной работать со скоростью 90/120 Гц на определённых устройствах, необходимо использовать `preferredDisplayModeId` или `setFrameRate`, **при условии, что производитель не заблокировал эту возможность**.> **Некоторые производители смартфонов вводят свои "стабилизирующие" стратегии для обеспечения стабильной работы графики ("дрессировка дракона") и контроля температуры, что может привести к принудительному ограничению частоты кадров и отображению ложной частоты кадров**.
Итоговое решение обсуждения в [тема #78117](https://github.com/flutter/flutter/issues/78117) заключается в том, что **Flutter не будет специально адаптироваться к этим производителям, если это требуется, вы можете использовать сторонние плагины для решения этой проблемы; конечно, по моим тестам, большинство устройств поддерживают нормальную работу частоты кадров**.
Кроме того, в ранних версиях плагина Flutter для IntelliJ также были ошибки, при которых даже если приложение работает со скоростью 90 fps, плагин Flutter в Android Studio / IntelliJ всё равно показывал 60 fps. Однако эта проблема была решена в последующих обновлениях, таких как [PR #4289](https://github.com/flutter/flutter-intellij/pull/4289).
> В дополнение стоит отметить, что производители обычно проверяют, занимает ли SurfaceView/TextureView более половины экрана, так как это может указывать на просмотр видео или игры, что может привести к снижению частоты кадров.
При желании узнать больше о коде Flutter, связанном с частотой кадров на Android, можно обратиться к следующим файлам: [vsync_waiter.cc](https://github.com/flutter/engine/blob/ebcd86f681b9421318b3b4a8abd75839e70000a5/shell/common/vsync_waiter.cc), [vsync_waiter_android.cc](https://github.com/flutter/engine/blob/266d3360a7babfb5f20d5e9f8ea84772b2a247dc/shell/platform/android/vsync_waiter_android.cc), [android_display.cc](https://github.com/flutter/engine/blob/266d3360a7babfb5f20d5e9f8ea84772b2a247dc/shell/platform/android/android_display.cc).
## III. iOSПерейдем к iOS. Поддержка ProMotion отличается от подхода, используемого в нативных приложениях. Когда ProMotion был представлен, Apple уже упомянула его адаптацию в [документации "Optimization of Refresh Rates"](https://developer.apple.com/documentation/quartzcore/optimizing_promotion_refresh_rates_for_iphone_13_pro_and_ipad_pro):Если вы используете следующие фреймворки, то ваше приложение не требует никаких изменений для поддержки изменения частоты обновлений:
- [UIKit](https://developer.apple.com/documentation/uikit)
- [SwiftUI](https://developer.apple.com/documentation/swiftui)
- [SpriteKit](https://developer.apple.com/documentation/spritekit)
- [CAAnimation](https://developer.apple.com/documentation/quartzcore/caanimation)
Однако для Flutter использование нативных компонентов системы не предусмотрено, поэтому в настоящее время требуется настроить следующие параметры в файле `Info.plist`, чтобы активировать поддержку частот сброса выше 120 Гц для `CADisplayLink` и `CAAnimation`:
```xml
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
В официальных обсуждениях Flutter (flutter.dev/go/variable-refresh-rate) и записи issue #90675 можно найти информацию о том, что текущее решение заключается в использовании реализации #29797, которая позволяет достичь высокой частоты обновлений путём изменения содержимого файла vsync_waiter_ios.mm:
- (void)setMaxRefreshRateIfEnabled {
NSNumber *minimumFrameRateDisabled =
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CADisableMinimumFrameDurationOnPhone"];
if (!minimumFrameRateDisabled) {
return;
}
double maxFrameRate = fmax([DisplayLinkManager displayRefreshRate], 60);
double minFrameRate = fmax(maxFrameRate / 2, 60);
if (@available(iOS 15.0, *)) {
display_link_.get().preferredFrameRateRange =
CAFrameRateRangeMake(minFrameRate, maxFrameRate, maxFrameRate);
} else if (@available(iOS 10.0, *)) {
display_link_.get().preferredFramesPerSecond = maxFrameRate;
}
}
```- По умолчанию частота кадров установлена на 60 Гц;
- На устройствах, поддерживающих ProMotion, используется максимальная частота сброса, которую поддерживает экран;
- **На устройствах с iOS 15 и более поздними версиями также добавлено определение диапазона частот кадров**, где preferred и max равняются максимальной частоте сброса, которую поддерживает экран, а min — половине максимальной частоты.
В предыдущих обсуждениях рассматривалась более гибкая реализация, такая как [#29692](https://github.com/flutter/engine/pull/29692), которая исследует возможность автоматического выбора текущей частоты кадров Flutter Engine в зависимости от условий рендера и использования. Это было сделано потому, что сообщество считает, что *для обычных пользователей самостоятельный выбор правильной частоты сброса со стороны разработчиков при отсутствии знаний о платформе и производительности является неэффективным решением, поэтому адаптация через Engine должна стать будущим направлением*.
---
Также:
- По умолчанию частота кадров установлена на 60 Гц;
- На устройствах, поддерживающих ProMotion, используется максимальная частота сброса, которую поддерживает экран;
- **На устройствах с iOS 15 и более поздними версиями также добавлено определение диапазона частот кадров**, где preferred и max равняются максимальной частоте сброса, которую поддерживает экран, а min — половине максимальной частоты.
В предыдущих обсуждениях рассматривалась более гибкая реализация, такая как [#29692](https://github.com/flutter/engine/pull/29692), которая исследует возможность автоматического выбора текущей частоты кадров Flutter Engine в зависимости от условий рендера и использования. Это было сделано потому, что сообщество считает, что *для обычных пользователей самостоятельный выбор правильной частоты сброса со стороны разработчиков при отсутствии знаний о платформе и производительности является неэффективным решением, поэтому адаптация через Engine должна стать будущим направлением*.**Конечно, учитывая настоятельную потребность сообщества в обеспечении Flutter возможностью работы на частоте 120 Гц, временно будет применяться указанный выше метод `CADisableMinimumFrameDurationOnPhone`, который является рекомендованным способом решения данной проблемы согласно официальному подходу Apple.** Кроме того, следует отметить, что Apple в iOS 15.4 исправила баг, связанный с ProMotion. До этого момента существовало странное явление, когда ProMotion не предоставлял полной поддержки сторонним разработчикам. **После iOS 15.4 iOS автоматически активирует частоту обновления экрана 120 Гц для всех пользовательских анимаций приложений,** поэтому возникает удивительная ситуация:- В iOS 15.4 приложения могут использовать анимацию со скоростью 120 Гц;
- До iOS 15.4 некоторые анимации поддерживают технологию ProMotion;

## Четвертый раздел: Последнее слово
Как видно, высокие частоты обновления остаются вызовом для Flutter. Как независимой системы отображения, это проблема, которую Flutter не может игнорировать. На данный момент ситуация такова:
- На Android вам не требуется никаких специальных настроек. При наличии особых устройств или систем рекомендуется использовать [flutter_displaymode](https://github.com/ajinasokan/flutter_displaymode);
- На iOS вы можете добавить `CADisableMinimumFrameDurationOnPhone`, чтобы решить проблему грубо, и ждать слияния и выпуска [#29797](https://github.com/flutter/engine/pull/29797).
Наконец, если у вас есть какие-либо материалы или идеи относительно высоких частот обновления, пожалуйста, оставьте свои комментарии для обсуждения.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )