• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 众包
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
LOFLY
终其一生,编织快乐
博客园    首页    新随笔    联系   管理    订阅  订阅

DXIL 之着色器参数和签名

DXIL 之着色器参数和签名

  本节将规范了在DXIL中如何表达HLSL着色器的输入和输出参数。

HLSL的签名和语义

   在HLSL中,着色器入口函数的形式参数指定了着色器如何与图形管线进行交互。输入参数作为输入签名指定了着色器接收的值。输出参数作为输出签名指定了着色器产生的值。着色器编译器将HLSL的输入和输出签名映射到符合Direct3D功能规范中硬件约束的DXIL规范中。DXIL规范也被称为签名。

   签名映射是一个复杂的过程,因为有许多限制条件。所有签名参数必须适应有限的N个4x32位寄存器空间。出于效率的考虑,参数被组合在一起,以符合规范的约束条件,这个过程称为签名打包(signature packing)。大多数签名都是紧密打包的;然而,顶点着色器(VS)的输入签名并不是打包的,因为其值来自于输入装配器(IA)阶段而非图形管线。相反地,像素着色器(PS)的输出签名则会分配对齐,以使得SV_Target语义索引与输出寄存器索引对齐。

   每个HLSL签名参数都通过类似C语言类型、插值模式和语义名称和索引进行定义。类型定义了参数的形状,可能非常复杂。插值模式增加了打包的约束条件,即打包在一起的参数必须具有兼容的插值模式。语义是与参数关联的额外名称,用于以下目的:(1)指定一个参数是否为特殊的系统值(SV),(2)将参数链接到IA或StreamOut API流,以及(3)帮助调试。语义索引用于消除使用相同语义名称的参数之间的歧义,或跨越多个寄存器空间的行的参数之间的歧义。

   SV(System value)语义为相关参数添加特定的含义和约束。参数可以由硬件提供,这时被称为系统生成值(SGV)。另外,参数也可以由硬件进行解释,这时被称为系统解释值(SIV)。SGV和SIV是与管线阶段相关的;此外,有些参与签名打包,而有些则不参与。非SV语义始终参与签名打包。

   大多数系统生成值(SGV)使用特殊的Dxil内部函数加载,而不是从签名中加载输入。它们通常在签名中根本不存在。可以通过声明和使用特殊的内部函数来检测它们的存在。只有少数例外情况。其中一种情况是,它们存在并且从签名中加载,而不是从特殊内部函数加载,因为它们必须是可能从前一个阶段传递的打包签名的一部分,允许前一个阶段覆盖这些值,例如用于几何着色器中的SV_PrimitiveID和SV_IsFrontFace。在另一种情况下,它们标识仍然为DXBC签名做出贡献以提供信息的签名元素,但仅使用特殊的内部函数来读取值,例如GS输入中的SV_PrimitiveID和PS输入中的SampleIndex。

   对于各种签名位置中的不同系统值,其行为分类通过SemanticKind和SigPointKind组织的表进行描述。SigPointKind是一种新的分类,唯一地标识每个入口点可能的输入或输出参数集合。对于每个SemanticKind和SigPointKind的组合,都有一个SemanticInterpretationKind定义了该位置的处理类别。

   在SigPointKind中,签名点(Signature Points)被枚举如下:

