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 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 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 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 128 void swapBytes() { 129 sys::swapByteOrder(ShaderKind); 130 sys::swapByteOrder(Size); 131 Bitcode.swapBytes(); 132 } 133 uint8_t getMajorVersion() { return Version >> 4; } 134 uint8_t getMinorVersion() { return Version & 0xF; } 135 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 161 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 172 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 186 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 199 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 211 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 223 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 235 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 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 #define RESOURCE_TYPE(Val, Enum) Enum = Val, 303 enum class ResourceType : uint32_t { 304 #include "DXContainerConstants.def" 305 }; 306 307 ArrayRef<EnumEntry<ResourceType>> getResourceTypes(); 308 309 #define RESOURCE_KIND(Val, Enum) Enum = Val, 310 enum class ResourceKind : uint32_t { 311 #include "DXContainerConstants.def" 312 }; 313 314 ArrayRef<EnumEntry<ResourceKind>> getResourceKinds(); 315 316 #define RESOURCE_FLAG(Index, Enum) bool Enum = false; 317 struct ResourceFlags { 318 ResourceFlags() {}; 319 struct FlagsBits { 320 #include "llvm/BinaryFormat/DXContainerConstants.def" 321 }; 322 union { 323 uint32_t Flags; 324 FlagsBits Bits; 325 }; 326 bool operator==(const uint32_t RFlags) const { return Flags == RFlags; } 327 }; 328 329 namespace v0 { 330 struct RuntimeInfo { 331 PipelinePSVInfo StageInfo; 332 uint32_t MinimumWaveLaneCount; // minimum lane count required, 0 if unused 333 uint32_t MaximumWaveLaneCount; // maximum lane count required, 334 // 0xffffffff if unused 335 void swapBytes() { 336 // Skip the union because we don't know which field it has 337 sys::swapByteOrder(MinimumWaveLaneCount); 338 sys::swapByteOrder(MaximumWaveLaneCount); 339 } 340 341 void swapBytes(Triple::EnvironmentType Stage) { StageInfo.swapBytes(Stage); } 342 }; 343 344 struct ResourceBindInfo { 345 ResourceType Type; 346 uint32_t Space; 347 uint32_t LowerBound; 348 uint32_t UpperBound; 349 350 void swapBytes() { 351 sys::swapByteOrder(Type); 352 sys::swapByteOrder(Space); 353 sys::swapByteOrder(LowerBound); 354 sys::swapByteOrder(UpperBound); 355 } 356 }; 357 358 struct SignatureElement { 359 uint32_t NameOffset; 360 uint32_t IndicesOffset; 361 362 uint8_t Rows; 363 uint8_t StartRow; 364 uint8_t Cols : 4; 365 uint8_t StartCol : 2; 366 uint8_t Allocated : 1; 367 uint8_t Unused : 1; 368 SemanticKind Kind; 369 370 ComponentType Type; 371 InterpolationMode Mode; 372 uint8_t DynamicMask : 4; 373 uint8_t Stream : 2; 374 uint8_t Unused2 : 2; 375 uint8_t Reserved; 376 377 void swapBytes() { 378 sys::swapByteOrder(NameOffset); 379 sys::swapByteOrder(IndicesOffset); 380 } 381 }; 382 383 static_assert(sizeof(SignatureElement) == 4 * sizeof(uint32_t), 384 "PSV Signature elements must fit in 16 bytes."); 385 386 } // namespace v0 387 388 namespace v1 { 389 390 struct MeshRuntimeInfo { 391 uint8_t SigPrimVectors; // Primitive output for MS 392 uint8_t MeshOutputTopology; 393 }; 394 395 union GeometryExtraInfo { 396 uint16_t MaxVertexCount; // MaxVertexCount for GS only (max 1024) 397 uint8_t SigPatchConstOrPrimVectors; // Output for HS; Input for DS; 398 // Primitive output for MS (overlaps 399 // MeshInfo::SigPrimVectors) 400 MeshRuntimeInfo MeshInfo; 401 }; 402 struct RuntimeInfo : public v0::RuntimeInfo { 403 uint8_t ShaderStage; // PSVShaderKind 404 uint8_t UsesViewID; 405 GeometryExtraInfo GeomData; 406 407 // PSVSignatureElement counts 408 uint8_t SigInputElements; 409 uint8_t SigOutputElements; 410 uint8_t SigPatchOrPrimElements; 411 412 // Number of packed vectors per signature 413 uint8_t SigInputVectors; 414 uint8_t SigOutputVectors[4]; 415 416 void swapBytes() { 417 // nothing to swap since everything is single-byte or a union field 418 } 419 420 void swapBytes(Triple::EnvironmentType Stage) { 421 v0::RuntimeInfo::swapBytes(Stage); 422 if (Stage == Triple::EnvironmentType::Geometry) 423 sys::swapByteOrder(GeomData.MaxVertexCount); 424 } 425 }; 426 427 } // namespace v1 428 429 namespace v2 { 430 struct RuntimeInfo : public v1::RuntimeInfo { 431 uint32_t NumThreadsX; 432 uint32_t NumThreadsY; 433 uint32_t NumThreadsZ; 434 435 void swapBytes() { 436 sys::swapByteOrder(NumThreadsX); 437 sys::swapByteOrder(NumThreadsY); 438 sys::swapByteOrder(NumThreadsZ); 439 } 440 441 void swapBytes(Triple::EnvironmentType Stage) { 442 v1::RuntimeInfo::swapBytes(Stage); 443 } 444 }; 445 446 struct ResourceBindInfo : public v0::ResourceBindInfo { 447 ResourceKind Kind; 448 ResourceFlags Flags; 449 450 void swapBytes() { 451 v0::ResourceBindInfo::swapBytes(); 452 sys::swapByteOrder(Kind); 453 sys::swapByteOrder(Flags.Flags); 454 } 455 }; 456 457 } // namespace v2 458 459 namespace v3 { 460 struct RuntimeInfo : public v2::RuntimeInfo { 461 uint32_t EntryNameOffset; 462 463 void swapBytes() { 464 v2::RuntimeInfo::swapBytes(); 465 sys::swapByteOrder(EntryNameOffset); 466 } 467 468 void swapBytes(Triple::EnvironmentType Stage) { 469 v2::RuntimeInfo::swapBytes(Stage); 470 } 471 }; 472 473 } // namespace v3 474 } // namespace PSV 475 476 #define COMPONENT_PRECISION(Val, Enum) Enum = Val, 477 enum class SigMinPrecision : uint32_t { 478 #include "DXContainerConstants.def" 479 }; 480 481 ArrayRef<EnumEntry<SigMinPrecision>> getSigMinPrecisions(); 482 483 #define D3D_SYSTEM_VALUE(Val, Enum) Enum = Val, 484 enum class D3DSystemValue : uint32_t { 485 #include "DXContainerConstants.def" 486 }; 487 488 ArrayRef<EnumEntry<D3DSystemValue>> getD3DSystemValues(); 489 490 #define COMPONENT_TYPE(Val, Enum) Enum = Val, 491 enum class SigComponentType : uint32_t { 492 #include "DXContainerConstants.def" 493 }; 494 495 ArrayRef<EnumEntry<SigComponentType>> getSigComponentTypes(); 496 497 struct ProgramSignatureHeader { 498 uint32_t ParamCount; 499 uint32_t FirstParamOffset; 500 501 void swapBytes() { 502 sys::swapByteOrder(ParamCount); 503 sys::swapByteOrder(FirstParamOffset); 504 } 505 }; 506 507 struct ProgramSignatureElement { 508 uint32_t Stream; // Stream index (parameters must appear in non-decreasing 509 // stream order) 510 uint32_t NameOffset; // Offset from the start of the ProgramSignatureHeader to 511 // the start of the null terminated string for the name. 512 uint32_t Index; // Semantic Index 513 D3DSystemValue SystemValue; // Semantic type. Similar to PSV::SemanticKind. 514 SigComponentType CompType; // Type of bits. 515 uint32_t Register; // Register Index (row index) 516 uint8_t Mask; // Mask (column allocation) 517 518 // The ExclusiveMask has a different meaning for input and output signatures. 519 // For an output signature, masked components of the output register are never 520 // written to. 521 // For an input signature, masked components of the input register are always 522 // read. 523 uint8_t ExclusiveMask; 524 525 uint16_t Unused; 526 SigMinPrecision MinPrecision; // Minimum precision of input/output data 527 528 void swapBytes() { 529 sys::swapByteOrder(Stream); 530 sys::swapByteOrder(NameOffset); 531 sys::swapByteOrder(Index); 532 sys::swapByteOrder(SystemValue); 533 sys::swapByteOrder(CompType); 534 sys::swapByteOrder(Register); 535 sys::swapByteOrder(Mask); 536 sys::swapByteOrder(ExclusiveMask); 537 sys::swapByteOrder(MinPrecision); 538 } 539 }; 540 541 static_assert(sizeof(ProgramSignatureElement) == 32, 542 "ProgramSignatureElement is misaligned"); 543 544 } // namespace dxbc 545 } // namespace llvm 546 547 #endif // LLVM_BINARYFORMAT_DXCONTAINER_H 548