| # DirectX Container | |
| ```{toctree} | |
| :hidden: true | |
| ``` | |
| ## Overview | |
| The DirectX Container (DXContainer) file format is the binary file format for | |
| compiled shaders targeting the DirectX runtime. The file format is also called | |
| the DXIL Container or DXBC file format. Because the file format can be used to | |
| include either DXIL or DXBC compiled shaders, the nomenclature in LLVM is simply | |
| DirectX Container. | |
| DirectX Container files are read by the compiler and associated tools as well as | |
| the DirectX runtime, profiling tools and other users. This document serves as a | |
| companion to the implementation in LLVM to more completely document the file | |
| format for its many users. | |
| ## Basic Structure | |
| A DXContainer file begins with a header, and is then followed by a sequence of | |
| "parts", which are analogous to object file sections. Each part contains a part | |
| header, and some number of bytes of data after the header in a defined format. | |
| DX Container data structures are encoded little-endian in the binary file. | |
| The LLVM versions of all data structures described and/or referenced in this | |
| file are defined in | |
| [llvm/include/llvm/BinaryFormat/DXContainer.h](https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/BinaryFormat/DXContainer.h). | |
| Some pseudo code is provided in blocks below to ease understanding of this | |
| document, but reading it with the header available will provide the most | |
| clarity. | |
| ### File Header | |
| ```c | |
| struct Header { | |
| uint8_t Magic[4]; | |
| uint8_t Digest[16]; | |
| uint16_t MajorVersion; | |
| uint16_t MinorVersion; | |
| uint32_t FileSize; | |
| uint32_t PartCount; | |
| }; | |
| ``` | |
| The DXContainer header matches the pseudo-definition above. It begins with a | |
| four character code (magic number) with the value `DXBC` to denote the file | |
| format. | |
| The `Digest` is a 128bit hash digest computed with a proprietary algorithm and | |
| encoded in the binary by the bytecode validator. | |
| The `MajorVersion` and `MinorVersion` encode the file format version | |
| `1.0`. | |
| The remaining fields encode 32-bit unsigned integers for the file size and | |
| number of parts. | |
| Following the part header is an array of `PartCount` 32-bit unsigned integers | |
| specifying the offsets of each part header. | |
| ### Part Data | |
| ```c | |
| struct PartHeader { | |
| uint8_t Name[4]; | |
| uint32_t Size; | |
| } | |
| ``` | |
| Each part begins with a part header. A part header includes the 4-character part | |
| name, and a 32-bit unsigned integer specifying the size of the part data. The | |
| part header is followed by `Size` bytes of data comprising the part. The | |
| format does not explicitly require 32-bit alignment of parts, although LLVM does | |
| implement this restriction in the writer code (because it's a good idea). The | |
| LLVM object reader code does not assume inputs are correctly aligned to avoid | |
| undefined behavior caused by misaligned inputs generated by other compilers. | |
| The {ref}`PRIV <PRIV>` part is an exception: DXContainer writer code in LLVM may | |
| produce a PRIV part with size which is not a multiple of four bytes. | |
| ## Part Formats | |
| The part name indicates the format of the part data. There are 24 part headers | |
| used by DXC and FXC. Not all compiled shaders contain all parts. In the list | |
| below parts generated only by DXC are marked with †, and parts generated only by | |
| FXC are marked with \*. | |
| 01. {ref}`DXIL <DXIL>`† - Stores the DXIL bytecode. | |
| 02. {ref}`HASH <HASH>`† - Stores the shader MD5 hash. | |
| 03. {ref}`ILDB <ILDB>`† - Stores the DXIL bytecode with LLVM Debug Information embedded in the module. | |
| 04. {ref}`ILDN <ILDN>`† - Stores shader debug name for external debug information. | |
| 05. {ref}`ISG1 <ISG1>` - Stores the input signature for Shader Model 5.1+. | |
| 06. ISGN\* - Stores the input signature for Shader Model 4 and earlier. | |
| 07. {ref}`OSG1 <OSG1>` - Stores the output signature for Shader Model 5.1+. | |
| 08. OSG5\* - Stores the output signature for Shader Model 5. | |
| 09. OSGN\* - Stores the output signature for Shader Model 4 and earlier. | |
| 10. PCSG\* - Stores the patch constant signature for Shader Model 5.1 and earlier. | |
| 11. PDBI† - Stores PDB information. | |
| 12. {ref}`PRIV <PRIV>`† - Stores private data, including embedded companion PDB files. | |
| 13. {ref}`PSG1 <PSG1>` - Stores the patch constant signature for Shader Model 6+. | |
| 14. {ref}`PSV0 <PSV0>` - Stores Pipeline State Validation data. | |
| 15. RDAT† - Stores Runtime Data. | |
| 16. RDEF\* - Stores resource definitions. | |
| 17. {ref}`RTS0 <RTS0>` - Stores compiled root signature. | |
| 18. {ref}`SFI0 <SFI0>` - Stores shader feature flags. | |
| 19. SHDR\* - Stores compiled DXBC bytecode. | |
| 20. SHEX\* - Stores compiled DXBC bytecode. | |
| 21. DXBC\* - Stores compiled DXBC bytecode. | |
| 22. {ref}`SRCI <SRCI>`† - Stores shader source information. | |
| 23. STAT† - Stores shader statistics. | |
| 24. {ref}`VERS <VERS>`† - Stores shader compiler version information. | |
| ### DXIL Part | |
| (DXIL)= | |
| The DXIL part is comprised of three data structures: the `ProgramHeader`, the | |
| `BitcodeHeader` and the bitcode serialized LLVM 3.7 IR Module. | |
| The `ProgramHeader` contains the shader model version and pipeline stage | |
| enumeration value. This identifies the target profile of the contained shader | |
| bitcode. | |
| The `BitcodeHeader` contains the DXIL version information and refers to the | |
| start of the bitcode data. | |
| ### HASH Part | |
| (HASH)= | |
| The HASH part contains a 32-bit unsigned integer with the shader hash flags, and | |
| a 128-bit MD5 hash digest. The flags field can either have the value `0` to | |
| indicate no flags, or `1` to indicate that the file hash was computed | |
| including the source code that produced the binary. See {ref}`Compiler Flags | |
| <compiler_flags>` for how `/Zss` and `/Zsb` select the hashed bitcode. | |
| ### ILDB Part | |
| (ILDB)= | |
| The ILDB part follows the structure of the {ref}`DXIL <DXIL>` part. It stores the | |
| unstripped DXIL bitcode module with debug information embedded. | |
| The ILDB part is emitted when the shader is compiled with full debug information | |
| (`/Zi`). It is omitted from all outputs when slim debug (`/Zs`) is used. | |
| See {ref}`Compiler Flags <compiler_flags>` for how `/Qembed_debug`, | |
| `/Qstrip_debug`, `/Fd`, and `/Zs` control whether it appears in the main | |
| output, the companion PDB, or both. | |
| The stripped {ref}`DXIL <DXIL>` part has the `Dwarf Version` and `Debug Info Version` | |
| module flags removed, and `dx.source` metadata nodes are stripped from it. | |
| Those nodes are preserved in the ILDB module when `/Qsource_in_debug_module` | |
| is used; otherwise they are replaced with empty placeholder values in the ILDB | |
| module written to the companion PDB file. | |
| ```{rubric} Reading this part | |
| ``` | |
| When the ILDB part is present in a DXContainer file, {program}`obj2yaml` prints | |
| it under a `Program` mapping with the embedded DXIL bitcode. Use | |
| {program}`llvm-objcopy` to extract the raw bitcode, then {program}`llvm-dis` to | |
| disassemble it: | |
| ``` | |
| llvm-objcopy --dump-section=ILDB=shader.bc shader.dxbc | |
| llvm-dis shader.bc | |
| ``` | |
| When the ILDB part is stored in a companion PDB file, use {program}`llvm-pdbutil` | |
| to access it (see {doc}`llvm-pdbutil <../CommandGuide/llvm-pdbutil>`). | |
| ### ILDN Part | |
| (ILDN)= | |
| The ILDN part stores the name of the companion PDB file used for external | |
| debug information. It is always emitted when the shader is compiled with debug | |
| information, and is included in both the main DXContainer output and the | |
| companion PDB file. | |
| The part begins with a `DebugNameHeader` followed by a null-terminated UTF-8 | |
| string containing the debug file name: | |
| ```c | |
| struct DebugNameHeader { | |
| uint16_t Flags; | |
| uint16_t NameLength; | |
| }; | |
| ``` | |
| The `Flags` field is reserved and must be zero. `NameLength` is the length | |
| of the debug file name in bytes, not including the null terminator. | |
| If no PDB output path is specified, the debug file name defaults to | |
| `<MD5 hash>.pdb`, where `<MD5 hash>` is the stringified MD5 digest from the | |
| {ref}`HASH <HASH>` part. See {ref}`Compiler Flags <compiler_flags>` for how `/Fd`, `/Zss`, | |
| and `/Zsb` affect the debug file name and hash computation. | |
| ```{rubric} Reading this part | |
| ``` | |
| When the ILDN part is present in a DXContainer file, {program}`obj2yaml` prints | |
| it under a `DebugName` mapping. | |
| ### PRIV Part | |
| (PRIV)= | |
| The PRIV part stores opaque binary data. DXC may emit it when the `/Qpdb_in_private` | |
| flag is used to embed the companion debug info PDB file in the main DXContainer output. | |
| The part data may also hold arbitrary user-provided binary blobs attached by | |
| custom tooling. | |
| Unlike most other parts, the PRIV part data does not need to be padded to a | |
| 4-byte boundary. Thus, when a PRIV part is present, it must be the last part in the | |
| container. LLVM enforces this constraint in both the object reader and the | |
| ObjectYAML writer. A DXContainer may contain at most one PRIV part. | |
| ```{rubric} Reading this part | |
| ``` | |
| When the PRIV part is present in a DXContainer file, {program}`obj2yaml` prints | |
| it under a `PrivateData` mapping. | |
| Use {program}`llvm-objcopy` to extract the raw part data: | |
| ``` | |
| llvm-objcopy --dump-section=PRIV=output.priv shader.dxbc | |
| ``` | |
| ### SRCI Part | |
| (SRCI)= | |
| The SRCI part stores shader source information extracted from `dx.source` | |
| metadata in the LLVM module. It is emitted when source information is available. | |
| See {ref}`Compiler Flags <compiler_flags>` for output placement and related flags. | |
| The SRCI part is written only to the companion PDB file. It consists of a part | |
| header followed by three 4-byte aligned sections. Each section begins with a | |
| `SectionHeader` and is followed by section-specific data: | |
| ```c | |
| struct Header { | |
| uint32_t AlignedSizeInBytes; | |
| uint16_t Flags; | |
| uint16_t SectionCount; | |
| }; | |
| struct SectionHeader { | |
| uint32_t AlignedSizeInBytes; | |
| uint16_t Flags; | |
| uint16_t Type; | |
| }; | |
| ``` | |
| The part `Flags` field is reserved and must be zero. `SectionCount` must be | |
| `3`. Each section `Flags` field is reserved and must be zero. The | |
| `Type` field identifies the section. The section type values are: | |
| ```c | |
| SOURCE_INFO_TYPE(0, SourceContents) | |
| SOURCE_INFO_TYPE(1, SourceNames) | |
| SOURCE_INFO_TYPE(2, Args) | |
| ``` | |
| #### Source Names Section | |
| The source names section stores the file names of the HLSL translation units | |
| that contributed source to the shader. It begins with a section header of type | |
| `SourceNames`, followed by a section-specific header and a sequence of name | |
| entries: | |
| ```c | |
| struct SourceNamesHeader { | |
| uint32_t Flags; | |
| uint32_t Count; | |
| uint16_t EntriesSizeInBytes; | |
| }; | |
| struct SourceNamesEntry { | |
| uint32_t AlignedSizeInBytes; | |
| uint32_t Flags; | |
| uint32_t NameSizeInBytes; | |
| uint32_t ContentSizeInBytes; | |
| }; | |
| ``` | |
| The section-specific `Flags` field is reserved and must be zero. `Count` is | |
| the number of entries that follow. `EntriesSizeInBytes` is the total size of | |
| the entry data following the section-specific header, including entry padding. | |
| Each entry is 4-byte aligned. The first entry is usually the main shader source | |
| file, and the remaining entries are sorted by file name. | |
| Each entry is followed by a null-terminated UTF-8 file name of length | |
| `NameSizeInBytes`. The `ContentSizeInBytes` field records the size of the | |
| corresponding source content entry in the source contents section, including its | |
| null terminator. | |
| #### Source Contents Section | |
| The source contents section stores the HLSL source text for each file named in | |
| the source names section. It begins with a section header of type | |
| `SourceContents`, followed by a section-specific header and the (optionally | |
| compressed) entry data: | |
| ```c | |
| struct SourceContentsHeader { | |
| uint32_t AlignedSizeInBytes; | |
| uint16_t Flags; | |
| uint16_t Type; | |
| uint32_t EntriesSizeInBytes; | |
| uint32_t UncompressedEntriesSizeInBytes; | |
| uint32_t Count; | |
| }; | |
| struct SourceContentsEntry { | |
| uint32_t AlignedSizeInBytes; | |
| uint32_t Flags; | |
| uint32_t ContentSizeInBytes; | |
| }; | |
| ``` | |
| The section-specific `Flags` field is reserved and must be zero. The | |
| `Type` field specifies the compression applied to the entry data. The | |
| compression type values are: | |
| ```c | |
| COMPRESSION_TYPE(0, None) | |
| COMPRESSION_TYPE(1, Zlib) | |
| ``` | |
| When no compression is used, `EntriesSizeInBytes` and | |
| `UncompressedEntriesSizeInBytes` are equal. | |
| When Zlib compression is used, the bytes following the section-specific header | |
| contain the compressed aggregate of all entries. After decompression, the data is | |
| a sequence of `Count` entries. | |
| Each uncompressed entry is 4-byte aligned and is followed by a null-terminated | |
| UTF-8 string containing the file source text. | |
| The entries must appear in the same order as the entries in the source names | |
| section. | |
| #### Args Section | |
| The args section stores the HLSL compiler command-line arguments used to produce | |
| the shader. It begins with a section header of type `Args`, followed by a | |
| section-specific header and the argument data: | |
| ```c | |
| struct ArgsHeader { | |
| uint32_t Flags; | |
| uint32_t SizeInBytes; | |
| uint32_t Count; | |
| }; | |
| ``` | |
| The section-specific `Flags` field is reserved and must be zero. | |
| `SizeInBytes` is the total size of the argument data following the | |
| section-specific header. `Count` is the number of argument pairs that | |
| follow. | |
| The header is followed by `Count` argument pairs. Each pair consists of two | |
| null-terminated UTF-8 strings: an argument name and an argument value. | |
| Padding is not applied between argument pairs. The section is padded with zero | |
| bytes at the end to a 4-byte boundary. | |
| ```{rubric} Reading this part | |
| ``` | |
| The SRCI part is normally found in a companion PDB file rather than the main | |
| DXContainer output. When present, {program}`obj2yaml` prints it under a | |
| `SourceInfo` mapping. | |
| To read SRCI part from a companion PDB file, use {program}`llvm-pdbutil`. | |
| ### VERS Part | |
| (VERS)= | |
| The VERS part stores compiler version information. It is emitted when the | |
| shader is compiled with debug information. When a companion PDB file is produced, | |
| the VERS part is written to that file. When compiling a shader library, the VERS | |
| part is also written to the main DXContainer output. | |
| The part begins with a `CompilerVersionHeader` followed by two sequential | |
| null-terminated UTF-8 strings: the compiler commit SHA and a custom version | |
| string: | |
| ```c | |
| struct CompilerVersionHeader { | |
| uint16_t Major; | |
| uint16_t Minor; | |
| uint32_t Flags; | |
| uint32_t CommitCount; | |
| uint32_t ContentSizeInBytes; | |
| }; | |
| ``` | |
| `Major` and `Minor` encode the compiler version. | |
| The `Flags` field is a bitmask. The flag values are: | |
| - `Default` (`0`) - default value | |
| - `Debug` (`1`) - indicates whether the compiler was built in debug mode | |
| - `Internal` (`2`) - indicates whether the shader was modified by a validator | |
| `CommitCount` records how many commits are reachable from the compiler's HEAD | |
| revision. In DXC, this is the value produced by `git rev-list --count HEAD` | |
| in the compiler repository. | |
| LLVM always emits `0` for `CommitCount`. This is a deliberate difference | |
| from DXC; the commit SHA in the part data is considered sufficient for | |
| identifying the compiler build. | |
| `ContentSizeInBytes` is the combined size of the commit SHA and custom version | |
| strings, including their null terminators but excluding any trailing part padding. | |
| ```{rubric} Reading this part | |
| ``` | |
| When the VERS part is present in a DXContainer file, {program}`obj2yaml` prints | |
| it under a `CompilerVersion` mapping. | |
| To read VERS part from a companion PDB file, use {program}`llvm-pdbutil`. | |
| ### Program Signature (SG1) Parts | |
| (ISG1)= | |
| (OSG1)= | |
| (PSG1)= | |
| ```c | |
| struct ProgramSignatureHeader { | |
| uint32_t ParamCount; | |
| uint32_t FirstParamOffset; | |
| } | |
| ``` | |
| The program signature parts (ISG1, OSG1, & PSG1) all use the same data | |
| structures to encode inputs, outputs and patch information. The | |
| `ProgramSignatureHeader` includes two 32-bit unsigned integers to specify the | |
| number of signature parameters and the offset of the first parameter. | |
| Beginning at `FirstParamOffset` bytes from the start of the | |
| `ProgramSignatureHeader`, `ParamCount` `ProgramSignatureElement` | |
| structures are written. Following the `ProgramSignatureElements` is a string | |
| table of null terminated strings padded to 32-byte alignment. This string table | |
| matches the DWARF string table format as implemented by LLVM. | |
| Each `ProgramSignatureElement` encodes a `NameOffset` value which specifies | |
| the offset into the string table. A value of `0` denotes no name. The offsets | |
| encoded here are from the beginning of the `ProgramSignatureHeader` not the | |
| beginning of the string table. | |
| The `ProgramSignatureElement` contains several enumeration fields which are | |
| defined in [llvm/include/llvm/BinaryFormat/DXContainerConstants.def](https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/BinaryFormat/DXContainerConstants.def). | |
| These fields encode the D3D system value, the type of data and its precision | |
| requirements. | |
| ### PSV0 Part | |
| (PSV0)= | |
| The Pipeline State Validation data encodes versioned runtime information | |
| structures. These structures use a scheme where in lieu of encoding a version | |
| number, they encode the size of the structure and each new version of the | |
| structure is additive. This allows readers to infer the version of the structure | |
| by comparing the encoded size with the size of known structures. If the encoded | |
| size is larger than any known structure, the largest known structure can validly | |
| parse the data represented in the known structure. | |
| In LLVM we represent the versions of the associated data structures with | |
| versioned namespaces under the `llvm::dxbc::PSV` namespace (e.g. `v0`, | |
| `v1`). Each structure in the `v0` namespace is the base version, the | |
| structures in the `v1` namespace inherit from the `v0` namespace, and the | |
| `v2` structures inherit from the `v1` structures, and so on. | |
| The high-level structure of the PSV data is: | |
| 1. `RuntimeInfo` structure | |
| 2. Resource bindings | |
| 3. Signature elements | |
| 4. Mask Vectors (Output, Input, InputPatch, PatchOutput) | |
| Immediately following the part header for the PSV0 part is a 32-bit unsigned | |
| integer specifying the size of the `RuntimeInfo` structure that follows. | |
| Immediately following the `RuntimeInfo` structure is a 32-bit unsigned integer | |
| specifying the number of resource bindings. If the number of resources is | |
| greater than zero, another unsigned 32-bit integer follows to specify the size | |
| of the `ResourceBindInfo` structure. This is followed by the specified number | |
| of structures of the specified size (which infers the version of the structure). | |
| For version 0 of the data this ends the part data. | |
| #### PSV0 Signature Elements | |
| The signature elements are conceptually a single concept but the data is encoded | |
| in three different blocks. The first block is a string table, the second block | |
| is an index table, and the third block is the elements themselves, which in turn | |
| are separeated by input, output and patch constant or primitive elements. | |
| Signature elements capture much of the same data captured in the {ref}`SG1 | |
| <ISG1>` parts. The use of an index table allows de-duplication of data for a more | |
| compact final representation. | |
| The string table begins with a 32-bit unsigned integer specifying the table | |
| size. This string table uses the DXContainer format as implemented in LLVM. This | |
| format prefixes the string table with a null byte so that offset `0` is a null | |
| string, and pads to 32-byte alignment. | |
| The index table begins with a 32-bit unsigned integer specifying the size of the | |
| table, and is followed by that many 32-bit unsigned integers representing the | |
| table. The index table may or may not deduplicate repeated sequences (both DXC | |
| and Clang do). The indices signify the indices in the flattened aggregate | |
| representation which the signature element describes. A single semantic may have | |
| more than one entry in this table to denote the different attributes of its | |
| members. | |
| For example given the following code: | |
| ```c | |
| struct VSOut_1 | |
| { | |
| float4 f3 : VOUT2; | |
| float3 f4 : VOUT3; | |
| }; | |
| struct VSOut | |
| { | |
| float4 f1 : VOUT0; | |
| float2 f2[4] : VOUT1; | |
| VSOut_1 s; | |
| int4 f5 : VOUT4; | |
| }; | |
| void main(out VSOut o1 : A) { | |
| } | |
| ``` | |
| The semantic `A` gets expanded into 5 output signature elements. Those | |
| elements are: | |
| :::{note} | |
| In the example below, it is a coincidence that the rows match the indices, in | |
| more complicated examples with multiple semantics this is not the case. | |
| ::: | |
| 1. Index 0 starts at row 0, contains 4 columns, and is float32. This represents | |
| `f1` in the source. | |
| 2. Index 1, 2, 3, and 4 starts at row 1, contains two columns and is float32. | |
| This represents `f2` in the source, and it spreads across rows 1 - 4. | |
| 3. Index 5 starts at row 5, contains 4 columns, and is float32. This represents | |
| `f3` in the source. | |
| 4. Index 6 starts at row 6, contains 3 columns, and is float32. This represents | |
| `f4`. | |
| 5. Index 7 starts at row 7, contains 4 columns, and is signed 32-bit integer. | |
| This represents `f5` in the source. | |
| The LLVM `obj2yaml` tool can parse this data out of the PSV and present it in | |
| human-readable YAML. For the example above it produces the output: | |
| ```YAML | |
| SigOutputElements: | |
| - Name: A | |
| Indices: [ 0 ] | |
| StartRow: 0 | |
| Cols: 4 | |
| StartCol: 0 | |
| Allocated: true | |
| Kind: Arbitrary | |
| ComponentType: Float32 | |
| Interpolation: Linear | |
| DynamicMask: 0x0 | |
| Stream: 0 | |
| - Name: A | |
| Indices: [ 1, 2, 3, 4 ] | |
| StartRow: 1 | |
| Cols: 2 | |
| StartCol: 0 | |
| Allocated: true | |
| Kind: Arbitrary | |
| ComponentType: Float32 | |
| Interpolation: Linear | |
| DynamicMask: 0x0 | |
| Stream: 0 | |
| - Name: A | |
| Indices: [ 5 ] | |
| StartRow: 5 | |
| Cols: 4 | |
| StartCol: 0 | |
| Allocated: true | |
| Kind: Arbitrary | |
| ComponentType: Float32 | |
| Interpolation: Linear | |
| DynamicMask: 0x0 | |
| Stream: 0 | |
| - Name: A | |
| Indices: [ 6 ] | |
| StartRow: 6 | |
| Cols: 3 | |
| StartCol: 0 | |
| Allocated: true | |
| Kind: Arbitrary | |
| ComponentType: Float32 | |
| Interpolation: Linear | |
| DynamicMask: 0x0 | |
| Stream: 0 | |
| - Name: A | |
| Indices: [ 7 ] | |
| StartRow: 7 | |
| Cols: 4 | |
| StartCol: 0 | |
| Allocated: true | |
| Kind: Arbitrary | |
| ComponentType: SInt32 | |
| Interpolation: Constant | |
| DynamicMask: 0x0 | |
| Stream: 0 | |
| ``` | |
| The number of signature elements of each type is encoded in the | |
| `llvm::dxbc::PSV::v1::RuntimeInfo` structure. If any of the element count | |
| values are non-zero, the size of the `ProgramSignatureElement` structure is | |
| encoded next to allow versioning of that structure. Today there is only one | |
| version. Following the size field is the specified number of signature elements | |
| in the order input, output, then patch constant or primitive. | |
| Following the signature elements is a sequence of mask vectors encoded as a | |
| series of 32-bit integers. Each 32-bit integer in the mask encodes values for 8 | |
| input/output/patch or primitive elements. The mask vector is filled from least | |
| significant bit to most significant bit with each added element shifting the | |
| previous elements left. A reader needs to consult the total number of vectors | |
| encoded in the `RuntimeInfo` structure to know how to read the mask vector. | |
| If the shader has `UsesViewID` enabled in the `RuntimeInfo` an output mask | |
| vector will be included. The output mask vector is four arrays of 32-bit | |
| unsigned integers. Each of the four arrays corresponds to an output stream. | |
| Geometry shaders have a maximum of four output streams, all other shader stages | |
| only support one output stream. Each bit in the mask vector identifies one | |
| column of an output from the output signature depends on the ViewID. | |
| If the shader has `UsesViewID` enabled, it is a hull shader, and it has patch | |
| constant or primitive vector elements, a patch constant or primitive vector mask | |
| will be included. It is identical in structure to the output mask vector. Each | |
| bit in the mask vector identifies one column of a patch constant output which | |
| depends on the ViewID. | |
| The next series of mask vectors are similar in structure to the output mask | |
| vector, but they contain an extra dimension. | |
| The output/input map is encoded next if the shader has inputs and outputs. The | |
| output/input mask encodes which outputs are impacted by each column of each | |
| input. The size for each mask vector is the size of the output max vector * the | |
| number of inputs * 4 (for each component). Each bit in the mask vector | |
| identifies one column of an output and a column of an input. A value of 1 means | |
| the output is impacted by the input. | |
| If the shader is a hull shader, and it has inputs and patch outputs, an input to | |
| patch map will be included next. This is identical in structure to the | |
| output/input map. The dimensions are defined by the size of the patch constant | |
| or primitive vector mask * the number of inputs * 4 (for each component). Each | |
| bit in the mask vector identifies one column of a patch constant output and a | |
| column of an input. A value of 1 means the output is impacted by the input. | |
| If the shader is a domain shader, and it has outputs and patch outputs, an | |
| output patch map will be included next. This is identical in structure to the | |
| output/input map. The dimensions are defined by the size of the patch constant | |
| or primitive vector mask * the number of outputs * 4 (for each component). Each | |
| bit in the mask vector identifies one column of a patch constant input and a | |
| column of an output. A value of 1 means the output is impacted by the primitive | |
| input. | |
| ### Root Signature (RTS0) Part | |
| (RTS0)= | |
| The Root Signature data defines the shader's resource interface with Direct3D | |
| 12, specifying what resources the shader needs to access and how they're | |
| organized and bound to the pipeline. | |
| The RTS0 part comprises three data structures: `RootSignatureHeader`, | |
| `RootParameters` and `StaticSamplers`. The details of each will be described | |
| in the following sections. All `RootParameters` will be serialized following | |
| the order they were defined in the metadata representation. | |
| The table below summarizes the data being serialized as well as it's size. The | |
| details of it part will be discussed in further details on the next sections | |
| of this document. | |
| :::{list-table} | |
| :header-rows: 1 | |
| * - Part Name | |
| - Size In Bytes | |
| - Maximum number of Instances | |
| * - Root Signature Header | |
| - 24 | |
| - 1 | |
| * - Root Parameter Headers | |
| - 12 | |
| - Many | |
| * - Root Parameter | |
| - | Root Parameter Type | Size | | |
| |--------------------------------|------| | |
| | Root Constants | 12 | | |
| | Root Descriptor Version 1.0 | 8 | | |
| | Root Descriptor Version 1.1 | 12 | | |
| | Descriptors Tables Version 1.0 | 20 | | |
| | Descriptors Tables Version 1.1 | 24 | | |
| - Many | |
| * - Static Samplers | |
| - 52 | |
| - Many | |
| ::: | |
| #### Root Signature Header | |
| The root signature header is 24 bytes long, consisting of six 32-bit values | |
| representing the version, number and offset of parameters, number and offset | |
| of static samplers, and a flags field for global behaviours: | |
| ```c | |
| struct RootSignatureHeader { | |
| uint32_t Version; | |
| uint32_t NumParameters; | |
| uint32_t ParametersOffset; | |
| uint32_t NumStaticSamplers; | |
| uint32_t StaticSamplerOffset; | |
| uint32_t Flags; | |
| } | |
| ``` | |
| #### Root Parameters | |
| Root parameters define how resources are bound to the shader pipeline, each | |
| type having different size and fields. | |
| The slot of root parameters is preceded by a variable size section containing | |
| the header information for such parameters. Such structure is 12 bytes long, | |
| composed of three 32-bit values, representing the parameter type, a flag | |
| encoding the pipeline stages where the data is visible, and an offset | |
| calculated from the start of RTS0 section. | |
| ```c | |
| struct RootParameterHeader { | |
| uint32_t ParameterType; | |
| uint32_t ShaderVisibility; | |
| uint32_t ParameterOffset; | |
| }; | |
| ``` | |
| After the header information has been serialized, the actual data for each of the | |
| root parameters is layout in a single continuous blob. The parameters can be fetch | |
| from such using the offset information, present in the header. | |
| The following sections will describe each of the root parameters types and their | |
| encodings. | |
| ##### Root Constants | |
| The root constants are inline 32-bit values that show up in the shader | |
| as a constant buffer. It is a 12 bytes long structure, two 32-bit values | |
| encoding the register and space the constant is assigned to, and | |
| the last 32 bits encode the number of constants being defined in the buffer. | |
| ```c | |
| struct RootConstants { | |
| uint32_t Register; | |
| uint32_t Space; | |
| uint32_t NumOfConstants; | |
| }; | |
| ``` | |
| ##### Root Descriptor | |
| Root descriptors provide direct GPU memory addresses to resources. | |
| In version 1.0, the root descriptor is 8 bytes. It encodes the register and | |
| space as 2 32-bit values. | |
| In version 1.1, the root descriptor is 12 bytes. It matches the 1.0 descriptor | |
| but adds a 32-bit access flag. | |
| ```c | |
| struct RootDescriptor_V1_0 { | |
| uint32_t ShaderRegister; | |
| uint32_t RegisterSpace; | |
| }; | |
| struct RootDescriptor_V1_1 { | |
| uint32_t ShaderRegister; | |
| uint32_t RegisterSpace; | |
| uint32_t Flags; | |
| }; | |
| ``` | |
| ##### Root Descriptor Table | |
| Descriptor tables let shaders access multiple resources through a single pointer | |
| to a descriptor heap. | |
| The tables are made of a collection of descriptor ranges. In Version 1.0, the | |
| descriptor range is 20 bytes, containing five 32-bit values. It encodes a range | |
| of registers, including the register type, range length, register numbers and | |
| space within range and the offset locating each range inside the table. | |
| In version 1.1, the descriptor range is 24 bytes. It matches the 1.0 descriptor | |
| but adds a 32-bit access flag. | |
| ```c | |
| struct DescriptorRange_V1_0 { | |
| dxil::ResourceClass RangeType; | |
| uint32_t NumDescriptors; | |
| uint32_t BaseShaderRegister; | |
| uint32_t RegisterSpace; | |
| uint32_t OffsetInDescriptorsFromTableStart; | |
| }; | |
| struct DescriptorRange_V1_1 { | |
| dxil::ResourceClass RangeType; | |
| uint32_t NumDescriptors; | |
| uint32_t BaseShaderRegister; | |
| uint32_t RegisterSpace; | |
| uint32_t Flags; | |
| uint32_t OffsetInDescriptorsFromTableStart; | |
| }; | |
| ``` | |
| #### Static Samplers | |
| Static samplers are predefined filtering settings built into the root signature, | |
| avoiding descriptor heap lookups. | |
| This section also has a variable size, since it can contain multiple static | |
| samplers definitions. However, the definition is a fixed sized struct, | |
| containing 13 32-byte fields of various enum, float, and integer values. | |
| In version 1.2, the static sampler is 17 bytes. It matches the 1.0 static sampler | |
| but adds a 32-bit access flag. In Version 1.1, it matches static sampler | |
| version 1.0. | |
| ```c | |
| struct StaticSamplerDesc { | |
| dxbc::FilterMode Filter; | |
| dxbc::TextureAddressMode AddressU; | |
| dxbc::TextureAddressMode AddressV; | |
| dxbc::TextureAddressMode AddressW; | |
| float MipLODBias; | |
| uint32_t MaxAnisotropy; | |
| dxbc::ComparisonFunc ComparisonFunc; | |
| dxbc::StaticBorderColor BorderColor; | |
| float MinLOD; | |
| float MaxLOD; | |
| uint32_t ShaderRegister; | |
| uint32_t RegisterSpace; | |
| dxbc::ShaderVisibility ShaderVisibility; | |
| }; | |
| ``` | |
| ### SFI0 Part | |
| (SFI0)= | |
| The SFI0 part encodes a 64-bit unsigned integer bitmask of the feature flags. | |
| This denotes which optional features the shader requires. The flag values are | |
| defined in [llvm/include/llvm/BinaryFormat/DXContainerConstants.def](https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/BinaryFormat/DXContainerConstants.def). | |
| ## Compiler Flags | |
| (compiler_flags)= | |
| When compiling HLSL with {program}`dxc`, several flags control whether | |
| debug information is embedded in the main DXContainer output, written to a | |
| companion PDB file, or both. Use `/Zi` for full debug output or `/Zs` for | |
| slim debug output without an {ref}`ILDB <ILDB>` part. In {program}`clang-dxc`, most | |
| dxc-style flags are forwarded to {program}`llc` as `-mllvm` options. | |
| ### Debug Output Locations | |
| Debug information is enabled with either `/Zi` (full debug) or `/Zs` (slim | |
| debug). The two flags are mutually exclusive. | |
| **Full debug with `/Zi`** | |
| When `/Zi` is enabled, the {ref}`ILDB <ILDB>` part can appear in the main DXContainer | |
| output, in a companion PDB, or both: | |
| - **Embedded in the main DXContainer output.** The {ref}`ILDB <ILDB>` part holds the | |
| unstripped DXIL module with debug information. It is included when | |
| `/Qembed_debug` is used. The main output always contains the stripped {ref}`DXIL <DXIL>` | |
| part alongside other parts such as {ref}`HASH <HASH>`, {ref}`ILDN <ILDN>`, and {ref}`VERS <VERS>`. | |
| - **Omitted from the main DXContainer output.** When `/Qstrip_debug` is used, | |
| the {ref}`ILDB <ILDB>` part is not written to the main output. Other debug-related parts | |
| such as {ref}`ILDN <ILDN>` are still emitted. If `/Fd` is also specified, the {ref}`ILDB <ILDB>` | |
| part is still written to the companion PDB. `/Qstrip_debug` takes precedence | |
| over the default `/Qembed_debug` behavior when `/Zi` is used without | |
| `/Fd`. If both `/Qstrip_debug` and `/Qembed_debug` are specified, | |
| `/Qstrip_debug` is ignored and the {ref}`ILDB <ILDB>` part is embedded. | |
| - **In a companion PDB file.** A sidecar `.pdb` stores a DXContainer stream | |
| with debug-related parts including {ref}`ILDB <ILDB>`, {ref}`SRCI <SRCI>`, and {ref}`VERS <VERS>`. This is | |
| produced when `/Fd` names an output path. Use {program}`llvm-pdbutil` to | |
| inspect or extract that stream (see | |
| {doc}`llvm-pdbutil <../CommandGuide/llvm-pdbutil>`). | |
| - **Embedded in the private data of the main output.** When | |
| `/Qpdb_in_private` is used, a copy of the companion PDB file is stored as | |
| opaque bytes in {ref}`PRIV <PRIV>`. This can be used with or without `/Fd`; without | |
| `/Fd`, the PDB is not retained as a separate file on disk. After extraction, | |
| tools treat the bytes as a standalone `.pdb` file. | |
| `/Fd` can be combined with `/Qembed_debug` or `/Qpdb_in_private` to | |
| write full debug information to more than one location. | |
| **Slim debug with `/Zs`** | |
| When `/Zs` is enabled, slim debug information is emitted. The {ref}`ILDB <ILDB>` part is | |
| omitted from the main DXContainer output and from any companion PDB or {ref}`PRIV <PRIV>` | |
| embedding, but other debug-related parts such as {ref}`HASH <HASH>`, {ref}`ILDN <ILDN>`, {ref}`SRCI <SRCI>`, and | |
| {ref}`VERS <VERS>` are still emitted. A companion PDB from `/Fd` or a {ref}`PRIV <PRIV>` embedding | |
| from `/Qpdb_in_private` therefore contains slim debug data only. | |
| `/Zs` cannot be combined with `/Qembed_debug` or `/Qsource_in_debug_module`. | |
| The table below summarizes the {program}`dxc` flags that affect this behavior. | |
| The **llc flag** column lists the `-mllvm` option the driver forwards when | |
| invoking the backend. | |
| :::{list-table} | |
| :header-rows: 1 | |
| :widths: 20 20 20 40 | |
| * - dxc flag | |
| - clang-dxc alternative | |
| - llc flag | |
| - Effect | |
| * - `/Zi` | |
| - `/Zi`, `-g` | |
| - | |
| - Enable full debug information. Mutually exclusive with `/Zs`. Required | |
| for `/Qembed_debug` and `/Qstrip_debug`. The main {ref}`DXIL <DXIL>` part is | |
| stripped of debug metadata. If `/Zi` is used without `/Fd`, | |
| `/Qembed_debug`, and `/Qstrip_debug`, the driver warns and enables | |
| `/Qembed_debug` by default. | |
| * - `/Zs` | |
| - Not implemented yet | |
| - `--dx-slim-debug` | |
| - Enable slim debug information. Mutually exclusive with `/Zi`. Omits | |
| the {ref}`ILDB <ILDB>` part from all outputs while still emitting parts such as | |
| {ref}`ILDN <ILDN>`, {ref}`SRCI <SRCI>`, and {ref}`VERS <VERS>`. Incompatible with | |
| `/Qembed_debug` and `/Qsource_in_debug_module`. | |
| * - `/Fd` *path* | |
| - Not implemented yet | |
| - `--dx-Fd=` *path* | |
| - Write a companion PDB file. Requires `/Zi` or `/Zs`. The path is | |
| recorded in the {ref}`ILDN <ILDN>` part. If *path* ends with a directory separator, | |
| the file name defaults to `<MD5 hash>.pdb` from the {ref}`HASH <HASH>` part in that | |
| directory; otherwise *path* is used as the PDB file name. | |
| * - `/Qembed_debug` | |
| - Not implemented yet | |
| - `--dx-embed-debug` | |
| - Embed the {ref}`ILDB <ILDB>` part and other debug parts in the main DXContainer | |
| output. Requires `/Zi`. Takes precedence over `/Qstrip_debug` when | |
| both are specified. | |
| * - `/Qstrip_debug` | |
| - `/Qstrip_debug` | |
| - `--dx-strip-debug` | |
| - Omit the {ref}`ILDB <ILDB>` part from the main DXContainer output. Requires `/Zi`. | |
| The {ref}`ILDB <ILDB>` part is still written to a companion PDB | |
| when `/Fd` is specified. Prevents the default `/Qembed_debug` behavior | |
| when `/Zi` is used without `/Fd`. Otherwise, ignored when | |
| `/Qembed_debug` is also specified. | |
| * - `/Qpdb_in_private` | |
| - `/Qpdb_in_private` | |
| - `--dx-pdb-in-private` | |
| - Embed a copy of the companion PDB in the {ref}`PRIV <PRIV>` part of the main | |
| DXContainer output. Requires `/Zi` or `/Zs`. When `/Fd` is also | |
| specified, the PDB is written to that path as well. Without `/Fd`, the | |
| PDB is built in a temporary file, copied into {ref}`PRIV <PRIV>`, and not retained | |
| on disk. With `/Zs`, the embedded PDB contains slim debug data without | |
| an {ref}`ILDB <ILDB>` part. | |
| * - `/Zss` | |
| - `/Zss` | |
| - `--dx-Zss` | |
| - Compute the {ref}`HASH <HASH>` digest from the {ref}`ILDB <ILDB>` bitcode and set the | |
| `IncludesSource` hash flag. Requires `/Zi` or `/Zs`. | |
| * - `/Zsb` | |
| - `/Zsb` | |
| - | |
| - Default behavior. Compute the {ref}`HASH <HASH>` digest from the stripped {ref}`DXIL <DXIL>` | |
| bitcode. | |
| * - `/Qsource_in_debug_module` | |
| - `/Qsource_in_debug_module` | |
| - `--dx-source-in-debug-module` | |
| - Embed HLSL source in the {ref}`ILDB <ILDB>` module via `dx.source` metadata | |
| instead of emitting a separate {ref}`SRCI <SRCI>` part. | |
| * - | |
| - `-fdx-no-source-metadata` | |
| - | |
| - Do not embed `dx.source` metadata in the LLVM module, which prevents | |
| {ref}`SRCI <SRCI>` generation. | |
| ::: | |
| ### Part Placement | |
| The table below shows where each debug-related part is written for a typical | |
| shader compile. `Yes` means the part is present in that output whenever its | |
| preconditions are met. | |
| :::{list-table} | |
| :header-rows: 1 | |
| :widths: 12 28 28 32 | |
| * - Part | |
| - Main output | |
| - Companion PDB (as a separate file or embedded into private data) | |
| - Preconditions / notes | |
| * - {ref}`DXIL <DXIL>` | |
| - Yes | |
| - No | |
| - | |
| * - {ref}`ILDB <ILDB>` | |
| - If `/Qembed_debug` (default when `/Zi` is used without `/Fd` and | |
| `/Qstrip_debug`) | |
| - Yes | |
| - Omitted when `/Zs` is used. Omitted from the main output when | |
| `/Qstrip_debug` is used, or when `/Fd` is used without | |
| `/Qembed_debug`. | |
| * - {ref}`ILDN <ILDN>` | |
| - Yes | |
| - Yes | |
| - | |
| * - {ref}`HASH <HASH>` | |
| - Yes | |
| - Yes | |
| - | |
| * - {ref}`SRCI <SRCI>` | |
| - No | |
| - Yes | |
| - Requires available source metadata. Not emitted when | |
| `/Qsource_in_debug_module` or `-fdx-no-source-metadata` is used. | |
| * - {ref}`VERS <VERS>` | |
| - Yes | |
| - Yes | |
| - | |
| * - {ref}`PRIV <PRIV>` | |
| - If `/Qpdb_in_private` | |
| - No | |
| - Holds a copy of the companion PDB file. | |
| ::: |