在 HLSL 中指定根簽章
在 HLSL 著色器模型 5.1 中指定根簽章是C++程式代碼中指定根簽章的替代方案。
- 範例 HLSL 根簽章
- RootFlags
- 根常數
- 可見度
- 根層級 CBV
- 根層級 SRV
- 根層級無人機
- 描述元數據表
- 靜態取樣器
- 編譯 HLSL 根簽章
- 使用 FXC 編譯器操縱根簽章
- 附注
- 相關主題
範例 HLSL 根簽章
根簽章可以在 HLSL 中指定為字串。 字串包含逗號分隔子句的集合,這些子句描述根簽章組成元件。 在任何管線狀態物件(PSO)中,所有著色器的根簽章應該相同。 以下是範例:
根簽名版本 1.0
#define MyRS1 "RootFlags( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | " \
"DENY_VERTEX_SHADER_ROOT_ACCESS), " \
"CBV(b0, space = 1), " \
"SRV(t0), " \
"UAV(u0, visibility = SHADER_VISIBILITY_GEOMETRY), " \
"DescriptorTable( CBV(b0), " \
"UAV(u1, numDescriptors = 2), " \
"SRV(t1, numDescriptors = unbounded)), " \
"DescriptorTable(Sampler(s0, numDescriptors = 2)), " \
"RootConstants(num32BitConstants=1, b9), " \
"DescriptorTable( UAV(u3), " \
"UAV(u4), " \
"UAV(u5, offset=1)), " \
"StaticSampler(s2)," \
"StaticSampler(s3, " \
"addressU = TEXTURE_ADDRESS_CLAMP, " \
"filter = FILTER_MIN_MAG_MIP_LINEAR )"
此定義會提供下列根簽章,並指出:
- 使用預設參數。
- b0 和 (b0, space=1) 不衝突
- u0 只有幾何著色器可以看見
- u4 和 u5 在堆疊中引用相同的描述元
指定的根簽章
根簽章 1.1 版
根簽名版本 1.1 啟用針對根簽名描述符和數據的驅動程序優化。
#define MyRS1 "RootFlags( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | " \
"DENY_VERTEX_SHADER_ROOT_ACCESS), " \
"CBV(b0, space = 1, flags = DATA_STATIC), " \
"SRV(t0), " \
"UAV(u0), " \
"DescriptorTable( CBV(b1), " \
"SRV(t1, numDescriptors = 8, " \
" flags = DESCRIPTORS_VOLATILE), " \
"UAV(u1, numDescriptors = unbounded, " \
" flags = DESCRIPTORS_VOLATILE)), " \
"DescriptorTable(Sampler(s0, space=1, numDescriptors = 4)), " \
"RootConstants(num32BitConstants=3, b10), " \
"StaticSampler(s1)," \
"StaticSampler(s2, " \
"addressU = TEXTURE_ADDRESS_CLAMP, " \
"filter = FILTER_MIN_MAG_MIP_LINEAR )"
HLSL 根簽章語言會密切對應至C++根簽章 API,並且具有對等的表達能力。 根簽章會指定為子句序列,並以逗號分隔。 子句的順序很重要,因為解析的順序會決定根簽名中的插槽位置。 每個子句都會採用一或多個具名參數。 不過,參數的順序並不重要。
RootFlags
選擇性的 RootFlags 子句接受零(預設值表示無標誌),或透過 OR '|' 運算符連接的一個或多個預先定義的根標誌值。 允許的根旗標值是由 D3D12_ROOT_SIGNATURE_FLAGS所定義。
例如:
RootFlags(0) // default value – no flags
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT)
RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_VERTEX_SHADER_ROOT_ACCESS)
根常數
RootConstants 子句會指定根簽章中的根常數。 兩個強制參數為:num32BitConstants 和 bReg(與 C++ API 中的 BaseShaderRegister 對應的寄存器)的常量緩衝區。 C++ API 中的 space (RegisterSpace) 和可見度 (ShaderVisibility C++) 參數是選擇性的,預設值為:
RootConstants(num32BitConstants=N, bReg [, space=0,
visibility=SHADER_VISIBILITY_ALL ])
例如:
RootConstants(num32BitConstants=3, b3)
能見度
Visibility 是選擇性參數,可以從 D3D12_SHADER_VISIBILITY取得其中一個值。
SHADER_VISIBILITY_ALL將根引數廣播到所有著色器。 在某些硬體上,這不需要任何開銷,但在其他硬體上,將數據分叉到所有著色器階段會產生開銷。 設定其中一個選項,例如SHADER_VISIBILITY_VERTEX,會將根自變數限制為單一著色器階段。
將根自變數設定為單一著色器階段,可讓不同的階段使用相同的系結名稱。 例如,t0,SHADER_VISIBILITY_VERTEX
的SRV系結和 t0,SHADER_VISIBILITY_PIXEL
的SRV系結是有效的。 但是,如果其中一個系結的可見性設定 t0,SHADER_VISIBILITY_ALL
,則根簽章會無效。
基礎層級 CBV
CBV
(常數緩衝區檢視)子句會指定一個根層級常數緩衝區的 b-register Reg 項目。 請注意,這是一個純量輸入,無法為根層指定範圍。
CBV(bReg [, space=0, visibility=SHADER_VISIBILITY_ALL ]) // Version 1.0
CBV(bReg [, space=0, visibility=SHADER_VISIBILITY_ALL, // Version 1.1
flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])
根層級 SRV
SRV
(著色器資源檢視)子句會指定根層級 SRV t-register Reg 項目。 請注意,這是純量輸入,無法指定根層級的範圍。
SRV(tReg [, space=0, visibility=SHADER_VISIBILITY_ALL ]) // Version 1.0
SRV(tReg [, space=0, visibility=SHADER_VISIBILITY_ALL, // Version 1.1
flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])
基層無人機
UAV
(未排序存取檢視)子句指定根層級 UAV u-register 的 Reg 條目。 請注意,這是純量項目,無法指定根層級的範圍。
UAV(uReg [, space=0, visibility=SHADER_VISIBILITY_ALL ]) // Version 1.0
UAV(uReg [, space=0, visibility=SHADER_VISIBILITY_ALL, // Version 1.1
flags=DATA_VOLATILE ])
例如:
UAV(u3)
描述項數據表
DescriptorTable
子句本身是逗號分隔描述符表子句的清單,以及可選的可見性參數。
描述元數據表 子句包括 CBV、SRV、UAV 和 Sampler。 請注意,其參數與根層級子句的參數不同。
DescriptorTable( DTClause1, [ DTClause2, … DTClauseN,
visibility=SHADER_VISIBILITY_ALL ] )
描述元數據表 CBV
具有下列語法:
CBV(bReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ]) // Version 1.0
CBV(bReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND // Version 1.1
, flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])
例如:
DescriptorTable(CBV(b0),SRV(t3, numDescriptors=unbounded))
強制參數 bReg 指定 cbuffer 範圍的起始 Reg。
numDescriptors 參數會指定連續 cbuffer 範圍中的描述項數目;預設值為 1。 當 numDescriptors 為數位時,專案會宣告 cbuffer 範圍 [Reg, Reg + numDescriptors - 1]
。 如果 numDescriptors 等於「未系結」,範圍會 [Reg, UINT_MAX]
,這表示應用程式必須確保它不會參考超出範圍的區域。
位移 字段代表C++ API 中 OffsetInDescriptorsFromTableStart 參數,也就是數據表開頭的位移(以描述元為單位)。 如果位移設定為 DESCRIPTOR_RANGE_OFFSET_APPEND (預設值),則表示範圍會直接在上一個範圍之後。 不過,輸入特定位移可讓範圍彼此重疊,允許緩存器別名。
描述元數據表 SRV
具有下列語法:
SRV(tReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ]) // Version 1.0
SRV(tReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND, // Version 1.1
flags=DATA_STATIC_WHILE_SET_AT_EXECUTE ])
這類似於描述符表 CBV
條目,但指定的範圍是著色器資源視圖。
描述元數據表 UAV
具有下列語法:
UAV(uReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ]) // Version 1.0
UAV(uReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND, // Version 1.1
flags=DATA_VOLATILE ])
這類似於描述符表 CBV
項目,但指定的範圍適用於無序存取視圖。
描述元數據表 Sampler
具有下列語法:
Sampler(sReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND ]) // Version 1.0
Sampler(sReg [, numDescriptors=1, space=0, offset=DESCRIPTOR_RANGE_OFFSET_APPEND, // Version 1.1
flags=0 ])
這類似於描述符表 CBV
的項目,只是指定的範圍是用於著色器取樣器。 請注意,取樣器不能與相同描述元數據表中的其他描述元類型混合(因為它們位於個別描述元堆積中)。
靜態取樣器
靜態取樣器代表 D3D12_STATIC_SAMPLER_DESC 結構。 StaticSampler 的必要參數是純量取樣器 s-register Reg。其他參數是選擇性的,預設值如下所示。 大部分欄位都接受一組預先定義的列舉型。
StaticSampler( sReg,
[ filter = FILTER_ANISOTROPIC,
addressU = TEXTURE_ADDRESS_WRAP,
addressV = TEXTURE_ADDRESS_WRAP,
addressW = TEXTURE_ADDRESS_WRAP,
mipLODBias = 0.f,
maxAnisotropy = 16,
comparisonFunc = COMPARISON_LESS_EQUAL,
borderColor = STATIC_BORDER_COLOR_OPAQUE_WHITE,
minLOD = 0.f,
maxLOD = 3.402823466e+38f,
space = 0,
visibility = SHADER_VISIBILITY_ALL ])
例如:
StaticSampler(s4, filter=FILTER_MIN_MAG_MIP_LINEAR)
參數選項與 C++ API 呼叫非常類似,但 borderColor除外,它在 HLSL 中僅限於使用列舉值。
篩選欄位可以是其中一個 D3D12_FILTER。
地址欄位可為其中之一:D3D12_TEXTURE_ADDRESS_MODE。
比較函式可以是其中一個 D3D12_COMPARISON_FUNC。
框線色彩欄位可以是下列其中一個 D3D12_STATIC_BORDER_COLOR。
可見度可以是 D3D12_SHADER_VISIBILITY的可選擇之一。
編譯 HLSL 根簽章
有兩種機制可編譯 HLSL 根簽章。 首先,可以透過 RootSignature 屬性,將根簽章字串附加至特定著色器(在下列範例中,使用 MyRS1 進入點):
[RootSignature(MyRS1)]
float4 main(float4 coord : COORD) : SV_Target
{
…
}
編譯器將為著色器創建並驗證根簽章 Blob,然後將它與著色器位元組代碼一起內嵌到著色器 Blob 中。 編譯程式支援著色器模型 5.0 和更新版本的根簽章語法。 如果根簽章嵌入在著色器模型 5.0 的著色器中,且該著色器會被傳送到 D3D11 執行階段而非 D3D12,則 D3D11 會靜默忽略根簽章部分。
另一個機制是建立獨立的根簽章 Blob,或許可以重複使用一組大型著色器,以節省空間。 Effect-Compiler 工具 (FXC) 同時支援 rootsig_1_0 和rootsig_1_1 著色器模型。 定義字串的名稱是透過一般 /E 自變數來指定。 例如:
fxc.exe /T rootsig_1_1 MyRS1.hlsl /E MyRS1 /Fo MyRS1.fxo
請注意,根簽章字串定義也可以在命令行上傳遞,例如 /D MyRS1=“...”。
使用 FXC 編譯器操作根簽名
FXC 編譯程式會從 HLSL 原始程式檔建立著色器位元組程式代碼。 此編譯程式有許多選擇性參數,請參閱 Effect-Compiler Tool。
為了管理 HLSL 撰寫的根簽章,下表提供使用 FXC 的一些範例。
線 | 命令行 | 描述 |
---|---|---|
1 | fxc /T ps_5_1 shaderWithRootSig.hlsl /Fo rs1.fxo |
編譯圖元著色器 5.1 目標的著色器,著色器來源位於 shaderWithRootSig.hlsl 檔案中,其中包含根簽章。 著色器和根簽章會編譯為 rs1.fxo 二進位檔中的個別 blob。 |
2 | fxc /dumpbin rs1.fxo /extractrootsignature /Fo rs1.rs.fxo |
從第 1 行所建立的檔案擷取根簽章,因此 rs1.rs.fxo 檔案只包含根簽章。 |
3 | fxc /dumpbin rs1.fxo /Qstrip_rootsignature /Fo rs1.stripped.fxo |
從第 1 行所建立的檔案中移除根簽章,因此 rs1.stripped.fxo 檔案包含沒有根簽章的著色器。 |
4 | fxc /dumpbin rs1.stripped.fxo /setrootsignature rs1.rs.fxo /Fo rs1.new.fxo |
將不同檔案中的著色器和根簽章結合成包含這兩個 Blob 的二進位檔。 在此範例中,rs1.new.fx0 與第 1 行中的 rs1.fx0 相同。 |
5 | fxc /T rootsig_1_0 rootSigAndMaybeShaderInHereToo.hlsl /E RS1 /Fo rs2.fxo |
從可能包含超過根簽章的來源建立獨立根簽章二進位檔。 請注意rootsig_1_0目標,RS1 是 HLSL 檔案中根簽章 (#define) 巨集字串的名稱。 |
透過 FXC 提供的功能也可透過程式設計方式使用 D3DCompile 函式。 此呼叫會編譯具有根簽章或獨立根簽章的著色器(設定rootsig_1_0目標)。 D3DGetBlobPart 和 D3DSetBlobPart 可以將根簽章擷取和附加至現有的 Blob。 D3D_BLOB_ROOT_SIGNATURE用來指定根簽章 Blob 元件類型。 D3DStripShader 會從 blob 中移除根簽章(使用 D3DCOMPILER_STRIP_ROOT_SIGNATURE 旗標)。
筆記
注意
強烈建議先進行著色器的脫機編譯,但如果必須在運行時間編譯著色器,請參閱 D3DCompile2的備註。
注意
現有的 HLSL 資產不需要變更,即可處理要與它們搭配使用的根簽章。
相關主題