Tino又想吃肉了

离屏渲染 Off-Screen Rendering

Word count: 979Reading time: 3 min
2021/10/13

离屏渲染的定义、类型和解决思路。

定义:如果要在显示屏上显示内容,我们至少需要一块与屏幕像素数据量一样大的frame buffer,作为像素数据存储区域,而这也是GPU存储渲染结果的地方。如果有时因为面临一些限制,无法把渲染结果直接写入frame buffer,而是先暂存在另外的内存区域,之后再写入frame buffer,那么这个过程被称之为离屏渲染。

CPU中的离屏渲染

当我们实现了UIView中的drawRect方法时,即使方法体内没有实际代码,系统都会为该View申请一块额外的内存区域,等待CoreGraphics可能的绘画操作,对于这样的多开一块CGContext来绘制的操作,有些人把他称之为离屏渲染。然而,他实际上是离屏渲染在CPU上的一种体现。事实上,所有CPU进行的光栅化操作(如文字渲染、图片解码),都无法直接绘制到由GPU掌管的frame buffer上,只能暂时先放在另一块内存之中,说起来都属于“离屏渲染”。
然而,这样的CPU离屏渲染并不expensive。

In particular, a few (implementing drawRect and doing any CoreGraphics drawing, drawing with CoreText [which is just using CoreGraphics]) are indeed “offscreen drawing,” but they’re not what we usually mean when we say that. They’re very different from the rest of the list. When you implement drawRect or draw with CoreGraphics, you’re using the CPU to draw, and that drawing will happen synchronously within your application. You’re just calling some function which writes bits in a bitmap buffer, basically.

根据苹果工程师的回复,CPU上的离屏渲染并不是开发者常谈的离屏渲染,事实上,即使我们打开Xcode的Color offscreen rendered yellow调试开关,这一类的离屏渲染也不会被标记。

GPU中的离屏渲染

真正需要我们注意的离屏渲染,发生在GPU中。
GPU渲染管线
上图为iOS应用的渲染管线,可以看到,主要的渲染操作都是由CoreAnimation的Render Server模块,通过调用显卡驱动所提供的OpenGL/Metal接口来执行的。

当我们需要渲染的图像,无法根据画家算法一次遍历就绘制出来时,GPU则需要开辟另一块渲染缓存区。在GPU中,来回地在缓存区上下文之间切换,代价是非常昂贵的。根据Texture框架中对离屏渲染的讨论,当我们触发离屏渲染时,在滑动的每一帧GPU都要切换一次上下文,这意味着GPU至多(在60hz刷新率的机器上)每秒将要切换60次缓存区上下文,这对于GPU来说带来的负荷非常高。

Use of CALayer’s .cornerRadius property triggers offscreen rendering to perform the clipping operation on every frame - 60 FPS during scrolling - even if the content in that area isn’t changing! This means that the GPU has to switch contexts on every frame, between compositing the overall frame + additional passes for each use of .cornerRadius.

常见的离屏渲染

在iOS开发中,常见的一些情况都有可能触发离屏渲染。
1.cornerRadius+clipsToBounds
2.shadow
3.group opacity
4.mask
5.UIBlurEffect
6.allowsEdgeAntialiasing
7.backgroundColor(color设置为clear时)
8.修改已光栅化的内容

如何检测

1、模拟器Debug选项中选中Color Offscreen Renderd,离屏渲染的图层高亮成黄色,可能存在性能问题

2、真机Instrument,选中Core Animation,勾选Color Offscreen-Rendered Yellow

写在最后

离屏渲染是开发iOS App中一个非常常见的问题,其尤其影响滑动控件的性能,特别是当我们的列表存在大量的复杂控件或者图片时尤其需要注意。(各种头像圆角、卡片阴影等)
理解产生离屏渲染的原理和学习业界解决该问题的思路,可以帮助我们写出更流畅的滑动列表。

参考

关于iOS离屏渲染的深入研究 - 即刻团队
Texture文档

CATALOG
  1. 1. CPU中的离屏渲染
  2. 2. GPU中的离屏渲染
  3. 3. 常见的离屏渲染
  4. 4. 如何检测
  5. 5. 写在最后
    1. 5.1. 参考