aboutsummaryrefslogtreecommitdiff
path: root/llvm/docs/DirectX/DXContainer.rst
blob: 4ace8a13dd89f662ac04197d37e2e3daf24cecb9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
=================
DirectX Container
=================

.. contents::
   :local:

.. toctree::
   :hidden:

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

.. code-block:: 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
---------

.. code-block:: 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.

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

#. `DXIL`_† - Stores the DXIL bytecode.
#. `HASH`_† - Stores the shader MD5 hash.
#. ILDB† - Stores the DXIL bytecode with LLVM Debug Information embedded in the module.
#. ILDN† - Stores shader debug name for external debug information.
#. `ISG1`_ - Stores the input signature for Shader Model 5.1+.
#. ISGN\* - Stores the input signature for Shader Model 4 and earlier.
#. `OSG1`_ - Stores the output signature for Shader Model 5.1+.
#. OSG5\* - Stores the output signature for Shader Model 5.
#. OSGN\* - Stores the output signature for Shader Model 4 and earlier.
#. PCSG\* - Stores the patch constant signature for Shader Model 5.1 and earlier.
#. PDBI† - Stores PDB information.
#. PRIV - Stores arbitrary private data (Not encoded by either FXC or DXC).
#. `PSG1`_ - Stores the patch constant signature for Shader Model 6+.
#. `PSV0`_ - Stores Pipeline State Validation data.
#. RDAT† - Stores Runtime Data.
#. RDEF\* - Stores resource definitions.
#. `RTS0`_ - Stores compiled root signature.
#. `SFI0`_ - Stores shader feature flags.
#. SHDR\* - Stores compiled DXBC bytecode.
#. SHEX\* - Stores compiled DXBC bytecode.
#. DXBC\* - Stores compiled DXBC bytecode.
#. SRCI† - Stores shader source information.
#. STAT† - Stores shader statistics.
#. 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.

Program Signature (SG1) Parts
-----------------------------
.. _ISG1:
.. _OSG1:
.. _PSG1:

.. code-block:: 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:

#. ``RuntimeInfo`` structure
#. Resource bindings
#. Signature elements
#. 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:

.. code-block:: 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.

#. Index 0 starts at row 0, contains 4 columns, and is float32. This represents
   ``f1`` in the source.
#. 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.
#. Index 5 starts at row 5, contains 4 columns, and is float32. This represents
   ``f3`` in the source.
#. Index 6 starts at row 6, contains 3 columns, and is float32. This represents
   ``f4``.
#. 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:

.. code-block:: 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.

======================== =========================================== =============================
Part Name                Size In Bytes                                 Maximum number of Instances 
======================== =========================================== =============================
Root Signature Header    24                                          1               
Root Parameter Headers   12                                          Many              
Root Parameter           ================================ ===        Many
                         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                                      
                         ================================ ===       
                                             
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:

.. code-block:: 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.

.. code-block:: 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.

.. code-block:: 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.

.. code-block:: 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.

.. code-block:: c

   struct DescriptorRange_V1_0 {
      uint32_t RangeType;
      uint32_t NumDescriptors;
      uint32_t BaseShaderRegister;
      uint32_t RegisterSpace;
      uint32_t OffsetInDescriptorsFromTableStart;
   };

   struct DescriptorRange_V1_1 {
      dxbc::DescriptorRangeType RangeType;
      uint32_t NumDescriptors;
      uint32_t BaseShaderRegister;
      uint32_t RegisterSpace;
      uint32_t OffsetInDescriptorsFromTableStart;      
      uint32_t Flags;
   };

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. 

.. code-block:: c

   struct StaticSamplerDesc {
      FilterMode Filter; 
      TextureAddressMode AddressU;
      TextureAddressMode AddressV;
      TextureAddressMode AddressW;
      float MipLODBias;
      uint32_t MaxAnisotropy;
      ComparisonFunc ComparisonFunc; 
      StaticBorderColor BorderColor;
      float MinLOD;
      float MaxLOD;
      uint32_t ShaderRegister;
      uint32_t RegisterSpace;
      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>`_.