iOS离屏渲染

387 阅读3分钟

什么是离屏渲染?

离屏渲染的定义:如果要在显示屏上显示内容,我们至少需要 一块与屏幕像素数据量一样大的FRAME BUFFER(帧缓冲 区),作为像素数据存储区域,然后由显示控制器把帧缓存区 的数据显示到屏葬上。如果有时因为面临一些限制, 一些原 因,比如说阴影,遮罩MASK等,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 的卡顿和掉帧

离屏渲染的优化

1. 针对圆角、阴影效果等的方案

  1. 使用带圆角的图片
  2. 使用贝塞尔曲线进行圆角绘制
  3. 跟服务端讨论进行圆角处理
  4. 当不存在短时间内需要反复多次大量复用的layer时,shouldRasterize设置为NO