1、什么是离屏渲染?
1)On-Screen Rendering
意为当前屏幕渲染,指的是 GPU 的渲染操作是在当前用于显示的屏幕缓冲区中进行。
2)Off-Screen Rendering
意为离屏渲染,指的是 GPU 在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作。
2、离屏渲染触发的时机
当图层属性的混合体被指定为在未预合成之前不能直接在屏幕中绘制时,屏幕外渲染就被唤起了。屏幕外渲染并不意味着软件绘制,但是它意味着图层必须在被显示之前在一个屏幕外上下文中被渲染(不论 CPU 还是 GPU)。
离屏渲染可以被 Core Animation 自动触发,或者被应用程序强制触发。屏幕外的渲染会合并/渲染图层树的一部分到一个新的缓冲区,然后该缓冲区被渲染到屏幕上。
这里提到的 offscreen rendering 主要讲的是通过 GPU 执行的 offscreen,事实上还有的 offscreen rendering 是通过 CPU 来执行的。
如果我们重写了 drawRect 方法,并且使用任何 Core Graphics 的技术进行了绘制操作,就涉及到了 CPU 渲染。整个渲染过程由 CPU 在 App 内同步地完成,渲染得到的 bitmap 最后再交由 GPU 用于显示。其它类似 cornerRadios, masks, shadows 等触发的 offscreen 是基于 GPU 的。
PS:CoreGraphic 通常是线程安全的,所以可以进行异步绘制,显示的时候再放回主线程。
2.1 触发离屏渲染的方式
1、圆角(当和maskToBounds一起使用时)
2、图层蒙版
3、阴影
4、光栅化:设置 shouldRasterize = YES 便会触发光栅化
光栅化的概念:
将图转化为一个个栅格组成的图像,即从矢量的点线面的描述,变成像素的描述。
光栅化是一种特殊的离屏渲染,它的主要工作量集中在 CPU 上,而不是前文介绍的那种 GPU 单独开辟缓存进行图形生成计算,并且 CPU 光栅化完成后会将该 bitmap 缓存于本地,以便重复利用,它在形式上也是一种离屏渲染,但不属于 OpenGL 名字中特指的那种 GPU 新开 buffer 生成图形的过程。
光栅化注意两点:
1、不要过度使用,系统限制了缓存的大小为 2.5X Screen Size.
如果过度使用,超出缓存之后,同样会造成大量的 offscreen 渲染。
2、被光栅化的图片如果超过 100ms 没有被使用,则会被移除
因此我们应该只对连续不断使用的图片进行缓存。对于不常使用的图片缓存是没有意义,且耗费资源的。
注:对于那些需要动画而且要在屏幕外渲染的图层来说,你可以用 CAShapeLayer,contentsCenter 或者shadowPath 来获得同样的表现而且较少地影响到性能。
3、为什么要尽量避免离屏渲染?
一般导致图形性能的问题大部分都出在了 offscreen rendering, 因此如果我们发现列表滚动不流畅,动画卡顿等问题,就可以想想和找出我们哪部分代码导致了大量的 offscreen 渲染。
离屏渲染主要在两个地方开销较大:
1、创建新缓冲区
要想进行离屏渲染,首先要创建一个新的缓冲区。
2、上下文切换
离屏渲染的整个过程,需要多次切换上下文环境:先是从当前屏幕(On-Screen)切换到离屏(Off-Screen);等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上,又需要将上下文环境从离屏切换到当前屏幕。而上下文环境的切换是要付出很大代价的。
4、硬件加速
硬件加速是指用到了 GPU 的 API,以下这些情况不会用到硬件加速
1)使用 CGContexts 绘制的图形
2)所有在 drawRect 中完成的图形绘制。
3)shouldRasterize 属性为 YES 的 CALayer(在 CPU 渲染)。
4)用到了 mask 或 drop shadow 的 CALayer。
5)Text (包括UILabels, CATextLayers, Core Text, 等等)
参考文档:iOS图形原理与离屏渲染