DxilPipelineStateValidation.h 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilPipelineStateValidation.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. // Defines data used by the D3D runtime for PSO validation. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #ifndef __DXIL_PIPELINE_STATE_VALIDATION__H__
  12. #define __DXIL_PIPELINE_STATE_VALIDATION__H__
  13. #include <stdint.h>
  14. #include <string.h>
  15. // Don't include assert.h here.
  16. // Since this header is included from multiple environments,
  17. // it is necessary to define assert before this header is included.
  18. // #include <assert.h>
  19. #ifndef UINT_MAX
  20. #define UINT_MAX 0xffffffff
  21. #endif
  22. // How many dwords are required for mask with one bit per component, 4 components per vector
  23. inline uint32_t PSVComputeMaskDwordsFromVectors(uint32_t Vectors) { return (Vectors + 7) >> 3; }
  24. inline uint32_t PSVComputeInputOutputTableDwords(uint32_t InputVectors, uint32_t OutputVectors) {
  25. return PSVComputeMaskDwordsFromVectors(OutputVectors) * InputVectors * 4;
  26. }
  27. #define PSVALIGN(ptr, alignbits) (((ptr) + ((1 << (alignbits))-1)) & ~((1 << (alignbits))-1))
  28. #define PSVALIGN4(ptr) (((ptr) + 3) & ~3)
  29. #ifdef DBG
  30. #define PSV_RETB(exp) do { if(!(exp)) { assert(false && #exp); return false; } } while(0)
  31. #else // DBG
  32. #define PSV_RETB(exp) do { if(!(exp)) { return false; } } while(0)
  33. #endif // DBG
  34. struct VSInfo {
  35. char OutputPositionPresent;
  36. };
  37. struct HSInfo {
  38. uint32_t InputControlPointCount; // max control points == 32
  39. uint32_t OutputControlPointCount; // max control points == 32
  40. uint32_t TessellatorDomain; // hlsl::DXIL::TessellatorDomain/D3D11_SB_TESSELLATOR_DOMAIN
  41. uint32_t TessellatorOutputPrimitive; // hlsl::DXIL::TessellatorOutputPrimitive/D3D11_SB_TESSELLATOR_OUTPUT_PRIMITIVE
  42. };
  43. struct DSInfo {
  44. uint32_t InputControlPointCount; // max control points == 32
  45. char OutputPositionPresent;
  46. uint32_t TessellatorDomain; // hlsl::DXIL::TessellatorDomain/D3D11_SB_TESSELLATOR_DOMAIN
  47. };
  48. struct GSInfo {
  49. uint32_t InputPrimitive; // hlsl::DXIL::InputPrimitive/D3D10_SB_PRIMITIVE
  50. uint32_t OutputTopology; // hlsl::DXIL::PrimitiveTopology/D3D10_SB_PRIMITIVE_TOPOLOGY
  51. uint32_t OutputStreamMask; // max streams == 4
  52. char OutputPositionPresent;
  53. };
  54. struct PSInfo {
  55. char DepthOutput;
  56. char SampleFrequency;
  57. };
  58. struct MSInfo {
  59. uint32_t GroupSharedBytesUsed;
  60. uint32_t GroupSharedBytesDependentOnViewID;
  61. uint32_t PayloadSizeInBytes;
  62. uint16_t MaxOutputVertices;
  63. uint16_t MaxOutputPrimitives;
  64. };
  65. struct ASInfo {
  66. uint32_t PayloadSizeInBytes;
  67. };
  68. struct MSInfo1 {
  69. uint8_t SigPrimVectors; // Primitive output for MS
  70. uint8_t MeshOutputTopology;
  71. };
  72. // Versioning is additive and based on size
  73. struct PSVRuntimeInfo0
  74. {
  75. union {
  76. VSInfo VS;
  77. HSInfo HS;
  78. DSInfo DS;
  79. GSInfo GS;
  80. PSInfo PS;
  81. MSInfo MS;
  82. ASInfo AS;
  83. };
  84. uint32_t MinimumExpectedWaveLaneCount; // minimum lane count required, 0 if unused
  85. uint32_t MaximumExpectedWaveLaneCount; // maximum lane count required, 0xffffffff if unused
  86. };
  87. enum class PSVShaderKind : uint8_t // DXIL::ShaderKind
  88. {
  89. Pixel = 0,
  90. Vertex,
  91. Geometry,
  92. Hull,
  93. Domain,
  94. Compute,
  95. Library,
  96. RayGeneration,
  97. Intersection,
  98. AnyHit,
  99. ClosestHit,
  100. Miss,
  101. Callable,
  102. Mesh,
  103. Amplification,
  104. Invalid,
  105. };
  106. struct PSVRuntimeInfo1 : public PSVRuntimeInfo0
  107. {
  108. uint8_t ShaderStage; // PSVShaderKind
  109. uint8_t UsesViewID;
  110. union {
  111. uint16_t MaxVertexCount; // MaxVertexCount for GS only (max 1024)
  112. uint8_t SigPatchConstOrPrimVectors; // Output for HS; Input for DS; Primitive output for MS (overlaps MS1::SigPrimVectors)
  113. struct MSInfo1 MS1;
  114. };
  115. // PSVSignatureElement counts
  116. uint8_t SigInputElements;
  117. uint8_t SigOutputElements;
  118. uint8_t SigPatchConstOrPrimElements;
  119. // Number of packed vectors per signature
  120. uint8_t SigInputVectors;
  121. uint8_t SigOutputVectors[4]; // Array for GS Stream Out Index
  122. };
  123. struct PSVRuntimeInfo2 : public PSVRuntimeInfo1
  124. {
  125. uint32_t NumThreadsX;
  126. uint32_t NumThreadsY;
  127. uint32_t NumThreadsZ;
  128. };
  129. enum class PSVResourceType
  130. {
  131. Invalid = 0,
  132. Sampler,
  133. CBV,
  134. SRVTyped,
  135. SRVRaw,
  136. SRVStructured,
  137. UAVTyped,
  138. UAVRaw,
  139. UAVStructured,
  140. UAVStructuredWithCounter,
  141. NumEntries
  142. };
  143. enum class PSVResourceKind
  144. {
  145. Invalid = 0,
  146. Texture1D,
  147. Texture2D,
  148. Texture2DMS,
  149. Texture3D,
  150. TextureCube,
  151. Texture1DArray,
  152. Texture2DArray,
  153. Texture2DMSArray,
  154. TextureCubeArray,
  155. TypedBuffer,
  156. RawBuffer,
  157. StructuredBuffer,
  158. CBuffer,
  159. Sampler,
  160. TBuffer,
  161. RTAccelerationStructure,
  162. FeedbackTexture2D,
  163. FeedbackTexture2DArray,
  164. NumEntries
  165. };
  166. enum class PSVResourceFlag
  167. {
  168. None = 0x00000000,
  169. UsedByAtomic64 = 0x00000001,
  170. };
  171. // Table of null-terminated strings, overall size aligned to dword boundary, last byte must be null
  172. struct PSVStringTable {
  173. const char *Table;
  174. uint32_t Size;
  175. PSVStringTable() : Table(nullptr), Size(0) {}
  176. PSVStringTable(const char *table, uint32_t size) : Table(table), Size(size) {}
  177. const char *Get(uint32_t offset) const {
  178. _Analysis_assume_(offset < Size && Table && Table[Size-1] == '\0');
  179. return Table + offset;
  180. }
  181. };
  182. // Versioning is additive and based on size
  183. struct PSVResourceBindInfo0
  184. {
  185. uint32_t ResType; // PSVResourceType
  186. uint32_t Space;
  187. uint32_t LowerBound;
  188. uint32_t UpperBound;
  189. };
  190. struct PSVResourceBindInfo1 : public PSVResourceBindInfo0
  191. {
  192. uint32_t ResKind; // PSVResourceKind
  193. uint32_t ResFlags; // special characteristics of the resource
  194. };
  195. // Helpers for output dependencies (ViewID and Input-Output tables)
  196. struct PSVComponentMask {
  197. uint32_t *Mask;
  198. uint32_t NumVectors;
  199. PSVComponentMask() : Mask(nullptr), NumVectors(0) {}
  200. PSVComponentMask(const PSVComponentMask &other) : Mask(other.Mask), NumVectors(other.NumVectors) {}
  201. PSVComponentMask(uint32_t *pMask, uint32_t outputVectors)
  202. : Mask(pMask),
  203. NumVectors(outputVectors)
  204. {}
  205. const PSVComponentMask &operator|=(const PSVComponentMask &other) {
  206. uint32_t dwords = PSVComputeMaskDwordsFromVectors(NumVectors < other.NumVectors ? NumVectors : other.NumVectors);
  207. for (uint32_t i = 0; i < dwords; ++i) {
  208. Mask[i] |= other.Mask[i];
  209. }
  210. return *this;
  211. }
  212. bool Get(uint32_t ComponentIndex) const {
  213. if(ComponentIndex < NumVectors * 4)
  214. return (bool)(Mask[ComponentIndex >> 5] & (1 << (ComponentIndex & 0x1F)));
  215. return false;
  216. }
  217. void Set(uint32_t ComponentIndex) {
  218. if (ComponentIndex < NumVectors * 4)
  219. Mask[ComponentIndex >> 5] |= (1 << (ComponentIndex & 0x1F));
  220. }
  221. void Clear(uint32_t ComponentIndex) {
  222. if (ComponentIndex < NumVectors * 4)
  223. Mask[ComponentIndex >> 5] &= ~(1 << (ComponentIndex & 0x1F));
  224. }
  225. bool IsValid() { return Mask != nullptr; }
  226. };
  227. struct PSVDependencyTable {
  228. uint32_t *Table;
  229. uint32_t InputVectors;
  230. uint32_t OutputVectors;
  231. PSVDependencyTable() : Table(nullptr), InputVectors(0), OutputVectors(0) {}
  232. PSVDependencyTable(const PSVDependencyTable &other) : Table(other.Table), InputVectors(other.InputVectors), OutputVectors(other.OutputVectors) {}
  233. PSVDependencyTable(uint32_t *pTable, uint32_t inputVectors, uint32_t outputVectors)
  234. : Table(pTable),
  235. InputVectors(inputVectors),
  236. OutputVectors(outputVectors)
  237. {}
  238. PSVComponentMask GetMaskForInput(uint32_t inputComponentIndex) {
  239. if (!Table || !InputVectors || !OutputVectors)
  240. return PSVComponentMask();
  241. return PSVComponentMask(Table + (PSVComputeMaskDwordsFromVectors(OutputVectors) * inputComponentIndex), OutputVectors);
  242. }
  243. bool IsValid() { return Table != nullptr; }
  244. };
  245. struct PSVString {
  246. uint32_t Offset;
  247. PSVString() : Offset(0) {}
  248. PSVString(uint32_t offset) : Offset(offset) {}
  249. const char *Get(const PSVStringTable &table) const { return table.Get(Offset); }
  250. };
  251. struct PSVSemanticIndexTable {
  252. const uint32_t *Table;
  253. uint32_t Entries;
  254. PSVSemanticIndexTable() : Table(nullptr), Entries(0) {}
  255. PSVSemanticIndexTable(const uint32_t *table, uint32_t entries) : Table(table), Entries(entries) {}
  256. const uint32_t *Get(uint32_t offset) const {
  257. _Analysis_assume_(offset < Entries && Table);
  258. return Table + offset;
  259. }
  260. };
  261. struct PSVSemanticIndexes {
  262. uint32_t Offset;
  263. PSVSemanticIndexes() : Offset(0) {}
  264. PSVSemanticIndexes(uint32_t offset) : Offset(offset) {}
  265. const uint32_t *Get(const PSVSemanticIndexTable &table) const { return table.Get(Offset); }
  266. };
  267. enum class PSVSemanticKind : uint8_t // DXIL::SemanticKind
  268. {
  269. Arbitrary,
  270. VertexID,
  271. InstanceID,
  272. Position,
  273. RenderTargetArrayIndex,
  274. ViewPortArrayIndex,
  275. ClipDistance,
  276. CullDistance,
  277. OutputControlPointID,
  278. DomainLocation,
  279. PrimitiveID,
  280. GSInstanceID,
  281. SampleIndex,
  282. IsFrontFace,
  283. Coverage,
  284. InnerCoverage,
  285. Target,
  286. Depth,
  287. DepthLessEqual,
  288. DepthGreaterEqual,
  289. StencilRef,
  290. DispatchThreadID,
  291. GroupID,
  292. GroupIndex,
  293. GroupThreadID,
  294. TessFactor,
  295. InsideTessFactor,
  296. ViewID,
  297. Barycentrics,
  298. ShadingRate,
  299. CullPrimitive,
  300. Invalid,
  301. };
  302. struct PSVSignatureElement0
  303. {
  304. uint32_t SemanticName; // Offset into StringTable
  305. uint32_t SemanticIndexes; // Offset into PSVSemanticIndexTable, count == Rows
  306. uint8_t Rows; // Number of rows this element occupies
  307. uint8_t StartRow; // Starting row of packing location if allocated
  308. uint8_t ColsAndStart; // 0:4 = Cols, 4:6 = StartCol, 6:7 == Allocated
  309. uint8_t SemanticKind; // PSVSemanticKind
  310. uint8_t ComponentType; // DxilProgramSigCompType
  311. uint8_t InterpolationMode; // DXIL::InterpolationMode or D3D10_SB_INTERPOLATION_MODE
  312. uint8_t DynamicMaskAndStream; // 0:4 = DynamicIndexMask, 4:6 = OutputStream (0-3)
  313. uint8_t Reserved;
  314. };
  315. // Provides convenient access to packed PSVSignatureElementN structure
  316. class PSVSignatureElement
  317. {
  318. private:
  319. const PSVStringTable &m_StringTable;
  320. const PSVSemanticIndexTable &m_SemanticIndexTable;
  321. const PSVSignatureElement0 *m_pElement0;
  322. public:
  323. PSVSignatureElement(const PSVStringTable &stringTable, const PSVSemanticIndexTable &semanticIndexTable, const PSVSignatureElement0 *pElement0)
  324. : m_StringTable(stringTable), m_SemanticIndexTable(semanticIndexTable), m_pElement0(pElement0) {}
  325. const char *GetSemanticName() const { return !m_pElement0 ? "" : m_StringTable.Get(m_pElement0->SemanticName); }
  326. const uint32_t *GetSemanticIndexes() const { return !m_pElement0 ? nullptr: m_SemanticIndexTable.Get(m_pElement0->SemanticIndexes); }
  327. uint32_t GetRows() const { return !m_pElement0 ? 0 : ((uint32_t)m_pElement0->Rows); }
  328. uint32_t GetCols() const { return !m_pElement0 ? 0 : ((uint32_t)m_pElement0->ColsAndStart & 0xF); }
  329. bool IsAllocated() const { return !m_pElement0 ? false : !!(m_pElement0->ColsAndStart & 0x40); }
  330. int32_t GetStartRow() const { return !m_pElement0 ? 0 : !IsAllocated() ? -1 : (int32_t)m_pElement0->StartRow; }
  331. int32_t GetStartCol() const { return !m_pElement0 ? 0 : !IsAllocated() ? -1 : (int32_t)((m_pElement0->ColsAndStart >> 4) & 0x3); }
  332. PSVSemanticKind GetSemanticKind() const { return !m_pElement0 ? (PSVSemanticKind)0 : (PSVSemanticKind)m_pElement0->SemanticKind; }
  333. uint32_t GetComponentType() const { return !m_pElement0 ? 0 : (uint32_t)m_pElement0->ComponentType; }
  334. uint32_t GetInterpolationMode() const { return !m_pElement0 ? 0 : (uint32_t)m_pElement0->InterpolationMode; }
  335. uint32_t GetOutputStream() const { return !m_pElement0 ? 0 : (uint32_t)(m_pElement0->DynamicMaskAndStream >> 4) & 0x3; }
  336. uint32_t GetDynamicIndexMask() const { return !m_pElement0 ? 0 : (uint32_t)m_pElement0->DynamicMaskAndStream & 0xF; }
  337. };
  338. #define MAX_PSV_VERSION 2
  339. struct PSVInitInfo
  340. {
  341. PSVInitInfo(uint32_t psvVersion)
  342. : PSVVersion(psvVersion)
  343. {}
  344. uint32_t PSVVersion = 0;
  345. uint32_t ResourceCount = 0;
  346. PSVShaderKind ShaderStage = PSVShaderKind::Invalid;
  347. PSVStringTable StringTable;
  348. PSVSemanticIndexTable SemanticIndexTable;
  349. uint8_t UsesViewID = 0;
  350. uint8_t SigInputElements = 0;
  351. uint8_t SigOutputElements = 0;
  352. uint8_t SigPatchConstOrPrimElements = 0;
  353. uint8_t SigInputVectors = 0;
  354. uint8_t SigPatchConstOrPrimVectors = 0;
  355. uint8_t SigOutputVectors[4] = {0, 0, 0, 0};
  356. static_assert(MAX_PSV_VERSION == 2, "otherwise this needs updating.");
  357. uint32_t RuntimeInfoSize() const {
  358. switch (PSVVersion) {
  359. case 0: return sizeof(PSVRuntimeInfo0);
  360. case 1: return sizeof(PSVRuntimeInfo1);
  361. default: break;
  362. }
  363. return sizeof(PSVRuntimeInfo2);
  364. }
  365. uint32_t ResourceBindInfoSize() const {
  366. if (PSVVersion < 2)
  367. return sizeof(PSVResourceBindInfo0);
  368. return sizeof(PSVResourceBindInfo1);
  369. }
  370. uint32_t SignatureElementSize() const {
  371. return sizeof(PSVSignatureElement0);
  372. }
  373. };
  374. class DxilPipelineStateValidation
  375. {
  376. uint32_t m_uPSVRuntimeInfoSize = 0;
  377. PSVRuntimeInfo0* m_pPSVRuntimeInfo0 = nullptr;
  378. PSVRuntimeInfo1 *m_pPSVRuntimeInfo1 = nullptr;
  379. PSVRuntimeInfo2 *m_pPSVRuntimeInfo2 = nullptr;
  380. uint32_t m_uResourceCount = 0;
  381. uint32_t m_uPSVResourceBindInfoSize = 0;
  382. void *m_pPSVResourceBindInfo = nullptr;
  383. PSVStringTable m_StringTable;
  384. PSVSemanticIndexTable m_SemanticIndexTable;
  385. uint32_t m_uPSVSignatureElementSize = 0;
  386. void *m_pSigInputElements = nullptr;
  387. void *m_pSigOutputElements = nullptr;
  388. void *m_pSigPatchConstOrPrimElements = nullptr;
  389. uint32_t *m_pViewIDOutputMask = nullptr;
  390. uint32_t *m_pViewIDPCOrPrimOutputMask = nullptr;
  391. uint32_t *m_pInputToOutputTable = nullptr;
  392. uint32_t *m_pInputToPCOutputTable = nullptr;
  393. uint32_t *m_pPCInputToOutputTable = nullptr;
  394. public:
  395. DxilPipelineStateValidation() {}
  396. enum class RWMode {
  397. Read,
  398. CalcSize,
  399. Write,
  400. };
  401. class CheckedReaderWriter {
  402. private:
  403. char *Ptr;
  404. uint32_t Size;
  405. uint32_t Offset;
  406. RWMode Mode;
  407. public:
  408. CheckedReaderWriter(const void *ptr, uint32_t size, RWMode mode)
  409. : Ptr(reinterpret_cast<char*>(const_cast<void*>(ptr))),
  410. Size(mode == RWMode::CalcSize ? 0 : size), Offset(0), Mode(mode) {}
  411. uint32_t GetSize() { return Size; }
  412. RWMode GetMode() { return Mode; }
  413. // Return true if size fits in remaing buffer.
  414. bool CheckBounds(size_t size);
  415. // Increment Offset by size. Return false on error.
  416. bool IncrementPos(size_t size);
  417. // Cast and return true if it fits.
  418. template <typename _T> bool Cast(_T **ppPtr, size_t size);
  419. template <typename _T> bool Cast(_T **ppPtr);
  420. // Map* methods increment Offset.
  421. // Assign pointer, increment Offset, and return true if size fits.
  422. template<typename _T> bool MapPtr(_T **ppPtr, size_t size = 0);
  423. // Read value, increment Offset, and return true if value fits.
  424. template <typename _T> bool MapValue(_T *pValue, const _T init = {});
  425. // Assign pointer, increment Offset, and return true if array fits.
  426. template <typename _T>
  427. bool MapArray(_T **ppPtr, size_t count, size_t eltSize);
  428. //template <> bool MapArray<void>(void **ppPtr, size_t count, size_t eltSize);
  429. // Assign pointer, increment Offset, and return true if array fits.
  430. template <typename _T> bool MapArray(_T **ppPtr, size_t count = 1);
  431. void Clear();
  432. };
  433. // Assigned derived ptr to base if size large enough.
  434. template<typename _Base, typename _T>
  435. bool AssignDerived(_T** ppDerived, _Base* pBase, uint32_t size) {
  436. if ((size_t)size < sizeof(_T))
  437. return false; // size not large enough for type
  438. *ppDerived = reinterpret_cast<_T *>(pBase);
  439. return true;
  440. }
  441. private:
  442. bool ReadOrWrite(const void *pBits, uint32_t *pSize, RWMode mode,
  443. const PSVInitInfo &initInfo = PSVInitInfo(MAX_PSV_VERSION));
  444. public:
  445. bool InitFromPSV0(const void* pBits, uint32_t size) {
  446. return ReadOrWrite(pBits, &size, RWMode::Read);
  447. }
  448. // Initialize a new buffer
  449. // call with null pBuffer to get required size
  450. bool InitNew(uint32_t ResourceCount, void *pBuffer, uint32_t *pSize) {
  451. PSVInitInfo initInfo(0);
  452. initInfo.ResourceCount = ResourceCount;
  453. return InitNew(initInfo, pBuffer, pSize);
  454. }
  455. bool InitNew(const PSVInitInfo &initInfo, void *pBuffer, uint32_t *pSize) {
  456. RWMode Mode = nullptr != pBuffer ? RWMode::Write : RWMode::CalcSize;
  457. return ReadOrWrite(pBuffer, pSize, Mode, initInfo);
  458. }
  459. PSVRuntimeInfo0* GetPSVRuntimeInfo0() const {
  460. return m_pPSVRuntimeInfo0;
  461. }
  462. PSVRuntimeInfo1* GetPSVRuntimeInfo1() const {
  463. return m_pPSVRuntimeInfo1;
  464. }
  465. PSVRuntimeInfo2* GetPSVRuntimeInfo2() const {
  466. return m_pPSVRuntimeInfo2;
  467. }
  468. uint32_t GetBindCount() const {
  469. return m_uResourceCount;
  470. }
  471. template <typename _T>
  472. _T *GetRecord(void *pRecords, uint32_t recordSize, uint32_t numRecords,
  473. uint32_t index) const {
  474. if (pRecords && index < numRecords && sizeof(_T) <= recordSize) {
  475. __analysis_assume((size_t)index * (size_t)recordSize <= UINT_MAX);
  476. return reinterpret_cast<_T *>(reinterpret_cast<uint8_t *>(pRecords) +
  477. (index * recordSize));
  478. }
  479. return nullptr;
  480. }
  481. PSVResourceBindInfo0* GetPSVResourceBindInfo0(uint32_t index) const {
  482. return GetRecord<PSVResourceBindInfo0>(m_pPSVResourceBindInfo,
  483. m_uPSVResourceBindInfoSize,
  484. m_uResourceCount, index);
  485. }
  486. PSVResourceBindInfo1* GetPSVResourceBindInfo1(uint32_t index) const {
  487. return GetRecord<PSVResourceBindInfo1>(m_pPSVResourceBindInfo,
  488. m_uPSVResourceBindInfoSize,
  489. m_uResourceCount, index);
  490. }
  491. const PSVStringTable &GetStringTable() const { return m_StringTable; }
  492. const PSVSemanticIndexTable &GetSemanticIndexTable() const { return m_SemanticIndexTable; }
  493. // Signature element access
  494. uint32_t GetSigInputElements() const {
  495. if (m_pPSVRuntimeInfo1)
  496. return m_pPSVRuntimeInfo1->SigInputElements;
  497. return 0;
  498. }
  499. uint32_t GetSigOutputElements() const {
  500. if (m_pPSVRuntimeInfo1)
  501. return m_pPSVRuntimeInfo1->SigOutputElements;
  502. return 0;
  503. }
  504. uint32_t GetSigPatchConstOrPrimElements() const {
  505. if (m_pPSVRuntimeInfo1)
  506. return m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements;
  507. return 0;
  508. }
  509. PSVSignatureElement0* GetInputElement0(uint32_t index) const {
  510. return GetRecord<PSVSignatureElement0>(
  511. m_pSigInputElements, m_uPSVSignatureElementSize,
  512. m_pPSVRuntimeInfo1 ? m_pPSVRuntimeInfo1->SigInputElements : 0, index);
  513. }
  514. PSVSignatureElement0* GetOutputElement0(uint32_t index) const {
  515. return GetRecord<PSVSignatureElement0>(
  516. m_pSigOutputElements, m_uPSVSignatureElementSize,
  517. m_pPSVRuntimeInfo1 ? m_pPSVRuntimeInfo1->SigOutputElements : 0, index);
  518. }
  519. PSVSignatureElement0* GetPatchConstOrPrimElement0(uint32_t index) const {
  520. return GetRecord<PSVSignatureElement0>(
  521. m_pSigPatchConstOrPrimElements, m_uPSVSignatureElementSize,
  522. m_pPSVRuntimeInfo1 ? m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements : 0, index);
  523. }
  524. // More convenient wrapper:
  525. PSVSignatureElement GetSignatureElement(PSVSignatureElement0* pElement0) const {
  526. return PSVSignatureElement(m_StringTable, m_SemanticIndexTable, pElement0);
  527. }
  528. PSVShaderKind GetShaderKind() const {
  529. if (m_pPSVRuntimeInfo1 && m_pPSVRuntimeInfo1->ShaderStage < (uint8_t)PSVShaderKind::Invalid)
  530. return (PSVShaderKind)m_pPSVRuntimeInfo1->ShaderStage;
  531. return PSVShaderKind::Invalid;
  532. }
  533. bool IsVS() const { return GetShaderKind() == PSVShaderKind::Vertex; }
  534. bool IsHS() const { return GetShaderKind() == PSVShaderKind::Hull; }
  535. bool IsDS() const { return GetShaderKind() == PSVShaderKind::Domain; }
  536. bool IsGS() const { return GetShaderKind() == PSVShaderKind::Geometry; }
  537. bool IsPS() const { return GetShaderKind() == PSVShaderKind::Pixel; }
  538. bool IsCS() const { return GetShaderKind() == PSVShaderKind::Compute; }
  539. bool IsMS() const { return GetShaderKind() == PSVShaderKind::Mesh; }
  540. bool IsAS() const { return GetShaderKind() == PSVShaderKind::Amplification; }
  541. // ViewID dependencies
  542. PSVComponentMask GetViewIDOutputMask(unsigned streamIndex = 0) const {
  543. if (!m_pViewIDOutputMask || !m_pPSVRuntimeInfo1 || !m_pPSVRuntimeInfo1->SigOutputVectors[streamIndex])
  544. return PSVComponentMask();
  545. return PSVComponentMask(m_pViewIDOutputMask, m_pPSVRuntimeInfo1->SigOutputVectors[streamIndex]);
  546. }
  547. PSVComponentMask GetViewIDPCOutputMask() const {
  548. if ((!IsHS() && !IsMS()) || !m_pViewIDPCOrPrimOutputMask || !m_pPSVRuntimeInfo1 || !m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors)
  549. return PSVComponentMask();
  550. return PSVComponentMask(m_pViewIDPCOrPrimOutputMask, m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors);
  551. }
  552. // Input to Output dependencies
  553. PSVDependencyTable GetInputToOutputTable(unsigned streamIndex = 0) const {
  554. if (m_pInputToOutputTable && m_pPSVRuntimeInfo1) {
  555. return PSVDependencyTable(m_pInputToOutputTable, m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors[streamIndex]);
  556. }
  557. return PSVDependencyTable();
  558. }
  559. PSVDependencyTable GetInputToPCOutputTable() const {
  560. if (IsHS() && m_pInputToPCOutputTable && m_pPSVRuntimeInfo1) {
  561. return PSVDependencyTable(m_pInputToPCOutputTable, m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors);
  562. }
  563. return PSVDependencyTable();
  564. }
  565. PSVDependencyTable GetPCInputToOutputTable() const {
  566. if (IsDS() && m_pPCInputToOutputTable && m_pPSVRuntimeInfo1) {
  567. return PSVDependencyTable(m_pPCInputToOutputTable, m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0]);
  568. }
  569. return PSVDependencyTable();
  570. }
  571. bool GetNumThreads(uint32_t *pNumThreadsX, uint32_t *pNumThreadsY, uint32_t *pNumThreadsZ) {
  572. if (m_pPSVRuntimeInfo2) {
  573. if (pNumThreadsX) *pNumThreadsX = m_pPSVRuntimeInfo2->NumThreadsX;
  574. if (pNumThreadsY) *pNumThreadsY = m_pPSVRuntimeInfo2->NumThreadsY;
  575. if (pNumThreadsZ) *pNumThreadsZ = m_pPSVRuntimeInfo2->NumThreadsZ;
  576. return true;
  577. }
  578. return false;
  579. }
  580. };
  581. // Return true if size fits in remaing buffer.
  582. inline bool
  583. DxilPipelineStateValidation::CheckedReaderWriter::CheckBounds(size_t size) {
  584. if (Mode != RWMode::CalcSize) {
  585. PSV_RETB(size <= UINT_MAX);
  586. PSV_RETB(Offset <= Size);
  587. return (uint32_t)size <= Size - Offset;
  588. }
  589. return true;
  590. }
  591. // Increment Offset by size. Return false on error.
  592. inline bool
  593. DxilPipelineStateValidation::CheckedReaderWriter::IncrementPos(size_t size) {
  594. PSV_RETB(size <= UINT_MAX);
  595. uint32_t uSize = (uint32_t)size;
  596. if (Mode == RWMode::CalcSize) {
  597. PSV_RETB(uSize <= Size + uSize);
  598. Size += uSize;
  599. }
  600. PSV_RETB(CheckBounds(size));
  601. Offset += uSize;
  602. return true;
  603. }
  604. // Cast and return true if it fits.
  605. template <typename _T> inline bool
  606. DxilPipelineStateValidation::CheckedReaderWriter::Cast(_T **ppPtr, size_t size) {
  607. PSV_RETB(CheckBounds(size));
  608. *ppPtr = reinterpret_cast<_T*>(Ptr + Offset);
  609. return true;
  610. }
  611. template <typename _T>
  612. inline bool DxilPipelineStateValidation::CheckedReaderWriter::Cast(_T **ppPtr) {
  613. return Cast(ppPtr, sizeof(_T));
  614. }
  615. // Map* methods increment Offset.
  616. // Assign pointer, increment Offset, and return true if size fits.
  617. template<typename _T>
  618. inline bool
  619. DxilPipelineStateValidation::CheckedReaderWriter::MapPtr(_T **ppPtr, size_t size) {
  620. PSV_RETB(Cast(ppPtr, size));
  621. PSV_RETB(IncrementPos(size));
  622. return true;
  623. }
  624. // Read value, increment Offset, and return true if value fits.
  625. template <typename _T>
  626. inline bool
  627. DxilPipelineStateValidation::CheckedReaderWriter::MapValue(_T *pValue, const _T init) {
  628. _T *pPtr = nullptr;
  629. PSV_RETB(MapPtr(&pPtr, sizeof(_T)));
  630. switch (Mode) {
  631. case RWMode::Read: *pValue = *pPtr; break;
  632. case RWMode::CalcSize: *pValue = init; break;
  633. case RWMode::Write: *pPtr = *pValue = init; break;
  634. }
  635. return true;
  636. }
  637. // Assign pointer, increment Offset, and return true if array fits.
  638. template <typename _T>
  639. inline bool DxilPipelineStateValidation::CheckedReaderWriter::MapArray(
  640. _T **ppPtr, size_t count, size_t eltSize) {
  641. PSV_RETB(count <= UINT_MAX && eltSize <= UINT_MAX && eltSize >= sizeof(_T));
  642. return count ? MapPtr(ppPtr, eltSize * count) : true;
  643. }
  644. //template <> bool MapArray<void>(void **ppPtr, size_t count, size_t eltSize);
  645. template <>
  646. inline bool DxilPipelineStateValidation::CheckedReaderWriter::MapArray<void>(
  647. void **ppPtr, size_t count, size_t eltSize) {
  648. PSV_RETB(count <= UINT_MAX && eltSize <= UINT_MAX && eltSize > 0);
  649. return count ? MapPtr(ppPtr, eltSize * count) : true;
  650. }
  651. // Assign pointer, increment Offset, and return true if array fits.
  652. template <typename _T>
  653. inline bool
  654. DxilPipelineStateValidation::CheckedReaderWriter::MapArray(_T **ppPtr, size_t count) {
  655. return count ? MapArray(ppPtr, count, sizeof(_T)) : true;
  656. }
  657. inline void DxilPipelineStateValidation::CheckedReaderWriter::Clear() {
  658. if (Mode == RWMode::Write) {
  659. memset(Ptr, 0, Size);
  660. }
  661. }
  662. // PSV0 blob part looks like:
  663. // uint32_t PSVRuntimeInfo_size
  664. // { PSVRuntimeInfoN structure }
  665. // uint32_t ResourceCount
  666. // If ResourceCount > 0:
  667. // uint32_t PSVResourceBindInfo_size
  668. // { PSVResourceBindInfoN structure } * ResourceCount
  669. // If PSVRuntimeInfo1:
  670. // uint32_t StringTableSize (dword aligned)
  671. // If StringTableSize:
  672. // { StringTableSize bytes, null terminated }
  673. // uint32_t SemanticIndexTableEntries (number of dwords)
  674. // If SemanticIndexTableEntries:
  675. // { semantic index } * SemanticIndexTableEntries
  676. // If SigInputElements || SigOutputElements || SigPatchConstOrPrimElements:
  677. // uint32_t PSVSignatureElement_size
  678. // { PSVSignatureElementN structure } * SigInputElements
  679. // { PSVSignatureElementN structure } * SigOutputElements
  680. // { PSVSignatureElementN structure } * SigPatchConstOrPrimElements
  681. // If (UsesViewID):
  682. // For (i : each stream index 0-3):
  683. // If (SigOutputVectors[i] non-zero):
  684. // { uint32_t * PSVComputeMaskDwordsFromVectors(SigOutputVectors[i]) }
  685. // - Outputs affected by ViewID as a bitmask
  686. // If (HS and SigPatchConstOrPrimVectors non-zero):
  687. // { uint32_t * PSVComputeMaskDwordsFromVectors(SigPatchConstOrPrimVectors) }
  688. // - PCOutputs affected by ViewID as a bitmask
  689. // For (i : each stream index 0-3):
  690. // If (SigInputVectors and SigOutputVectors[i] non-zero):
  691. // { uint32_t * PSVComputeInputOutputTableDwords(SigInputVectors, SigOutputVectors[i]) }
  692. // - Outputs affected by inputs as a table of bitmasks
  693. // If (HS and SigPatchConstOrPrimVectors and SigInputVectors non-zero):
  694. // { uint32_t * PSVComputeInputOutputTableDwords(SigInputVectors, SigPatchConstOrPrimVectors) }
  695. // - Patch constant outputs affected by inputs as a table of bitmasks
  696. // If (DS and SigOutputVectors[0] and SigPatchConstOrPrimVectors non-zero):
  697. // { uint32_t * PSVComputeInputOutputTableDwords(SigPatchConstOrPrimVectors, SigOutputVectors[0]) }
  698. // - Outputs affected by patch constant inputs as a table of bitmasks
  699. // returns true if no errors occurred.
  700. inline bool DxilPipelineStateValidation::ReadOrWrite(
  701. const void *pBits, uint32_t *pSize, RWMode mode,
  702. const PSVInitInfo &initInfo) {
  703. PSV_RETB(pSize != nullptr);
  704. PSV_RETB(pBits != nullptr || mode == RWMode::CalcSize);
  705. PSV_RETB(initInfo.PSVVersion <= MAX_PSV_VERSION);
  706. CheckedReaderWriter rw(pBits, *pSize, mode);
  707. rw.Clear();
  708. PSV_RETB(rw.MapValue(&m_uPSVRuntimeInfoSize, initInfo.RuntimeInfoSize()));
  709. PSV_RETB(rw.MapArray(&m_pPSVRuntimeInfo0, 1, m_uPSVRuntimeInfoSize));
  710. AssignDerived(&m_pPSVRuntimeInfo1, m_pPSVRuntimeInfo0, m_uPSVRuntimeInfoSize); // failure ok
  711. AssignDerived(&m_pPSVRuntimeInfo2, m_pPSVRuntimeInfo0, m_uPSVRuntimeInfoSize); // failure ok
  712. // In RWMode::CalcSize, use temp runtime info to hold needed values from initInfo
  713. PSVRuntimeInfo1 tempRuntimeInfo = {};
  714. if (mode == RWMode::CalcSize && initInfo.PSVVersion > 0) {
  715. m_pPSVRuntimeInfo1 = &tempRuntimeInfo;
  716. }
  717. PSV_RETB(rw.MapValue(&m_uResourceCount, initInfo.ResourceCount));
  718. if (m_uResourceCount > 0) {
  719. PSV_RETB(rw.MapValue(&m_uPSVResourceBindInfoSize, initInfo.ResourceBindInfoSize()));
  720. PSV_RETB(sizeof(PSVResourceBindInfo0) <= m_uPSVResourceBindInfoSize);
  721. PSV_RETB(rw.MapArray(&m_pPSVResourceBindInfo, m_uResourceCount, m_uPSVResourceBindInfoSize));
  722. }
  723. if (m_pPSVRuntimeInfo1) {
  724. if (mode != RWMode::Read) {
  725. m_pPSVRuntimeInfo1->ShaderStage = (uint8_t)initInfo.ShaderStage;
  726. m_pPSVRuntimeInfo1->SigInputElements = initInfo.SigInputElements;
  727. m_pPSVRuntimeInfo1->SigOutputElements = initInfo.SigOutputElements;
  728. m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements = initInfo.SigPatchConstOrPrimElements;
  729. m_pPSVRuntimeInfo1->UsesViewID = initInfo.UsesViewID;
  730. for (unsigned i = 0; i < 4; i++) {
  731. m_pPSVRuntimeInfo1->SigOutputVectors[i] = initInfo.SigOutputVectors[i];
  732. }
  733. if (IsHS() || IsDS() || IsMS()) {
  734. m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors = initInfo.SigPatchConstOrPrimVectors;
  735. }
  736. m_pPSVRuntimeInfo1->SigInputVectors = initInfo.SigInputVectors;
  737. }
  738. PSV_RETB(rw.MapValue(&m_StringTable.Size, PSVALIGN4(initInfo.StringTable.Size)));
  739. PSV_RETB(PSVALIGN4(m_StringTable.Size) == m_StringTable.Size);
  740. if (m_StringTable.Size) {
  741. PSV_RETB(rw.MapArray(&m_StringTable.Table, m_StringTable.Size));
  742. if (mode == RWMode::Write) {
  743. memcpy(const_cast<char*>(m_StringTable.Table), initInfo.StringTable.Table, initInfo.StringTable.Size);
  744. }
  745. }
  746. PSV_RETB(rw.MapValue(&m_SemanticIndexTable.Entries, initInfo.SemanticIndexTable.Entries));
  747. if (m_SemanticIndexTable.Entries) {
  748. PSV_RETB(rw.MapArray(&m_SemanticIndexTable.Table, m_SemanticIndexTable.Entries));
  749. if (mode == RWMode::Write) {
  750. memcpy(const_cast<uint32_t*>(m_SemanticIndexTable.Table), initInfo.SemanticIndexTable.Table, sizeof(uint32_t) * initInfo.SemanticIndexTable.Entries);
  751. }
  752. }
  753. // Dxil Signature Elements
  754. if (m_pPSVRuntimeInfo1->SigInputElements || m_pPSVRuntimeInfo1->SigOutputElements || m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements) {
  755. PSV_RETB(rw.MapValue(&m_uPSVSignatureElementSize, initInfo.SignatureElementSize()));
  756. PSV_RETB(sizeof(PSVSignatureElement0) <= m_uPSVSignatureElementSize);
  757. if (m_pPSVRuntimeInfo1->SigInputElements) {
  758. PSV_RETB(rw.MapArray(&m_pSigInputElements, m_pPSVRuntimeInfo1->SigInputElements, m_uPSVSignatureElementSize));
  759. }
  760. if (m_pPSVRuntimeInfo1->SigOutputElements) {
  761. PSV_RETB(rw.MapArray(&m_pSigOutputElements, m_pPSVRuntimeInfo1->SigOutputElements, m_uPSVSignatureElementSize));
  762. }
  763. if (m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements) {
  764. PSV_RETB(rw.MapArray(&m_pSigPatchConstOrPrimElements, m_pPSVRuntimeInfo1->SigPatchConstOrPrimElements, m_uPSVSignatureElementSize));
  765. }
  766. }
  767. // ViewID dependencies
  768. if (m_pPSVRuntimeInfo1->UsesViewID) {
  769. for (unsigned i = 0; i < 4; i++) {
  770. if (m_pPSVRuntimeInfo1->SigOutputVectors[i]) {
  771. PSV_RETB(rw.MapArray(&m_pViewIDOutputMask,
  772. PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigOutputVectors[i])));
  773. }
  774. if (!IsGS())
  775. break;
  776. }
  777. if ((IsHS() || IsMS()) && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors) {
  778. PSV_RETB(rw.MapArray(&m_pViewIDPCOrPrimOutputMask,
  779. PSVComputeMaskDwordsFromVectors(m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors)));
  780. }
  781. }
  782. // Input to Output dependencies
  783. for (unsigned i = 0; i < 4; i++) {
  784. if (!IsMS() && m_pPSVRuntimeInfo1->SigOutputVectors[i] > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
  785. PSV_RETB(rw.MapArray(&m_pInputToOutputTable,
  786. PSVComputeInputOutputTableDwords(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigOutputVectors[i])));
  787. }
  788. if (!IsGS())
  789. break;
  790. }
  791. if (IsHS() && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors > 0 && m_pPSVRuntimeInfo1->SigInputVectors > 0) {
  792. PSV_RETB(rw.MapArray(&m_pInputToPCOutputTable,
  793. PSVComputeInputOutputTableDwords(m_pPSVRuntimeInfo1->SigInputVectors, m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors)));
  794. }
  795. if (IsDS() && m_pPSVRuntimeInfo1->SigOutputVectors[0] > 0 && m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors > 0) {
  796. PSV_RETB(rw.MapArray(&m_pPCInputToOutputTable,
  797. PSVComputeInputOutputTableDwords(m_pPSVRuntimeInfo1->SigPatchConstOrPrimVectors, m_pPSVRuntimeInfo1->SigOutputVectors[0])));
  798. }
  799. }
  800. if (mode == RWMode::CalcSize) {
  801. *pSize = rw.GetSize();
  802. m_pPSVRuntimeInfo1 = nullptr; // clear ptr to tempRuntimeInfo
  803. }
  804. return true;
  805. }
  806. namespace hlsl {
  807. class ViewIDValidator {
  808. public:
  809. enum class Result {
  810. Success = 0,
  811. SuccessWithViewIDDependentTessFactor,
  812. InsufficientInputSpace,
  813. InsufficientOutputSpace,
  814. InsufficientPCSpace,
  815. MismatchedSignatures,
  816. MismatchedPCSignatures,
  817. InvalidUsage,
  818. InvalidPSVVersion,
  819. InvalidPSV,
  820. };
  821. virtual ~ViewIDValidator() {}
  822. virtual Result ValidateStage(const DxilPipelineStateValidation &PSV,
  823. bool bFinalStage,
  824. bool bExpandInputOnly,
  825. unsigned &mismatchElementId) = 0;
  826. };
  827. ViewIDValidator* NewViewIDValidator(unsigned viewIDCount, unsigned gsRastStreamIndex);
  828. }
  829. #undef PSV_RETB
  830. #endif // __DXIL_PIPELINE_STATE_VALIDATION__H__