================ @@ -0,0 +1,426 @@ +==================== +HLSL Root Signatures +==================== + +.. contents:: + :local: + +Usage +===== + +In HLSL, the `root signature +<https://learn.microsoft.com/en-us/windows/win32/direct3d12/root-signatures>`_ +defines what types of resources are bound to the graphics pipeline. + +A root signature can be specified in HLSL as a `string +<https://learn.microsoft.com/en-us/windows/win32/direct3d12/specifying-root-signatures-in-hlsl#an-example-hlsl-root-signature>`_. +The string contains a collection of comma-separated clauses that describe root +signature constituent components. + +There are two mechanisms to compile an HLSL root signature. First, it is +possible to attach a root signature string to a particular shader via the +RootSignature attribute (in the following example, using the MyRS1 entry +point): + +.. code-block:: c++ + + #define RS "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 )" + + [RootSignature(RS)] + float4 main(float4 coord : COORD) : SV_Target + { + … + } + +The compiler will create and verify the root signature blob for the shader and +embed it alongside the shader byte code into the shader blob. + +The other mechanism is to create a standalone root signature blob, perhaps to +reuse it with a large set of shaders, saving space. The name of the define +string is specified via the usual -E argument. For example: + +.. code-block:: c++ + + dxc.exe -T rootsig_1_1 MyRS1.hlsl -E MyRS1 -Fo MyRS1.fxo + +Note that the root signature string define can also be passed on the command +line, e.g, -D MyRS1=”…”. + +Root Signature Grammar +====================== + +.. code-block:: c++ + + RootSignature : (RootElement(,RootElement)?)? + + RootElement : RootFlags | RootConstants | RootCBV | RootSRV | RootUAV | + DescriptorTable | StaticSampler + + RootFlags : 'RootFlags' '(' (RootFlag(|RootFlag)?)? ')' + + RootFlag : 'ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT' | + 'DENY_VERTEX_SHADER_ROOT_ACCESS' + + RootConstants : 'RootConstants' '(' 'num32BitConstants' '=' NUMBER ',' + bReg (',' 'space' '=' NUMBER)? + (',' 'visibility' '=' SHADER_VISIBILITY)? ')' + + RootCBV : 'CBV' '(' bReg (',' 'space' '=' NUMBER)? + (',' 'visibility' '=' SHADER_VISIBILITY)? + (',' 'flags' '=' DATA_FLAGS)? ')' + + RootSRV : 'SRV' '(' tReg (',' 'space' '=' NUMBER)? + (',' 'visibility' '=' SHADER_VISIBILITY)? + (',' 'flags' '=' DATA_FLAGS)? ')' + + RootUAV : 'UAV' '(' uReg (',' 'space' '=' NUMBER)? + (',' 'visibility' '=' SHADER_VISIBILITY)? + (',' 'flags' '=' DATA_FLAGS)? ')' + + DescriptorTable : 'DescriptorTable' '(' (DTClause(|DTClause)?)? + (',' 'visibility' '=' SHADER_VISIBILITY)? ')' + + DTClause : CBV | SRV | UAV | Sampler + + CBV : 'CBV' '(' bReg (',' 'numDescriptors' '=' NUMBER)? + (',' 'space' '=' NUMBER)? + (',' 'offset' '=' DESCRIPTOR_RANGE_OFFSET)? + (',' 'flags' '=' DATA_FLAGS)? ')' + + SRV : 'SRV' '(' tReg (',' 'numDescriptors' '=' NUMBER)? + (',' 'space' '=' NUMBER)? + (',' 'offset' '=' DESCRIPTOR_RANGE_OFFSET)? + (',' 'flags' '=' DATA_FLAGS)? ')' + + UAV : 'UAV' '(' uReg (',' 'numDescriptors' '=' NUMBER)? + (',' 'space' '=' NUMBER)? + (',' 'offset' '=' DESCRIPTOR_RANGE_OFFSET)? + (',' 'flags' '=' DATA_FLAGS)? ')' + + Sampler : 'Sampler' '(' sReg (',' 'numDescriptors' '=' NUMBER)? + (',' 'space' '=' NUMBER)? + (',' 'offset' '=' DESCRIPTOR_RANGE_OFFSET)? (',' 'flags' '=' NUMBER)? ')' + + + SHADER_VISIBILITY : 'SHADER_VISIBILITY_ALL' | 'SHADER_VISIBILITY_VERTEX' | + 'SHADER_VISIBILITY_HULL' | + 'SHADER_VISIBILITY_DOMAIN' | + 'SHADER_VISIBILITY_GEOMETRY' | + 'SHADER_VISIBILITY_PIXEL' | + 'SHADER_VISIBILITY_AMPLIFICATION' | + 'SHADER_VISIBILITY_MESH' + + DATA_FLAGS : 'DATA_STATIC_WHILE_SET_AT_EXECUTE' | 'DATA_VOLATILE' + + DESCRIPTOR_RANGE_OFFSET : 'DESCRIPTOR_RANGE_OFFSET_APPEND' | NUMBER + + StaticSampler : 'StaticSampler' '(' sReg (',' 'filter' '=' FILTER)? + (',' 'addressU' '=' TEXTURE_ADDRESS)? + (',' 'addressV' '=' TEXTURE_ADDRESS)? + (',' 'addressW' '=' TEXTURE_ADDRESS)? + (',' 'mipLODBias' '=' NUMBER)? + (',' 'maxAnisotropy' '=' NUMBER)? + (',' 'comparisonFunc' '=' COMPARISON_FUNC)? + (',' 'borderColor' '=' STATIC_BORDER_COLOR)? + (',' 'minLOD' '=' NUMBER)? + (',' 'maxLOD' '=' NUMBER)? (',' 'space' '=' NUMBER)? + (',' 'visibility' '=' SHADER_VISIBILITY)? ')' + + bReg : 'b' NUMBER + + tReg : 't' NUMBER + + uReg : 'u' NUMBER + + sReg : 's' NUMBER + + FILTER : 'FILTER_MIN_MAG_MIP_POINT' | + 'FILTER_MIN_MAG_POINT_MIP_LINEAR' | + 'FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT' | + 'FILTER_MIN_POINT_MAG_MIP_LINEAR' | + 'FILTER_MIN_LINEAR_MAG_MIP_POINT' | + 'FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR' | + 'FILTER_MIN_MAG_LINEAR_MIP_POINT' | + 'FILTER_MIN_MAG_MIP_LINEAR' | + 'FILTER_ANISOTROPIC' | + 'FILTER_COMPARISON_MIN_MAG_MIP_POINT' | + 'FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR' | + 'FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT' | + 'FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR' | + 'FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT' | + 'FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR' | + 'FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT' | + 'FILTER_COMPARISON_MIN_MAG_MIP_LINEAR' | + 'FILTER_COMPARISON_ANISOTROPIC' | + 'FILTER_MINIMUM_MIN_MAG_MIP_POINT' | + 'FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR' | + 'FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT' | + 'FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR' | + 'FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT' | + 'FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR' | + 'FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT' | + 'FILTER_MINIMUM_MIN_MAG_MIP_LINEAR' | + 'FILTER_MINIMUM_ANISOTROPIC' | + 'FILTER_MAXIMUM_MIN_MAG_MIP_POINT' | + 'FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR' | + 'FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT' | + 'FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR' | + 'FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT' | + 'FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR' | + 'FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT' | + 'FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR' | + 'FILTER_MAXIMUM_ANISOTROPIC' + + TEXTURE_ADDRESS : 'TEXTURE_ADDRESS_WRAP' | + 'TEXTURE_ADDRESS_MIRROR' | 'TEXTURE_ADDRESS_CLAMP' | + 'TEXTURE_ADDRESS_BORDER' | 'TEXTURE_ADDRESS_MIRROR_ONCE' + + COMPARISON_FUNC : 'COMPARISON_NEVER' | 'COMPARISON_LESS' | + 'COMPARISON_EQUAL' | 'COMPARISON_LESS_EQUAL' | + 'COMPARISON_GREATER' | 'COMPARISON_NOT_EQUAL' | + 'COMPARISON_GREATER_EQUAL' | 'COMPARISON_ALWAYS' + + STATIC_BORDER_COLOR : 'STATIC_BORDER_COLOR_TRANSPARENT_BLACK' | + 'STATIC_BORDER_COLOR_OPAQUE_BLACK' | + 'STATIC_BORDER_COLOR_OPAQUE_WHITE' + + +Serialized format +====================== +The root signature string is parsed and serialized into a binary format. The +binary format is a sequence of bytes that can be used to create a root signature +object in the Direct3D 12 API. The binary format is defined by the +`D3D12_ROOT_SIGNATURE_DESC (for rootsig_1_0) +<https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_root_signature_desc>`_ +or `D3D12_ROOT_SIGNATURE_DESC1 (for rootsig_1_1) +<https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_root_signature_desc1>`_ +structure in the Direct3D 12 API. (With the pointers translated to offsets.) + +It will be look like this: + +.. code-block:: c++ + + struct DxilContainerRootDescriptor1 { + uint32_t ShaderRegister; + uint32_t RegisterSpace; + uint32_t Flags; + }; + + struct DxilContainerDescriptorRange { + uint32_t RangeType; + uint32_t NumDescriptors; + uint32_t BaseShaderRegister; + uint32_t RegisterSpace; + uint32_t OffsetInDescriptorsFromTableStart; + }; + + struct DxilContainerDescriptorRange1 { + uint32_t RangeType; + uint32_t NumDescriptors; + uint32_t BaseShaderRegister; + uint32_t RegisterSpace; + uint32_t Flags; + uint32_t OffsetInDescriptorsFromTableStart; + }; + + struct DxilContainerRootDescriptorTable { + uint32_t NumDescriptorRanges; + uint32_t DescriptorRangesOffset; + }; + + struct DxilContainerRootParameter { + uint32_t ParameterType; + uint32_t ShaderVisibility; + uint32_t PayloadOffset; + }; + + struct DxilContainerRootSignatureDesc { + uint32_t Version; + uint32_t NumParameters; + uint32_t RootParametersOffset; + uint32_t NumStaticSamplers; + uint32_t StaticSamplersOffset; + uint32_t Flags; + }; + + +The binary representation begins with a **DxilContainerRootSignatureDesc** +object. + +The object will be followed by an array of +**DxilContainerRootParameter/Parameter1** objects located at +**DxilContainerRootSignatureDesc::RootParametersOffset**, which corresponds to +the size of **DxilContainerRootSignatureDesc**. + +Subsequently, there will be detailed object (**DxilRootConstants**, +**DxilContainerRootDescriptorTable**, or +**DxilRootDescriptor/DxilContainerRootDescriptor1**, depending on the parameter +type) for each **DxilContainerRootParameter** in the array. With +**DxilContainerRootParameter.PayloadOffset** pointing to the detailed object. + +In cases where the detailed object is a **DxilContainerRootDescriptorTable**, +it is succeeded by an array of +**DxilContainerDescriptorRange/DxilContainerDescriptorRange1** at +**DxilContainerRootDescriptorTable.DescriptorRangesOffset**. + +The binary representation is finalized with an array of +**DxilStaticSamplerDesc** at +**DxilContainerRootSignatureDesc::StaticSamplersOffset**. + +Implementation Details +====================== + +The root signature string will be parsed in Clang. +The parsing +will happened when build HLSLRootSignatureAttr or when build standalone root +signature blob. + +The root signature parsing will generate a HLSLRootSignatureAttr with member +represents the root signature string and the parsed information for each +resource in the root signature. It will bind to the entry function in the AST. +HLSLRootSignatureAttr will be something like this: +Note, VersionedRootSignatureDesc is not D3D12_ROOT_SIGNATURE_DESC, it is just +a simple struct to collect all the information in the root signature string. + +.. code-block:: c++ + + struct DescriptorRange { + DescriptorRangeType RangeType; + uint32_t NumDescriptors = 1; + uint32_t BaseShaderRegister; + uint32_t RegisterSpace = 0; + DescriptorRangeFlags Flags = DescriptorRangeFlags::None; + uint32_t OffsetInDescriptorsFromTableStart = DescriptorRangeOffsetAppend; + }; + + struct RootDescriptorTable { + std::vector<DescriptorRange> DescriptorRanges; + }; + struct RootConstants { + uint32_t ShaderRegister; + uint32_t RegisterSpace = 0; + uint32_t Num32BitValues; + }; + + struct RootDescriptor { + uint32_t ShaderRegister; + uint32_t RegisterSpace = 0; + RootDescriptorFlags Flags = RootDescriptorFlags::None; + }; + struct RootParameter { + RootParameterType ParameterType; + std::variant<RootDescriptorTable, RootConstants, RootDescriptor> + Parameter; + ShaderVisibility ShaderVisibility = ShaderVisibility::All; + }; + + struct StaticSamplerDesc { + Filter Filter = Filter::ANISOTROPIC; + TextureAddressMode AddressU = TextureAddressMode::Wrap; + TextureAddressMode AddressV = TextureAddressMode::Wrap; + TextureAddressMode AddressW = TextureAddressMode::Wrap; + float MipLODBias = 0.f; + uint32_t MaxAnisotropy = 16; + ComparisonFunc ComparisonFunc = ComparisonFunc::LessEqual; + StaticBorderColor BorderColor = StaticBorderColor::OpaqueWhite; + float MinLOD = 0.f; + float MaxLOD = MaxLOD; + uint32_t ShaderRegister; + uint32_t RegisterSpace = 0; + ShaderVisibility ShaderVisibility = ShaderVisibility::All; + }; + + struct RootSignatureDesc { + std::vector<RootParameter> Parameters; + std::vector<StaticSamplerDesc> StaticSamplers; + RootSignatureFlags Flags; + }; + + struct VersionedRootSignatureDesc { + RootSignatureVersion Version; + RootSignatureDesc Desc; + }; + + class HLSLRootSignatureAttr : public InheritableAttr { + protected: + std::string RootSignatureStr; + VersionedRootSignatureDesc RootSignature; + }; + + +.. code-block:: c++ + + def HLSLEntryRootSignature: HLSLRootSignatureAttr { + let Spellings = [GNU<"RootSignature">]; + let Subjects = Subjects<[HLSLEntry]>; + let LangOpts = [HLSL]; + let Args = [StringArgument<"InputString">]; + } + +For case compile to a standalone root signature blob, the +HLSLRootSignatureAttr will be bind to a fake empty entry. + +In clang code generation, the HLSLRootSignatureAttr in AST will be translated +into a global variable with struct type to express the layout and metadata to +save things like static sampler, root flags, space and NumDescriptors in LLVM IR. +The struct type will be look like this: + +.. code-block:: c++ + + %struct.TABLE0 = type { target("dx.rs.desc"), + target("dx.rs.sampler")} + + %struct.RS = type { target("dx.rs.rootconstant", 4), + %struct.TABLE0, + target("dx.rs.rootdescriptor") } + +The metadata will be look like this: + +.. code-block:: c++ ---------------- python3kgae wrote:
Changed to blank. https://github.com/llvm/llvm-project/pull/83933 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits