在HLSL Shader Model 5.1中指定根签名是在C ++代码中指定根签名的替代方法。

  • HLSL根签名示例
  1. 根签名版本1.0
  2. 根签名版本1.1
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别名是堆中的相同描述符

在HLSL中指定根签名_编程

根签名版本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子句采用0(默认值表示无标志)或一个或多个预定义的根标志值,这些值通过‘|’运算符连接。 允许的根标志值由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子句在根签名中指定根常量。 两个必需的参数是:cbuffer的num32BitConstants和bReg(与C ++ API中的BaseShaderRegister对应的寄存器)。 空间(C ++ API中的RegisterSpace)和可见性(C ++中的ShaderVisibility)参数是可选的,默认值为:

RootConstants(num32BitConstants=N, bReg [, space=0, 
              visibility=SHADER_VISIBILITY_ALL ])

例如:

RootConstants(num32BitConstants=3, b3)

 可见性

可见性是一个可选参数,可以具有D3D12_SHADER_VISIBILITY中的值之一。
SHADER_VISIBILITY_ALL将根参数广播到所有着色器。 在某些硬件上这没有成本,但是在其他硬件上则需要将数据派生到所有着色器阶段。 设置其中一个选项(例如SHADER_VISIBILITY_VERTEX)会将根参数限制为单个着色器阶段。
将根参数设置为单个着色器阶段允许在不同阶段使用相同的绑定名称。 例如,SRV绑定为t0,SHADER_VISIBILITY_VERTEX和SRV绑定为t0,SHADER_VISIBILITY_PIXEL。 但是,如果绑定之一的可见性设置为t0,SHADER_VISIBILITY_ALL,则根签名将无效。

 Root-level CBV

 CBV(常量缓冲区视图)子句指定了根级别的常量缓冲区b寄存器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 ])

 Root-level SRV

SRV(着色器资源视图)子句指定根级别的SRV t寄存器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 ])

Root-level UAV

UAV(无序访问视图)子句指定了根级别的UAV u注册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子句本身是逗号分隔的描述符表子句的列表,以及可选的可见性参数。 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等于“ unbounded”,则范围为[Reg,UINT_MAX],这意味着应用程序必须确保其未引用越界区域。 offset字段表示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(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寄存器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,也许可以将其与大量着色器一起重用,从而节省空间。 效果编译器工具(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源文件创建着色器字节码。 该编译器有很多可选参数,请参阅效果编译器工具。
为了管理HLSL创作的根签名,下表提供了一些使用FXC的示例。

Line Command line Description
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资产即可处理与它们一起使用的根签名。

相关话题

Dynamic Indexing using HLSL 5.1

HLSL Shader Model 5.1 Features for Direct3D 12

Resource Binding

Resource Binding in HLSL

Root Signatures

Shader Model 5.1

Shader Specified Stencil Reference Value

Typed Unordered Access View Loads