1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-120HZ.md 23 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61

Исследование высокой частоты обновления экрана в Flutter на Android и iOS

1. Ненужная информация

Сначала рассмотрим ненужную информацию. Когда говорят о высокой частоте обновления экрана, нельзя не упомянуть два термина: ProMotion и LTPO. ProMotion — это технология динамического изменения частоты обновления экрана, введенная Apple после поддержки 120 Гц, которая позволяет использовать различные частоты обновления в зависимости от сценария использования, что повышает качество восприятия и снижает потребление батареи.

c64c73ef829cb88f10f35ae24e5a6c59

LTPO (low-temperature polycrystalline oxide) позволяет дисплею динамически менять частоту обновления. Эта технология была внедрена в устройствах Samsung S20 Ultra, OPPO Find X3 серии, OnePlus 9 Pro и других продуктах. Однако производители используют эту технологию по-разному, что приводит к различным проблемам.

image-20220331153929592

Например, в эпоху LTPO 1.0 большинство реализаций просто жестко ограничивали частоту обновления экрана на 60 Гц или 120 Гц в зависимости от сценария использования. В эпоху LTPO 2.0 производители начали применять адаптивные стратегии, такие как изменение частоты при скролле:

0ecaee4af2444b87a73db171bd36ba3fКонечно, помимо скролла, производители могут также применять различные стратегии изменения частоты обновления экрана для анимаций, видео, ввода текста, переключения между приложениями и так далее. Причины этого следуют ниже:- Apple ProMotion основана на единой официальной реализации;

  • Android LTPO основан на самостоятельной настройке производителями оборудования после получения аппаратной части от поставщиков;

Данные выше взяты из статьи «[LTPO действительно экономит энергию? — Опыт использования OnePlus LTPO 2.0]»(https://mobile.it168.com/a2022/0121/6612/000006612347.shtml).

Именно поэтому Flutter требует отдельной настройки для Android и iOS.

2. Android

Ранее было упомянуто реализация 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**.![image-20220331170424637](http://img.cdn.guoshuyu.cn/20220627_Flutter-120HZ/image4)

> 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.

![8888](http://img.cdn.guoshuyu.cn/20220627_Flutter-120HZ/image5)

Мы знаем, что Flutter рендерит `Widget` на `Surface`, что аналогично тому, как работает `SurfaceView` и `OpenGL` в Google Maps. После тестирования стало очевидно, что Google Maps на этих устройствах может рендериться только со скоростью 60 Гц без специальных настроек.

> Производители устройств имеют право решать, будут ли они позволять приложениям использовать более высокую частоту обновления экрана, даже если приложение требует её. Это снова "белый список" режим?Поэтому, чтобы сделать `Surface` способной работать со скоростью 90/120 Гц на определённых устройствах, необходимо использовать `preferredDisplayModeId` или `setFrameRate`, **при условии, что производитель не заблокировал эту возможность**.> **Некоторые производители смартфонов вводят свои "стабилизирующие" стратегии для обеспечения стабильной работы графики ("дрессировка дракона") и контроля температуры, что может привести к принудительному ограничению частоты кадров и отображению ложной частоты кадров**.![](http://img.cdn.guoshuyu.cn/20220627_Flutter-120HZ/image6)

Итоговое решение обсуждения в [тема #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;

![](http://img.cdn.guoshuyu.cn/20220627_Flutter-120HZ/image7)

## Четвертый раздел: Последнее слово

Как видно, высокие частоты обновления остаются вызовом для Flutter. Как независимой системы отображения, это проблема, которую Flutter не может игнорировать. На данный момент ситуация такова:

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

Наконец, если у вас есть какие-либо материалы или идеи относительно высоких частот обновления, пожалуйста, оставьте свои комментарии для обсуждения.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master