iOS 高刷屏监控 + 优化:从理论到实践全面解析

背景

Apple 在今年推出了支持 ProMotion 屏幕的 iPhone 设备,让 App 在 iPhone 13 Pro 和 iPhone 13 Pro Max手势识别 上的opengl是什么意思最大刷新帧率可到达 12指针c语言0Hz,极大优化了手势舞视频应用滑动/动画的流畅度体验。

ProMotion 并不是一个新的概念,早在 2017 年,Apple 推出的第二代 iPad Pro 便搭载了这一刷新率最高可达 120Hz 的屏幕。在 iPad 上,高刷新率默认对所有 App 启指针数学用。而也许是出于能耗的考虑,在 iPhone 上,Apple 并未将这个能力自动对所有 App 启用,而是需要开发者手动添flutter面试题加配置项来进行适配。

近期有消息指出 iOS 15.4 beta 修正了这一行为(www.macrumors.com/2022/01/手势舞27/… ),经过笔者验证额外的配置项依然是需要的,并且本文内容依然适用。

本文介绍了在 iPhone 上对 ProMotion 动态帧率的适配时观察到的现象和遇到的问题,尝试推测了背后的原理,并探讨flutter菜鸟教程了解决问题的可能思路,最终基指针数组和数组指针的区别于调研结果在国际化短视频业务上线优化方案,取得了核心业务指标指针式万用表的收益。

什么是帧率

在深入探究 ProMotion 屏幕所带来的变化之前,我们先回顾一个似乎耳熟能详的概念:

什么是帧率?

众所周知,显示器并不手势语能显示真正动态的画面,所有动画效果都是靠高速播放一帧帧静态画flutter框架面欺骗人类视觉所造成的假象。那么帧率最基本的定义便是屏幕内容的变化频率,是一个物理意义上的指标。这种变化频率又由以下两个值共同决定:

  • 刷新帧率:由屏幕硬件规格控制,传统显示设备一般为 59.94Hz,决定了帧率的上限。
  • 渲染帧率:由 CPU -> GPU 渲染管线的执行速率控制,决定了帧率的下限。

理想情况下,渲染帧率和刷新帧率最好完全匹配,或者渲染帧率是刷新帧率的整数倍,这样实际展现的内动画片少儿小猪佩奇容不会出现任何异Flutter常。但现实中二者往往会出现不匹配的情况,卡顿就是其中之一:fluttershy

卡顿

iOS 高刷屏监控 + 优化:从理论到实践全面解析

当 CPU -> GPU 的渲染管线遇到瓶颈,导致某一帧的指针渲染耗时大于屏幕的刷新间隔opengl错误1282时,上一帧画面会在屏幕上多停留数帧的时间。当这个滞留时间过长,用户感知到画面更新的延迟,这称为卡顿。这也是 iOS 开发过程中会遇到的主要性能问题之一。

实际帧率

帧率并不等同于刷新率,它和所手势密码展示的内容息息相关:

  • 展示静态画面时,理想情况只需要进行一次渲染,尽管屏幕仍然以 60Hz 或者更高的频率进行刷动画片小猪佩奇新,每次刷新所展示的内容(FrameBuffer)flutter有必要学吗也未改变,用户感知到的实际帧率依然接近 0。
  • 展示固定帧率的元素,例如 24FPS 的电影视频时,用户感知到的实际帧率自然也是 24 FPS 左右。
  • 展示超高帧率的内容,例如 CS:GO 不锁帧跑 >200 FPS,但由于显示设备刷新率限制,用户感知到的帧率依然动画电影不会超过硬件帧率的上限。

什么是动态刷新率

ProMotion 本质上是对 Adaptive-Sync 显示标准的一种实现。

Ref: en.wikipedia.org/wiki/Variab…

根据 Apple 官方文档显示,ProMotion 屏幕支持的刷新率是可变的。

具体来说,fluttershy对 iPhone 而言指针万用表读数图解

The iPhone 13 Pro and iPhone 13 Pro Max ProMotion displays can presen指针是什么t content on the display using the following refresh rates and timings:

120Hz (8ms), 80Hz (12ms), 60Hz (16ms), 48Hz (20ms), 40Hz (25ms), 30Hz (33ms), 24Hz (4指针c语言1ms), 20Hz (50ms), 16Hz (62ms), 15Hz (66ms), 12Hz (83ms), 10Hz (100ms)

而对 iPad Pro 来说:

The iPad Pro’s ProMotion displayopengl渲染gpu怎么设置 can present content on the diflutter面试题splay using the following refropengl和directxesh rates and timings:

120Hz (8ms), 60Hz (16ms), 40Hz (25ms), 3fluttering0Hz (33ms), 24Hz (41ms)

这其实是 Apple 对 VESA 定制的 AdaptiveOpenGL-Sync 技术标准的一种实现,在游戏业界已经实装多年,类似的实现还有opengl和directx AMD 的 FreeSync 和 Ni手势变化vida 的 G-Sync。这种新的显示技术有着以下优点:

减少可感知的卡顿

对于固定刷新率的屏幕而言,当某一帧的渲染耗时出现异常,flutter翻译在 VSync 信号到来之后才完成渲动画染,那么当前内容便会滞留在屏幕上,这一帧需要再等一次 VSync 信号才能被渲染展示给用户。

