SRP Batcher,Draw Call優化,Shader SRP Batcher compatible

當我們使用SRP(Scriptable Render Pipeline)之後,例如HDRP,URP或者LWRP,在SPR的asset文件中有一個選項叫做SRP Batcher(如圖)。

這篇文章就讓我們來了解了解這個好東西。

 

作用

簡單的說,如果當你的場景中有很多的物體分別使用到了不同的Material,但是這些Material使用的Shader卻都是同一個時,SRP Batcher可以大大爲我們降低DrawCall,從而加快渲染速度。

官方介紹:https://blogs.unity3d.com/2019/02/28/srp-batcher-speed-up-your-rendering/

https://docs.unity3d.com/Manual/SRPBatcher.html

中文文檔:https://connect.unity.com/p/srp-batcher-jia-su-xuan-ran

接下來我們可以通過一個簡單的示例來驗證這個效果。

 

示例

首先我們先通過Create->Shader->Unlit Shader創建一個簡單的無光照Shader命名爲SampleUnlit。接着我們創建三個Material,分別命名爲SampleMaterial1,SampleMaterial2,SampleMaterial3。這三個Material都使用我們剛剛創建好的SampleShader,並分別引用不同的Texture。

接着我們在場景中創建15個Cube,分別引用上面的這些Material,效果如圖

   

此時打開Game視圖的Statistics面板,可以看見15個Cube一共產生了15個DrawCall(由於SkyBox會產生一個DrawCall所以顯示的有16個),而Saved By Batching爲0。

我們通過Window->Analysis->Frame Debugger打開Frame Debug窗口,點擊Enable按鈕,可以觀察到當前幀的繪製信息

按往常我們可能會通過動態批處理或者靜態批處理來進行優化。

動態批處理:我們可以勾選SRP asset文件的Dynamic Batching,勾選後可以發現,DrawCall數量變爲12,Saved By Batching變爲4。同意通過Frame Debug可以發現有些方塊的繪製被合併到了一起,從而減少了DrawCall。

    

靜態批處理:我們可以將這些小方塊全部變爲靜態物體(勾選其Static屬性),運行後發現DrawCall同樣變少了(未運行狀態下不變),以及對應的Frame Debug視圖如下:

         

 

但是使用SRP後,這種情況我們就可以使用SRP Batcher來處理了,而且效果會更好。

 

SRP Batcher

首先我們勾選SRP asset的SRP Batcher選項,嗯哼,怎麼沒有任何變化,說好的會減少DrawCall呢?

通過官方的文檔,我們可以找到問題的所在,那就是Shader了。我們點擊前面創建的SampleUnlit,會發現其有個SRP Batcher的屬性,顯示着not compatible,哇擦,不兼容。同時下面還有個看不懂的提示。

官方文檔有如下一句話:

For a Shader to be compatible with SRP:

  • All built-in engine properties must be declared in a single CBUFFER named “UnityPerDraw”. For example, unity_ObjectToWorld, or unity_SHAr.
  • All Material properties must be declared in a single CBUFFER named “UnityPerMaterial”.

翻譯成白話來說,Shader中所有的內置屬性例如unity_ObjectToWorld,unity_SHAr等,都要在一個名爲UnityPerDraw的CBUFFER中聲明,而所有的Material屬性都要在一個名爲UnityPerMaterial的CBUFFER中聲明。

官方文檔後面也給到了一個代碼示例

Properties
 
{
 
_Color1 ("Color 1", Color) = (1,1,1,1)
 
_Color2 ("Color 2", Color) = (1,1,1,1)
 
}

//原本的寫法
//float4 _Color1;
 
//float4 _Color2;


//兼容SRP Batcher的寫法

CBUFFER_START(UnityPerMaterial)
 
float4 _Color1;
 
float4 _Color2;
 
CBUFFER_END

可以看出Material屬性,也就是Properties中的參數在聲明時,都被包含在了一個下面這樣的語法快中

CBUFFER_START(UnityPerMaterial)
//Properties
CBUFFER_END

再回過頭來看前面我們Shader的提示:Material property is found in another cbuffer than "UnityPerMaterial"(_MainText_ST)。

也就是說我們Shader中的_MainText_ST屬性沒有聲明在名爲UnityPerMaterial的CBUFFER中,我們將其改爲如下代碼

sampler2D _MainTex;
CBUFFER_START(UnityPerMaterial)
    float4 _MainTex_ST;
CBUFFER_END

注:何爲_MainText_ST?當Shader中使用到Texture屬性(如例子中的_MainText),Unity會自動爲我們添加一個類型爲float4後綴爲_ST的屬性(float4 _MainText_ST),用來表示Texture的Tiling和Offset。

再次查看我們的Shader會發現已經兼容了SRP Batcher了,同時Statistics面板中的Save By batching變爲了-15。

          

此時查看Frame Debug,發現由原來的RenderLoop.Draw變爲了RenderLoopNewBatcher.Draw,同時底下只有一個SRP Batch。不過這不代表只使用了一個DrawCall來顯示了這些內容,而是對它們進行了序列上的優化。

此時我們已經實現了SRP Batcher的功能了,不過前文還提到了一個用來處理內置屬性名爲UnityPerDraw的CBUFFER卻沒有用到,按照UnityPerMaterial的樣式,我們可以在Shader中添加一下測試代碼:

CBUFFER_START(UnityPerDraw)
    float4x4 unity_ObjectToWorld;
CBUFFER_END

注:有關內置Shader屬性的說明可以參照:https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html

結果會報錯:Shader error in 'Unlit/SampleUnlit': redefinition of 'unity_ObjectToWorld',重複定義了unity_ObjectToWorld。而我們的Shader代碼中,怎麼也找不到又在哪定義了這個unity_ObjectToWorld。那麼只可能是在通過#include引入的其他文件當中了。

如果是CG語言(CGPROGRAM),我們會引用UnityCG.cginc,在Unity安裝目錄的Editor/Data/CGIncludes文件夾中我們可以找到它,打開查看內容可以發現其又引用了UnityShaderVariables.cginc,相同目錄下找到並查看內容,我們就會發現有如下一些定義,替我們定義好了這些內置屬性

......
CBUFFER_START(UnityPerDraw)
    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
    float4 unity_WorldTransformParams; // w is usually 1.0, or -1.0 for odd-negative scale transforms
    float4 unity_RenderingLayer;
CBUFFER_END
......

如果用的是HLSL語言(HLSLPROGRAM),在我們項目工程的Library/PackageCache/com.unity.render-pipelines.universal/ShaderLibrary目錄下有個Core.hlsl文件,在裏面又引用了Input.hlsl,在其中又引用了UnityInput.hlsl,打開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

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章