深入URP之Shader篇13: SRP Batcher

news/2024/10/18 18:15:53/

SRP Batcher是URP中非常重要的draw call优化方式。本篇介绍SRP Batcher的原理,使用条件,以及如何在自定义的URP Shader中支持SRP Batcher。

SRP Batcher原理

我们通常的draw call优化都是从减少draw call入手,其中有基于几何体合并的合批,包括静态batch和动态batch,都是讲不同的mesh合并成一个mesh,减少draw call的调用次数,以及当mesh相同时使用GPU Instancing一次性批量绘制也可大大减少draw call。而SRP Batcher另辟蹊径,Unity再研究之后认为,大部分的draw call比较费的其实不是draw call本身,因为对于CPU来说,一个draw call仅仅是提交几个简单的指令。真正费的是伴随着draw call的渲染状态切换,比如材质使用的uniform。早期的平台不支持uniform buffer object,设置每个uniform都要使用一条指令,如果两个材质的uniform大不相同,切换材质时就要重复设置,造成大量的渲染状态切换。另外标准的unity渲染工作流可以在一帧中任意时候修改材质的属性,这虽然很灵活,但是也造成了渲染状态的切换。下图是unity标准的渲染工作流:

image.png

在渲染循环中,当发生材质切换时,CPU会搜集材质需要的各种属性,并且会设置到GPU显存的各个CBuffer中,CBuffer的数量取决于shader定义了多少CBuffer。

而Unity在实现SRP时,修改了底层代码,通过尽可能在显存中缓存材质属性,来提升材质多而shader变体少这种通常情况下的渲染状态切换的效率。

image.png
SRP Batcher的渲染工作流如上图,显存中有一个存放逐个Object属性的大buffer,并且CPU上有专用的代码将引擎内置属性填充到这个buffer中(比如每个物体的矩阵)。同时显存中还缓存了每个材质的CBuffer,当切换材质时CPU并不需要重复的设置材质的属性,而只是简单的告诉GPU现在用哪个材质缓存的属性。如果材质的属性不变,就不需要从CPU往GPU传递新的属性值。从这两个方面入手,切换材质时从CPU向GPU传递的数据量以及次数被大大降低了。想象一下如果你有几百个物体使用各自不同的材质,但是这些材质使用了同一个shader变体,如果材质不变化,那么只有刚开始加载时传递了材质属性,之后如果这些物体的矩阵改变才会更新一下改变的per-Object属性,否则啥都不用作。对比之前的标准操作,省了不是一点半点。

image.png

从上图可以对比看一下,老的流程需要搜集并上传object的CBuffer,搜集并上传Material的各个CBuffer,绑定材质的CBuffer,绑定Object CBuffer最后才能执行draw call。而SRP Batcher优化后,只需要做bind和draw就行。当shader变体没改变时就是bind材质属性,从object大buffer中使用offset bind object CBUffer,然后draw call。如果shader变体改变,则执行set pass call。

SRP Batcher和静态Batcher, GPU Instancing,动态batch的优先级

  • 如果物体是静态的(Batching Static),则会使用Static Batching。如果物体的材质兼容SRP Batcher,则会同时使用SRP Batcher。
  • 动态物体,优先使用 SRP Batcher
  • 在非静态Batch,且不支持SRP Batcher的情况下,如果物体的材质和Renderer兼容GPU Instancing,则会启用GPU Instancing
  • 以上都不支持的情况下,如果开启了Dynamic Batching,则会使用动态Batch。

SRP Batcher的使用条件

  • 首先要在URP Asset的高级设置中开启:

image.png

也可以在代码中开关:

GraphicsSettings.useScriptableRenderPipelineBatching = true;
  • GameObject要兼容SRP Batcher
    • GameObject必须是包含Mesh或SkinnedMesh,而粒子是不支持SRP Batcher的
    • 不可以使用MaterialPropertyBlocks.
    • GameObject材质的shader要兼容与SRP Batcher,在Shader的Inspector中能看到是否兼容:

image.png

自定义Shader兼容SRP Batcher

  • 首先对于Unity内置属性,比如unity_ObjectToWorld要放在一个名字为UnityPerDraw的CBuffer中。其实我们写自定义shader都是直接include URP的Libraray的,其中已经做好了这个。在Packages\com.unity.render-pipelines.universal\ShaderLibrary\UnityInput.hlsl中我们看到:
