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 MajorVersion; // DXIL version.
107 uint8_t MinorVersion; // 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 MinorVersion : 4;
123 uint8_t MajorVersion : 4;
124 uint8_t Unused;
125 uint16_t ShaderKind;
126 uint32_t Size; // Size in uint32_t words including this header.
127 BitcodeHeader Bitcode;
128
swapBytesProgramHeader129 void swapBytes() {
130 sys::swapByteOrder(ShaderKind);
131 sys::swapByteOrder(Size);
132 Bitcode.swapBytes();
133 }
134 };
135
136 static_assert(sizeof(ProgramHeader) == 24, "ProgramHeader Size incorrect!");
137
138 #define CONTAINER_PART(Part) Part,
139 enum class PartType {
140 Unknown = 0,
141 #include "DXContainerConstants.def"
142 };
143
144 #define SHADER_FLAG(Num, Val, Str) Val = 1ull << Num,
145 enum class FeatureFlags : uint64_t {
146 #include "DXContainerConstants.def"
147 };
148 static_assert((uint64_t)FeatureFlags::NextUnusedBit <= 1ull << 63,
149 "Shader flag bits exceed enum size.");
150
151 PartType parsePartType(StringRef S);
152
153 struct VertexPSVInfo {
154 uint8_t OutputPositionPresent;
155 uint8_t Unused[3];
156
swapBytesVertexPSVInfo157 void swapBytes() {
158 // nothing to swap
159 }
160 };
161
162 struct HullPSVInfo {
163 uint32_t InputControlPointCount;
164 uint32_t OutputControlPointCount;
165 uint32_t TessellatorDomain;
166 uint32_t TessellatorOutputPrimitive;
167
swapBytesHullPSVInfo168 void swapBytes() {
169 sys::swapByteOrder(InputControlPointCount);
170 sys::swapByteOrder(OutputControlPointCount);
171 sys::swapByteOrder(TessellatorDomain);
172 sys::swapByteOrder(TessellatorOutputPrimitive);
173 }
174 };
175
176 struct DomainPSVInfo {
177 uint32_t InputControlPointCount;
178 uint8_t OutputPositionPresent;
179 uint8_t Unused[3];
180 uint32_t TessellatorDomain;
181
swapBytesDomainPSVInfo182 void swapBytes() {
183 sys::swapByteOrder(InputControlPointCount);
184 sys::swapByteOrder(TessellatorDomain);
185 }
186 };
187
188 struct GeometryPSVInfo {
189 uint32_t InputPrimitive;
190 uint32_t OutputTopology;
191 uint32_t OutputStreamMask;
192 uint8_t OutputPositionPresent;
193 uint8_t Unused[3];
194
swapBytesGeometryPSVInfo195 void swapBytes() {
196 sys::swapByteOrder(InputPrimitive);
197 sys::swapByteOrder(OutputTopology);
198 sys::swapByteOrder(OutputStreamMask);
199 }
200 };
201
202 struct PixelPSVInfo {
203 uint8_t DepthOutput;
204 uint8_t SampleFrequency;
205 uint8_t Unused[2];
206
swapBytesPixelPSVInfo207 void swapBytes() {
208 // nothing to swap
209 }
210 };
211
212 struct MeshPSVInfo {
213 uint32_t GroupSharedBytesUsed;
214 uint32_t GroupSharedBytesDependentOnViewID;
215 uint32_t PayloadSizeInBytes;
216 uint16_t MaxOutputVertices;
217 uint16_t MaxOutputPrimitives;
218
swapBytesMeshPSVInfo219 void swapBytes() {
220 sys::swapByteOrder(GroupSharedBytesUsed);
221 sys::swapByteOrder(GroupSharedBytesDependentOnViewID);
222 sys::swapByteOrder(PayloadSizeInBytes);
223 sys::swapByteOrder(MaxOutputVertices);
224 sys::swapByteOrder(MaxOutputPrimitives);
225 }
226 };
227
228 struct AmplificationPSVInfo {
229 uint32_t PayloadSizeInBytes;
230
swapBytesAmplificationPSVInfo231 void swapBytes() { sys::swapByteOrder(PayloadSizeInBytes); }
232 };
233
234 union PipelinePSVInfo {
235 VertexPSVInfo VS;
236 HullPSVInfo HS;
237 DomainPSVInfo DS;
238 GeometryPSVInfo GS;
239 PixelPSVInfo PS;
240 MeshPSVInfo MS;
241 AmplificationPSVInfo AS;
242
swapBytes(Triple::EnvironmentType Stage)243 void swapBytes(Triple::EnvironmentType Stage) {
244 switch (Stage) {
245 case Triple::EnvironmentType::Pixel:
246 PS.swapBytes();
247 break;
248 case Triple::EnvironmentType::Vertex:
249 VS.swapBytes();
250 break;
251 case Triple::EnvironmentType::Geometry:
252 GS.swapBytes();
253 break;
254 case Triple::EnvironmentType::Hull:
255 HS.swapBytes();
256 break;
257 case Triple::EnvironmentType::Domain:
258 DS.swapBytes();
259 break;
260 case Triple::EnvironmentType::Mesh:
261 MS.swapBytes();
262 break;
263 case Triple::EnvironmentType::Amplification:
264 AS.swapBytes();
265 break;
266 default:
267 break;
268 }
269 }
270 };
271
272 static_assert(sizeof(PipelinePSVInfo) == 4 * sizeof(uint32_t),
273 "Pipeline-specific PSV info must fit in 16 bytes.");
274
275 namespace PSV {
276
277 #define SEMANTIC_KIND(Val, Enum) Enum = Val,
278 enum class SemanticKind : uint8_t {
279 #include "DXContainerConstants.def"
280 };
281
282 ArrayRef<EnumEntry<SemanticKind>> getSemanticKinds();
283
284 #define COMPONENT_TYPE(Val, Enum) Enum = Val,
285 enum class ComponentType : uint8_t {
286 #include "DXContainerConstants.def"
287 };
288
289 ArrayRef<EnumEntry<ComponentType>> getComponentTypes();
290
291 #define INTERPOLATION_MODE(Val, Enum) Enum = Val,
292 enum class InterpolationMode : uint8_t {
293 #include "DXContainerConstants.def"
294 };
295
296 ArrayRef<EnumEntry<InterpolationMode>> getInterpolationModes();
297
298 namespace v0 {
299 struct RuntimeInfo {
300 PipelinePSVInfo StageInfo;
301 uint32_t MinimumWaveLaneCount; // minimum lane count required, 0 if unused
302 uint32_t MaximumWaveLaneCount; // maximum lane count required,
303 // 0xffffffff if unused
swapBytesRuntimeInfo304 void swapBytes() {
305 // Skip the union because we don't know which field it has
306 sys::swapByteOrder(MinimumWaveLaneCount);
307 sys::swapByteOrder(MaximumWaveLaneCount);
308 }
309
swapBytesRuntimeInfo310 void swapBytes(Triple::EnvironmentType Stage) { StageInfo.swapBytes(Stage); }
311 };
312
313 struct ResourceBindInfo {
314 uint32_t Type;
315 uint32_t Space;
316 uint32_t LowerBound;
317 uint32_t UpperBound;
318
swapBytesResourceBindInfo319 void swapBytes() {
320 sys::swapByteOrder(Type);
321 sys::swapByteOrder(Space);
322 sys::swapByteOrder(LowerBound);
323 sys::swapByteOrder(UpperBound);
324 }
325 };
326
327 struct SignatureElement {
328 uint32_t NameOffset;
329 uint32_t IndicesOffset;
330
331 uint8_t Rows;
332 uint8_t StartRow;
333 uint8_t Cols : 4;
334 uint8_t StartCol : 2;
335 uint8_t Allocated : 1;
336 uint8_t Unused : 1;
337 SemanticKind Kind;
338
339 ComponentType Type;
340 InterpolationMode Mode;
341 uint8_t DynamicMask : 4;
342 uint8_t Stream : 2;
343 uint8_t Unused2 : 2;
344 uint8_t Reserved;
345
swapBytesSignatureElement346 void swapBytes() {
347 sys::swapByteOrder(NameOffset);
348 sys::swapByteOrder(IndicesOffset);
349 }
350 };
351
352 static_assert(sizeof(SignatureElement) == 4 * sizeof(uint32_t),
353 "PSV Signature elements must fit in 16 bytes.");
354
355 } // namespace v0
356
357 namespace v1 {
358
359 struct MeshRuntimeInfo {
360 uint8_t SigPrimVectors; // Primitive output for MS
361 uint8_t MeshOutputTopology;
362 };
363
364 union GeometryExtraInfo {
365 uint16_t MaxVertexCount; // MaxVertexCount for GS only (max 1024)
366 uint8_t SigPatchConstOrPrimVectors; // Output for HS; Input for DS;
367 // Primitive output for MS (overlaps
368 // MeshInfo::SigPrimVectors)
369 MeshRuntimeInfo MeshInfo;
370 };
371 struct RuntimeInfo : public v0::RuntimeInfo {
372 uint8_t ShaderStage; // PSVShaderKind
373 uint8_t UsesViewID;
374 GeometryExtraInfo GeomData;
375
376 // PSVSignatureElement counts
377 uint8_t SigInputElements;
378 uint8_t SigOutputElements;
379 uint8_t SigPatchOrPrimElements;
380
381 // Number of packed vectors per signature
382 uint8_t SigInputVectors;
383 uint8_t SigOutputVectors[4];
384
swapBytesRuntimeInfo385 void swapBytes() {
386 // nothing to swap since everything is single-byte or a union field
387 }
388
swapBytesRuntimeInfo389 void swapBytes(Triple::EnvironmentType Stage) {
390 v0::RuntimeInfo::swapBytes(Stage);
391 if (Stage == Triple::EnvironmentType::Geometry)
392 sys::swapByteOrder(GeomData.MaxVertexCount);
393 }
394 };
395
396 } // namespace v1
397
398 namespace v2 {
399 struct RuntimeInfo : public v1::RuntimeInfo {
400 uint32_t NumThreadsX;
401 uint32_t NumThreadsY;
402 uint32_t NumThreadsZ;
403
swapBytesRuntimeInfo404 void swapBytes() {
405 sys::swapByteOrder(NumThreadsX);
406 sys::swapByteOrder(NumThreadsY);
407 sys::swapByteOrder(NumThreadsZ);
408 }
409
swapBytesRuntimeInfo410 void swapBytes(Triple::EnvironmentType Stage) {
411 v1::RuntimeInfo::swapBytes(Stage);
412 }
413 };
414
415 struct ResourceBindInfo : public v0::ResourceBindInfo {
416 uint32_t Kind;
417 uint32_t Flags;
418
swapBytesResourceBindInfo419 void swapBytes() {
420 v0::ResourceBindInfo::swapBytes();
421 sys::swapByteOrder(Kind);
422 sys::swapByteOrder(Flags);
423 }
424 };
425
426 } // namespace v2
427 } // namespace PSV
428
429 #define COMPONENT_PRECISION(Val, Enum) Enum = Val,
430 enum class SigMinPrecision : uint32_t {
431 #include "DXContainerConstants.def"
432 };
433
434 ArrayRef<EnumEntry<SigMinPrecision>> getSigMinPrecisions();
435
436 #define D3D_SYSTEM_VALUE(Val, Enum) Enum = Val,
437 enum class D3DSystemValue : uint32_t {
438 #include "DXContainerConstants.def"
439 };
440
441 ArrayRef<EnumEntry<D3DSystemValue>> getD3DSystemValues();
442
443 #define COMPONENT_TYPE(Val, Enum) Enum = Val,
444 enum class SigComponentType : uint32_t {
445 #include "DXContainerConstants.def"
446 };
447
448 ArrayRef<EnumEntry<SigComponentType>> getSigComponentTypes();
449
450 struct ProgramSignatureHeader {
451 uint32_t ParamCount;
452 uint32_t FirstParamOffset;
453
swapBytesProgramSignatureHeader454 void swapBytes() {
455 sys::swapByteOrder(ParamCount);
456 sys::swapByteOrder(FirstParamOffset);
457 }
458 };
459
460 struct ProgramSignatureElement {
461 uint32_t Stream; // Stream index (parameters must appear in non-decreasing
462 // stream order)
463 uint32_t NameOffset; // Offset from the start of the ProgramSignatureHeader to
464 // the start of the null terminated string for the name.
465 uint32_t Index; // Semantic Index
466 D3DSystemValue SystemValue; // Semantic type. Similar to PSV::SemanticKind.
467 SigComponentType CompType; // Type of bits.
468 uint32_t Register; // Register Index (row index)
469 uint8_t Mask; // Mask (column allocation)
470
471 // The ExclusiveMask has a different meaning for input and output signatures.
472 // For an output signature, masked components of the output register are never
473 // written to.
474 // For an input signature, masked components of the input register are always
475 // read.
476 uint8_t ExclusiveMask;
477
478 uint16_t Unused;
479 SigMinPrecision MinPrecision; // Minimum precision of input/output data
480
swapBytesProgramSignatureElement481 void swapBytes() {
482 sys::swapByteOrder(Stream);
483 sys::swapByteOrder(NameOffset);
484 sys::swapByteOrder(Index);
485 sys::swapByteOrder(SystemValue);
486 sys::swapByteOrder(CompType);
487 sys::swapByteOrder(Register);
488 sys::swapByteOrder(Mask);
489 sys::swapByteOrder(ExclusiveMask);
490 sys::swapByteOrder(MinPrecision);
491 }
492 };
493
494 static_assert(sizeof(ProgramSignatureElement) == 32,
495 "ProgramSignatureElement is misaligned");
496
497 } // namespace dxbc
498 } // namespace llvm
499
500 #endif // LLVM_BINARYFORMAT_DXCONTAINER_H
501