Meta Quest 的绘制调用成本分析
当材质和网格提交给 GPU 进行绘制时,便会发生绘制调用。VR 游戏的绘制调用往往高于 2D 游戏,再加上运行时的帧率更高,所以 CPU 资源会被大量占用。这会导致绘制所有对象时,每一帧可用的 CPU 时间缩短,然而对象数量却会翻倍。
绘制调用时间会因此前的绘制调用状态而不同。对此前调用的材质、网格或纹理进行更改,会增加绘制调用时间。
本文档主要介绍各种调用参数的测试结果,以及它们对 CPU 和 GPU 绘制调用在时间方面的影响。
这些测试均在使用 Unity 2018.1.6f1 的 Meta Quest 1 上执行,其结果适用于任意应用的开发。
Unity 测试应用:
测试设置:
- 生成 500 个正方形对象,显示几帧让着色器进行编译,然后加以禁用
测试流程:
- 启用 10 个对象,等待 5 帧并记录
OnPreRender 和 OnPostRender 之间的平均时间。
- 禁用异步时间扭曲 (ATW),防止 ATW 线程阻止主渲染线程。每次原始 GPU 测量中都包含时间扭曲。
- 禁用 VrPowerManager,防止设备休眠
渲染测试如下图中所示:
第一组测试结果显示了更改着色器、材质、网格、纹理和颜色对 CPU 的影响。
如要优化性能,您应该:
- 避免切换着色器程序
- 避免切换材质
- 注意网格变化和纹理计数的影响
随后几个部分会提供图表结果和这些参数影响的更多详情。
测试表明,使用相同的着色器但切换材质(不改变任何其他属性)导致绘制调用的时间增加了 64%。
切换着色器程序会导致结果变得更糟糕。测试表明,切换着色器使绘制调用时间成本增加了 175%。
下图表示的是切换着色器和材质对于渲染无纹理和共享网格的对象所花费时间的影响。
为帮助缩短更改材质的时间,您可以按材质对您的绘图调用进行排序。
尽量避免在绘制调用之间更改网格。该图表示的是使用相同材质时,在绘制调用之间切换网格所增加的时间。
更改材质的影响大于更改网格。下图是对二者的比较。
如果要更改材质和使用多种纹理,那么当您增加纹理数量时,进行绘制调用会付出更昂贵的成本。
而如果重复使用具有多个纹理的材质,那么在绘制调用之间对其加以更改,仍会产生少量成本。
下图表示的是增加纹理对更改材质和重复使用材质所产生的影响。
对纹理、材质颜色、纹理大小、滤镜或压缩算法的更改对于绘制调用时间的影响最小。
在 Unity 2018 中,更改纹理产生的成本不会高于更改材质所产生的成本。下图展示的正是这一点。
在绘制调用之间更改材质的颜色不存在显著成本差异,所以如果要更换材质,可以不必担心更换颜色的问题。但如果只需要更改颜色,应使用相同的材质,并更改网格颜色即可。
纹理大小不会对绘制调用成本产生重大影响。下图展示的正是这一点。
更改滤镜算法或压缩方式不会对绘制调用成本产生任何影响。
下图表示更改滤镜算法的影响。
下图表示压缩算法的影响。
与纹理大小类似,网格的大小对于绘制调用来说并不会显著增加 CPU 成本,而是会影响 GPU。下图展示了纹理大小对 CPU 的影响。
如果知道各种排列下一帧的总渲染时间,就能估算出每次绘制调用的时间。为了计算测试中的绘制时间,我们观察了渲染不同对象计数之间的平均增量。
这些测试表明,重新绘制相同对象的成本约为绘制不同对象成本的 25%。
所以要缩短绘制时间,可考虑以下几点:
- 给对象进行分类
- 采用 Atlas 纹理
- 考虑不用纹理。使用合适的着色器,您仍然可以制作出效果极佳的游戏。
第二组测试仔细检测了更改材质、复杂网格等内容对 GPU 的影响。
若要缩短 GPU 绘制时间,可遵循以下准则:
- 避免使用复杂网格
- 在较小程度上,避免材质更改
- 避免更改着色器
以下部分包含各种参数更改的图表结果。
材质更改的 CPU 成本最为昂贵,但它对于 GPU 成本又有何影响呢?结果表明,更改材质的确会影响 GPU 时间,尤其是在新材质采用不同的着色器时。下图表示更改材质对 GPU 的影响:

