Core Animation渲染流水线工作流程
我们的App本身是不负责渲染的,渲染由Render Server进程来完成。
- App处理事件。这个过程会更新图层树。
- App使用CPU完成计算,打包发给Render Server。这些计算包括图层创建、布局、文本绘制、图片解码等。
- Render Server 调用OpenGL、Core Graphics,使用GPU完成图像的渲染。
- GPU通过Frame Buffer(帧缓冲区)和视频控制器等将图像在屏幕上显示。
离屏渲染触发原理
以上案例代码中,模拟器打开了离屏渲染展示开关“Color Off-screen Rendered”。左侧一列是三个UIImageView,右侧一列是三个UIButton。可以看到两列的第三个控件都发生了离屏渲染。
-
普通渲染
当我们为一个UIButton设置一个背景颜色和一个图片,渲染时,会按图层依次存入帧缓冲区。
-
渲染流程:
-
离屏渲染
当我们为一个UIButton设置一个背景颜色和一个图片,同时设置了圆角和maskToBounds,渲染时,会将图层存入离屏渲染缓冲区触发离屏渲染。当设置了maskToBounds时,要对背景图层和内容图层同时进行圆角裁剪,这时就不能按照普通的渲染流程一层一层的显示并丢弃。 -
渲染流程:
常见的触发离屏渲染情况
App需要进行额外的渲染和合并时会触发离屏渲染。一方面,设置了特殊的效果,一次性不能完成渲染时,系统会自动触发离屏渲染,使用Off-screen Buffer保存中间状态;另一方面,出于效率优势的考量,希望复用的效果可以通过设置layer的shouldRasterize(光栅化)属性为yes进行复用。需要注意的是,离屏渲染缓冲区是有空间大小限制的,可以存储屏幕像素点数量等2.5倍,超过空间时离屏渲染无效。当存入离屏渲染缓冲区100ms内没有被使用,也会被丢弃。
- 使用了mask的layer(layer.mask)
- 需要进行裁剪的layer(layer.maskToBounds)
- 设置了组透明度,并且透明度不为1。(layer.allowsGroupOpacity/ layer.opacity )
- 添加了投影的 layer (layer.shadow*)
- 采用了光栅化的 layer (layer.shouldRasterize)
- 绘制了文字的 layer (UILabel, CATextLayer, Core Text 等)
离屏渲染的缺点
- 需要使用额外的存储空间,可能会造成内存压力。
- 使用离屏渲染缓冲区存储的图层最终还是要通过放入帧缓冲区最终显示在屏幕上,从离屏渲染缓冲区进入帧缓冲区也耗费时间,造成性能问题,有掉帧的可能。