// Block Layout should be respected due to SRP Batcher
CBUFFER_START(UnityPerDraw)
// Space block Feature
float4x4 unity_ObjectToWorld;
float4x4 unity_WorldToObject;
float4 unity_LODFade; // x is the fade value ranging within [0,1]. y is x quantized into 16 levels
real4 unity_WorldTransformParams; // w is usually 1.0, or -1.0 for odd-negative scale transforms// Light Indices block feature
// These are set internally by the engine upon request by RendererConfiguration.
real4 unity_LightData;
real4 unity_LightIndices[2];float4 unity_ProbesOcclusion;// Reflection Probe 0 block feature
// HDR environment map decode instructions
real4 unity_SpecCube0_HDR;// Lightmap block feature
float4 unity_LightmapST;
float4 unity_DynamicLightmapST;// SH block feature
real4 unity_SHAr;
real4 unity_SHAg;
real4 unity_SHAb;
real4 unity_SHBr;
real4 unity_SHBg;
real4 unity_SHBb;
real4 unity_SHC;
CBUFFER_END

这些属性被分为不同的block,虽然我们可能只使用一部分block,但是还是得按照这个布局来。

  • 材质自定义的属性要放在UnityPerMaterial的CBuffer中。
    以之前看过的SimpleLitInput.hlsl为例:
CBUFFER_START(UnityPerMaterial)float4 _BaseMap_ST;half4 _BaseColor;half4 _SpecColor;half4 _EmissionColor;half _Cutoff;half _Surface;
CBUFFER_END

这些属性都是在逐材质的属性,因此需要定义在这个cbuffer中,才能在材质切换时直接绑定显存中的cbuffer。另外虽然贴图也是在Properties中指定的,但是贴图本身不能放到CBuffer中,但是其缩放(这儿的_BaseMap_ST)要放进去。这是因为贴图和Sampler都不是Uniform。

本篇总结

本篇从SRP Batcher的原理入手,理解了原理自然知道Shader应该怎么写才能支持。


http://www.ppmy.cn/news/37737.html

相关文章

喜报!昂视荣获深圳市「专精特新」中小企业认定

近期,深圳市中小企业服务局公示了2022年专精特新中小企业名单,昂视名列其中,被授予“专精特新”中小企业称号。 何为“专精特新”? “专精特新”是指中小企业具备专业化、精细化、特色化、新颖化的特征,“专精特新”企…

MagicBook安装Ubuntu

荣耀MagicBook 安装 Ubuntu 18.04遇到的问题 系统盘制作 使用软件 Rufus 制作系统盘 准备一个U盘(空盘,最好事先进行过格式化),Rufus刻录工具,Ubuntu18.04 操作系统的iso文件。 Rufus 下载使用 Rufus Ubuntu 18.0…

一分钟了解全行业的商业模式

梦龙商业案例分析,带你了解商业背后的秘密 其实商业模式有很多人讲出来,其实商业模式没那么复杂,我只需要一分钟我都可以把你搞明白,我会在一分钟几个关键问题,第一个问题叫你的客户是谁,不是谁。 第二个…

【计算机二级Python】综合题目

计算机二级python真题 文章目录计算机二级python真题一、简单应用题——学生就业二、综合应用题——论语一、简单应用题——学生就业 学生就业 描述: 键盘输入某个班级各个同学就业的行业名称,行业名称之间用空格间隔(回车结束输入&#xf…

Apache James JMX本地反序列化漏洞(CVE-2023-26269)

漏洞描述 Apache James 是一个基于Java语言开发的邮件服务器软件。 该项目受影响版本存在权限提升漏洞,由于Apache James 3.7.3及之前版本默认提供无需身份验证的 JMX 管理服务且使用LOG4J MBeans接口等导致存在反序列化漏洞。具备本地用户权限的攻击者可通过Log4…

语句【C++】

简单语句空语句复合语句条件语句if 语句switch 语句迭代语句while语句传统 for 语句范围 for 语句&#xff08;C11&#xff09;do while 语句跳转语句break 语句continue 语句goto 语句简单语句 大多数语句以分号结束。 ival 5; //没有实际用处的表达式 cout<<ival; …

赋能工业智能化升级 | 基于ACM32 MCU的工业通用变频器方案

近年来&#xff0c;随着智能制造对节能的更高要求&#xff0c;通用变频器在工业领域的应用愈加广泛。变频器是一种先进的调速控制设备&#xff0c;通过对电源频率的控制可以实现对电机转速的精确调节&#xff0c;从而提高设备的性能和节能效果。 变频器概述 变频器&#xff0…

上海亚商投顾:创业板指高开高走 ChatGPT概念卷土重来

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪沪指今日红盘震荡&#xff0c;深成指、创业板指小幅走高&#xff0c;科创50指数涨近1.5%。ChatGPT概念股再度爆发&a…