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 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 308 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 314 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 323 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 350 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 389 void swapBytes() { 390 // nothing to swap since everything is single-byte or a union field 391 } 392 393 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 408 void swapBytes() { 409 sys::swapByteOrder(NumThreadsX); 410 sys::swapByteOrder(NumThreadsY); 411 sys::swapByteOrder(NumThreadsZ); 412 } 413 414 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 423 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 436 void swapBytes() { 437 v2::RuntimeInfo::swapBytes(); 438 sys::swapByteOrder(EntryNameOffset); 439 } 440 441 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 474 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 501 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