Android 11 增加了对具有多种刷新率的设备的支持。此功能包含三个主要组件:
-
android.hardware.graphics.composer@2.4
中引入了新的 HAL API。 - 用于解析设备配置以获取不同刷新率并设置所需刷新率的平台代码
- 新的 SDK 和 NDK API 允许应用设置所需的帧速率
执行
android.hardware.graphics.composer@2.4 HAL
添加了对刷新率切换的专用支持。我们强烈建议使用此版本,因为之前版本的 composer HAL 对刷新率切换的支持有限。
配置组
向IComposerClient::Attribute
添加了一个新属性CONFIG_GROUP
,该属性可使用getDisplayAttribute_2_4
API 进行查询。此属性允许供应商将显示配置组合在一起。在大多数情况下,同一组中的配置允许它们之间的无缝切换。平台使用配置组来区分可以在它们之间切换哪些配置,以便切换刷新率而不是配置的其他属性。
考虑以下示例,该示例演示了将配置组与支持四种显示配置的设备一起使用的好处:
- 1080p@60Hz
- 1080p@90Hz
- 1080i@72Hz
- 1080i@48Hz
尽管该设备支持 48Hz、60Hz、72Hz 和 90Hz 刷新率,但显示器在不同的模式下运行,并且从 60Hz 切换到 72Hz 会将显示配置从 1080p 更改为 1080i,这可能不是所需的行为。这可以通过使用配置组来解决。通过将 60Hz 和 90Hz 组合在一个配置组中,将 48Hz 和 72Hz 组合在另一个配置组中。该平台知道它可以在 60Hz 和 90Hz 以及 48Hz 和 72Hz 之间切换,但不能在 60Hz 和 72Hz 之间切换,因为这将导致配置更改,而不是简单地更改刷新率。
作曲家 API 更新
- getDisplayVsyncPeriod
- 为了在更改刷新率时获得更好的控制和可预测性,添加了
getDisplayVsyncPeriod
。getDisplayVsyncPeriod
返回显示器运行的当前刷新率(根据垂直同步周期)。当平台需要在刷新率和当前刷新率之间转换来决定何时开始下一帧时,这尤其有用。 - setActiveConfigWithConstraints
-
setActiveConfigWithConstraints
方法是对现有setActiveConfig
方法的新扩展,并提供有关配置更改的更多信息。约束作为vsyncPeriodChangeConstraints
参数的一部分给出,并包含以下参数。 - 期望时间纳米
- CLOCK_MONOTONIC 中的时间,之后
CLOCK_MONOTONIC
周期可能会更改(即 vsync 周期在此时间之前不得更改)。当平台想要提前计划刷新率更改但队列中已经有一些缓冲区要呈现时,这很有用。平台会相应地设置此时间以考虑这些缓冲区,并确保刷新率转换尽可能平滑。 - 无缝需要
- 如果为真,则要求垂直同步周期更改必须无缝发生,而不会出现明显的视觉伪影。当由于内容更改而需要更改刷新率时(例如,设备空闲并且动画开始),平台会使用此标志。这使供应商有机会在某些配置更改可能导致明显的视觉伪影时不允许它们进行更改。如果无法无缝更改配置并且将
seamlessRequired
设置为true
,则实现应返回SEAMLESS_NOT_POSSIBLE
作为返回码,并在可以无缝完成相同的配置更改时调用新的onSeamlessPossible
回调。 成功后,实现返回一个
VsyncPeriodChangeTimeline
,它告诉平台何时预期刷新率更改发生。newVsyncAppliedTimeNanos
参数需要设置为CLOCK_MONOTONIC
中的时间,新显示器将在新的垂直同步周期开始刷新。这与desiredTimeNanos
一起允许平台提前计划刷新率切换并提前开始为新的刷新率勾选应用程序。这允许刷新率的无缝转换。一些实现需要在发送刷新率之前发送刷新帧。为此,HAL 具有
refreshRequired
参数以指示需要刷新帧,并具有refreshTimeNanos
参数以指示需要在之后发送刷新帧的第一个 vsync。- onVsyncPeriodTimingChanged [回调]
- 可以由 HAL 调用的新回调,以向平台指示时间线的某些参数已更改,并且平台需要调整其时间线。如果由于某种原因由于 HAL 上的处理时间过长或延迟刷新帧而错过了旧时间线,则预计将调用此回调。
平台如何决定更改刷新率?
刷新率选择发生在以下两个系统服务中:
- 显示管理器
DisplayManager
围绕刷新率设置高级策略。它设置了一个默认的显示配置,与 composer HAL 配置相同。此外,它为SurfaceFlinger
设置了一系列最小值和最大值,以选择作为刷新率。- SurfaceFlinger
- 通过设置与默认配置在同一配置组中且刷新率在最小/最大范围内的配置来确定刷新率。
显示管理器通过以下步骤来确定策略:
- 通过从
SurfaceFlinger
查询活动配置来查找默认配置 ID - 通过迭代系统条件来限制最小值和最大值的范围
- 默认刷新率设置:默认刷新率值在
R.integer.config_defaultRefreshRate
配置覆盖中设置。此值用于确定动画和触摸交互的标准设备刷新率。 - 峰值刷新率设置:峰值刷新率值从
Settings.System.PEAK_REFRESH_RATE
读取。此值在运行时更改以反映当前设备设置(例如来自菜单选项)。默认值在R.integer.config_defaultPeakRefreshRate
配置覆盖中设置。 - 最低刷新率设置:最低刷新率值从
Settings.System.MIN_REFRESH_RATE
中读取。可以在运行时更改此值以反映当前的设备设置(例如从菜单选项中)。默认值为 0,因此没有默认最小值。 - 应用程序请求的 ModeId :应用程序可以设置
WindowManager.LayoutParams.preferredDisplayModeId
以反映显示器应运行的首选配置。在大多数情况下,DisplayManager
会相应地设置默认配置 ID,并设置最小和最大刷新率以匹配配置的刷新率。 - 省电模式:当设备处于低功耗模式时,刷新率限制为 60Hz 或更低,这通过
Settings.Global.LOW_POWER_MODE.
- 默认刷新率设置:默认刷新率值在
一旦DisplayManager
设置了策略, SurfaceFlinger
就会根据活动层(队列帧更新的层)设置刷新率。如果图层的所有者设置了帧速率,SurfaceFlinger 会尝试将刷新率设置为该速率的倍数。例如,如果两个活动层将其帧速率设置为 24 和 60,SurfaceFlinger 将选择 120Hz(如果可用)。如果 SurfaceFlinger 没有这样的刷新率,它将尝试选择帧率误差最小的刷新率。有关更多信息,请参阅 developer.android.com 上的开发者文档
SurfaceFlinger
维护以下标志来控制如何决定刷新率:
-
ro.surface_flinger.use_content_detection_for_refresh_rate:
如果设置刷新率是根据活动层决定的,即使没有设置帧率。 SurfaceFlinger 维护一个启发式方法,它通过查看附加到缓冲区的表示时间戳来找到该层发布缓冲区的平均 fps。 -
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 时)配置超时时将使用默认刷新率。
帧率 API
帧速率 API 可让应用通知 Android 平台其预期的帧速率,并且适用于面向 Android 11 的应用。要了解有关帧速率 API 的更多信息,请查看 developer.android.com 上的开发者文档。
开发人员选项
菜单中添加了一个新的开发人员选项,可使用当前刷新率切换显示屏上的覆盖。新选项位于设置>系统>开发人员选项>显示刷新率下。