ID SigPoint Related ShaderKind PackingKind SignatureKind Description
0 VSIn Invalid Vertex InputAssembler Input Ordinary Vertex Shader input from Input Assembler
1 VSOut Invalid Vertex Vertex Output Ordinary Vertex Shader output that may feed Rasterizer
2 PCIn HSCPIn Hull None Invalid Patch Constant function non-patch inputs
3 HSIn HSCPIn Hull None Invalid Hull Shader function non-patch inputs
4 HSCPIn Invalid Hull Vertex Input Hull Shader patch inputs - Control Points
5 HSCPOut Invalid Hull Vertex Output Hull Shader function output - Control Point
6 PCOut Invalid Hull PatchConstant PatchConstOrPrim Patch Constant function output - Patch Constant data passed to Domain Shader
7 DSIn Invalid Domain PatchConstant PatchConstOrPrim Domain Shader regular input - Patch Constant data plus system values
8 DSCPIn Invalid Domain Vertex Input Domain Shader patch input - Control Points
9 DSOut Invalid Domain Vertex Output Domain Shader output - vertex data that may feed Rasterizer
10 GSVIn Invalid Geometry Vertex Input Geometry Shader vertex input - qualified with primitive type
11 GSIn GSVIn Geometry None Invalid Geometry Shader non-vertex inputs (system values)
12 GSOut Invalid Geometry Vertex Output Geometry Shader output - vertex data that may feed Rasterizer
13 PSIn Invalid Pixel Vertex Input Pixel Shader input
14 PSOut Invalid Pixel Target Output Pixel Shader output
15 CSIn Invalid Compute None Invalid Compute Shader input
16 MSIn Invalid Mesh None Invalid Mesh Shader input
17 MSOut Invalid Mesh Vertex Output Mesh Shader vertices output
18 MSPOut Invalid Mesh Vertex PatchConstOrPrim Mesh Shader primitives output
19 ASIn Invalid Amplification None Invalid Amplification Shader input

语义解释的分类如下(SemanticInterpretationKind):

ID Name Description
0 NA Not Available
1 SV Normal System Value
2 SGV System Generated Value (sorted last)
3 Arb Treated as Arbitrary
4 NotInSig Not included in signature (intrinsic access)
5 NotPacked Included in signature, but does not contribute to packing
6 Target Special handling for SV_Target
7 TessFactor Special handling for tessellation factors
8 Shadow Shadow element must be added to a signature for compatibility
8 ClipCull Special packing rules for SV_ClipDistance or SV_CullDistance

在每个SigPointKind下,每个SemanticKind的语义解释如下:

Semantic VSIn VSOut PCIn HSIn HSCPIn HSCPOut PCOut DSIn DSCPIn DSOut GSVIn GSIn GSOut PSIn PSOut CSIn MSIn MSOut MSPOut ASIn
Arbitrary Arb Arb NA NA Arb Arb Arb Arb Arb Arb Arb NA Arb Arb NA NA NA Arb Arb NA
VertexID SV NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
InstanceID SV Arb NA NA Arb Arb NA NA Arb Arb Arb NA Arb Arb NA NA NA NA NA NA
Position Arb SV NA NA SV SV Arb Arb SV SV SV NA SV SV NA NA NA SV NA NA
RenderTargetArrayIndex Arb SV NA NA SV SV Arb Arb SV SV SV NA SV SV NA NA NA NA SV NA
ViewPortArrayIndex Arb SV NA NA SV SV Arb Arb SV SV SV NA SV SV NA NA NA NA SV NA
ClipDistance Arb ClipCull NA NA ClipCull ClipCull Arb Arb ClipCull ClipCull ClipCull NA ClipCull ClipCull NA NA NA ClipCull NA NA
CullDistance Arb ClipCull NA NA ClipCull ClipCull Arb Arb ClipCull ClipCull ClipCull NA ClipCull ClipCull NA NA NA ClipCull NA NA
OutputControlPointID NA NA NA NotInSig NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA
DomainLocation NA NA NA NA NA NA NA NotInSig NA NA NA NA NA NA NA NA NA NA NA NA
PrimitiveID NA NA NotInSig NotInSig NA NA NA NotInSig NA NA NA Shadow SGV SGV NA NA NA NA SV NA
GSInstanceID NA NA NA NA NA NA NA NA NA NA NA NotInSig NA NA NA NA NA NA NA NA
SampleIndex NA NA NA NA NA NA NA NA NA NA NA NA NA Shadow _41 NA NA NA NA NA NA
IsFrontFace NA NA NA NA NA NA NA NA NA NA NA NA SGV SGV NA NA NA NA NA NA
Coverage NA NA NA NA NA NA NA NA NA NA NA NA NA NotInSig _50 NotPacked _41 NA NA NA NA NA
InnerCoverage NA NA NA NA NA NA NA NA NA NA NA NA NA NotInSig _50 NA NA NA NA NA NA
Target NA NA NA NA NA NA NA NA NA NA NA NA NA NA Target NA NA NA NA NA
Depth NA NA NA NA NA NA NA NA NA NA NA NA NA NA NotPacked NA NA NA NA NA
DepthLessEqual NA NA NA NA NA NA NA NA NA NA NA NA NA NA NotPacked _50 NA NA NA NA NA
DepthGreaterEqual NA NA NA NA NA NA NA NA NA NA NA NA NA NA NotPacked _50 NA NA NA NA NA
StencilRef NA NA NA NA NA NA NA NA NA NA NA NA NA NA NotPacked _50 NA NA NA NA NA
DispatchThreadID NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NotInSig NotInSig NA NA NotInSig
GroupID NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NotInSig NotInSig NA NA NotInSig
GroupIndex NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NotInSig NotInSig NA NA NotInSig
GroupThreadID NA NA NA NA NA NA NA NA NA NA NA NA NA NA NA NotInSig NotInSig NA NA NotInSig
TessFactor NA NA NA NA NA NA TessFactor TessFactor NA NA NA NA NA NA NA NA NA NA NA NA
InsideTessFactor NA NA NA NA NA NA TessFactor TessFactor NA NA NA NA NA NA NA NA NA NA NA NA
ViewID NotInSig _61 NA NotInSig _61 NotInSig _61 NA NA NA NotInSig _61 NA NA NA NotInSig _61 NA NotInSig _61 NA NA NotInSig NA NA NA
Barycentrics NA NA NA NA NA NA NA NA NA NA NA NA NA NotPacked _61 NA NA NA NA NA NA
ShadingRate NA SV _64 NA NA SV _64 SV _64 NA NA SV _64 SV _64 SV _64 NA SV _64 SV _64 NA NA NA NA SV NA
CullPrimitive NA NA NA NA NA NA NA NA NA NA NA NA NA NotInSig NA NA NA NA NotPacked NA

