作为 iOS开发者, 大家都知道, 做阴影, 圆角等等会触发离屏渲染, 会额外开辟空间, 消耗性能. 这对移动端来说不是一件好事. 今天就来聊聊关于离屏渲染相关问题.
- 非离屏渲染过程
- 离屏渲染过程
- 离屏渲染的原因
- 有哪些情况会触发离屏渲染
- 特殊的离屏渲染
非离屏渲染过程
我们先来认识一下非离屏渲染的逻辑, 就是正常的渲染过程.
我们需要显示一个下图最右边的图案, 这个图案有三个图层组成, 最终渲染展示在屏幕上.
-
第一步, 在帖缓冲区绘制 sublayer1, 屏幕从帖缓冲区中获取图层并显示到屏幕上, 此时 sublayer1 已经完成了使命, 所以帖缓冲区就丢弃 sublayer1, 释放空间.
-
第二步, 绘制 sublayer2, 屏幕从帖缓冲区中获取图层并显示到屏幕上, 此时 sublayer2 已经完成了使命, 所以帖缓冲区就丢弃 sublayer2, 释放空间.
-
第三步, 绘制 sublayer3, 屏幕从帖缓冲区中获取图层并显示到屏幕上, 此时再丢弃 sublayer3, 所以帖缓冲区就丢弃 sublayer3, 释放空间.
- 非离屏渲染过程.jpg
离屏渲染过程
我们要绘制如下图最右边的图案, 本次带圆角(圆角自己发挥一下想像, 我没有画出来),
- 第一步, 绘制 sublayer1, 保存到 离屏缓冲区( offscreenBuffer ).
- 第二步, 绘制 sublayer2, 保存到 离屏缓冲区( offscreenBuffer ).
- 第三步, 绘制 sublayer3, 保存到 离屏缓冲区( offscreenBuffer ).
- 第四步, 分别将 sublayer1 sublayer2 sublayer3 做圆角.
- 第五步, 将圆角后三个图层叠加混合.
因为圆角需要等到三个图层全部绘制完成后才能进行, 所以每个图层绘制完成后都需要保存起来, 这个操作过程就需要额外开辟一块空间来保存这三个图层, 这块空间就是 离屏缓冲区( offscreenBuffer ), 需要开辟离屏缓冲区的渲染过程, 就是离屏渲染.
- 离屏缓冲区( offscreenBuffer )的空间大小是有限的, 超过 2.5 倍屏幕大小就会失效, 也不能复用,
- 缓存内容有时间限制, 如果超过 100 ms 没有被使用, 那么他就会丢弃, 也不能复用.
- 离屏渲染过程.jpg
离屏渲染的原因
视图包括多个图层, 在绘制过程中需要做混合图层的操作.
离屏渲染的利弊
利
- 特殊效果
需要使用额外的 offscreenBuffer 保存中间状态, 不得不使用离屏渲染, 系统自动触发.
- 提高效率
当一个效果会多次出现时, 可以提前在 offscreenBuffer 中渲染, 达到复用目的.
弊
- 性能开销
离屏渲染会带来一定的性能开销, 创建缓冲区和切换上下文最消耗性能,而绘制其实不是性能损耗的主要原因.
有哪些情况会触发离屏渲染
常见触发离屏渲染的几种情况:
- 使用了 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, Core Text 等)
- 重写 UIView 及其子类的 drawRect.
特殊的离屏渲染
一般的离屏渲染都是发生在 GPU 中, 但是有一种特殊的情况是发生在 CPU 中的, 重写 UIView 及其子类的 drawRect, 凡是使用 CoreGraphics 绘图的, 都发生在 CPU 中. CoreGraphics 是线程安全的, 所以可以异步在子线程中进行绘制.
网友评论