小米电池休眠自动解除打开后盖 小米电池休眠自动解除( 六 )


动态帧率的应用场景监控动态帧率下的流畅度表现业界中一般采用 CADisplayLink 对应用的流畅度进行监控 。由于 CADisplayLink 的行为在 iOS 15 上的变化,原先的监控方案无法评估 ProMotion 屏幕在超过 60Hz 时的表现 。
根据上面的探索结论,目前笔者设想了三种针对 ProMotion 设备的兼容性修改方案:
方案一 [Pass]对于任何设备都以 60Hz 为优化目标,只考虑刷新间隔长于 16.67ms 的情况 。换句话说,在屏幕以 120Hz 刷新时,对于丢 1 帧的情况也认为不丢帧,因为此时两帧之间的间隔仍然小于 16.67ms,理论上用户感知不大 。
优点:
方案简单,仅需设置 preferredFramesPerSecond 为固定值 60 即可兼容之前的指标 。依然可以计算 FPS 指标,对于刷新率高于 60Hz 的情况统一认为刷新率为 60Hz缺点:
由于只能监控更高 60Hz 的情况,无法评估更高刷新率下一些微小丢帧对用户体验带来的影响,也无法评估对高刷屏的一些优化所带来的技术影响在低刷新率时,MainRunLoop 依然会以 60Hz 运行,对功耗有一定影响方案二 [Pass]通过一些手段,可以替换驱动 display_timer_callback 的 Source 1 信号的回调,使用它来准确监听 VSync 信号,实现对动态帧率的准确监控 。
优点:
理论上最精确的监控方案对功耗的影响最小,回调频率只有在屏幕刷新率实际升高时才会随之提升缺点:
使用了私有 APIFPS 指标从此不再适用VSync 信号目前和渲染流程不完全匹配,虽然精确但不一定实用方案三 [Pick]通过在 CADisplayLink 回调中确认 duration 参数,计算得到当前屏幕的实时刷新率,并修改 preferredFrameRateRange 来进行跟踪 。
优点:
方案相对简单,只需在每次回调中更新 DisplayLink 对象的 preferredFrameRateRange 属性即可
缺点:
由于动态帧率的存在,FPS 指标可以反映实时屏幕刷新情况,但是聚合后的意义不大,消费时需要区分特定机型/场景观察到目前的最小回调频率为 60Hz,也就是说无法确认 ProMotion 屏幕在 48Hz、30Hz 甚至更低刷新率下的表现在低刷新率时,MainRunLoop 依然会以 60Hz 运行,对功耗有一定影响需要注意的是,CADisplayLink 的 preferredFrameRateRange 需要以类似一下格式进行设置:
NSInteger currentFPS = (NSInteger)ceil(1.0 / displayLink.duration);displayLink.preferredFrameRateRange = CAFrameRateRangeMake(10.0, currentFPS, 0.0);CAFrameRateRange.minimum 传最小值 10.0,preferred 传 0.0,可以让该 CADisplayLink 只用于监控当前的系统帧率,而不影响帧率的动态选择 。
相比前两个方案,方案三改动小,不使用私有 API,监控准确性也较高,缺点相对来说可以接受 。
FPS 的替代指标考虑到在 ProMotion 屏幕上 FPS 指标不再与应用运行是否流畅直接相关,它的聚合值参考价值不大,有必要寻找一个新指标作为替换 。
Apple 官方在 WWDC20 - 10077 Eliminate animation hitches with XCTest 中介绍了 Hitch Time Ratio 这一概念,并着重说明了它比单纯的 FPS 更能适配不同刷新率的场景 。
在 XCTest 框架中,苹果提供了 API XCTOSSignpostMetric 帮助开发者在单测中即时地获取该指标,但相关 API 尽在单测中提供,线上无法使用 。而 MetricKit 中的 MXAnimationMetric 尽管可以在线上获取,但却不是实时的,无法满足大型 App 对不同场景的监控需求 。
因此,遵循下面 Apple 对 Hitch Ratio 的定义:
Hitch time:
Time in ms that a frame is late to display.
Hitch time ratio:
Hitch time in ms per second for a given duration.
笔者尝试实现了基于 CADisplayLink 的 (Scroll) Hitch Time Ratio 的计算方案:

小米电池休眠自动解除打开后盖  小米电池休眠自动解除

文章插图
计算上一帧的帧时间戳与上上一帧的目标帧时间戳得到上一帧的 Hitch Time确定该帧是否是在滑动中渲染累计得到整体的 Hitch Frame,与累积的帧间隔相比,得到 (Scroll) Hitch Time Ratio关键场景提升帧率在测试过程中笔者发现,系统 App 滑动时是稳定以更高刷新率 120Hz 运行的:
小米电池休眠自动解除打开后盖  小米电池休眠自动解除

文章插图
而第三方 App 即便设置了 CADisableMinimumFrameDurationOnPhone 为 true 也无法稳定以满帧率滑动(经过验证,这一点在 iOS 15.4 beta 系统上依然成立) 。
通过利用 iOS 15 引入的新 API,我们可以在关键场景如滑动、转场、动画过程中主动解锁更高/限制更低的动态帧率,从而优化流畅度或者优化功率,提升用户体验目标 。
滑动中稳定 120Hz首先,笔者希望非系统 App 也可以尽可能实现滑动中稳定 120Hz 刷新 。
结合上述分析,这一点可以用 CADisplayLink 来实现 。这里笔者提出两种可能方案仅供参考:

推荐阅读