以下是在本节中用于说明的一个顶点着色器示例:


struct Foo {
  float a;
  float b[2];
};

struct VSIn {
  uint    vid     : SV_VertexID;
  float3  pos     : Position;
  Foo     foo[3]  : SemIn1;
  float   f       : SemIn10;
};

struct VSOut
{
  float   f       : SemOut1;
  Foo     foo[3]  : SemOut2;
  float4  pos     : SV_Position;
};

void main(in  VSIn  In,        // input  signature
          out VSOut Out)       // output signature
{
  ...
}

签名打包必须高效。它应该尽量使用较少的寄存器,而且打包算法应该在合理的时间内运行。复杂之处在于该问题是NP完全问题,算法需要采用启发式方法来解决。

虽然当前不需要详细了解打包算法的细节,但重要的是概述一些与在DXIL中表示打包签名相关的概念。由于C/C++类型系统引发的参数形状复杂性,打包变得更加复杂。在上面的示例中,Out.foo数组字段的各个字段实际上也是数组,在内存中跨度排序。有效地分配这种跨度形状是困难的。为了简化打包过程,第一步是将用户自定义的(结构体)参数拆分为组成部分,并使跨度数组连续。这个准备步骤使算法能够操作稠密的矩形形状,我们称之为签名元素。在上述示例中,输出签名具有以下元素:float Out_f、float Out_foo_a[3]、float Out_foo_b[2][3]和float4 pos。每个元素都由行数和列数来描述。它们分别是1x1、3x1、6x1和1x4。打包算法的目标是将这些元素适应Nx4的寄存器空间,并满足所有打包兼容性约束。

签名元素记录

在DXIL中,每个签名元素都被表示为元数据记录。

对于上面的示例输出签名,元素记录如下所示:

