iOS 离屏渲染

离屏渲染是基于 GPU 层面上的,指 GPU 在当前屏幕缓冲区外开辟了一个缓冲区,进行渲染操作。

什么是离屏渲染?

离屏渲染是基于 GPU 层面上的,指 GPU 在当前屏幕缓冲区外开辟了一个缓冲区,进行渲染操作。

当设置某些 UI 图层属性时候,如果指定为被未预合成之前,不能直接显示在屏幕上的时候,就触发了离屏渲染。

当我们要在屏幕上显示内容, 至少需要一块与屏幕像素数据量一样大的 frame buffer 来作为数据存储区域 (GPU 渲染结果存储的地方)。但是此时出现了特殊情况导致渲染结果无法直接写入 frame buffer, 而是需要先暂存到另外的区域进行处理, 之后再写入到 frame buffer, 这种情况就称之为 离屏渲染

检测离屏渲染

模拟器 可以通过设置 Debug -> Color Off-screen Rendered 来打开离屏渲染检测

真机 则通过设置 Debug -> View Debugging -> Rendering -> Color Off-screen Rendered 来打开离屏渲染检测

颜色呈现 黄色 的区域就是触发了 离屏渲染 的区域

为什么会产生离屏渲染?

正常的情况下, OpenGL 提交一个命令到 Command Buffer , 随后 GPU 就开始渲染, 最后将渲染结果放到 Render Buffer 中。

这里如果想要绘制一个带有圆角并剪切圆角的容器 (maskToBounds 为 YES, 背景色不是透明, 具体可以看下面的例子), 就可能触发离屏渲染。

  1. 首先将 layer 的内容裁剪成圆角
  2. 容器的子控件在渲染的过程中, 因为父 layer 是被裁剪过的, 那么也需要被裁剪; 但是这时的 父 layer 已经被渲染完成而子 layer 还在队列中, 没有办法进行统一裁剪, 所以这个过程就没办法实现了

所以系统就不得不去 开辟独立于 frame buffer 的内存, 先把父 layer 以及他的子 layer 依次画好, 然后合并到一起进行裁剪, 再把结果放到 frame buffer 中, 这就是为什么需要离屏渲染。

何时触发

  • ~圆角(当和 makeToBounds 或者 clipToBounds 同时使用)~ iOS9 后, 圆角 + maskToBounds, 然后设置了背景颜色, 产生了离屏渲染, 但是 圆角 + maskToBounds 不设置背景色 , 是不会触发离屏渲染 (单层情况下)
  • 图层蒙版
  • 阴影
  • 光栅化
  • 光栅化(Rasterization)是把顶点数据转换为片元的过程,具有将图转化为一个个栅格组成的图象的作用,特点是每个元素对应帧缓冲区中的一像素。(应用:较为广泛的应用于深度学习卷积神经网络的结构中)

关于 iOS 9 的优化后:

可以理解为,因为只有 单层 内容需要添加圆角和裁切,所以可以不需要用到离屏渲染技术。但如果加上了背景色、边框或其他有图像内容的图层,就会产生为 多层 添加圆角和裁切,所以还是会触发离屏渲染。

为何要避免离屏渲染

离屏渲染发生在 GPU 层面上,因为离屏渲染使 GPU 触发 Opengl 多通道渲染管线,产生额外开销,所以要避免。 在触发离屏渲染时候,会增加 GPU 工作量,增加 GPU 工作量,可能会导致 GPU 和 CPU 工作耗时的总耗时超出 Vsync 信号 (16.7 毫秒) 时间,导致 UI 卡顿或者掉帧。

离屏渲染会创建新的渲染缓冲区,导致内存上的开销,有多通道渲染管线,最终要把多通道的渲染结果进行合成,所有会有上下文的切换,就有 GPU 的额外开销,那么可能就会导致 UI 的卡顿和掉帧

Reference:

iOS 探索 – 离屏渲染

Page

< Previous
Next >