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