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(Value&: Flags); } |
64 | }; |
65 | |
66 | struct ContainerVersion { |
67 | uint16_t Major; |
68 | uint16_t Minor; |
69 | |
70 | void swapBytes() { |
71 | sys::swapByteOrder(Value&: Major); |
72 | sys::swapByteOrder(Value&: Minor); |
73 | } |
74 | }; |
75 | |
76 | struct { |
77 | uint8_t [4]; // "DXBC" |
78 | Hash ; |
79 | ContainerVersion ; |
80 | uint32_t ; |
81 | uint32_t ; |
82 | |
83 | void () { |
84 | Version.swapBytes(); |
85 | sys::swapByteOrder(Value&: FileSize); |
86 | sys::swapByteOrder(Value&: 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 { |
94 | uint8_t [4]; |
95 | uint32_t ; |
96 | |
97 | void () { sys::swapByteOrder(Value&: Size); } |
98 | StringRef () 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 { |
105 | uint8_t [4]; // ACSII "DXIL". |
106 | uint8_t ; // DXIL version. |
107 | uint8_t ; // DXIL version. |
108 | uint16_t ; |
109 | uint32_t ; // Offset to LLVM bitcode (from start of header). |
110 | uint32_t ; // Size of LLVM bitcode (in bytes). |
111 | // Followed by uint8_t[BitcodeHeader.Size] at &BitcodeHeader + Header.Offset |
112 | |
113 | void () { |
114 | sys::swapByteOrder(Value&: MinorVersion); |
115 | sys::swapByteOrder(Value&: MajorVersion); |
116 | sys::swapByteOrder(Value&: Offset); |
117 | sys::swapByteOrder(Value&: Size); |
118 | } |
119 | }; |
120 | |
121 | struct { |
122 | uint8_t : 4; |
123 | uint8_t : 4; |
124 | uint8_t ; |
125 | uint16_t ; |
126 | uint32_t ; // Size in uint32_t words including this header. |
127 | BitcodeHeader ; |
128 | |
129 | void () { |
130 | sys::swapByteOrder(Value&: ShaderKind); |
131 | sys::swapByteOrder(Value&: 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_FEATURE_FLAG(Num, DxilModuleNum, 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(Value&: InputControlPointCount); |
170 | sys::swapByteOrder(Value&: OutputControlPointCount); |
171 | sys::swapByteOrder(Value&: TessellatorDomain); |
172 | sys::swapByteOrder(Value&: 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(Value&: InputControlPointCount); |
184 | sys::swapByteOrder(Value&: 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(Value&: InputPrimitive); |
197 | sys::swapByteOrder(Value&: OutputTopology); |
198 | sys::swapByteOrder(Value&: 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(Value&: GroupSharedBytesUsed); |
221 | sys::swapByteOrder(Value&: GroupSharedBytesDependentOnViewID); |
222 | sys::swapByteOrder(Value&: PayloadSizeInBytes); |
223 | sys::swapByteOrder(Value&: MaxOutputVertices); |
224 | sys::swapByteOrder(Value&: MaxOutputPrimitives); |
225 | } |
226 | }; |
227 | |
228 | struct AmplificationPSVInfo { |
229 | uint32_t PayloadSizeInBytes; |
230 | |
231 | void swapBytes() { sys::swapByteOrder(Value&: 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(Value&: MinimumWaveLaneCount); |
307 | sys::swapByteOrder(Value&: 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(Value&: Type); |
321 | sys::swapByteOrder(Value&: Space); |
322 | sys::swapByteOrder(Value&: LowerBound); |
323 | sys::swapByteOrder(Value&: 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(Value&: NameOffset); |
348 | sys::swapByteOrder(Value&: 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 { |
365 | uint16_t ; // MaxVertexCount for GS only (max 1024) |
366 | uint8_t ; // Output for HS; Input for DS; |
367 | // Primitive output for MS (overlaps |
368 | // MeshInfo::SigPrimVectors) |
369 | MeshRuntimeInfo ; |
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(Value&: 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(Value&: NumThreadsX); |
406 | sys::swapByteOrder(Value&: NumThreadsY); |
407 | sys::swapByteOrder(Value&: 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(Value&: Kind); |
422 | sys::swapByteOrder(Value&: Flags); |
423 | } |
424 | }; |
425 | |
426 | } // namespace v2 |
427 | |
428 | namespace v3 { |
429 | struct RuntimeInfo : public v2::RuntimeInfo { |
430 | uint32_t EntryNameOffset; |
431 | |
432 | void swapBytes() { |
433 | v2::RuntimeInfo::swapBytes(); |
434 | sys::swapByteOrder(Value&: EntryNameOffset); |
435 | } |
436 | |
437 | void swapBytes(Triple::EnvironmentType Stage) { |
438 | v2::RuntimeInfo::swapBytes(Stage); |
439 | } |
440 | }; |
441 | |
442 | } // namespace v3 |
443 | } // namespace PSV |
444 | |
445 | #define COMPONENT_PRECISION(Val, Enum) Enum = Val, |
446 | enum class SigMinPrecision : uint32_t { |
447 | #include "DXContainerConstants.def" |
448 | }; |
449 | |
450 | ArrayRef<EnumEntry<SigMinPrecision>> getSigMinPrecisions(); |
451 | |
452 | #define D3D_SYSTEM_VALUE(Val, Enum) Enum = Val, |
453 | enum class D3DSystemValue : uint32_t { |
454 | #include "DXContainerConstants.def" |
455 | }; |
456 | |
457 | ArrayRef<EnumEntry<D3DSystemValue>> getD3DSystemValues(); |
458 | |
459 | #define COMPONENT_TYPE(Val, Enum) Enum = Val, |
460 | enum class SigComponentType : uint32_t { |
461 | #include "DXContainerConstants.def" |
462 | }; |
463 | |
464 | ArrayRef<EnumEntry<SigComponentType>> getSigComponentTypes(); |
465 | |
466 | struct { |
467 | uint32_t ; |
468 | uint32_t ; |
469 | |
470 | void () { |
471 | sys::swapByteOrder(Value&: ParamCount); |
472 | sys::swapByteOrder(Value&: FirstParamOffset); |
473 | } |
474 | }; |
475 | |
476 | struct ProgramSignatureElement { |
477 | uint32_t Stream; // Stream index (parameters must appear in non-decreasing |
478 | // stream order) |
479 | uint32_t NameOffset; // Offset from the start of the ProgramSignatureHeader to |
480 | // the start of the null terminated string for the name. |
481 | uint32_t Index; // Semantic Index |
482 | D3DSystemValue SystemValue; // Semantic type. Similar to PSV::SemanticKind. |
483 | SigComponentType CompType; // Type of bits. |
484 | uint32_t Register; // Register Index (row index) |
485 | uint8_t Mask; // Mask (column allocation) |
486 | |
487 | // The ExclusiveMask has a different meaning for input and output signatures. |
488 | // For an output signature, masked components of the output register are never |
489 | // written to. |
490 | // For an input signature, masked components of the input register are always |
491 | // read. |
492 | uint8_t ExclusiveMask; |
493 | |
494 | uint16_t Unused; |
495 | SigMinPrecision MinPrecision; // Minimum precision of input/output data |
496 | |
497 | void swapBytes() { |
498 | sys::swapByteOrder(Value&: Stream); |
499 | sys::swapByteOrder(Value&: NameOffset); |
500 | sys::swapByteOrder(Value&: Index); |
501 | sys::swapByteOrder(Value&: SystemValue); |
502 | sys::swapByteOrder(Value&: CompType); |
503 | sys::swapByteOrder(Value&: Register); |
504 | sys::swapByteOrder(Value&: Mask); |
505 | sys::swapByteOrder(Value&: ExclusiveMask); |
506 | sys::swapByteOrder(Value&: MinPrecision); |
507 | } |
508 | }; |
509 | |
510 | static_assert(sizeof(ProgramSignatureElement) == 32, |
511 | "ProgramSignatureElement is misaligned" ); |
512 | |
513 | } // namespace dxbc |
514 | } // namespace llvm |
515 | |
516 | #endif // LLVM_BINARYFORMAT_DXCONTAINER_H |
517 | |