Advanced Graphics and Animations
主题:
- Core Animation pipeline
- 动画
- 渲染相关概念
- UIBlurEffect and UIVibrancyEffect
- Profiling Tools and demon
一、Core Animation pipeline
app 直接使用 core Animation 或者通过 UIKit 间接使用 core Animation 来创建图层;
app 进程不为 Core Animation 提供渲染工作,Core Animation 会将所有的图层提交到 render server 来完成渲染工作。
render server
- 独立的进程;
- 具有一个 Core Animatio 对应的服务端版本,专门接收 Core Animation 提交的图层;
- 使用 GPU进行渲染,硬件加速;
- 对应框架为 OpenGL 或者 metal 框架进行渲染,
硬件加速即指 GPU 渲染。因为一般而言,CPU 虽然也是硬件,但是工作内容大部分是面向软件层面,需要处理很多中断指令。相对而言,GPU 工作内容是纯计算,其设计上也是为了高并发和高效率的计算,所以 GPU 渲染一般称为硬件加速,使用 CPU 渲染则效率相对低下;
大概流程
app:
- 用户通过操作 app 触发事件;
- 事务提交到 render server(具体分为4步,见后文);
render server/GPU
- 解码图层;
- 等待下一帧开始的信号。iOS 上是双缓冲机制,所以这个信号表示上一个 buffer 已经扫描展示,显示器已经切换到了另一个 buffer。当下,需要绘制新的位图并更新到上一帧所在的 buffer 上;
- 调用 openGL 或者 metal 函数,利用 GPU 进行绘制渲染;
-
将绘制完成的位图存储到 buffer 中,等待显示器扫描展示,这个步骤和上个步骤如果未在 16.67ms 内完成,则会造成卡顿;
coreAnimation pipline
commit transaction
1. layout
两个关键方法:layoutSubviews
和 addSubview
;这一步中,view 被创建,layer 被创建并被添加到视图树中;这一步中,可以做一些轻量的数据库操作,比如 label 的布局需要字符串;
这一步发生在 CPU,一般都是 CPU 操作或者 I/O 操作(外存);
2. display
关键方法:drawRect
;如果这个方法被重写了,那么就会调用 Core Graphic 来利用 CPU 进行绘制。
因为此时的绘制时不可见的,所以这里使用的 CPU 在内存中进行位图的绘制;这里严格来说,可以说成是离屏渲染,因为不是直接绘制在 buffer 上的。
GPU 的绘制一般都是直接绘制在 buffer 上,GPU 的离屏渲染大概是开辟一块内存进行渲染操作,最后将两块内存混合,在两块内存之间进行切换会消耗性能。 Apple 对于离屏渲染的界定其实就是 GPU 离屏渲染,所以 CG 相关的绘制函数不被认定为时离屏渲染;
这一步一般是 CPU 操作或者 memory(内存) 操作,因为是使用 CPU 绘制位图,需要使用到内存,而不是本地化存取;
这一步是适用 CPU 渲染,所以应当尽量避免过多或者范围过大的绘制,最好直接使用 layer,因为 Layer 实际就是一个指向 bitmap 的指针,而且 layer 是通过 core Animation 实现,而不是 core Graphic,其会尽可能将渲染操作提交到 GPU 上执行,这也就是 Apple 所说的硬件加速;
上面已经解释,但是再啰嗦几句。硬件软件只是一种说法,CPU 处理的事物更多的是来自软件,所以常说 CPU 面向的是软件层面,而 GPU 的操作基本都是全量利用 GPU 的计算能力来进行渲染,不会处理各种中断、if 判断等,所以常说 GPU 面向硬件。
3. prepare
这一步主要是对图层中所包含的图片进行解码和转换。
解码就是我们常说的将图片解码成 bitmap 格式存储在内存中。bitmap 的大小是否和原图相同,取决于图片的格式,也就是压缩方式,PNG 是保真类型的图片,压缩之后的图片存储大小会变现,但是在这一步,会被加载到内存,解码之后的 bitmap 和原图大小一致;JPEG 则是对 bitmap 中相邻的点进行了裁剪等操作,压缩之后不仅存储大小变小,被加载到内存中,还原成 bitmap 之后,因为原图的信息部分丢失,所以解码之后的 bitmap 大小会比原 bitmap 要小;
iOS 的 GPU 支持 JPEG 和 PNG,其他格式需要进行转换;
4. package up
关键词:recursive
递归图层树,打包所有 layer 信息,传递给 render server;
正因为要递归 layer tree,所以布局时尽量减少视图层级(as flat as possible)能够保证这一步尽量的高效快速;
animation
animation步骤和图层绘制一样,唯一不同的是在 commit 阶段,不仅提交图层,还提交了动画。这样在动画执行过程中,render server 按照既定的流程执行动画,不需要在进程之间进行通信了。这也是 core Animation 动画高效的原因;
以下暂时没看到,暂略
渲染的几个概念
- tile based rendering is how all GPUs work
- introduce the concept of render passes
- doing a first example by showing you how masking works with render passes
UIBlurEffect 和 UIVibrancyEffect 原理
项目中的 toast 有用到,需要好好总结下;
instrument
这种使用的东西,比较不好说,要自己体会,略;