;  element ID, semantic name, etype, sv, s.idx, interp,  rows, cols, start row, col, ext. list
!20 = !{i32 6, !"SemOut",      i8 0, i8 0, !40,   i8 2, i32 1, i8 1, i32 1,    i8 2, null}
!21 = !{i32 7, !"SemOut",      i8 0, i8 0, !41,   i8 2, i32 3, i8 1, i32 1,    i8 1, null}
!22 = !{i32 8, !"SemOut",      i8 0, i8 0, !42,   i8 2, i32 6, i8 1, i32 1,    i8 0, null}
!23 = !{i32 9, !"SV_Position", i8 0, i8 3, !43,   i8 2, i32 1, i8 4, i32 0,    i8 0, null}

每个记录包含以下字段:

Idx Type Description
0 i32 Unique signature element record ID, used to identify the element in operations.
1 String metadata Semantic name.
2 i8 ComponentType (enum value).
3 i8 SemanticKind (enum value).
4 Metadata Metadata list that enumerates all semantic indexes of the flattened parameter.
5 i8 InterpolationMode (enum value).
6 i32 Number of element rows.
7 i8 Number of element columns.
8 i32 Starting row of element packing location.
9 i8 Starting column of element packing location.
10 Metadata Metadata list of additional tag-value pairs; can be 'null' or empty.
语义名称系统值始终以 'S'、'V' 和 '_' 开头,以此前缀开头的用户语义是非法的。驱动程序可以忽略非SVs。调试层可能会使用这些信息来帮助验证不同阶段之间的签名兼容性。

最后的元数据列表用于指定附加属性和未来扩展。

签名记录元数据

典型情况下,着色器通常有两个签名:输入和输出,而域着色器有一个额外的补丁常量签名。这些签名由签名元素记录组成,并附加到着色器入口元数据中。下面的示例将解释元数据的详细信息。

Vertex shader HLSL

以下是上述顶点着色器的HLSL代码。语义索引的分配将在下面的部分中解释:

struct Foo
{
  float a;
  float b[2];
};

struct VSIn
{
  uint    vid     : SV_VertexID;
  float3  pos     : Position;
  Foo     foo[3]  : SemIn1;
    // semantic index assignment:
    // foo[0].a     : SemIn1
    // foo[0].b[0]  : SemIn2
    // foo[0].b[1]  : SemIn3
    // foo[1].a     : SemIn4
    // foo[1].b[0]  : SemIn5
    // foo[1].b[1]  : SemIn6
    // foo[2].a     : SemIn7
    // foo[2].b[0]  : SemIn8
    // foo[2].b[1]  : SemIn9
  float   f       : SemIn10;
};

struct VSOut
{
  float   f       : SemOut1;
  Foo     foo[3]  : SemOut2;
    // semantic index assignment:
    // foo[0].a     : SemOut2
    // foo[0].b[0]  : SemOut3
    // foo[0].b[1]  : SemOut4
    // foo[1].a     : SemOut5
    // foo[1].b[0]  : SemOut6
    // foo[1].b[1]  : SemOut7
    // foo[2].a     : SemOut8
    // foo[2].b[0]  : SemOut9
    // foo[2].b[1]  : SemOut10
  float4  pos     : SV_Position;
};

void main(in  VSIn  In,        // input  signature
          out VSOut Out)       // output signature
{
  ...
}

输入签名被打包为与IA阶段兼容的形式。打包算法必须为输入签名元素分配以下起始位置:

Input element Rows Columns Start row Start column
uint VSIn.vid 1 1 0 0
float3 VSIn.pos 1 3 1 0
float VSIn.foo.a[3] 3 1 2 0
float VSIn.foo.b[6] 6 1 5 0
float VSIn.f 1 1 11 0
一个合理的打包算法将为输出签名元素分配以下起始位置:
Input element Rows Columns Start row Start column
uint VSOut.f 1 1 1 2
float VSOut.foo.a[3] 3 1 1 1
float VSOut.foo.b[6] 6 1 1 0
float VSOut.pos 1 4 0 0

