1 //===-- llvm/BinaryFormat/DXContainer.h - The DXBC file format --*- C++/-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines manifest constants for the DXContainer object file format.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_BINARYFORMAT_DXCONTAINER_H
14 #define LLVM_BINARYFORMAT_DXCONTAINER_H
15
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/SwapByteOrder.h"
18 #include "llvm/TargetParser/Triple.h"
19
20 #include <stdint.h>
21
22 namespace llvm {
23 template <typename T> struct EnumEntry;
24
25 // The DXContainer file format is arranged as a header and "parts". Semantically
26 // parts are similar to sections in other object file formats. The File format
27 // structure is roughly:
28
29 // ┌────────────────────────────────┐
30 // │ Header │
31 // ├────────────────────────────────┤
32 // │ Part │
33 // ├────────────────────────────────┤
34 // │ Part │
35 // ├────────────────────────────────┤
36 // │ ... │
37 // └────────────────────────────────┘
38
39 namespace dxbc {
40
getShaderStage(uint32_t Kind)41 inline Triple::EnvironmentType getShaderStage(uint32_t Kind) {
42 assert(Kind <= Triple::Amplification - Triple::Pixel &&
43 "Shader kind out of expected range.");
44 return static_cast<Triple::EnvironmentType>(Triple::Pixel + Kind);
45 }
46
47 struct Hash {
48 uint8_t Digest[16];
49 };
50
51 enum class HashFlags : uint32_t {
52 None = 0, // No flags defined.
53 IncludesSource = 1, // This flag indicates that the shader hash was computed
54 // taking into account source information (-Zss)
55 };
56
57 struct ShaderHash {
58 uint32_t Flags; // dxbc::HashFlags
59 uint8_t Digest[16];
60
61 bool isPopulated();
62
swapBytesShaderHash63 void swapBytes() { sys::swapByteOrder(Flags); }
64 };
65
66 struct ContainerVersion {
67 uint16_t Major;
68 uint16_t Minor;
69
swapBytesContainerVersion70 void swapBytes() {
71 sys::swapByteOrder(Major);
72 sys::swapByteOrder(Minor);
73 }
74 };
75
76 struct Header {
77 uint8_t Magic[4]; // "DXBC"
78 Hash FileHash;
79 ContainerVersion Version;
80 uint32_t FileSize;
81 uint32_t PartCount;
82
swapBytesHeader83 void swapBytes() {
84 Version.swapBytes();
85 sys::swapByteOrder(FileSize);
86 sys::swapByteOrder(PartCount);
87 }
88 // Structure is followed by part offsets: uint32_t PartOffset[PartCount];
89 // The offset is to a PartHeader, which is followed by the Part Data.
90 };
91
92 /// Use this type to describe the size and type of a DXIL container part.
93 struct PartHeader {
94 uint8_t Name[4];
95 uint32_t Size;
96
swapBytesPartHeader97 void swapBytes() { sys::swapByteOrder(Size); }
getNamePartHeader98 StringRef getName() const {
99 return StringRef(reinterpret_cast<const char *>(&Name[0]), 4);
100 }
101 // Structure is followed directly by part data: uint8_t PartData[PartSize].
102 };
103
104 struct BitcodeHeader {
105 uint8_t Magic[4]; // ACSII "DXIL".
106 uint8_t MinorVersion; // DXIL version.
107 uint8_t MajorVersion; // DXIL version.
108 uint16_t Unused;
109 uint32_t Offset; // Offset to LLVM bitcode (from start of header).
110 uint32_t Size; // Size of LLVM bitcode (in bytes).
111 // Followed by uint8_t[BitcodeHeader.Size] at &BitcodeHeader + Header.Offset
112
swapBytesBitcodeHeader113 void swapBytes() {
114 sys::swapByteOrder(MinorVersion);
115 sys::swapByteOrder(MajorVersion);
116 sys::swapByteOrder(Offset);
117 sys::swapByteOrder(Size);
118 }
119 };
120
121 struct ProgramHeader {
122 uint8_t Version;
123 uint8_t Unused;
124 uint16_t ShaderKind;
125 uint32_t Size; // Size in uint32_t words including this header.
126 BitcodeHeader Bitcode;
127
swapBytesProgramHeader128 void swapBytes() {
129 sys::swapByteOrder(ShaderKind);
130 sys::swapByteOrder(Size);
131 Bitcode.swapBytes();
132 }
getMajorVersionProgramHeader133 uint8_t getMajorVersion() { return Version >> 4; }
getMinorVersionProgramHeader134 uint8_t getMinorVersion() { return Version & 0xF; }
getVersionProgramHeader135 static uint8_t getVersion(uint8_t Major, uint8_t Minor) {
136 return (Major << 4) | Minor;
137 }
138 };
139
140 static_assert(sizeof(ProgramHeader) == 24, "ProgramHeader Size incorrect!");
141
142 #define CONTAINER_PART(Part) Part,
143 enum class PartType {
144 Unknown = 0,
145 #include "DXContainerConstants.def"
146 };
147
148 #define SHADER_FEATURE_FLAG(Num, DxilModuleNum, Val, Str) Val = 1ull << Num,
149 enum class FeatureFlags : uint64_t {
150 #include "DXContainerConstants.def"
151 };
152 static_assert((uint64_t)FeatureFlags::NextUnusedBit <= 1ull << 63,
153 "Shader flag bits exceed enum size.");
154
155 PartType parsePartType(StringRef S);
156
157 struct VertexPSVInfo {
158 uint8_t OutputPositionPresent;
159 uint8_t Unused[3];
160
swapBytesVertexPSVInfo161 void swapBytes() {
162 // nothing to swap
163 }
164 };
165
166 struct HullPSVInfo {
167 uint32_t InputControlPointCount;
168 uint32_t OutputControlPointCount;
169 uint32_t TessellatorDomain;
170 uint32_t TessellatorOutputPrimitive;
171
swapBytesHullPSVInfo172 void swapBytes() {
173 sys::swapByteOrder(InputControlPointCount);
174 sys::swapByteOrder(OutputControlPointCount);
175 sys::swapByteOrder(TessellatorDomain);
176 sys::swapByteOrder(TessellatorOutputPrimitive);
177 }
178 };
179
180 struct DomainPSVInfo {
181 uint32_t InputControlPointCount;
182 uint8_t OutputPositionPresent;
183 uint8_t Unused[3];
184 uint32_t TessellatorDomain;
185
swapBytesDomainPSVInfo186 void swapBytes() {
187 sys::swapByteOrder(InputControlPointCount);
188 sys::swapByteOrder(TessellatorDomain);
189 }
190 };
191
192 struct GeometryPSVInfo {
193 uint32_t InputPrimitive;
194 uint32_t OutputTopology;
195 uint32_t OutputStreamMask;
196 uint8_t OutputPositionPresent;
197 uint8_t Unused[3];
198
swapBytesGeometryPSVInfo199 void swapBytes() {
200 sys::swapByteOrder(InputPrimitive);
201 sys::swapByteOrder(OutputTopology);
202 sys::swapByteOrder(OutputStreamMask);
203 }
204 };
205
206 struct PixelPSVInfo {
207 uint8_t DepthOutput;
208 uint8_t SampleFrequency;
209 uint8_t Unused[2];
210
swapBytesPixelPSVInfo211 void swapBytes() {
212 // nothing to swap
213 }
214 };
215
216 struct MeshPSVInfo {
217 uint32_t GroupSharedBytesUsed;
218 uint32_t GroupSharedBytesDependentOnViewID;
219 uint32_t PayloadSizeInBytes;
220 uint16_t MaxOutputVertices;
221 uint16_t MaxOutputPrimitives;
222
swapBytesMeshPSVInfo223 void swapBytes() {
224 sys::swapByteOrder(GroupSharedBytesUsed);
225 sys::swapByteOrder(GroupSharedBytesDependentOnViewID);
226 sys::swapByteOrder(PayloadSizeInBytes);
227 sys::swapByteOrder(MaxOutputVertices);
228 sys::swapByteOrder(MaxOutputPrimitives);
229 }
230 };
231
232 struct AmplificationPSVInfo {
233 uint32_t PayloadSizeInBytes;
234
swapBytesAmplificationPSVInfo235 void swapBytes() { sys::swapByteOrder(PayloadSizeInBytes); }
236 };
237
238 union PipelinePSVInfo {
239 VertexPSVInfo VS;
240 HullPSVInfo HS;
241 DomainPSVInfo DS;
242 GeometryPSVInfo GS;
243 PixelPSVInfo PS;
244 MeshPSVInfo MS;
245 AmplificationPSVInfo AS;
246
swapBytes(Triple::EnvironmentType Stage)247 void swapBytes(Triple::EnvironmentType Stage) {
248 switch (Stage) {
249 case Triple::EnvironmentType::Pixel:
250 PS.swapBytes();
251 break;
252 case Triple::EnvironmentType::Vertex:
253 VS.swapBytes();
254 break;
255 case Triple::EnvironmentType::Geometry:
256 GS.swapBytes();
257 break;
258 case Triple::EnvironmentType::Hull:
259 HS.swapBytes();
260 break;
261 case Triple::EnvironmentType::Domain:
262 DS.swapBytes();
263 break;
264 case Triple::EnvironmentType::Mesh:
265 MS.swapBytes();
266 break;
267 case Triple::EnvironmentType::Amplification:
268 AS.swapBytes();
269 break;
270 default:
271 break;
272 }
273 }
274 };
275
276 static_assert(sizeof(PipelinePSVInfo) == 4 * sizeof(uint32_t),
277 "Pipeline-specific PSV info must fit in 16 bytes.");
278
279 namespace PSV {
280
281 #define SEMANTIC_KIND(Val, Enum) Enum = Val,
282 enum class SemanticKind : uint8_t {
283 #include "DXContainerConstants.def"
284 };
285
286 ArrayRef<EnumEntry<SemanticKind>> getSemanticKinds();
287
288 #define COMPONENT_TYPE(Val, Enum) Enum = Val,
289 enum class ComponentType : uint8_t {
290 #include "DXContainerConstants.def"
291 };
292
293 ArrayRef<EnumEntry<ComponentType>> getComponentTypes();
294
295 #define INTERPOLATION_MODE(Val, Enum) Enum = Val,
296 enum class InterpolationMode : uint8_t {
297 #include "DXContainerConstants.def"
298 };
299
300 ArrayRef<EnumEntry<InterpolationMode>> getInterpolationModes();
301
302 namespace v0 {
303 struct RuntimeInfo {
304 PipelinePSVInfo StageInfo;
305 uint32_t MinimumWaveLaneCount; // minimum lane count required, 0 if unused
306 uint32_t MaximumWaveLaneCount; // maximum lane count required,
307 // 0xffffffff if unused
swapBytesRuntimeInfo308 void swapBytes() {
309 // Skip the union because we don't know which field it has
310 sys::swapByteOrder(MinimumWaveLaneCount);
311 sys::swapByteOrder(MaximumWaveLaneCount);
312 }
313
swapBytesRuntimeInfo314 void swapBytes(Triple::EnvironmentType Stage) { StageInfo.swapBytes(Stage); }
315 };
316
317 struct ResourceBindInfo {
318 uint32_t Type;
319 uint32_t Space;
320 uint32_t LowerBound;
321 uint32_t UpperBound;
322
swapBytesResourceBindInfo323 void swapBytes() {
324 sys::swapByteOrder(Type);
325 sys::swapByteOrder(Space);
326 sys::swapByteOrder(LowerBound);
327 sys::swapByteOrder(UpperBound);
328 }
329 };
330
331 struct SignatureElement {
332 uint32_t NameOffset;
333 uint32_t IndicesOffset;
334
335 uint8_t Rows;
336 uint8_t StartRow;
337 uint8_t Cols : 4;
338 uint8_t StartCol : 2;
339 uint8_t Allocated : 1;
340 uint8_t Unused : 1;
341 SemanticKind Kind;
342
343 ComponentType Type;
344 InterpolationMode Mode;
345 uint8_t DynamicMask : 4;
346 uint8_t Stream : 2;
347 uint8_t Unused2 : 2;
348 uint8_t Reserved;
349
swapBytesSignatureElement350 void swapBytes() {
351 sys::swapByteOrder(NameOffset);
352 sys::swapByteOrder(IndicesOffset);
353 }
354 };
355
356 static_assert(sizeof(SignatureElement) == 4 * sizeof(uint32_t),
357 "PSV Signature elements must fit in 16 bytes.");
358
359 } // namespace v0
360
361 namespace v1 {
362
363 struct MeshRuntimeInfo {
364 uint8_t SigPrimVectors; // Primitive output for MS
365 uint8_t MeshOutputTopology;
366 };
367
368 union GeometryExtraInfo {
369 uint16_t MaxVertexCount; // MaxVertexCount for GS only (max 1024)
370 uint8_t SigPatchConstOrPrimVectors; // Output for HS; Input for DS;
371 // Primitive output for MS (overlaps
372 // MeshInfo::SigPrimVectors)
373 MeshRuntimeInfo MeshInfo;
374 };
375 struct RuntimeInfo : public v0::RuntimeInfo {
376 uint8_t ShaderStage; // PSVShaderKind
377 uint8_t UsesViewID;
378 GeometryExtraInfo GeomData;
379
380 // PSVSignatureElement counts
381 uint8_t SigInputElements;
382 uint8_t SigOutputElements;
383 uint8_t SigPatchOrPrimElements;
384
385 // Number of packed vectors per signature
386 uint8_t SigInputVectors;
387 uint8_t SigOutputVectors[4];
388
swapBytesRuntimeInfo389 void swapBytes() {
390 // nothing to swap since everything is single-byte or a union field
391 }
392
swapBytesRuntimeInfo393 void swapBytes(Triple::EnvironmentType Stage) {
394 v0::RuntimeInfo::swapBytes(Stage);
395 if (Stage == Triple::EnvironmentType::Geometry)
396 sys::swapByteOrder(GeomData.MaxVertexCount);
397 }
398 };
399
400 } // namespace v1
401
402 namespace v2 {
403 struct RuntimeInfo : public v1::RuntimeInfo {
404 uint32_t NumThreadsX;
405 uint32_t NumThreadsY;
406 uint32_t NumThreadsZ;
407
swapBytesRuntimeInfo408 void swapBytes() {
409 sys::swapByteOrder(NumThreadsX);
410 sys::swapByteOrder(NumThreadsY);
411 sys::swapByteOrder(NumThreadsZ);
412 }
413
swapBytesRuntimeInfo414 void swapBytes(Triple::EnvironmentType Stage) {
415 v1::RuntimeInfo::swapBytes(Stage);
416 }
417 };
418
419 struct ResourceBindInfo : public v0::ResourceBindInfo {
420 uint32_t Kind;
421 uint32_t Flags;
422
swapBytesResourceBindInfo423 void swapBytes() {
424 v0::ResourceBindInfo::swapBytes();
425 sys::swapByteOrder(Kind);
426 sys::swapByteOrder(Flags);
427 }
428 };
429
430 } // namespace v2
431
432 namespace v3 {
433 struct RuntimeInfo : public v2::RuntimeInfo {
434 uint32_t EntryNameOffset;
435
swapBytesRuntimeInfo436 void swapBytes() {
437 v2::RuntimeInfo::swapBytes();
438 sys::swapByteOrder(EntryNameOffset);
439 }
440
swapBytesRuntimeInfo441 void swapBytes(Triple::EnvironmentType Stage) {
442 v2::RuntimeInfo::swapBytes(Stage);
443 }
444 };
445
446 } // namespace v3
447 } // namespace PSV
448
449 #define COMPONENT_PRECISION(Val, Enum) Enum = Val,
450 enum class SigMinPrecision : uint32_t {
451 #include "DXContainerConstants.def"
452 };
453
454 ArrayRef<EnumEntry<SigMinPrecision>> getSigMinPrecisions();
455
456 #define D3D_SYSTEM_VALUE(Val, Enum) Enum = Val,
457 enum class D3DSystemValue : uint32_t {
458 #include "DXContainerConstants.def"
459 };
460
461 ArrayRef<EnumEntry<D3DSystemValue>> getD3DSystemValues();
462
463 #define COMPONENT_TYPE(Val, Enum) Enum = Val,
464 enum class SigComponentType : uint32_t {
465 #include "DXContainerConstants.def"
466 };
467
468 ArrayRef<EnumEntry<SigComponentType>> getSigComponentTypes();
469
470 struct ProgramSignatureHeader {
471 uint32_t ParamCount;
472 uint32_t FirstParamOffset;
473
swapBytesProgramSignatureHeader474 void swapBytes() {
475 sys::swapByteOrder(ParamCount);
476 sys::swapByteOrder(FirstParamOffset);
477 }
478 };
479
480 struct ProgramSignatureElement {
481 uint32_t Stream; // Stream index (parameters must appear in non-decreasing
482 // stream order)
483 uint32_t NameOffset; // Offset from the start of the ProgramSignatureHeader to
484 // the start of the null terminated string for the name.
485 uint32_t Index; // Semantic Index
486 D3DSystemValue SystemValue; // Semantic type. Similar to PSV::SemanticKind.
487 SigComponentType CompType; // Type of bits.
488 uint32_t Register; // Register Index (row index)
489 uint8_t Mask; // Mask (column allocation)
490
491 // The ExclusiveMask has a different meaning for input and output signatures.
492 // For an output signature, masked components of the output register are never
493 // written to.
494 // For an input signature, masked components of the input register are always
495 // read.
496 uint8_t ExclusiveMask;
497
498 uint16_t Unused;
499 SigMinPrecision MinPrecision; // Minimum precision of input/output data
500
swapBytesProgramSignatureElement501 void swapBytes() {
502 sys::swapByteOrder(Stream);
503 sys::swapByteOrder(NameOffset);
504 sys::swapByteOrder(Index);
505 sys::swapByteOrder(SystemValue);
506 sys::swapByteOrder(CompType);
507 sys::swapByteOrder(Register);
508 sys::swapByteOrder(Mask);
509 sys::swapByteOrder(ExclusiveMask);
510 sys::swapByteOrder(MinPrecision);
511 }
512 };
513
514 static_assert(sizeof(ProgramSignatureElement) == 32,
515 "ProgramSignatureElement is misaligned");
516
517 } // namespace dxbc
518 } // namespace llvm
519
520 #endif // LLVM_BINARYFORMAT_DXCONTAINER_H
521