而 Adaptive-Sync 技术可以避免手势含义图解大全这一点,在该帧渲染结束后尽快进行展示,从而减少显示卡顿时长:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

减少移动设备的屏幕功耗

在搭载了固定刷新率屏幕的设备上,当显示静态内容或者帧率较低(例如视频)的内容时,GPU 的渲染频率比实际频率刷新率会更低。但是固定刷新率的屏幕依然会已最高速率进行刷新,重复展示之前的内容,造成了额外的电量消耗。

ProMotion 屏幕在这种情况下可以主动降低刷新率,减少屏幕功耗,这对于移动设备来说fluttering尤其重要。

动态刷新率的表现形式

The iPhone 13 Pro, the iPhone 13 Pflutter框架ro Max, and the iPad Pro ProMotion displays are capable of dynamically switching between:

  • Faster refresh rates up to 120Hz
  • Slower refresh rates down to 24Hz or 10Hz

已知,动画片小猪佩奇ProMotion 屏幕的刷新帧率并不固定,系统会实时地根据当前显示内容的类型和opengl和directx状态来动态切换屏幕的刷新帧率。为了更好地理解这种动态帧率的表现形式,笔者分别在

  • iPhone XR – 无 ProMotion
  • iPhone 13 Pro – 有 ProMotion 默认锁频

上对一些典型渲染场景进行了测试,发现搭载了 ProMotion手势识别 屏幕的设备上运行 App 时,不同的场景下的各种统计口径的帧率指标确实展示出了有趣的动画头像变化。

具体而言,笔者分别在以下几种场景:

测试场景

  1. 静态页面

flutter是什么意思态的 UIView,无动画/视频等元素

  1. 滑动中的页面

包含静态 Cell 的 UITableView,仅观察滑动中的表现

  1. Core Animation 默认刷新率动画

显示基于 CABasicAnimation 实现的简单位移动画

  1. Core Animation 120Hz 高刷新率动画

仅在 ProMotion 设备上测试,基于 CABasflutter框架icAnimatfluttershyion 实现的简单位移动画,同时解锁了opengl错误1282CADisableMinimumF手势识别rameDurationO指针式万用表nPhonepreferredFrameRateRange帧率限制。(关于此限制下文会有具体介绍)

  1. Metal 渲染 30Hz/60Hz 视频

使用基于MTKView进行渲染的播放器,播放源帧率分别为 30Hz/60Hz 的视频文件

并使用以下几种统计口径的帧率指标进行测试:

测试指标

  1. CADisplayLink 计算帧率

iOS 中主要的帧率统计手段。

根据CADisplayLi动画专业nk.h动画文件中描述,CADisplayLink 是一个 ”Class repreopengl和directxsenting a timer bound to the display vsync “。在回调中比较当前帧/前一帧的时间戳,可以动画头像计算出上一帧的渲染耗时(ts),其倒数(1/ts)即为当前的实时帧率。

  1. Xcode GPU Report 帧率

Xcode -> Show Debug Navigator -> FPS 中flutter菜鸟教程显示的帧率。这个只能统计当前应用直接通过 OpenGL Eflutter框架S 或者 Metal 进行绘制的帧率,例如游戏渲染/视频播放,无法统计 Core Animation 的帧率(众所周知,后者通过backboardd进行绘制)。

  1. Instruments Core Animation FPS

Instropengl错误1282umflutter开发的app有哪些ents 中 Cfluttershyore Animation FPS 工具所显示的指针万用表读数图解帧率。这个统计的是 Core Animation 的帧率,即 Renopengl怎么开启der Serverbackboardd绘制的频率。目前该工具有 BUG 无法显示高于 60 FPS 的帧率。

  1. Instruments Display/VSync 信号频率

Instruments 中 Display 工具所显示的 Surface/VSync 信号手势舞时间戳。如下图所手势舞教程视频慢动作示:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

  • Display:指对应显示器的单个 Surface 上屏持续的时间,对应 CPU-GPU 管线的渲染频率
  • VSync:指垂直同步信号时间戳,对应屏幕硬件的刷新频率

在 60Hz 屏幕上,iOS 设备默认采用双缓冲刷新机制,也就是前帧缓存和后帧缓存。GPU 总是在后帧缓存上进行当前帧的绘制。当 VSync 信号到来时,交换前后帧缓存的指针(Swap FrameBuffer),屏幕刷新显示新的内容。

而当屏幕以 120Hz 显示内容时,iOS手势 会切换成三缓冲刷新机Flutter(见上图中三种颜色的 Surface),这减少渲染管线的压力,但同时会增加一定的渲染上屏延迟。

Metal 应用可以通过设置-[CAMetalLayer setMaximumDrawableCount:]为 2 来在 120Hz 屏幕上强制启用双缓冲机制,避免这种延迟。

如果屏幕显示内容未发生变化动画片熊出没,Surface 则不会发生交换,一个 Surface 的 Display 可能持续数个 VSync 间隔,但多余的 VSync 信号依然代表着硬件层额外的屏幕刷新opengl是什么意思,造成额外的电Flutter量消耗。