语义索引分配

  DXIL中的语义索引分配与DXBC完全相同。语义索引分配,简写为s.idx,是对所有具有相同语义名称的字段进行连续枚举,就像签名被打包用于IA阶段一样。也就是说,给定一个复杂的签名元素,例如VSOut的foo[3],它的语义名称是SemOut,起始索引为2,该元素被展开为单独的字段:foo[0].a,foo[0].b[0],...,foo[2].b[1],并且这些字段分别获得连续的语义索引2、3、...、10。语义索引对用于设置IA阶段和通过StreamOut API捕获单个签名寄存器的值。

用于VS签名的DXIL

相应的DXIL元数据如下所示:

!dx.entryPoints = !{ !1 }
!1 = !{ void @main(), !"main", !2, null, null }
; Signatures: In, Out, Patch Constant (optional)
!2 = !{ !3, !4, null }
; Input signature (packed accordiong to IA rules)
!3 = !{ !10, !11, !12, !13, !14 }
; element idx, semantic name, etype, sv, s.idx, interp, rows, cols, start row, col, ext. list
!10 = !{i32 1, !"SV_VertexID", i8 0, i8 1, !30, i32 0, i32 1, i8 1, i32 0, i8 0, null}
!11 = !{i32 2, !"Position", i8 0, i8 0, !30, i32 0, i32 1, i8 3, i32 1, i8 0, null}
!12 = !{i32 3, !"SemIn", i8 0, i8 0, !32, i32 0, i32 3, i8 1, i32 2, i8 0, null}
!13 = !{i32 4, !"SemIn", i8 0, i8 0, !33, i32 0, i32 6, i8 1, i32 5, i8 0, null}
!14 = !{i32 5, !"SemIn", i8 0, i8 0, !34, i32 0, i32 1, i8 1, i32 11, i8 0, null}
; semantic index assignment:
!30 = !{ i32 0 }
!32 = !{ i32 1, i32 4, i32 7 }
!33 = !{ i32 2, i32 3, i32 5, i32 6, i32 8, i32 9 }
!34 = !{ i32 10 }
; Output signature (tightly packed according to pipeline stage packing rules)
!4 = !{ !20, !21, !22, !23 }
; element ID, semantic name, etype, sv, s.idx, interp, rows, cols, start row, col, ext. list
!20 = !{i32 6, !"SemOut", i8 0, i8 0, !40, i32 2, i32 1, i8 1, i32 1, i8 2, null}
!21 = !{i32 7, !"SemOut", i8 0, i8 0, !41, i32 2, i32 3, i8 1, i32 1, i8 1, null}
!22 = !{i32 8, !"SemOut", i8 0, i8 0, !42, i32 2, i32 6, i8 1, i32 1, i8 0, null}
!23 = !{i32 9, !"SV_Position", i8 0, i8 3, !43, i32 2, i32 1, i8 4, i32 0, i8 0, null}
; semantic index assignment:
!40 = !{ i32 1 }
!41 = !{ i32 2, i32 5, i32 8 }
!42 = !{ i32 3, i32 4, i32 6, i32 7, i32 9, i32 10 }
!43 = !{ i32 0 }

细分着色器的例子 Hull Shader example

   一个曲面细分着色器(Hull Shader,HS)由两个入口点函数定义:控制点(Control Point,CP)函数用于计算控制点,以及片元常量(Patch Constant,PC)函数用于计算片元常量数据,包括细分因子。这两个函数的输入都是整个片元的输入控制点,因此每个元素可以通过行索引,并且还可以通过顶点索引进行索引。

以下是一个HS示例的入口点元数据和签名列表:

; !105 is extended parameter list containing reference to HS State:
!101 = !{ void @HSMain(), !"HSMain", !102, null, !105 }
; Signatures: In, Out, Patch Constant
!102 = !{ !103, !104, !204 }

入口点记录指定了以下内容:(1) CP函数HSMain作为主要符号,以及(2) 通过可选的元数据节点!105指定的PC函数。

CP输入签名描述一个输入控制点:

!103 = !{ !110, !111 }
; element ID, semantic name, etype, sv, s.idx, interp, rows, cols, start row, col, ext. list
!110= !{i32 1, !"SV_Position", i8 0, i8 3, !130, i32 0, i32 1, i8 4, i32 0, i8 0, null}
!111= !{i32 2, !"array", i8 0, i8 0, !131, i32 0, i32 4, i8 3, i32 1, i8 0, null}
; semantic indexing for flattened elements:
!130 = !{ i32 0 }
!131 = !{ i32 0, i32 1, i32 2, i32 3 }

