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 
24 // The DXContainer file format is arranged as a header and "parts". Semantically
25 // parts are similar to sections in other object file formats. The File format
26 // structure is roughly:
27 
28 // ┌────────────────────────────────┐
29 // │             Header             │
30 // ├────────────────────────────────┤
31 // │              Part              │
32 // ├────────────────────────────────┤
33 // │              Part              │
34 // ├────────────────────────────────┤
35 // │              ...               │
36 // └────────────────────────────────┘
37 
38 namespace dxbc {
39 
40 inline Triple::EnvironmentType getShaderStage(uint32_t Kind) {
41   assert(Kind <= Triple::Amplification - Triple::Pixel &&
42          "Shader kind out of expected range.");
43   return static_cast<Triple::EnvironmentType>(Triple::Pixel + Kind);
44 }
45 
46 struct Hash {
47   uint8_t Digest[16];
48 };
49 
50 enum class HashFlags : uint32_t {
51   None = 0,           // No flags defined.
52   IncludesSource = 1, // This flag indicates that the shader hash was computed
53                       // taking into account source information (-Zss)
54 };
55 
56 struct ShaderHash {
57   uint32_t Flags; // dxbc::HashFlags
58   uint8_t Digest[16];
59 
60   bool isPopulated();
61 
62   void swapBytes() { sys::swapByteOrder(Flags); }
63 };
64 
65 struct ContainerVersion {
66   uint16_t Major;
67   uint16_t Minor;
68 
69   void swapBytes() {
70     sys::swapByteOrder(Major);
71     sys::swapByteOrder(Minor);
72   }
73 };
74 
75 struct Header {
76   uint8_t Magic[4]; // "DXBC"
77   Hash FileHash;
78   ContainerVersion Version;
79   uint32_t FileSize;
80   uint32_t PartCount;
81 
82   void swapBytes() {
83     Version.swapBytes();
84     sys::swapByteOrder(FileSize);
85     sys::swapByteOrder(PartCount);
86   }
87   // Structure is followed by part offsets: uint32_t PartOffset[PartCount];
88   // The offset is to a PartHeader, which is followed by the Part Data.
89 };
90 
91 /// Use this type to describe the size and type of a DXIL container part.
92 struct PartHeader {
93   uint8_t Name[4];
94   uint32_t Size;
95 
96   void swapBytes() { sys::swapByteOrder(Size); }
97   StringRef getName() const {
98     return StringRef(reinterpret_cast<const char *>(&Name[0]), 4);
99   }
100   // Structure is followed directly by part data: uint8_t PartData[PartSize].
101 };
102 
103 struct BitcodeHeader {
104   uint8_t Magic[4];     // ACSII "DXIL".
105   uint8_t MajorVersion; // DXIL version.
106   uint8_t MinorVersion; // DXIL version.
107   uint16_t Unused;
108   uint32_t Offset; // Offset to LLVM bitcode (from start of header).
109   uint32_t Size;   // Size of LLVM bitcode (in bytes).
110   // Followed by uint8_t[BitcodeHeader.Size] at &BitcodeHeader + Header.Offset
111 
112   void swapBytes() {
113     sys::swapByteOrder(MinorVersion);
114     sys::swapByteOrder(MajorVersion);
115     sys::swapByteOrder(Offset);
116     sys::swapByteOrder(Size);
117   }
118 };
119 
120 struct ProgramHeader {
121   uint8_t MinorVersion : 4;
122   uint8_t MajorVersion : 4;
123   uint8_t Unused;
124   uint16_t ShaderKind;
125   uint32_t Size; // Size in uint32_t words including this header.
126   BitcodeHeader Bitcode;
127 
128   void swapBytes() {
129     sys::swapByteOrder(ShaderKind);
130     sys::swapByteOrder(Size);
131     Bitcode.swapBytes();
132   }
133 };
134 
135 static_assert(sizeof(ProgramHeader) == 24, "ProgramHeader Size incorrect!");
136 
137 #define CONTAINER_PART(Part) Part,
138 enum class PartType {
139   Unknown = 0,
140 #include "DXContainerConstants.def"
141 };
142 
143 #define SHADER_FLAG(Num, Val, Str) Val = 1ull << Num,
144 enum class FeatureFlags : uint64_t {
145 #include "DXContainerConstants.def"
146 };
147 static_assert((uint64_t)FeatureFlags::NextUnusedBit <= 1ull << 63,
148               "Shader flag bits exceed enum size.");
149 
150 PartType parsePartType(StringRef S);
151 
152 struct VertexPSVInfo {
153   uint8_t OutputPositionPresent;
154   uint8_t Unused[3];
155 
156   void swapBytes() {
157     // nothing to swap
158   }
159 };
160 
161 struct HullPSVInfo {
162   uint32_t InputControlPointCount;
163   uint32_t OutputControlPointCount;
164   uint32_t TessellatorDomain;
165   uint32_t TessellatorOutputPrimitive;
166 
167   void swapBytes() {
168     sys::swapByteOrder(InputControlPointCount);
169     sys::swapByteOrder(OutputControlPointCount);
170     sys::swapByteOrder(TessellatorDomain);
171     sys::swapByteOrder(TessellatorOutputPrimitive);
172   }
173 };
174 
175 struct DomainPSVInfo {
176   uint32_t InputControlPointCount;
177   uint8_t OutputPositionPresent;
178   uint8_t Unused[3];
179   uint32_t TessellatorDomain;
180 
181   void swapBytes() {
182     sys::swapByteOrder(InputControlPointCount);
183     sys::swapByteOrder(TessellatorDomain);
184   }
185 };
186 
187 struct GeometryPSVInfo {
188   uint32_t InputPrimitive;
189   uint32_t OutputTopology;
190   uint32_t OutputStreamMask;
191   uint8_t OutputPositionPresent;
192   uint8_t Unused[3];
193 
194   void swapBytes() {
195     sys::swapByteOrder(InputPrimitive);
196     sys::swapByteOrder(OutputTopology);
197     sys::swapByteOrder(OutputStreamMask);
198   }
199 };
200 
201 struct PixelPSVInfo {
202   uint8_t DepthOutput;
203   uint8_t SampleFrequency;
204   uint8_t Unused[2];
205 
206   void swapBytes() {
207     // nothing to swap
208   }
209 };
210 
211 struct MeshPSVInfo {
212   uint32_t GroupSharedBytesUsed;
213   uint32_t GroupSharedBytesDependentOnViewID;
214   uint32_t PayloadSizeInBytes;
215   uint16_t MaxOutputVertices;
216   uint16_t MaxOutputPrimitives;
217 
218   void swapBytes() {
219     sys::swapByteOrder(GroupSharedBytesUsed);
220     sys::swapByteOrder(GroupSharedBytesDependentOnViewID);
221     sys::swapByteOrder(PayloadSizeInBytes);
222     sys::swapByteOrder(MaxOutputVertices);
223     sys::swapByteOrder(MaxOutputPrimitives);
224   }
225 };
226 
227 struct AmplificationPSVInfo {
228   uint32_t PayloadSizeInBytes;
229 
230   void swapBytes() { sys::swapByteOrder(PayloadSizeInBytes); }
231 };
232 
233 union PipelinePSVInfo {
234   VertexPSVInfo VS;
235   HullPSVInfo HS;
236   DomainPSVInfo DS;
237   GeometryPSVInfo GS;
238   PixelPSVInfo PS;
239   MeshPSVInfo MS;
240   AmplificationPSVInfo AS;
241 
242   void swapBytes(Triple::EnvironmentType Stage) {
243     switch (Stage) {
244     case Triple::EnvironmentType::Pixel:
245       PS.swapBytes();
246       break;
247     case Triple::EnvironmentType::Vertex:
248       VS.swapBytes();
249       break;
250     case Triple::EnvironmentType::Geometry:
251       GS.swapBytes();
252       break;
253     case Triple::EnvironmentType::Hull:
254       HS.swapBytes();
255       break;
256     case Triple::EnvironmentType::Domain:
257       DS.swapBytes();
258       break;
259     case Triple::EnvironmentType::Mesh:
260       MS.swapBytes();
261       break;
262     case Triple::EnvironmentType::Amplification:
263       AS.swapBytes();
264       break;
265     default:
266       break;
267     }
268   }
269 };
270 
271 static_assert(sizeof(PipelinePSVInfo) == 4 * sizeof(uint32_t),
272               "Pipeline-specific PSV info must fit in 16 bytes.");
273 
274 namespace PSV {
275 
276 namespace v0 {
277 struct RuntimeInfo {
278   PipelinePSVInfo StageInfo;
279   uint32_t MinimumWaveLaneCount; // minimum lane count required, 0 if unused
280   uint32_t MaximumWaveLaneCount; // maximum lane count required,
281                                  // 0xffffffff if unused
282   void swapBytes() {
283     // Skip the union because we don't know which field it has
284     sys::swapByteOrder(MinimumWaveLaneCount);
285     sys::swapByteOrder(MaximumWaveLaneCount);
286   }
287 
288   void swapBytes(Triple::EnvironmentType Stage) { StageInfo.swapBytes(Stage); }
289 };
290 
291 struct ResourceBindInfo {
292   uint32_t Type;
293   uint32_t Space;
294   uint32_t LowerBound;
295   uint32_t UpperBound;
296 
297   void swapBytes() {
298     sys::swapByteOrder(Type);
299     sys::swapByteOrder(Space);
300     sys::swapByteOrder(LowerBound);
301     sys::swapByteOrder(UpperBound);
302   }
303 };
304 
305 } // namespace v0
306 
307 namespace v1 {
308 
309 struct MeshRuntimeInfo {
310   uint8_t SigPrimVectors; // Primitive output for MS
311   uint8_t MeshOutputTopology;
312 };
313 
314 union GeometryExtraInfo {
315   uint16_t MaxVertexCount;            // MaxVertexCount for GS only (max 1024)
316   uint8_t SigPatchConstOrPrimVectors; // Output for HS; Input for DS;
317                                       // Primitive output for MS (overlaps
318                                       // MeshInfo::SigPrimVectors)
319   MeshRuntimeInfo MeshInfo;
320 };
321 struct RuntimeInfo : public v0::RuntimeInfo {
322   uint8_t ShaderStage; // PSVShaderKind
323   uint8_t UsesViewID;
324   GeometryExtraInfo GeomData;
325 
326   // PSVSignatureElement counts
327   uint8_t SigInputElements;
328   uint8_t SigOutputElements;
329   uint8_t SigPatchConstOrPrimElements;
330 
331   // Number of packed vectors per signature
332   uint8_t SigInputVectors;
333   uint8_t SigOutputVectors[4];
334 
335   void swapBytes() {
336     // nothing to swap since everything is single-byte or a union field
337   }
338 
339   void swapBytes(Triple::EnvironmentType Stage) {
340     v0::RuntimeInfo::swapBytes(Stage);
341     if (Stage == Triple::EnvironmentType::Geometry)
342       sys::swapByteOrder(GeomData.MaxVertexCount);
343   }
344 };
345 
346 } // namespace v1
347 
348 namespace v2 {
349 struct RuntimeInfo : public v1::RuntimeInfo {
350   uint32_t NumThreadsX;
351   uint32_t NumThreadsY;
352   uint32_t NumThreadsZ;
353 
354   void swapBytes() {
355     sys::swapByteOrder(NumThreadsX);
356     sys::swapByteOrder(NumThreadsY);
357     sys::swapByteOrder(NumThreadsZ);
358   }
359 
360   void swapBytes(Triple::EnvironmentType Stage) {
361     v1::RuntimeInfo::swapBytes(Stage);
362   }
363 };
364 
365 struct ResourceBindInfo : public v0::ResourceBindInfo {
366   uint32_t Kind;
367   uint32_t Flags;
368 
369   void swapBytes() {
370     v0::ResourceBindInfo::swapBytes();
371     sys::swapByteOrder(Kind);
372     sys::swapByteOrder(Flags);
373   }
374 };
375 
376 } // namespace v2
377 } // namespace PSV
378 
379 } // namespace dxbc
380 } // namespace llvm
381 
382 #endif // LLVM_BINARYFORMAT_DXCONTAINER_H
383