DirectX Container#

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

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#

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 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 *.

  1. DXIL† - Stores the DXIL bytecode.

  2. HASH† - Stores the shader MD5 hash.

  3. ILDB† - Stores the DXIL bytecode with LLVM Debug Information embedded in the module.

  4. ILDN† - Stores shader debug name for external debug information.

  5. ISG1 - Stores the input signature for Shader Model 5.1+.

  6. ISGN* - Stores the input signature for Shader Model 4 and earlier.

  7. OSG1 - Stores the output signature for Shader Model 5.1+.

  8. OSG5* - Stores the output signature for Shader Model 5.

  9. 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. PRIV† - Stores private data, including embedded companion PDB files.

  13. PSG1 - Stores the patch constant signature for Shader Model 6+.

  14. PSV0 - Stores Pipeline State Validation data.

  15. RDAT† - Stores Runtime Data.

  16. RDEF* - Stores resource definitions.

  17. RTS0 - Stores compiled root signature.

  18. SFI0 - Stores shader feature flags.

  19. SHDR* - Stores compiled DXBC bytecode.

  20. SHEX* - Stores compiled DXBC bytecode.

  21. DXBC* - Stores compiled DXBC bytecode.

  22. SRCI† - Stores shader source information.

  23. STAT† - Stores shader statistics.

  24. VERS† - Stores shader compiler version information.

DXIL Part#

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#

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 Compiler Flags for how /Zss and /Zsb select the hashed bitcode.

ILDB Part#

The ILDB part follows the structure of the 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 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 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.

Reading this part

When the ILDB part is present in a DXContainer file, obj2yaml prints it under a Program mapping with the embedded DXIL bitcode. Use llvm-objcopy to extract the raw bitcode, then 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 llvm-pdbutil to access it (see llvm-pdbutil).

ILDN Part#

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:

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 HASH part. See Compiler Flags for how /Fd, /Zss, and /Zsb affect the debug file name and hash computation.

Reading this part

When the ILDN part is present in a DXContainer file, obj2yaml prints it under a DebugName mapping.

PRIV Part#

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.

Reading this part

When the PRIV part is present in a DXContainer file, obj2yaml prints it under a PrivateData mapping.

Use llvm-objcopy to extract the raw part data:

llvm-objcopy --dump-section=PRIV=output.priv shader.dxbc

SRCI Part#

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

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:

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:

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:

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:

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:

struct ArgsHeader {
  uint32_t Flags;
  uint32_t SizeInBytes;
  uint32_t Count