请注意,SV_OutputControlPointID和SV_PrimitiveID输入元素是通过特殊的Dxil内置函数加载的SGV,它们在签名中根本不存在。它们具有SemanticInterpretationKind::NotInSig的语义解释。

CP输出签名描述一个输出控制点:

!104 = !{ !120, !121 }
;  element ID, semantic name, etype, sv, s.idx, interp,  rows, cols, start row, col, ext. list
!120= !{i32 3, !"SV_Position", i8 0, i8 3, !130, i32 0, i32 1, i8 4, i32 0,    i8 0, null}
!121= !{i32 4, !"array",       i8 0, i8 0, !131, i32 0, i32 4, i8 3, i32 1,    i8 0, null}

Hull着色器需要一个扩展参数来定义额外的状态:

; extended parameter HS State
!105 = !{ i32 3, !201 }
; HS State record defines patch constant function and other properties
; Patch Constant Function, in CP count, out CP count, tess domain, tess part, out prim, max tess factor
!201 = !{ void @PCMain(), 4, 4, 3, 1, 3, 16.0 }

PC-output signature:

!204 = !{ !220, !221, !222 }
; element ID, semantic name, etype, sv, s.idx, interp, rows, cols, start row, col, ext. list
!220= !{i32 3, !"SV_TessFactor", i8 0, i8 25, !130, i32 0, i32 4, i8 1, i32 0, i8 3, null}
!221= !{i32 4, !"SV_InsideTessFactor", i8 0, i8 26, !231, i32 0, i32 2, i8 1, i32 4, i8 3, null}
!222= !{i32 5, !"array", i8 0, i8 0, !131, i32 0, i32 4, i8 3, i32 0, i8 0, null}
; semantic indexing for flattened elements:
!231 = !{ i32 0, i32 1 }

在操作中访问签名值

  没有与签名元素对应的函数参数或变量。而是使用loadInput和storeOutput函数来在操作中访问签名元素的值。这些访问是标量的。

以下是操作的签名:

; overloads: SM5.1: f16|f32|i16|i32, SM6.0: f16|f32|f64|i8|i16|i32|i64
declare float @dx.op.loadInput.f32(
i32, ; opcode
i32, ; input ID
i32, ; row (relative to start row of input ID)
i8, ; column (relative to start column of input ID), constant in [0,3]
i32) ; vertex index
; overloads: SM5.1: f16|f32|i16|i32, SM6.0: f16|f32|f64|i8|i16|i32|i64
declare void @dx.op.storeOutput.f32(
i32, ; opcode
i32, ; output ID
i32, ; row (relative to start row of output ID)
i8, ; column (relative to start column of output ID), constant in [0,3]
float) ; value to store

LoadInput/storeOutput接受input/output元素ID,该ID是签名元数据记录的唯一标识。row参数是从元素开始的数组元素行索引;寄存器索引是通过将元素的起始行和行参数值相加来获得的。类似地,column参数是相对列索引;打包的寄存器组件是通过将元素的起始列(打包列)和列值相加得到的。存在多个重载函数来访问不同原始类型的元素。LoadInput还接受一个额外的顶点索引参数,该参数表示DS CP-inputs和GS inputs的顶点索引;在其他情况下,顶点索引必须为undef(未定义)。

签名打包

  根据运行时的限制,签名元素必须打包到N个4-32位寄存器的空间中。DXIL包含了打包后的签名。打包算法比DX11更加激进。然而,DXIL的打包只是对驱动程序实现的建议。驱动程序编译器可以根据需要重新排列签名元素,同时保持连接的流水线阶段的兼容性。DXIL被设计成易于“重定位”签名元素,因为loadInput/storeOutput的行和列索引不需要改变,因为它们相对于每个元素的起始行/列而言。