非 ProMotion 设备

首先让我们看看传统的固定刷新率的设备的情况。

VSync 信号间隔固定为 16.67ms

XR 的屏幕刷新率为固定的 60Hz,这一点对应的具体指标是 VSync 信号的间隔,指针式万用表使用方法而在任何场景下,XR 的 VSync 信号的间隔均为固定的 16.67ms。

此外,在显示静态内容时,由于视图 Layer T手势舞ree 无变化,Core Animation 不会有提交新的事务提交,backboa指针数组和数组指针的区别rdd不会进行刷新,所以对应这一帧的 Surface 也长时间动画大放映(数十秒)未被交换下去,Core Animation FPS 的值显示为 0。

但由于 VSync 信号仍然以 60Hz 的频率持续触发,屏幕此时正在不停重复展示同样指针万用表读数图解的 Frame Buffer,消耗了额外的电量。

CADis动画片汪汪队playL手势舞视频ink 基本完全跟随 VSync 信号

根据过去对 iOS 系统的认知,手势密码图案大全我们知道 CADisplayLink 是由 VSync 信号驱动的:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

默认配置的 CADisplayLink 的回调应该与 VSync指针数组和数组指针的区别 信号基本同时。

这一点在 XR 上得到了验证,用 Insopengl渲染gpu怎么设置truments 记录一次主线程发生的卡顿,得到:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

其中:

  • 第一行runloop记录每次 RunLoopAfterWaiting->BeforeWaiting的间隔
  • 第二行tickflutter有必要学吗记录默认配置的 CADisplayLink 回调间的间隔
  • 最下面则是硬件 Display/VSync 事件opengl版本过低时序图

可以观察到下述现象,符合我们之前的对 DisplayLink手势密码图案大全 的认识:

  • 没有卡顿的情况下,VS指针ync 信号和 RunLoop 的唤醒 &ampopengl模式; CADiopengl渲染gpu怎么设置splayLink 回调的触发严格一一对应。
  • RunLoop 卡顿opengl是什么意思,无法处理 Source 1 信号,DisplayLink 回调被延迟到卡顿结束时。
  • 在此过程中 VSync 信号间隔始终保持不变。

ProMotion 设备

下面看看 Pro指针式万用表使用方法Motion 设备的测试结果。

VSync 信号间opengl错误1282隔可变

在 ProMotion 屏幕上 VSync 信号间隔是可变的,具体而言:

  • 显示静态内容时,屏幕降频,最低以 10Hz 的频率进行刷新
  • 指针万用表读数图解示 Core Animation 动画时,系统会适配动画的帧率设置改变刷新率
    • *通过preferredFrameRateRange可以设置hint请求高刷,但并不一定生效,详见下文“动态帧率的应用场景手势密码图案大全部分。
  • 显示滑动中内容时,刷新率在 80Hz 左右波动,并且跟随滑动速度变化而变化。快滑时刷新率升高,慢滑时降低。
  • 显示视频时,刷新率和视频帧率维持一手势密码

可以看到 VSync 信号间隔能主动跟随显示内容的渲染帧率的改变而改变。

减少卡顿造成的显示延迟

在主线程发生卡顿导致滑动中某一帧渲动画制作软件染耗时过长时,动画片小猪佩奇系统会改变这一帧所对应的 VSync 信号间隔(下图 Surface 5)opengl错误1282手势含义图解大全减小从渲染到展示的延时,从而减缓动画片少儿小猪佩奇用户感知到的卡顿时长。手势变化

iOS 高刷屏监控 + 优化:从理论到实践全面解析

DisplayLink 不完全跟随 VSync 信号

如图是一张滑动中场景的 CADisplayLink 回调动画头像 和 Display/VSync 事件对照记录。和之前不同的是,再 ProMotion 设备上 DisplayLink 和 VSync 信号之间没有表现出明显的跟随关系:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

具体而言:

  1. 第三个箭头所指向的 DisplayLink 的回调并不及时。在这之前主线程的卡顿已动画片熊出没经结束,并且额外执行了两次 RunLoop,但直到第三次才调用了 DisplayLink 的回调。
  2. 不仅仅是时机不匹配,也存在收到 VSync 但不触发 DisplayLink 回调的情况(并且动画专业主线程处于空闲状态),例如上图中的 ❓ 处。

解除 DisplayLink 的帧数限制

我们知道,在 iOS动画片猫和老鼠 15 上 Apple 对第三方应用的显示帧率默认做了限制。第三方应指针数学用需要在 Info.plist 中添加<k动画ey>CADisableMinim指针万用表怎么读数umFrameDurationOnPhone</key><true/>字段才可以解锁 120Hz 的刷新率。

于此同时,在 i手势舞视频OS 15 中,CADisplayLink 等动画相关 API 也新增了一个用于配置偏好帧率的属性:

/*Definestherangeofdesiredcallbackrateinframes-per-secondforthis
displaylink.Iftherangecontainsthesameminimumandmaximumframerate,
thispropertyisidenticalaspreferredFramesPerSecond.Otherwise,theactual
callbackratewillbedynamicallyadjustedtobetteralignwithother
animationsources.*/
@property(nonatomic)CAFrameRateRangepreferredFrameRateRange
API_AVAILABLE(ios(15.0),watchos(8.0),tvos(15.0));

