离屏渲染概念
- 当
layer
不做触发离屏渲染的操作时,是可以直接放入缓冲区中让GPU
直接渲染在屏幕内的。但是当你设置圆角、阴影、遮罩、边界反锯齿、设置组不透明、光栅化等触发离屏渲染的操作后,layer
绘制以后的帧不能直接放入到GPU
读取帧所在的缓冲区了。因此需要再创建一个新的缓冲区,在绘制图层时,会在这两个缓冲区之间进行上下文切换。这种切换上下文的操作代价是,如果切换时间过长或者渲染操作过长就会导致卡顿和性能问题。综上所述,GPU
直接读取帧渲染到屏幕上的缓冲区就是屏幕内渲染,而在屏幕之外所创建的缓冲区就是离屏渲染。
-
drawRect
也会引起离屏渲染,在drawRect
中,一般使用Core Graphic
来绘制图形和文字,这些图形的计算和渲染是CPU
来负责的,渲染结束以后再交付给GPU
显示。
光栅化
- 光栅化可以理解为是
CPU
对绘制内容的图层生成位图来缓存一段时间,如果该时间内需要再次渲染该图层,可以直接通过该位图来进行渲染,不需要再次计算和切换上下文,但是这仅仅限于相同的图层。
优化建议
下面两种方法都可以在一定程度上优化离屏渲染产生的性能问题,但是不能避免离屏渲染:
- 使用
dractRect
方法用CPU
来分担GPU
压力。
- 通过上面对光栅化的描述,可以使用光栅化对图层进行短暂缓存。
下面来说一下如何避免设置圆角产生的离屏渲染问题。
- 对图片进行重新绘制,利用
CoreGraphics
重新绘制一张带圆角的图片,这样就可以不用设置图层属性而达到圆角的效果。不过这个方法也有缺点:绘制是无法避免的,对于UITableView来说,每次复用都要重新绘制一次,对CPU会产生一定的压力。如果绘制的圆角内容比较多的话,用这种方法有可能会产生更大的性能问题。解决办法可以针对此种方案专门设置一套缓存策略,但是如果缓存的图片过多,也会带来内存压力。所以建议如果图片较少的情况下,可以采用此种方案,如果图片过多的话建议采用其他方案。
- 在
UIImageView
上面再覆盖一个UIImageView
,覆盖的UIImageView
是带有透明圆角中心的图片。这样也可以避免离屏渲染。
注意事项
Tips:
1.亲测,iOS9以后,UIImageView在没有设置背景颜色的情况下,直接设置圆角是不会触发离屏渲染的。
2.iOS9以后,设置圆角时只有在同时设置了layer.backgroundColor以及layer.contents后才会触发离屏渲染。