Flutter 120hz 高刷新率在 Android 和 iOS 上的调研总结

2022-04-02 15:28:14 浏览数 (1)

一、无用的知识

首先科普无用的知识,说起高刷新率,就不得不提两个词汇 ProMotionLTPO 。 ProMotion 是 iOS 在支持 120hz 之后出现的动态刷新率支持,也就是不同场景使用不同的屏幕刷新率,从而实现体验上提升的同时降低了电池的消耗。

LTPO(low-temperature Polycrystalline oxide) 允许显示器动态改变屏幕刷新率 ,而早在三星S20 Ultra、OPPO Find X3系列、一加 9 Pro 等系列产品上都率先采用了这种显示技术,但是实际上大家在 LTPO 又有不同的技术调教,从而出现了我们后续要聊的问题。

例如 LTPO 1.0 时代可能大部分实现都只是强硬的根据场景锁死 60Hz/120Hz 的刷新率,而 LTPO 2.0 开始各大厂家则是升级了自适应策略,例如最常见的就是升级了滑动变频:

当然,除了最常见的滑动, LTPO 2.0 上厂家可能还会有对动画、视频、文字输入、应用切换等场景进行不同的升频和降频策略,而其实介绍上面这些的原因是:

  • 苹果 ProMotion 是基于官方实现的统一方案
  • Android 的 LTPO 是基于供应商硬件后Android OEM 厂家自主调教的实现

以上部分资料来自《LTPO到底是不是真的省电?-一加LTPO 2.0上手体验》

所以这也造就了 Flutter 需要在 Android 和 iOS 上进行单独适配的主要原因。

二、Android

前面介绍里引用了一加的 LTPO 2.0 实现是有原因的,首先知道自适应屏幕刷新率是 OEM 厂商自主调教,也就是理论上作为 App 是不需要做任何适配,因为跟随 Android 就行,Android 本身也是使用 Skia 渲染。

但是往往事与愿违,在 Flutter 关于 高刷问题 最先被提及的就是一加,那时候基本都引用了 《The OnePlus 7 Pro’s 90Hz Refresh Rate Doesn’t Support Every App 》 这篇文章:

一加 7 Pro 的 90 fps 模式对于某些 App 而言只有 60 fps,要在所有 App 上都强制 90 fps,需要执行 adb shell settings put global oneplus_screen_refresh_rate 0 命令, 相比之下 Pixel 4 无需任何更改就直接可以支持渲染 90 fps 的 Flutter App。

也就是问题最开始是在一加的 90 fps 上不支持,而社区通过和一加的沟通得到的回复是:

  • 一加7 Pro 为了平衡性能和功耗,采用的是基于 Android 定制自己的帧率控制逻辑,一般屏幕会以高帧率工作,但在某些场景下系统会切回到低帧率,而由于引入了这种机制,可能会出现当 App 希望屏幕以高帧率运行时却被系统强制设置为低帧率的问题。
  • 那如何通过 App 设置 fps ? 如果应用程序需要设置帧速率,那首先需要通过 getSupportedModes() 获取目前屏幕支持的模式列表,然后遍历列表,根据找到想要使用的分辨率和刷新率的 modeId,赋值给窗口的preferredDisplayModeId

所以基于这个问题修复的方案,社区内提出了 flutter_displaymode 插件,插件主要提供了获取 Display.Mode 和设置 preferredDisplayModeId 的支持,用于临时解决类似 一加7 Pro 上的这种刷新率问题。

代码语言:javascript复制
/// On OnePlus 7 Pro:
/// #1 1080x2340 @ 60Hz
/// #2 1080x2340 @ 90Hz
/// #3 1440x3120 @ 90Hz
/// #4 1440x3120 @ 60Hz
/// On OnePlus 8 Pro:
/// #1 1080x2376 @ 60Hz
/// #2 1440x3168 @ 120Hz
/// #3 1440x3168 @ 60Hz
/// #4 1080x2376 @ 120Hz

那什么是 PreferredDisplayModeId ?通过官方的 《setframerate-vs-preferreddisplaymodeid》 可以了解:

WindowManager.LayoutParams.preferredDisplayModeId 是 App 向平台设置所需帧率的一种方式,因为有时候 App 只想改变刷新率,但是不需要更改其他显示模式如分辨率等。类似设置还有 setFrameRate() ,使用 setFrameRate() 代替 preferredDisplayModeId会更简单, 因为setFrameRate() 可以自动匹配显示模式列表里具有特定帧速率的模式。

那为什么不直接用 setFrameRate ?其中之一因为这是一个 Target 很高的 API

PS:这里和大家介绍一位 Flutter 大佬, 事实上这个 问题 作为 GDE 的 AlexV525 大佬跟进了很久,上面的插件也是他在参与维护,同时也恭喜

0 人点赞