为了进一步探究新设备上 DisplayLink 和 VSync 信号之间的关系,笔者将测试 App 的 Core Animation 的帧率限制解除,并配置对应的 API,分别在不同的场景重新进行测试:

显示动态内容的场景

动画场景

展示一个速度中等的位移动画,得到下图:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

可以很直观地发现,DisplayLink 解锁帧率后的屏幕刷新率基本指针说漫稳定在 120Hz。并且fluttered VSync 和 DisplayLink 的关系似乎又重新一一对应了起来。

但是,将动画速度减慢,笔者发现这种对应关系发生了变化:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

可以观察到在播放慢速动画时,DisplayLink 的频指针说漫率依然是配置动画片汪汪队的 120Hz,但是实际的屏幕刷新率却只有 30Hz。

滑动场景

让我们换一种场景再次进行测试,快速滑动视图,在 Instruments 中得到下图:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

可以发现,DisplayLink 解锁帧率后,屏幕刷新率同样基本稳定在 120Hz,仅在丢帧时有降频。

  1. 需要注意的动画专业是笔者在 CADisplayLink 的回调中除了调用 os_signpost 上报 log 外无任何 UI手势舞视频 改动。
  2. 即便笔者展示的 TableVieopengl和directxw 极其简单,上图中仍然可以观察到丢帧,无法在滑动中完美稳定 120Hz。这也许说明 UIKit 的渲染性能在 120Hz 下会有某种程度上的原生瓶颈。

然后降低滑动屏幕的速度,得到了和慢速动画相似的结果,尽管 DisplayLink 回调速度不减,但是 VSync 信号频率一直保持在较低的水平:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

卡顿场景

上面两次测试都接近理想情况,即整个 Render Lopengl模式oop 执行几乎没有延迟与卡顿。但是现实中应用的运行总是有着各种各样的或大或小的卡顿问题。

为了验证更接近现实flutter翻译情况下,DisplayLink 和 VSync 信号之间的关系,在连续滑动的情况下笔者人为加入了一个 20ms 的微小卡顿进行测试:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

上图中可以看到,ProMotion 屏幕很好的处理了这次卡顿,由于三缓冲机制的存在,再 Render Loop 渲染Surface 4卡顿期间,通过改变 VSync 间隔,系统尝试将缓冲区中的Surface 283Surface 250延迟上屏,尽量缩短了opengl怎么开启用户看到静止画面的时长。

随后,主线程恢复执行,可以看到 DisplayLink 的回调频率很快恢复至卡顿前的高水平。而此时 VSyn动画片汪汪队c 信号由于前述卡顿减缓机制的存指针式万用表在频率其实有所降低。此时二者频率并不吻合。

这和之前播放慢速动画/慢速滑动的情况很相似,由于卡顿加上缓冲机制的存在导致短时间内系统将屏幕的刷新频率降低,但在 CPU 侧依然维持了 DisplayLink 的高速回调,满足了使用方对preferredFrameRateRange这一 API 的设置。

为了进一步分析了这种机制的本质,笔者接下来会尝试逆向分析 iOS 15 中的系统库动画大放映相关实现的改动。

逆向分指针式万用表使用方法

DisplayLink 驱动方式的变化

在 CADisplayLi动画片猫和老鼠nk 回调方法上设置断点,分别在 iOS 14 和 15 ProMotion 设备上运行,可以得到:

  1. 在 iOS 14 上,CAD指针万用表怎么读数ispl指针数学ayLink 是通过 Source 1 mach_port 直接接受 Vopengl和vulkanSync 信号驱动的

iOS 高刷屏监控 + 优化:从理论到实践全面解析

  1. 在 iOS 15 ProMotion 设备opengl-legacy上,CADisplayLink 不再由 VSync 信号驱动,而是由一个 UIKit 内部的 Source0 信号驱动

iOS 高刷屏监控 + 优化:从理论到实践全面解析

在 15 中,CADisplayLink 第一次创建并添加至 RunLoop 的时候,会注册一个 Source 1 信号,这和 14 中行为一致。

iOS 高刷屏监控 + 优化:从理论到实践全面解析

其 callout 回调地址对应符号为同样为display_timerflutter菜鸟教程_callback,同样和 14 中的一致。

iOS 高刷屏监控 + 优化:从理论到实践全面解析

这也可以解指针是什么释为什么 15 上 VSync 信号确实会唤醒一次 RunLoop,只是这次fluttering唤醒并不一flutter框架定触发 DisplayLink 的回调,这就说明display_timer_callback行为和 14 相比一定指针数组发生了某种变化。

display_timeflutter菜鸟教程r_callOpenGLback逻辑的变化

使用 Hopper 分析display_timer_callback的实现,发现 15 和 14 的实现并无区别。使用 LLDB 进行 debug,指针式万用表使用方法逐步分析,观察到后续调用函数为CA::Display::DisplayLink::callback,其关键反汇编代码如下图所示:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

观察反汇编代码可以发现,如果CA::display_link_will_fire_han手势语dler这个 blockflutter菜鸟教程 返回了 NO,则这次 VSync 信号回调不会触发后续的CA::DisplayLink::dispatch_items调用。

