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 
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 
63   void swapBytes() { sys::swapByteOrder(Flags); }
64 };
65 
66 struct ContainerVersion {
67   uint16_t Major;
68   uint16_t Minor;
69 
70   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 
83   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 
97   void swapBytes() { sys::swapByteOrder(Size); }
98   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 
113   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 
129   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 
157   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 
168   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 
182   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 
195   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 
207   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 
219   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 
231   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 
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
304   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 
310   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 
319   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 
346   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 
385   void swapBytes() {
386     // nothing to swap since everything is single-byte or a union field
387   }
388 
389   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 
404   void swapBytes() {
405     sys::swapByteOrder(NumThreadsX);
406     sys::swapByteOrder(NumThreadsY);
407     sys::swapByteOrder(NumThreadsZ);
408   }
409 
410   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 
419   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 
454   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 
481   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