网络知识 娱乐 OpenGL-离屏渲染

OpenGL-离屏渲染

什么叫做离屏渲染

正常情况下,渲染数据存放在帧缓冲区(Frame Buffer)中,但是在特定条件下,需要先将渲染数据先放在离屏缓冲区(Offscreen Buffer)中,在将多个图层的渲染数据叠加计算后,再传入帧缓冲区进行渲染,这种情况就叫做离屏渲染。

在这里插入图片描述

正常渲染流程

APP中的数据经过CPU计算和GPU渲染后,将结果存放在帧缓冲区,利用视频控制器从帧缓冲区中取出,并显示到屏幕上。

  • 在GPU的渲染流程中,显示到屏幕上的图像是遵循大画家算法按照由远及近的顺序,依次将结果存储到帧缓冲区
  • 视屏控制器从帧缓冲区中读取一帧数据,将其显示到屏幕上后,会立即丢弃这帧数据,不会做任何保留,这样做的目的是可以节省空间,且在屏幕上是各自显示各自的,互相不影响。

离屏渲染流程

当App需要进行额外的渲染和合并时,例如按钮设置圆角,我们是需要对UIButton这个控件中的所有图层都进行圆角+裁剪,然后再将合并后的结果存入帧缓存区,再从帧缓存中取出交由屏幕显示,这时,在正常的渲染流程中,我们是无法做到对所有图层进行圆角裁剪的,因为它是用一个丢一个。所以我们需要提前将处理好的结果放入离屏缓冲区,最后将几个图层进行叠加合并,存放到帧缓冲区,最后屏幕上就是我们想实现的效果。

优点:实现某些特殊的渲染效果;某些情境中可以节省性能。

缺点:需要专门开辟一块离屏缓冲区造成存储量开销,在离屏缓冲区和帧缓冲区中切换上下文造成性能开销。

什么情况会触发离屏渲染

  1. 遮罩(masks)

    • mask是覆盖在所有layer及其子layer之上的,可能还带有一定的透明度。
    • mask也是需要等整个layer树绘制完成,再加上mask和组合后的layer进行组合,所以需要开辟一个独立于FrameBuffer的内存,用于将layer及其子layer画完,最后再和mask进行组合,存储到FrameBuffer,视频控制器从FrameBuffer中读取数据显示到屏幕上。
  2. 光栅化(shouldRasterize)

    开启光栅化是通过设置属性shouldRasterize,开启光栅化后CALayer会被保存为bitmap放到缓存中,这样在下次需要时可以直接从缓存中取出来显示,这样节省了渲染时间,例如对于设置有阴影效果的复杂视图会对性能有一定的提升。

    nameLabel.layer.shouldRasterize = true//开启光栅化
    

    光栅化使用建议

    • 如果layer不被复用,则没有必要打开光栅化。
    • 如果layer不是静态的,需要被频繁修改,比如处于动画之中,那么开启离屏渲染反而影响效率了。
    • 离屏渲染缓存内容有时间限制,缓存内容100ms,如果这期间没有被使用,就会被丢弃,无法进行复用。
    • 离屏渲染缓存空间有限,超过2.5倍屏幕像素大小的话,也会失效,且无法进行复用了。
  3. 裁剪(layer.masksToBounds / view.clipsToBounds)

    我们平时看到的一个CALayer,其实是可以分成三个显示部分的,分别是backgroundColor(背景)、contents(内容)、border(边框)。根据官方文档的说法,设置layer圆角时,只会设置backgroundColor和border的圆角,并不会设置content的圆角,除非同时设置了masksToBounds为true(对应UIView的clipsToBounds属性)。例如

    img1.layer.cornerRadius = 50;			//设置圆角
    img1.layer.masksToBounds = YES;		//使content跟着变为圆角
    

在这里插入图片描述

上面图片,在实际渲染中,其实是将backgroundColor和contents叠加后放在帧缓冲区中的。如果设置了圆角,就会先将backgroundColor设置圆角并放在离屏缓冲区,再将contents设置圆角放在缓冲区中。再将离屏缓冲区中叠加后的内容放入帧缓冲区渲染。所以出发了离屏渲染。

经试验,如果背景图设为透明色,则不会触发离屏渲染,原因是,只需要将内容圆角计算即可,不需要和其他图层进行计算后叠加了。

同理,背景色设为透明后,再添加其他拥有内容或背景色的子layer,则又会触发离屏渲染。

总结: 当设置圆角时,需要多个图层计算并叠加的情况,就会触发离屏渲染。

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

在这里插入图片描述

如图,有蓝色、黄色、粉色三个图层,并且黄色和粉色都设置了透明度,则图层叠加的部分(红色边框圈住的部分)所显示的颜色为三种颜色叠加后的颜色。这个叠加颜色并不是自然而然就有的,而是需要计算机底层计算得出来的,这时候就需要依次将三个图层放入离屏缓冲区中,并依次计算重叠部分的颜色,造成离屏渲染。

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

    需要将layer绘制完成后才能确定阴影的形状和区域,所以需要将layer渲染后暂时保存在离屏缓冲区,再渲染阴影。