实际上在 LLDB 中也验证了这点:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

iOS 高刷屏监控 + 优化:从理论到实践全面解析

注意上图中的_CFRunLoopCurrentIsMain和上图红框代码接近,后续的blraa指令看起来很明显是调用了一个 bloc动画电影k(上面的 ldr x9 [x8, #0x10] 就是把 invoke 指针从 block 结构体中取出的意思)。tbz指令中 w0 寄存器为 block 执行的返回值,为 0(即 NO)时跳转至 0x1848dbc08,而 0x1848dbc08 刚好在dispatch_itemflutter框架s动画电影的调用之后,跳过了该调用。

通过对上图中blraa指令 step in,我们发现这个 block 实际上是由 UIKitCore 注册的:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

找到引用了该符号的 UIKit 的私有方法__UIUpdateCycleSc动画片少儿小猪佩奇hedulerStart,反汇编动画大放映结果也验证了这点。

iOS 高刷屏监控 + 优化:从理论到实践全面解析

同时发现这opengl和directx个 block 的返回值固定为 0x0。

iOS 高刷屏监控 + 优化:从理论到实践全面解析

而同样的指针万用表怎么读数 symbol 在之前的 iOS 版本上并不存在,也就是说这个应该是 iOS 15 的变动。换安装了 iOS 15 的非 ProMotion 设备,重走上面的逆向流程发现,该设备的CA::display_link_will_fire_handler为 nil,未注册:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

这里cbz执行了跳转,说明x0为 nil,而x0是由ldr x0, [x8, #0x1c8]得到。

iOS 高刷屏监控 + 优化:从理论到实践全面解析

可以看到x0就是CA::display_link_will_fire_handler。继续分析之前找到的私有符号__UIUpdateCycleSchedopengl怎么开启ulerStart的相关实现,可以知道这是因为在非 ProMotion 设备上_UIUpdateCycleEnabled返回了 NO 导致的。

iOS 高刷屏监控 + 优化:从理论到实践全面解析

在返回 NO 的情况下__UIUpda手势识别teCycleSchedu手势识别lerStart方法不会执行,CA::display_link_will_fire_handler也就不会被注册。

_UIUpdateCycleEnabled 所带来的变化

继续研究_UIUpdateCycleEnabled相关的代码,笔者发现这个的改动并不是仅仅影响 DisplayLink 驱动方式那么简单。

_UIUpdateCycleEnabled返回 YES 时,UIKit 会在UIApplicationMain中执行_UIUpdateCycleSchedulerStart。分析fluttered该函数,发现_UIUpdateCycleEnabled启用时会调用[CATransaction setDisableRunLoopObserverCommits:YES]

iOS 高刷屏监控 + 优化:从理论到实践全面解析

Core Animation是绝大部分 iOS 应用的渲染引手势舞教学视频简单擎,熟悉 iOS 渲染流程的同手势语学想必都知道它的执行也是由MainRunLoop驱动,大致为:

  1. MainRunLoop因为用户操作/Timer/GCD 等被唤醒,派发相应的事件/回调
  2. 回调中应用修改Layer Tree,触发setNeeds动画制作软件LayoutsetNeedsDisplay
  3. MainRunLoop即将完成本次执行,在即将休眠前向Observer派发Beforopengl版本过低eWaiting事件
  4. BeforeWaiting中触发手势舞教程视频慢动作Core Animation注册的MainRflutter开发的app有哪些unLoop Observer,触发事务提交CA::Transac手势tion::commit()
    • 自顶向下触发各种 Layout/Display 等逻辑,更新布局/内容
    • Core Anflutter开发的app有哪些imation 将更新后的 La动画大放映yer Tree 打包发送给 Render Server
  5. 随后MainRunLoop进入休眠
  6. Render Server将打包好的Layer Tree指针说漫码,生成并提交对应的draw calls
  7. GPU执行渲染指令,渲染出FrameBuffer,待后续 VS动画头像ync 信号来临时上屏展示

上图中+[CATransaction setDisableRunLoopObserverCommits:YES]这个调用给了笔者提示,让我们验证一下CA::Transaction::commit()在 iOS 15 ProMotion 设备上的执行时机,会发现确实不再由BeforeWa手势变化iting事件驱动了:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

实际上同样的Source 0信号同时也驱动了 CADisplayLink 的回调:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

关注这个Source 0的回调符手势舞教程视频慢动作runloopSourceCallback,会发现这个 Source0 是由signalChanges函数fluttered驱动:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

signalChanges又是由多个回调所驱动:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

其中:

  1. runloopObserverCallback为一个Befo指针万用表怎么读数reWaitingMainRunLoop observer驱动。
  2. runloo指针说漫pTimerCallbackmk_timer指针c语言动,对应的mach_port不明,测试发现其回调频率在动画片汪汪队 1Hz 左右,但也会不断变化,猜测是某种系统计时器。
  3. inputGro手势舞upSignaledCallbackmk_timer驱动,对应的maflutter是什么意思ch_port正是 VSync 信号。

iOS 高刷屏监控 + 优化:从理论到实践全面解析

  1. ropengl版本过低equestRegistrySignaledCallback动画制作软件UIScrollView在即将开始滑动时驱动。

iOS 高刷屏监控 + 优化:从理论到实践全面解析

通过上面的分手势识别析,笔者有理由认为在 iOS 15 上应用的渲染驱动机制出现了比较大的变化指针式万用表使用方法。其中之一便是 DisplayLink 的驱动源的改变。

结论

  1. iOS 15 上 Apple 改变了在 ProMotion 设备的fluttershy渲染flutter有必要学吗事件循环的驱动方式,CoreAnimation 的事务提交不再由完全由 RunLoop 驱动,而是涉及了手势密码多个信号源
  2. 系统动态帧率选择的机制会综合指针数组考虑使用方设置的 API(如 pref手势密码erredFrameRateRange)和实际展示的内容的变化频opengl渲染gpu怎么设置率。具体对 CADisplayLink 而言:
    • 内容低速变化时,CADisplayLink 解锁高刷新率仅影响自身的回调频率,系统仍可能选择较低flutter框架的屏幕刷新率来降低功耗
    • 内容中高速变化时,CADisplayLinflutteredk 解锁高刷新率可以让系统选择更高的刷新频率,甚至实现锁定 120Hz 的刷新

关于如何界定低速/中高速,笔指针数组和数组指针的区别者在下文中 CAAnimation 设置动态帧率 部分做了一些试验,可作为参考。

同时,默认配置手势语的 CADisplayLinkopengl怎么开启 回调频率最高为 60Hz,无手势舞教学视频简单法监控更高频率的刷新事件。

  1. ProMotion 设备中,DisplayLink 不再由 VSync 信号直接动画片猫和老鼠驱动,而是在新引入的渲染事件循环中执行。新版本 iOS 系统实现了某种更复杂的机制来尽可能满足使用者设置的偏好频率进行回调,但并不保证它与 VSync 信号的强关联性。这意味着默认的 CADisplayLink 的回调频率与实际帧率并不匹配,之前基于 CADisplayLink 进行帧率监控的方案在 ProMotion 设备上变得不再可行。

动态帧率的应用场景

监控指针万用表读数图解动态帧率下的流畅度表现

业界中一般采用 CADisplayLink 对应用的流畅度进行监控。由于 CADisplayLi指针万用表读数图解nk 的行为在 iOS 15 上的变化,原先的监控方案无法评估 ProMotion 屏幕在超过 60Hz 时的表现。

根据上面的探索结论,目前笔者设想了三种针对 ProMot指针是什么ion 设备的兼容性修改方案:

方案一 [Pass]

对于任何设备都以 60Hz 为优化目标手势舞教学视频简单,只考虑刷新间隔长于16.67ms的情况。换句话说,在屏幕以 120Hz 刷新时,对于丢 1 帧的情况也认为不丢帧,因为此时两帧之间的间隔仍然小于16.67ms,理论上用户感知不大。

优点

  • 方案简单,仅需设置preferredFramesPerSecond为固定值 60 即可
  • 兼容之前的指标。依然可以计算 FPS 指标,对于刷新率高于 60Hz 的情况统一认为刷新率为 60Hz

缺点

  • 由于只能监控最高 60Hz 的情况,无法评估更高刷新率下一些微小丢帧对用户体验指针数组带来的影响,也无法评估对高刷屏的一些优化所带来的技术影响
  • 在低刷新率时,MainRu动画大放映nLoop 依然会以 60Hz 运行,对功耗有一定影响

方案二 [Pass]

通过一些手段,可动画片猫和老鼠以替换驱动display_timer_callback的 Source 1 信号的回调,使用它来准确监听指针 VSync 信号,实现手势含义图解大全对动态帧率的准确监控。

优点

  • 理论上最精确的监控方案
  • 对功耗的影响最小,回调频率只有在屏幕刷新率实际升高时才会随之提升

缺点

  • 使用flutter翻译了私有 API
  • FPS 指标从此不再适用
  • VSync 信号目前和渲染流程不完全匹配,虽然精确但不一定实用

方案三 [Pick]

通过在 CADisplayLink 回调中确认duration参数,计算得到当前屏幕的实时刷新率,并修改preferredFrameRateRange来进行跟踪。

优点

方案相对简单,只需在每次回调中更新 Diopengl是什么意思splayLink 对象的preferredFrameRateRange属性即可手势密码

缺点

  • 由于动态帧率的存在,FPS 指标可以反映实手势时屏幕刷新情况,但是聚合后的指针式万用表使用方法意义不大,消费时需要区分特定机型/场景
  • 观察到目前的最opengl是什么意思小回调频率为 60Hz,也就是说无法确认 ProMotion 屏幕在 48Hz、30Hz 甚至更低刷新率下的表现
  • 在低刷新率时,MainRunLoop 依然会以 60Hz 运行,对功耗有一定影响

需要注意的是,CADisplayLink 的preferredFrameRateRange需要以类似一下格式进行设置:

NSIntegercurrentFPS=(NSInteger)ceil(1.0/displayLink.duration);
displayLink.preferredFrameRateRange=CAFrameRateRangeMake(10.0,currentFPS,0.0);

CAFrameRateRange.minimum 传最小值指针式万用表使用方法 10.0,preferred 传 0.0,可以让该 CADisplayLink 只用于监flutter有必要学吗控当前的系统帧率指针万用表怎么读数,而不影响帧率的动态选择OpenGL

相比前两个方案,方案三改动小,不使用私有 API,监控准确性也较高,缺点相对来说可以接受。指针

FPS 的替代指标

考虑到在动画片熊出没 ProMotion 屏幕上 FPS 指标不再与应用运行是否流动画畅直接相关,它的聚合值参考价值不大,有必要寻找一个新指标作为替换。

Apple 官方在 WWDC20 – 10077 Eliminate animation hitch动画片少儿小猪佩奇es with XCTest 中介绍opengl模式Hitch Time Ratio这一概念,并着重说明了它比单flutter面试题纯的opengl和vulkan FPS 更能适配不同刷新率的场景。

在 XCTest 框架中,苹果提供了 APIXCTOSSignp动画专业ostMetric帮助开发者在单测中即时地获取该指标,但相关 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 pflutteringer second for a given duration.

笔者尝试实现了基于 CADisplayLink 的(Scroll) Hitch Time Ratio的计算方案:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

  1. 计算上一帧的帧时间戳与上上一帧的目标帧时间戳得到上一帧的 Hitch Time
  2. 确定该帧是opengl和directx否是在滑动中渲染
  3. 累计得到整体的 Hitch Frame,与累积的帧间隔相比,得到 (Scroll) Hitch Time Ratio

关键场景提升帧率

在测试过程中笔flutter翻译opengl模式发现,系统 App 滑动时是稳定以最高刷新opengl怎么开启率 120Hz 运行手势舞教学视频简单的:

iOS 高刷屏监控 + 优化:从理论到实践全面解析

而第三方 App 即便设置了C指针ADisableMinimumFrameDurationOnPhonetrue也无opengl是什么意思法稳定以满帧率滑动(经过验证,这一点在 iOS 15.4 beta 系统上依然成立)。

通过利用 iO指针式万用表使用方法S 15 引入的新 API,我们可以在关键场景如滑动、转场、动画过程中主动解锁更高/限制更低的动态帧率,从而优化流畅度或者优化功率,提升用户体验目标。

滑动中稳定 120Hz

首先,笔者希望非系统 App 也可以尽可能实现滑动中稳定 120Hz 刷新。

结合上述分析,这一点可指针说漫以用 CADisplayLink 来实现。这里笔者提出两种可能方案手势语仅供参考:

  1. 创建 CADisplayLink,配置其preferredFramesPerS动画头像econd为 120,然后将其添加到UITrackingopengl和vulkanRunLoopMode中。
CADisplayLink *dp = ...
dp.preferredFramesPerSecond = 120;
// 或者
dp.preferredFrameRateRange = CAFrameRateRangeMake(120.0, 120.0, 0.0);
[dp addToRunLoop:[NSRunLoop mainRunLoop] forMode:UITrackingRunLoopMode];

在滑动中,指针数组该 CADisplayLink 被激活,系统指针是什么锁定当前帧率为最高 120Hz(仅在内容中高速变化时生效)。动画片汪汪队停止滑动时则恢复正指针c语言常帧率。

  1. 添加 CADisplayLink 至CommonModes中,分别在开始/停止滑动时启用/暂停 CADisplayLink,并修改动画片猫和老鼠对应的preferredFramesPerSecond等属性,触发帧率变化。
CADisplayLink *dp = ...
dp.paused = YES;
[dp addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
CFRunLoopAddObserver(CFRunLoopGetMain(),
                         CFRunLoopObserverCreateWithHandler(kCFAllocatorDefault, kCFRunLoopEntry | kCFRunLoopExit, YES, 0,
                                                            ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
        if (activity == kCFRunLoopEntry) {
             dp.paused = NO;
             dp.preferredFramePerSecond = 120;
        } else {
             dp.paused = YES;
             dp.preferredFramePerSecond = 0;
        }
    }), (__bridge CFStringRef)UITrackingRunLoopMode);

在实手势舞践中,由于也存在需要在非滑动状态下解锁帧率上限的情况,所以方案 2 的flutter框架通用性会更好。

CAAnimation 设置动态帧率

目前苹果只提供了修改CAAnim指针说漫ation动画帧率的 API,设置CAAnimation.preferredFrameRateRange即可改变其对屏幕刷新率的影响。

  • 对于用指针数组和数组指针的区别户感知明显的,如转场动画,可以设置为 120Hz。
  • 对于感知不明显的,如旋转动画,可以OpenGL降低其帧率,比如设置为 30Hz。

但是,和 DisplayLink 相同,过上述 API 的设置虽然会“影响”系统的opengl坐标转换学步园动态帧率的选择,flutter有必要学吗但这种影响并不是绝对的。在实际使用中,笔者发现屏幕选择指针说漫的刷新率和 CAAnimation 在屏幕上变化的速度有关。

关于此点,以 iPhone 13 Pro 为例,笔者使用了一个简单的、偏好帧率为固定 120Hz 平移动画进行说明:

CABasicAnimation*anim=[CABasicAnimationanimationWithKeyPath:@"transform.translation.y"];
CGFloatspeed=170.0/330.0;
anim.toValue=@(100);
anim.fromValue=@(0);
anim.duration=10.0;
anim.repeatCount=FLT_MAX;
anim.preferredFrameRateRange=CAFrameRateRangeMake(120,120,120);

其中speed变量为平移的速度,单位为 pt/s,试验发现:

  • speedflutter翻译 (0, 16手势变化0] 时,屏幕刷新率为 60Hz
  • speed取 [161, 320] 时,屏幕刷新率为 80Hz
  • speed取 [321, +∞) 时,屏幕刷新率为 120Hz

笔者仅在 iPhone 13 Pro 上测试了平移动画指针式万用表的场景,以上数据仅供参考。

最后,对于其他的常见的动画 API,例如UIView.animateWithDurationUIViewPropertyAnimfluttershyator等,则没有提供对应 API 进行修改。理论上也可以通过某flutter是什么意思些手段拿到这些上层 API 所创建的 CA动画片汪汪队Animation 对象来实现修改。

手势/转场等其他场景解锁 120Hz

其他场景需要控制动态帧率的也可以通过手动修改 CADisplayLink 的preferredFramePerSecond/preferredFrameRateRange属性来实现,其实现和通过动画片汪汪队监听 RunLoop 来修改滑动帧率基本相同。

UIGestureRecognizer指针被用于实现的指针数组和数组指针的区别交互式动画。经过测试,发现在触发手势回调的同时启用一个解锁了频率的 CADisplayLopengl坐标转换学步园ink 也可以间接提高UIGestureRecognizer的回调频率,从而实现更高帧率的交互动画。

对于转场的场景,一个简单的方案是 swizzle UI指针数组ViewController 的生命周期消息,在出现/消失的节点启用/停用 CADisplayLink 帧率的解锁,从而实现通用的页动画片猫和老鼠面转场动画帧率解锁方案

Flutter 官方也计划提供类指针万用表读数图解似 API 让应用侧可以针对不同的场景(滑动、动画 etc)动态切换屏幕刷新率:github.com/flut手势舞教程视频慢动作ter/flu…

上线收益

手势识别于上述思路,笔者所在团队在国际化短视频业务落地了动画大放映优化项目,经过实验验证:

  • 大盘滑动帧率 P50 从 81.57 上升至 11opengl和directx2.2
  • 核心业务指标也有一定收益

结语

近年来,Apple 生态中软硬件的发展日新月异,有软件层的 dyld 的持续优化和 iOS 15 新手势密码引入的 Prewarm 机制,也有新的 Pro动画片猫和老鼠Motion 屏幕,可以看到 Apple 一直致力于打造更丝滑流畅的用户体验。

Apple 提供的系统级优化方案一般通用而无感知,但通用往往也意味着一定的局限性,可能预留了额外优化空间,应用开发者们可以进一步去研究如何更好地适配。

例如本文中,笔者通过研究新引入的 ProMotion 屏幕背后的机制,透过表象/深入汇编管中窥手势舞教学视频简单豹看到一部分动画电影本质,最终落地了监控 + 优化的方案,让大盘滑动帧率 P手势语50 从 80 上升至 112 左右,取得了额外的业务收益。

最后,笔fluttering者认为,我们普通指针c语言开发者作为 Apple 生态链中的一环,在享受系统级别优化自动带来的收益的同时,也应该主动去了解上述优化背后的底层原理。一方面,了解与学习 Apple 的成熟优化思路可flutter翻译以提升我们作为工程师的眼界。另一方面,对系统底层原理的了解可以拓充我们的“弹药库”,对业务价值交手势变化付的flutter开发的app有哪些全链路了解越广越深,越有可能抓住潜在的优化点,从而在性能优化工程师这条职业道路上走得更远更好。

参考资料

  1. WWDC20 – 10077 Eliminate aniflutter框架mation hitches with XCTest

    de动画片熊出没veloper.appl动画片汪汪队e.com/videos/play…

  2. WWDC21 – 10147 Optimize for variable refresh rate dflutter面试题isplays

    developer.apple.com/videos/play…

  3. Optimizi指针数组ng ProMotion Refresh Rates for iPhone 13 Pro and iPad Pro

    developer.apple.com/documentati…

  4. What is Adaptive Sy动画片小猪佩奇nc动画片少儿小猪佩奇?

    www.viewsonic.com/library/tec…

  5. github.com/flutter/flu…

加入我们

我们是字节国际化短视频基础技术团队,是一个深度追求极致的团队,我们专注于性能、架构、包大小、稳定性、自动化测试、基础库、编译构建等方向的深耕,保障超大规模团队的研发效率和全球数亿用户的使用体验。目前上海、杭州、新加坡动画电影、美国都手势舞教程视频慢动作有大手势舞量人才需要,欢迎有志之士与我们共同建设亿级用指针式万用表使用方法户全球化 APP!

可以点击 jobs.bytedance指针c语言.c手势密码om/experienced… ,进入字节跳动招聘官网手势含义图解大全投递简历,也可fluttered以邮件联系:kazec.liu动画制作软件@bytedance.cofluttershym咨询相关信息或者直接发送简历内推!

发表评论

提供最优质的资源集合

立即查看 了解详情