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 MajorVersion; // DXIL version. 107 uint8_t MinorVersion; // 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 MinorVersion : 4; 123 uint8_t MajorVersion : 4; 124 uint8_t Unused; 125 uint16_t ShaderKind; 126 uint32_t Size; // Size in uint32_t words including this header. 127 BitcodeHeader Bitcode; 128 129 void swapBytes() { 130 sys::swapByteOrder(ShaderKind); 131 sys::swapByteOrder(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_FLAG(Num, 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(InputControlPointCount); 170 sys::swapByteOrder(OutputControlPointCount); 171 sys::swapByteOrder(TessellatorDomain); 172 sys::swapByteOrder(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(InputControlPointCount); 184 sys::swapByteOrder(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(InputPrimitive); 197 sys::swapByteOrder(OutputTopology); 198 sys::swapByteOrder(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(GroupSharedBytesUsed); 221 sys::swapByteOrder(GroupSharedBytesDependentOnViewID); 222 sys::swapByteOrder(PayloadSizeInBytes); 223 sys::swapByteOrder(MaxOutputVertices); 224 sys::swapByteOrder(MaxOutputPrimitives); 225 } 226 }; 227 228 struct AmplificationPSVInfo { 229 uint32_t PayloadSizeInBytes; 230 231 void swapBytes() { sys::swapByteOrder(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(MinimumWaveLaneCount); 307 sys::swapByteOrder(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(Type); 321 sys::swapByteOrder(Space); 322 sys::swapByteOrder(LowerBound); 323 sys::swapByteOrder(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(NameOffset); 348 sys::swapByteOrder(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 GeometryExtraInfo { 365 uint16_t MaxVertexCount; // MaxVertexCount for GS only (max 1024) 366 uint8_t SigPatchConstOrPrimVectors; // Output for HS; Input for DS; 367 // Primitive output for MS (overlaps 368 // MeshInfo::SigPrimVectors) 369 MeshRuntimeInfo MeshInfo; 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(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(NumThreadsX); 406 sys::swapByteOrder(NumThreadsY); 407 sys::swapByteOrder(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(Kind); 422 sys::swapByteOrder(Flags); 423 } 424 }; 425 426 } // namespace v2 427 } // namespace PSV 428 429 #define COMPONENT_PRECISION(Val, Enum) Enum = Val, 430 enum class SigMinPrecision : uint32_t { 431 #include "DXContainerConstants.def" 432 }; 433 434 ArrayRef<EnumEntry<SigMinPrecision>> getSigMinPrecisions(); 435 436 #define D3D_SYSTEM_VALUE(Val, Enum) Enum = Val, 437 enum class D3DSystemValue : uint32_t { 438 #include "DXContainerConstants.def" 439 }; 440 441 ArrayRef<EnumEntry<D3DSystemValue>> getD3DSystemValues(); 442 443 #define COMPONENT_TYPE(Val, Enum) Enum = Val, 444 enum class SigComponentType : uint32_t { 445 #include "DXContainerConstants.def" 446 }; 447 448 ArrayRef<EnumEntry<SigComponentType>> getSigComponentTypes(); 449 450 struct ProgramSignatureHeader { 451 uint32_t ParamCount; 452 uint32_t FirstParamOffset; 453 454 void swapBytes() { 455 sys::swapByteOrder(ParamCount); 456 sys::swapByteOrder(FirstParamOffset); 457 } 458 }; 459 460 struct ProgramSignatureElement { 461 uint32_t Stream; // Stream index (parameters must appear in non-decreasing 462 // stream order) 463 uint32_t NameOffset; // Offset from the start of the ProgramSignatureHeader to 464 // the start of the null terminated string for the name. 465 uint32_t Index; // Semantic Index 466 D3DSystemValue SystemValue; // Semantic type. Similar to PSV::SemanticKind. 467 SigComponentType CompType; // Type of bits. 468 uint32_t Register; // Register Index (row index) 469 uint8_t Mask; // Mask (column allocation) 470 471 // The ExclusiveMask has a different meaning for input and output signatures. 472 // For an output signature, masked components of the output register are never 473 // written to. 474 // For an input signature, masked components of the input register are always 475 // read. 476 uint8_t ExclusiveMask; 477 478 uint16_t Unused; 479 SigMinPrecision MinPrecision; // Minimum precision of input/output data 480 481 void swapBytes() { 482 sys::swapByteOrder(Stream); 483 sys::swapByteOrder(NameOffset); 484 sys::swapByteOrder(Index); 485 sys::swapByteOrder(SystemValue); 486 sys::swapByteOrder(CompType); 487 sys::swapByteOrder(Register); 488 sys::swapByteOrder(Mask); 489 sys::swapByteOrder(ExclusiveMask); 490 sys::swapByteOrder(MinPrecision); 491 } 492 }; 493 494 static_assert(sizeof(ProgramSignatureElement) == 32, 495 "ProgramSignatureElement is misaligned"); 496 497 } // namespace dxbc 498 } // namespace llvm 499 500 #endif // LLVM_BINARYFORMAT_DXCONTAINER_H 501