一步步学习计算机视觉 in IOS番外篇(三)离屏渲染

什么是离屏渲染

首先我们来看一下渲染架构:


image.png

CPU 计算好显示内容提交到 GPU,如果要在显示屏上显示内容,我们至少需要一块与屏幕像素数据量一样大的帧缓冲区(frame buffer),作为像素数据存储区域,而这也是GPU存储渲染结果的地方。GPU 渲染完成后将渲染结果放入frame buffer,随后视频控制器会按照 VSync 信号逐行读取frame buffer的数据,经过可能的数模转换传递给显示器显示。显示完成后,frame buffer中的数据直接丢弃

如果有时因为面临一些限制,无法把渲染结果直接写入frame buffer,而是先暂存在另外的内存区域,之后再写入frame buffer,那么这个过程被称之为离屏渲染

image.png

这里要注意,被iOS认定的离屏渲染是GPU产生的,如果重写了drawRect方法,并且使用任何Core Graphics 的技术进行了绘制操作,就涉及到CPU渲染。这种CPU渲染可以成为软件渲染,不会被iOS系统认定为离屏渲染。

离屏渲染带来的影响

1)额外的内存

离屏渲染需要开放一块内存存放渲染数据,这部分内存最大为屏幕展示的2.5倍

2)上下文切换

离屏渲染的整个过程需要切换上下文环境,先从当前屏幕切换到离屏,等结束后,又要将上下文环境切换回来。虽然在iOS中,设备主存和GPU的显存共享物理内存,这样可以省去一些数据传输开销,但是还是要占用系统资源。

离屏渲染的原因

先说下我的理解:

离屏渲染是由于渲染层之间存在依赖引发的。

在上面的渲染流水线示意图中我们可以看到,主要的渲染操作都是由CoreAnimation的Render Server模块,通过调用显卡驱动所提供的OpenGL/Metal接口来执行的。通常对于每一层layer,Render Server会遵循“画家算法”,按次序输出到frame buffer,后一层 After Layer 会覆盖前一层 Before Layer,就能得到最终的显示结果。

但是,如果此时After Layer的渲染数据是半透明的,需要混合Before Layer的数据,按照正常的渲染流程,此时frame buffer中Before Layer已经被丢弃了,根本无法进行混合。为了保留Before Layer,iOS开辟了离屏渲染缓冲区,对Before Layer进行存储。

圆角 与 masksToBounds

首先我们要了解 CALayer的层次结构:CALayer由背景色backgroundColor、内容contents、边缘borderWidth&borderColor构成

image.png

cornerRadius的文档中明确说明:
cornerRadius的设置只对 CALayer 的背景色层和边缘层起作用

当我们只配置cornerRadius时,背景色层和边缘层生成圆角,内容层的渲染数据是直接覆盖背景色层,边缘层的数据也是同样,这时候不会触发离屏渲染

当我们配置 masksToBounds的时候,这个时候,内容层也要被裁剪圆角,而裁剪方式依赖边缘层。还记得我们说过的,离屏渲染是由于渲染层之间存在依赖引发的。现在内容层与边缘层就相互依赖了,从而导致了离屏渲染。

常见的触发离屏渲染情况

  1. 需要进行裁剪的 layer (layer.masksToBounds / view.clipsToBounds)

在View上设置相同形状的Mask View,要背裁剪掉的部分设置成背景色

image.png
  1. 设置了组透明度为 YES,并且透明度不为 1 的 layer (layer.allowsGroupOpacity/ layer.opacity)

这个只能尽量不要使用

  1. 添加了投影的 layer (layer.shadow*)

使用阴影路径计算

  1. 绘制了文字的 layer (UILabel, CATextLayer, Core Text 等)
    尽量使用Label代替

  2. 采用了光栅化的 layer (layer.shouldRasterize)
    这是主动进行离屏渲染,提高渲染效率.

image.png

你可能感兴趣的:(一步步学习计算机视觉 in IOS番外篇(三)离屏渲染)