材质更改有影响,但要注意的是,顶点/三角形计数高的复杂网格对 GPU 绘制时间的影响高于材质更改。下图展示了使用更高的多边形网格会快速消耗您的 GPU 预算。
注意在着色器中对额外纹理进行采样的成本。使用一个简单着色器的话,可在图中看出额外纹理样本的成本增加情况。纹理增多会提高内存成本,但较之更改着色器的成本,避免增加额外纹理不算太过重要。
有三个方面不会影响绘制调用的 GPU 成本,它们分别是纹理压缩、纹理滤镜和纹理大小。
下图是重复使用着色器与更改着色器对比下的各种纹理压缩级别。
下图是重复使用着色器与更改着色器对比下的各种纹理大小级别。
下图是重复使用着色器与更改着色器对比下的各种纹理滤镜技术。
下图展示了使用简单着色器绘制小四边形时,每个绘制调用所需的实际时间。该测试采用受控的方式执行,因此只适合用来对比调用之间的相对成本差异,不适合对比测量时间。
下一组测试研究的是更改着色器对 GPU 绘制成本的影响。
一般认为,从立方体采样比从 Texture2D 采样要更昂贵。虽然这是事实,但其实差别很小,如果您的应用需要立方体,尽管使用即可。下图表示的是立方体与 Texture2D 的对比。
业界认为纹理读取成本更高,应当避免使用。然而,在 Quest 上读取依赖型纹理只比读取独立型纹理略贵一点。所以可以考虑对查找表 (LUT) 取样,代替更加昂贵的着色器操作。
着色器复杂性很可能是 GPU 耗时最高的操作。请看简单漫射着色器与 PBR 着色器(Unity 标准着色器)之间的对比。逻辑操作的数量和复杂性通常比采样额外纹理花费的时间更多。
最后,下图表示的是组合不同纹理参数得到的结果。该图表明,在几乎所有情况下,着色器的复杂性都会导致绘制调用时间加长。
我们也可以用相同的推导来计算不同参数的“实际 GPU时间”成本。与之前的说明一样,这种计算只适用于相对比较。结果表明,着色器复杂性是测量 GPU 时间时需要考虑在内的因素。

测试和结果数据表明了更改参数对于绘制调用长度的部分影响。在设计应用程序时,还有许多其他事项需要考虑。
网格的形状和(屏幕空间)大小
不透明度与透明度
- Alpha 值混合处理并不便宜,如果您使用线性或 sRGB 色彩空间,成本也会增加。在线性空间中,所有颜色在采样时都会应用伽玛曲线,并在写入时进行反向应用。这使得混合操作的成本比所有内容保留在 sRGB 空间时要高得多。
MSAA 级别
- 有传言称 MSAA 没有成本,或者说成本极低,因此可以一直开启。然而结果并非如此,它会实际产生成本。不过对于 VR 来说,使用 MSAA 能够获得视觉改善,所以可谓是一项实质性的需求。这意味着增加的成本只能从其他方面给予补偿。
帧缓冲区提取
- Unity 大大简化了使用
GL_EXT_shader_framebuffer_fetch 的方式(只需要用一个 inout 着色器参数写入您的片元着色器,无需返回最终颜色)。然而这种方式却隐藏了一个事实,那就是它用起来可能相当昂贵,而且成本还会随着 MSAA 级别的增加而提高(帧缓冲区提取要在每个样本基础上进行处理,而不是每个片元)。