xref: /freebsd/contrib/llvm-project/llvm/include/llvm/BinaryFormat/DXContainer.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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