首先假设我们app每秒显示60帧,数据会存在于帧缓冲区Frame Buffer当中,然后屏幕不断从帧缓冲区中取数据去显示。
与正常流程不同的是,当触发离屏渲染时,数据不会先放到帧缓冲区,而是会先放到离屏缓冲区offscreen Buffer(这个缓冲区是帧缓冲区之外额外开辟的缓冲区)。等到几个结果叠加之后,然后会到帧缓冲区去显示出来。
离屏渲染触发原理
app进行额外的渲染和合并->offscreen Buffer组合->FrameBuffer->屏幕;
离屏渲染会造成性能问题:
- 会造成额外的存储空间,可能会造成压力比较大
- 从离屏缓冲区(offscreen Buffer)到帧缓冲区(Frame Buffer)是需要一段时间的,其实离屏缓冲区的空间大小也是有限制的,为屏幕像素的2.5倍。
- 如果出现很多的离屏渲染情况,很容易出现掉帧情况
反正尽可能能不要离屏渲染就不离屏渲染。
离屏渲染的原因
既然离屏渲染这么容易造成性能问题,为啥还要用它呢?
- 特殊的效果(高斯模糊、抗锯齿、毛玻璃等等)使得我需要使用额外的offscreen Buffer来保存中间状态,不得不使用离屏渲染(系统自动触发离屏渲染,圆角、阴影也是)
- 还有一个效率优势:既然效果会多次出现在屏幕上,我们为什么不能提前渲染好,保存在offscreen Buffer里面,然后可以达到复用目的,避免再重复的进行GPU、CPU的计算
光栅化(shoulRasterize)
也是出现离屏渲染的一种原因,不过光栅化是选择主动触发的
光栅化使用建议:
- 如果layer不能被复用,则没有打开光栅化的必要。
- 如果layer不是静态的,需要被频繁修改,比如处于动画之中,那么开启离屏渲染反而影响效率。
- 离屏渲染缓存内容有时间限制,缓存内容 100ms 内没有被使用,那么它就会被丢弃,无法再进行复用了。
- 离屏渲染缓存空间有限,超过2.5倍屏幕像素大小的话,也会失效的,且无法进行复用。
圆角触发的离屏渲染 (offscreen Rendering)
正常渲染逻辑
对于单一一个渲染(如只有一张内容图片),当sublayer绘制到屏幕后,就会将sublayer从帧缓冲区移除,以节省空间。
离屏渲染逻辑(圆角)
对于多个组合在一起的(如有内容图片、有背景、有圆角、阴影等),如果想要圆角效果,需要背景圆角、边框圆角、图片内容圆角,然后组合在一起就是整体圆角效果了。这个时候系统就会自动触发离屏渲染,把所有的组合在离屏缓冲区组合在一起再一起显示再屏幕上。view.layer.masksToBounds == true
是触发离屏渲染的原因(必须要在多个图层的基础上触发)
常见的离屏渲染的几种情况:
- 使用了mask的layer(layer.mask)
- 需要进行裁剪的layer(layer.masksToBounds / view.clipsToBounds)
- 设置了透明度为YES,并且透明度不为1 的layer(layer.allowsGroupOpacity/layer.Opacity)
- 添加了投影的layer(layer.shadow)
- 采用了光栅化的layer(layer.shouldRasterize)
- 绘制了文字的layer(UILabel, CATextLayer, coreText等)