iOS 离屏渲染

什么是离屏渲染?

离屏渲染是基于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 探索--离屏渲染

results matching ""

    No results matching ""