签名打包类型

  两个流水线阶段可以以四种不同的方式连接,从而产生四种打包类型。

  1. 输入汇编(Input Assembly):仅有VS输入。所有元素都映射到唯一的寄存器,它们不能被打包在一起。不使用插值模式。

  2. 连接到光栅化器(Connects to Rasterizer):包括VS输出、HS CP-input/output和PC-input、DS CP-input/output、GS input/output、PS input。 根据约束、元素可以被打包在一起。 使用插值模式,并且连接的签名之间必须保持一致。 虽然HS CP-output和DS CP-input签名不经过光栅化器,但它们仍然被视为如此。原因是HS CP-input和HS CP-output在通过的HS情况下,必须具有相同的打包方式以提高效率。

  3. 片元常量(Patch Constant): 包括HS PC-output和DS PC-inout。 SV_TessFactor和SV_InsideTessFactor是唯一在此处相关的系统值(SVs),并且这是它们唯一合法的位置。它们具有特殊的打包考虑。 不使用插值模式。

  4. Pixel Shader Output:只有PS 输出。只有SV_Target映射到输出寄存器空间。不执行任何打包操作,语义索引对应于渲染目标的索引。

打包约束

  在DXIL中,打包算法比DXBC更严格和更激进,尽管仍然兼容。特别是,数组签名元素不会被拆分为标量,即使每个数组访问可以通过文字索引消除歧义。DXIL和DXBC签名的打包方式并不相同,因此跨编译器版本将它们链接到单个流水线中是不被支持的。
   签名元素的行维度表示索引范围。如果约束允许,两个相邻或重叠的索引范围将合并为一个单独的索引范围。

打包约束如下:

1.一个寄存器的所有4个分量必须具有相同的插值模式
2.包含系统值(SVs)的寄存器分量必须位于不包含系统值的分量的右侧。
3.SV_ClipDistance 和 SV_CullDistance 有额外的约束条件:a. 它们可以一起打包。b. 必须占用最多2个寄存器(8 个分量)。c. SV_ClipDistance 必须使用线性插值模式。

  1. 包含系统值(SVs)的寄存器不能在索引范围内,但例外情况是Tessellation Factors(TessFactors)。

5.如果索引范围R1与TessFactor索引范围R2重叠,那么R1必须完全包含在R2内。因此,当打包时,外部和内部TessFactors占据不相交的索引范围。

  1. 如果非TessFactor索引范围重叠,它们会被合并为一个更大的范围。

  2. 所有非SGV(系统几何值)被打包后,SGV必须被打包。如果有多个SGV,则按照HLSL声明的顺序进行打包。

为SGV打包

  两个连接签名的非SGV部分必须匹配;但是,SGV部分不需要匹配。一个例子是像在PS中声明SV_PrimitiveID作为输入。如果VS连接到PS,PS的SV_PrimitiveID值将由硬件合成;此外,在VS中输出SV_PrimitiveID是不允许的。如果GS连接到PS,GS可以将SV_PrimitiveID声明为其输出。

   不幸的是,SGV(系统几何值)规范对于连接着色器的分离编译造成了一些复杂性。例如,GS输出SV_PrimitiveID,而PS按顺序输入SV_IsFrontFace和SV_PrimitiveID。在GS和PS签名中,SV_PrimitiveID的位置是不兼容的。在SM5.0及之前的版本中,对于这种模糊性,很难进行更多的处理;程序员将不得不依赖SDKLayers来捕捉潜在的不匹配情况。

  SM5.1及更高版本的着色器在使用PSO对象描述流水线状态的D3D12+运行时上工作。因此,驱动编译器在编译过程中可以访问连接着色器,尽管HLSL编译器不能。驱动编译器可以轻松解决签名中SGV歧义的问题。对于SM5.1及更高版本,HLSL编译器将确保声明的SGV适合于打包的签名;然而,它会将SGV的起始行列位置设置为(-1, 0),以便驱动编译器必须在PSO编译期间解决SGV的放置问题。

上一节 下一节

posted @ 2023-06-25 15:59  编织快乐  阅读(316)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3