| # 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. |
| ::: |