DxilContainer.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilContainer.h //
  4. // Copyright (C) Microsoft Corporation. All rights reserved. //
  5. // This file is distributed under the University of Illinois Open Source //
  6. // License. See LICENSE.TXT for details. //
  7. // //
  8. // Provides declarations for the DXIL container format. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #pragma once
  12. #ifndef __DXC_CONTAINER__
  13. #define __DXC_CONTAINER__
  14. #include <stdint.h>
  15. #include <iterator>
  16. #include "dxc/DXIL/DxilConstants.h"
  17. #include "dxc/Support/WinAdapter.h"
  18. struct IDxcContainerReflection;
  19. namespace llvm { class Module; }
  20. namespace hlsl {
  21. class AbstractMemoryStream;
  22. class RootSignatureHandle;
  23. class DxilModule;
  24. #pragma pack(push, 1)
  25. static const size_t DxilContainerHashSize = 16;
  26. static const uint16_t DxilContainerVersionMajor = 1; // Current major version
  27. static const uint16_t DxilContainerVersionMinor = 0; // Current minor version
  28. static const uint32_t DxilContainerMaxSize = 0x80000000; // Max size for container.
  29. /// Use this type to represent the hash for the full container.
  30. struct DxilContainerHash {
  31. uint8_t Digest[DxilContainerHashSize];
  32. };
  33. enum class DxilShaderHashFlags : uint32_t {
  34. None = 0, // No flags defined.
  35. IncludesSource = 1, // This flag indicates that the shader hash was computed
  36. // taking into account source information (-Zss)
  37. };
  38. typedef struct DxilShaderHash {
  39. uint32_t Flags; // DxilShaderHashFlags
  40. uint8_t Digest[DxilContainerHashSize];
  41. } DxilShaderHash;
  42. struct DxilContainerVersion {
  43. uint16_t Major;
  44. uint16_t Minor;
  45. };
  46. /// Use this type to describe a DXIL container of parts.
  47. struct DxilContainerHeader {
  48. uint32_t HeaderFourCC;
  49. DxilContainerHash Hash;
  50. DxilContainerVersion Version;
  51. uint32_t ContainerSizeInBytes; // From start of this header
  52. uint32_t PartCount;
  53. // Structure is followed by uint32_t PartOffset[PartCount];
  54. // The offset is to a DxilPartHeader.
  55. };
  56. /// Use this type to describe the size and type of a DXIL container part.
  57. struct DxilPartHeader {
  58. uint32_t PartFourCC; // Four char code for part type.
  59. uint32_t PartSize; // Byte count for PartData.
  60. // Structure is followed by uint8_t PartData[PartSize].
  61. };
  62. #define DXIL_FOURCC(ch0, ch1, ch2, ch3) ( \
  63. (uint32_t)(uint8_t)(ch0) | (uint32_t)(uint8_t)(ch1) << 8 | \
  64. (uint32_t)(uint8_t)(ch2) << 16 | (uint32_t)(uint8_t)(ch3) << 24 \
  65. )
  66. enum DxilFourCC {
  67. DFCC_Container = DXIL_FOURCC('D', 'X', 'B', 'C'), // for back-compat with tools that look for DXBC containers
  68. DFCC_ResourceDef = DXIL_FOURCC('R', 'D', 'E', 'F'),
  69. DFCC_InputSignature = DXIL_FOURCC('I', 'S', 'G', '1'),
  70. DFCC_OutputSignature = DXIL_FOURCC('O', 'S', 'G', '1'),
  71. DFCC_PatchConstantSignature = DXIL_FOURCC('P', 'S', 'G', '1'),
  72. DFCC_ShaderStatistics = DXIL_FOURCC('S', 'T', 'A', 'T'),
  73. DFCC_ShaderDebugInfoDXIL = DXIL_FOURCC('I', 'L', 'D', 'B'),
  74. DFCC_ShaderDebugName = DXIL_FOURCC('I', 'L', 'D', 'N'),
  75. DFCC_FeatureInfo = DXIL_FOURCC('S', 'F', 'I', '0'),
  76. DFCC_PrivateData = DXIL_FOURCC('P', 'R', 'I', 'V'),
  77. DFCC_RootSignature = DXIL_FOURCC('R', 'T', 'S', '0'),
  78. DFCC_DXIL = DXIL_FOURCC('D', 'X', 'I', 'L'),
  79. DFCC_PipelineStateValidation = DXIL_FOURCC('P', 'S', 'V', '0'),
  80. DFCC_RuntimeData = DXIL_FOURCC('R', 'D', 'A', 'T'),
  81. DFCC_ShaderHash = DXIL_FOURCC('H', 'A', 'S', 'H'),
  82. };
  83. #undef DXIL_FOURCC
  84. struct DxilShaderFeatureInfo {
  85. uint64_t FeatureFlags;
  86. };
  87. // DXIL program information.
  88. struct DxilBitcodeHeader {
  89. uint32_t DxilMagic; // ACSII "DXIL".
  90. uint32_t DxilVersion; // DXIL version.
  91. uint32_t BitcodeOffset; // Offset to LLVM bitcode (from start of header).
  92. uint32_t BitcodeSize; // Size of LLVM bitcode.
  93. };
  94. static const uint32_t DxilMagicValue = 0x4C495844; // 'DXIL'
  95. struct DxilProgramHeader {
  96. uint32_t ProgramVersion; /// Major and minor version, including type.
  97. uint32_t SizeInUint32; /// Size in uint32_t units including this header.
  98. DxilBitcodeHeader BitcodeHeader; /// Bitcode-specific header.
  99. // Followed by uint8_t[BitcodeHeader.BitcodeOffset]
  100. };
  101. struct DxilProgramSignature {
  102. uint32_t ParamCount;
  103. uint32_t ParamOffset;
  104. };
  105. enum class DxilProgramSigMinPrecision : uint32_t {
  106. Default = 0,
  107. Float16 = 1,
  108. Float2_8 = 2,
  109. Reserved = 3,
  110. SInt16 = 4,
  111. UInt16 = 5,
  112. Any16 = 0xf0,
  113. Any10 = 0xf1
  114. };
  115. // Corresponds to D3D_NAME and D3D10_SB_NAME
  116. enum class DxilProgramSigSemantic : uint32_t {
  117. Undefined = 0,
  118. Position = 1,
  119. ClipDistance = 2,
  120. CullDistance = 3,
  121. RenderTargetArrayIndex = 4,
  122. ViewPortArrayIndex = 5,
  123. VertexID = 6,
  124. PrimitiveID = 7,
  125. InstanceID = 8,
  126. IsFrontFace = 9,
  127. SampleIndex = 10,
  128. FinalQuadEdgeTessfactor = 11,
  129. FinalQuadInsideTessfactor = 12,
  130. FinalTriEdgeTessfactor = 13,
  131. FinalTriInsideTessfactor = 14,
  132. FinalLineDetailTessfactor = 15,
  133. FinalLineDensityTessfactor = 16,
  134. Barycentrics = 23,
  135. ShadingRate = 24,
  136. CullPrimitive = 25,
  137. Target = 64,
  138. Depth = 65,
  139. Coverage = 66,
  140. DepthGE = 67,
  141. DepthLE = 68,
  142. StencilRef = 69,
  143. InnerCoverage = 70,
  144. };
  145. enum class DxilProgramSigCompType : uint32_t {
  146. Unknown = 0,
  147. UInt32 = 1,
  148. SInt32 = 2,
  149. Float32 = 3,
  150. UInt16 = 4,
  151. SInt16 = 5,
  152. Float16 = 6,
  153. UInt64 = 7,
  154. SInt64 = 8,
  155. Float64 = 9,
  156. };
  157. struct DxilProgramSignatureElement {
  158. uint32_t Stream; // Stream index (parameters must appear in non-decreasing stream order)
  159. uint32_t SemanticName; // Offset to LPCSTR from start of DxilProgramSignature.
  160. uint32_t SemanticIndex; // Semantic Index
  161. DxilProgramSigSemantic SystemValue; // Semantic type. Similar to DxilSemantic::Kind, but a serialized rather than processing rep.
  162. DxilProgramSigCompType CompType; // Type of bits.
  163. uint32_t Register; // Register Index (row index)
  164. uint8_t Mask; // Mask (column allocation)
  165. union // Unconditional cases useful for validation of shader linkage.
  166. {
  167. uint8_t NeverWrites_Mask; // For an output signature, the shader the signature belongs to never
  168. // writes the masked components of the output register.
  169. uint8_t AlwaysReads_Mask; // For an input signature, the shader the signature belongs to always
  170. // reads the masked components of the input register.
  171. };
  172. uint16_t Pad;
  173. DxilProgramSigMinPrecision MinPrecision; // Minimum precision of input/output data
  174. };
  175. // Easy to get this wrong. Earlier assertions can help determine
  176. static_assert(sizeof(DxilProgramSignatureElement) == 0x20, "else DxilProgramSignatureElement is misaligned");
  177. struct DxilShaderDebugName {
  178. uint16_t Flags; // Reserved, must be set to zero.
  179. uint16_t NameLength; // Length of the debug name, without null terminator.
  180. // Followed by NameLength bytes of the UTF-8-encoded name.
  181. // Followed by a null terminator.
  182. // Followed by [0-3] zero bytes to align to a 4-byte boundary.
  183. };
  184. static const size_t MinDxilShaderDebugNameSize = sizeof(DxilShaderDebugName) + 4;
  185. #pragma pack(pop)
  186. /// Gets a part header by index.
  187. inline const DxilPartHeader *
  188. GetDxilContainerPart(const DxilContainerHeader *pHeader, uint32_t index) {
  189. const uint8_t *pLinearContainer = reinterpret_cast<const uint8_t *>(pHeader);
  190. const uint32_t *pPartOffsetTable =
  191. reinterpret_cast<const uint32_t *>(pHeader + 1);
  192. return reinterpret_cast<const DxilPartHeader *>(
  193. pLinearContainer + pPartOffsetTable[index]);
  194. }
  195. /// Gets a part header by index.
  196. inline DxilPartHeader *GetDxilContainerPart(DxilContainerHeader *pHeader,
  197. uint32_t index) {
  198. return const_cast<DxilPartHeader *>(GetDxilContainerPart(
  199. reinterpret_cast<const DxilContainerHeader *>(pHeader), index));
  200. }
  201. /// Gets the part data from the header.
  202. inline const char *GetDxilPartData(const DxilPartHeader *pPart) {
  203. return reinterpret_cast<const char *>(pPart + 1);
  204. }
  205. /// Gets the part data from the header.
  206. inline char *GetDxilPartData(DxilPartHeader *pPart) {
  207. return reinterpret_cast<char *>(pPart + 1);
  208. }
  209. /// Gets a part header by fourCC
  210. DxilPartHeader *GetDxilPartByType(DxilContainerHeader *pHeader,
  211. DxilFourCC fourCC);
  212. /// Gets a part header by fourCC
  213. const DxilPartHeader *
  214. GetDxilPartByType(const DxilContainerHeader *pHeader,
  215. DxilFourCC fourCC);
  216. /// Returns valid DxilProgramHeader. nullptr if does not exist.
  217. DxilProgramHeader *GetDxilProgramHeader(DxilContainerHeader *pHeader, DxilFourCC fourCC);
  218. /// Returns valid DxilProgramHeader. nullptr if does not exist.
  219. const DxilProgramHeader *
  220. GetDxilProgramHeader(const DxilContainerHeader *pHeader, DxilFourCC fourCC);
  221. /// Initializes container with the specified values.
  222. void InitDxilContainer(_Out_ DxilContainerHeader *pHeader, uint32_t partCount,
  223. uint32_t containerSizeInBytes);
  224. /// Checks whether pHeader claims by signature to be a DXIL container
  225. /// and the length is at least sizeof(DxilContainerHeader).
  226. const DxilContainerHeader *IsDxilContainerLike(const void *ptr, size_t length);
  227. DxilContainerHeader *IsDxilContainerLike(void *ptr, size_t length);
  228. /// Checks whether the DXIL container is valid and in-bounds.
  229. bool IsValidDxilContainer(const DxilContainerHeader *pHeader, size_t length);
  230. /// Use this type as a unary predicate functor.
  231. struct DxilPartIsType {
  232. uint32_t IsFourCC;
  233. DxilPartIsType(uint32_t FourCC) : IsFourCC(FourCC) { }
  234. bool operator()(const DxilPartHeader *pPart) const {
  235. return pPart->PartFourCC == IsFourCC;
  236. }
  237. };
  238. /// Use this type as an iterator over the part headers.
  239. struct DxilPartIterator : public std::iterator<std::input_iterator_tag,
  240. const DxilContainerHeader *> {
  241. const DxilContainerHeader *pHeader;
  242. uint32_t index;
  243. DxilPartIterator(const DxilContainerHeader *h, uint32_t i)
  244. : pHeader(h), index(i) {}
  245. // increment
  246. DxilPartIterator &operator++() {
  247. ++index;
  248. return *this;
  249. }
  250. DxilPartIterator operator++(int) {
  251. DxilPartIterator result(pHeader, index);
  252. ++index;
  253. return result;
  254. }
  255. // input iterator - compare and deref
  256. bool operator==(const DxilPartIterator &other) const {
  257. return index == other.index && pHeader == other.pHeader;
  258. }
  259. bool operator!=(const DxilPartIterator &other) const {
  260. return index != other.index || pHeader != other.pHeader;
  261. }
  262. const DxilPartHeader *operator*() const {
  263. return GetDxilContainerPart(pHeader, index);
  264. }
  265. };
  266. DxilPartIterator begin(const DxilContainerHeader *pHeader);
  267. DxilPartIterator end(const DxilContainerHeader *pHeader);
  268. inline bool IsValidDxilBitcodeHeader(const DxilBitcodeHeader *pHeader,
  269. uint32_t length) {
  270. return length > sizeof(DxilBitcodeHeader) &&
  271. pHeader->BitcodeOffset + pHeader->BitcodeSize >
  272. pHeader->BitcodeOffset &&
  273. length >= pHeader->BitcodeOffset + pHeader->BitcodeSize &&
  274. pHeader->DxilMagic == DxilMagicValue;
  275. }
  276. inline void InitBitcodeHeader(DxilBitcodeHeader &header,
  277. uint32_t dxilVersion,
  278. uint32_t bitcodeSize) {
  279. header.DxilMagic = DxilMagicValue;
  280. header.DxilVersion = dxilVersion;
  281. header.BitcodeOffset = sizeof(DxilBitcodeHeader);
  282. header.BitcodeSize = bitcodeSize;
  283. }
  284. inline void GetDxilProgramBitcode(const DxilProgramHeader *pHeader,
  285. const char **pBitcode,
  286. uint32_t *pBitcodeLength) {
  287. *pBitcode = reinterpret_cast<const char *>(&pHeader->BitcodeHeader) +
  288. pHeader->BitcodeHeader.BitcodeOffset;
  289. *pBitcodeLength = pHeader->BitcodeHeader.BitcodeSize;
  290. }
  291. inline bool IsValidDxilProgramHeader(const DxilProgramHeader *pHeader,
  292. uint32_t length) {
  293. return length >= sizeof(DxilProgramHeader) &&
  294. length >= (pHeader->SizeInUint32 * sizeof(uint32_t)) &&
  295. IsValidDxilBitcodeHeader(
  296. &pHeader->BitcodeHeader,
  297. length - offsetof(DxilProgramHeader, BitcodeHeader));
  298. }
  299. inline void InitProgramHeader(DxilProgramHeader &header, uint32_t shaderVersion,
  300. uint32_t dxilVersion,
  301. uint32_t bitcodeSize) {
  302. header.ProgramVersion = shaderVersion;
  303. header.SizeInUint32 =
  304. sizeof(DxilProgramHeader) / sizeof(uint32_t) +
  305. bitcodeSize / sizeof(uint32_t) + ((bitcodeSize % 4) ? 1 : 0);
  306. InitBitcodeHeader(header.BitcodeHeader, dxilVersion, bitcodeSize);
  307. }
  308. inline const char *GetDxilBitcodeData(const DxilProgramHeader *pHeader) {
  309. const DxilBitcodeHeader *pBCHdr = &(pHeader->BitcodeHeader);
  310. return (const char *)pBCHdr + pBCHdr->BitcodeOffset;
  311. }
  312. inline uint32_t GetDxilBitcodeSize(const DxilProgramHeader *pHeader) {
  313. return pHeader->BitcodeHeader.BitcodeSize;
  314. }
  315. /// Extract the shader type from the program version value.
  316. inline DXIL::ShaderKind GetVersionShaderType(uint32_t programVersion) {
  317. return (DXIL::ShaderKind)((programVersion & 0xffff0000) >> 16);
  318. }
  319. inline uint32_t GetVersionMajor(uint32_t programVersion) {
  320. return (programVersion & 0xf0) >> 4;
  321. }
  322. inline uint32_t GetVersionMinor(uint32_t programVersion) {
  323. return (programVersion & 0xf);
  324. }
  325. inline uint32_t EncodeVersion(DXIL::ShaderKind shaderType, uint32_t major,
  326. uint32_t minor) {
  327. return ((unsigned)shaderType << 16) | (major << 4) | minor;
  328. }
  329. inline bool IsDxilShaderDebugNameValid(const DxilPartHeader *pPart) {
  330. if (pPart->PartFourCC != DFCC_ShaderDebugName) return false;
  331. if (pPart->PartSize < MinDxilShaderDebugNameSize) return false;
  332. const DxilShaderDebugName *pDebugNameContent = reinterpret_cast<const DxilShaderDebugName *>(GetDxilPartData(pPart));
  333. uint16_t ExpectedSize = sizeof(DxilShaderDebugName) + pDebugNameContent->NameLength + 1;
  334. if (ExpectedSize & 0x3) {
  335. ExpectedSize += 0x4;
  336. ExpectedSize &= ~(0x3);
  337. }
  338. if (pPart->PartSize != ExpectedSize) return false;
  339. return true;
  340. }
  341. inline bool GetDxilShaderDebugName(const DxilPartHeader *pDebugNamePart,
  342. const char **ppUtf8Name, _Out_opt_ uint16_t *pUtf8NameLen) {
  343. *ppUtf8Name = nullptr;
  344. if (!IsDxilShaderDebugNameValid(pDebugNamePart)) {
  345. return false;
  346. }
  347. const DxilShaderDebugName *pDebugNameContent = reinterpret_cast<const DxilShaderDebugName *>(GetDxilPartData(pDebugNamePart));
  348. if (pUtf8NameLen) {
  349. *pUtf8NameLen = pDebugNameContent->NameLength;
  350. }
  351. *ppUtf8Name = (const char *)(pDebugNameContent + 1);
  352. return true;
  353. }
  354. enum class SerializeDxilFlags : uint32_t {
  355. None = 0, // No flags defined.
  356. IncludeDebugInfoPart = 1 << 0, // Include the debug info part in the container.
  357. IncludeDebugNamePart = 1 << 1, // Include the debug name part in the container.
  358. DebugNameDependOnSource = 1 << 2, // Make the debug name depend on source (and not just final module).
  359. StripReflectionFromDxilPart = 1 << 3, // Strip Reflection info from DXIL part.
  360. IncludeReflectionPart = 1 << 4, // Include reflection in STAT part.
  361. StripRootSignature = 1 << 5, // Strip Root Signature from main shader container.
  362. };
  363. inline SerializeDxilFlags& operator |=(SerializeDxilFlags& l, const SerializeDxilFlags& r) {
  364. l = static_cast<SerializeDxilFlags>(static_cast<int>(l) | static_cast<int>(r));
  365. return l;
  366. }
  367. inline SerializeDxilFlags& operator &=(SerializeDxilFlags& l, const SerializeDxilFlags& r) {
  368. l = static_cast<SerializeDxilFlags>(static_cast<int>(l) & static_cast<int>(r));
  369. return l;
  370. }
  371. inline int operator&(SerializeDxilFlags l, SerializeDxilFlags r) {
  372. return static_cast<int>(l) & static_cast<int>(r);
  373. }
  374. inline SerializeDxilFlags operator~(SerializeDxilFlags l) {
  375. return static_cast<SerializeDxilFlags>(~static_cast<uint32_t>(l));
  376. }
  377. void CreateDxcContainerReflection(IDxcContainerReflection **ppResult);
  378. // Converts uint32_t partKind to char array object.
  379. inline char * PartKindToCharArray(uint32_t partKind, _Out_writes_(5) char* pText) {
  380. pText[0] = (char)((partKind & 0x000000FF) >> 0);
  381. pText[1] = (char)((partKind & 0x0000FF00) >> 8);
  382. pText[2] = (char)((partKind & 0x00FF0000) >> 16);
  383. pText[3] = (char)((partKind & 0xFF000000) >> 24);
  384. pText[4] = '\0';
  385. return pText;
  386. }
  387. inline size_t GetOffsetTableSize(uint32_t partCount) {
  388. return sizeof(uint32_t) * partCount;
  389. }
  390. // Compute total size of the dxil container from parts information
  391. inline size_t GetDxilContainerSizeFromParts(uint32_t partCount, uint32_t partsSize) {
  392. return partsSize + (uint32_t)sizeof(DxilContainerHeader) +
  393. GetOffsetTableSize(partCount) +
  394. (uint32_t)sizeof(DxilPartHeader) * partCount;
  395. }
  396. } // namespace hlsl
  397. #endif // __DXC_CONTAINER__