DxilRootSignatureValidator.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // //
  3. // DxilRootSignature.cpp //
  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 support for manipulating root signature structures. //
  9. // //
  10. ///////////////////////////////////////////////////////////////////////////////
  11. #include "dxc/DXIL/DxilConstants.h"
  12. #include "dxc/DxilRootSignature/DxilRootSignature.h"
  13. #include "dxc/DxilContainer/DxilPipelineStateValidation.h"
  14. #include "dxc/Support/Global.h"
  15. #include "dxc/Support/WinIncludes.h"
  16. #include "dxc/Support/WinFunctions.h"
  17. #include "dxc/Support/FileIOHelper.h"
  18. #include "dxc/dxcapi.h"
  19. #include "llvm/Support/raw_ostream.h"
  20. #include "llvm/IR/DiagnosticPrinter.h"
  21. #include <string>
  22. #include <algorithm>
  23. #include <utility>
  24. #include <vector>
  25. #include <set>
  26. #include <iostream>
  27. #include "DxilRootSignatureHelper.h"
  28. using namespace llvm;
  29. using std::string;
  30. namespace hlsl {
  31. using namespace root_sig_helper;
  32. //////////////////////////////////////////////////////////////////////////////
  33. // Interval helper.
  34. template <typename T>
  35. class CIntervalCollection {
  36. private:
  37. std::set<T> m_set;
  38. public:
  39. const T* FindIntersectingInterval(const T &I) {
  40. auto it = m_set.find(I);
  41. if (it != m_set.end())
  42. return &*it;
  43. return nullptr;
  44. }
  45. void Insert(const T& value) {
  46. auto result = m_set.insert(value);
  47. UNREFERENCED_PARAMETER(result);
  48. #if DBG
  49. DXASSERT(result.second, "otherwise interval collides with existing in collection");
  50. #endif
  51. }
  52. };
  53. //////////////////////////////////////////////////////////////////////////////
  54. // Verifier classes.
  55. class DescriptorTableVerifier {
  56. public:
  57. void Verify(const DxilDescriptorRange1 *pRanges, unsigned NumRanges,
  58. unsigned iRTS, DiagnosticPrinter &DiagPrinter);
  59. };
  60. class StaticSamplerVerifier {
  61. public:
  62. void Verify(const DxilStaticSamplerDesc *pDesc, DiagnosticPrinter &DiagPrinter);
  63. };
  64. class RootSignatureVerifier {
  65. public:
  66. RootSignatureVerifier();
  67. ~RootSignatureVerifier();
  68. void AllowReservedRegisterSpace(bool bAllow);
  69. // Call this before calling VerifyShader, as it accumulates root signature state.
  70. void VerifyRootSignature(const DxilVersionedRootSignatureDesc *pRootSignature,
  71. DiagnosticPrinter &DiagPrinter);
  72. void VerifyShader(DxilShaderVisibility VisType,
  73. const void *pPSVData,
  74. uint32_t PSVSize,
  75. DiagnosticPrinter &DiagPrinter);
  76. typedef enum NODE_TYPE {
  77. DESCRIPTOR_TABLE_ENTRY,
  78. ROOT_DESCRIPTOR,
  79. ROOT_CONSTANT,
  80. STATIC_SAMPLER
  81. } NODE_TYPE;
  82. private:
  83. static const unsigned kMinVisType = (unsigned)DxilShaderVisibility::All;
  84. static const unsigned kMaxVisType = (unsigned)DxilShaderVisibility::MaxValue;
  85. static const unsigned kMinDescType = (unsigned)DxilDescriptorRangeType::SRV;
  86. static const unsigned kMaxDescType = (unsigned)DxilDescriptorRangeType::MaxValue;
  87. struct RegisterRange {
  88. NODE_TYPE nt;
  89. unsigned space;
  90. unsigned lb; // inclusive lower bound
  91. unsigned ub; // inclusive upper bound
  92. unsigned iRP;
  93. unsigned iDTS;
  94. // Sort by space, then lower bound.
  95. bool operator<(const RegisterRange& other) const {
  96. return space < other.space ||
  97. (space == other.space && ub < other.lb);
  98. }
  99. // Like a regular -1,0,1 comparison, but 0 indicates overlap.
  100. int overlap(const RegisterRange& other) const {
  101. if (space < other.space) return -1;
  102. if (space > other.space) return 1;
  103. if (ub < other.lb) return -1;
  104. if (lb > other.ub) return 1;
  105. return 0;
  106. }
  107. // Check containment.
  108. bool contains(const RegisterRange& other) const {
  109. return (space == other.space) && (lb <= other.lb && other.ub <= ub);
  110. }
  111. };
  112. typedef CIntervalCollection<RegisterRange> RegisterRanges;
  113. void AddRegisterRange(unsigned iRTS, NODE_TYPE nt, unsigned iDTS,
  114. DxilDescriptorRangeType DescType,
  115. DxilShaderVisibility VisType,
  116. unsigned NumRegisters, unsigned BaseRegister,
  117. unsigned RegisterSpace, DiagnosticPrinter &DiagPrinter);
  118. const RegisterRange *FindCoveringInterval(DxilDescriptorRangeType RangeType,
  119. DxilShaderVisibility VisType,
  120. unsigned Num,
  121. unsigned LB,
  122. unsigned Space);
  123. RegisterRanges &
  124. GetRanges(DxilShaderVisibility VisType, DxilDescriptorRangeType DescType) {
  125. return RangeKinds[(unsigned)VisType][(unsigned)DescType];
  126. }
  127. RegisterRanges RangeKinds[kMaxVisType + 1][kMaxDescType + 1];
  128. bool m_bAllowReservedRegisterSpace;
  129. DxilRootSignatureFlags m_RootSignatureFlags;
  130. };
  131. void DescriptorTableVerifier::Verify(const DxilDescriptorRange1 *pRanges,
  132. uint32_t NumRanges, uint32_t iRP,
  133. DiagnosticPrinter &DiagPrinter) {
  134. bool bHasSamplers = false;
  135. bool bHasResources = false;
  136. uint64_t iAppendStartSlot = 0;
  137. for (unsigned iDTS = 0; iDTS < NumRanges; iDTS++) {
  138. const DxilDescriptorRange1 *pRange = &pRanges[iDTS];
  139. switch (pRange->RangeType) {
  140. case DxilDescriptorRangeType::SRV:
  141. case DxilDescriptorRangeType::UAV:
  142. case DxilDescriptorRangeType::CBV:
  143. bHasResources = true;
  144. break;
  145. case DxilDescriptorRangeType::Sampler:
  146. bHasSamplers = true;
  147. break;
  148. default:
  149. static_assert(DxilDescriptorRangeType::Sampler == DxilDescriptorRangeType::MaxValue,
  150. "otherwise, need to update cases here");
  151. EAT(DiagPrinter << "Unsupported RangeType value " << (uint32_t)pRange->RangeType
  152. << " (descriptor table slot [" << iDTS << "], root parameter [" << iRP << "]).\n");
  153. }
  154. // Samplers cannot be mixed with other resources.
  155. if (bHasResources && bHasSamplers) {
  156. EAT(DiagPrinter << "Samplers cannot be mixed with other "
  157. << "resource types in a descriptor table (root "
  158. << "parameter [" << iRP << "]).\n");
  159. }
  160. // NumDescriptors is not 0.
  161. if (pRange->NumDescriptors == 0) {
  162. EAT(DiagPrinter << "NumDescriptors cannot be 0 (descriptor "
  163. << "table slot [" << iDTS << "], root parameter [" << iRP << "]).\n");
  164. }
  165. // Range start.
  166. uint64_t iStartSlot = iAppendStartSlot;
  167. if (pRange->OffsetInDescriptorsFromTableStart != DxilDescriptorRangeOffsetAppend) {
  168. iStartSlot = pRange->OffsetInDescriptorsFromTableStart;
  169. }
  170. if (iStartSlot > UINT_MAX) {
  171. EAT(DiagPrinter << "Cannot append range with implicit lower "
  172. << "bound after an unbounded range (descriptor "
  173. << "table slot [" << iDTS << "], root parameter [" << iRP << "]).\n");
  174. }
  175. // Descriptor range and shader register range overlow.
  176. if (pRange->NumDescriptors != UINT_MAX) {
  177. // Bounded range.
  178. uint64_t ub1 = (uint64_t)pRange->BaseShaderRegister +
  179. (uint64_t)pRange->NumDescriptors - 1ull;
  180. if (ub1 > UINT_MAX) {
  181. EAT(DiagPrinter << "Overflow for shader register range: "
  182. << "BaseShaderRegister=" << pRange->BaseShaderRegister
  183. << ", NumDescriptor=" << pRange->NumDescriptors
  184. << "; (descriptor table slot [" << iDTS
  185. << "], root parameter [" << iRP << "]).\n");
  186. }
  187. uint64_t ub2 = (uint64_t)iStartSlot + (uint64_t)pRange->NumDescriptors - 1ull;
  188. if (ub2 > UINT_MAX) {
  189. EAT(DiagPrinter << "Overflow for descriptor range (descriptor "
  190. << "table slot [" << iDTS << "], root parameter [" << iRP << "])\n");
  191. }
  192. iAppendStartSlot = iStartSlot + (uint64_t)pRange->NumDescriptors;
  193. } else {
  194. // Unbounded range.
  195. iAppendStartSlot = 1ull + (uint64_t)UINT_MAX;
  196. }
  197. }
  198. }
  199. RootSignatureVerifier::RootSignatureVerifier() {
  200. m_RootSignatureFlags = DxilRootSignatureFlags::None;
  201. m_bAllowReservedRegisterSpace = false;
  202. }
  203. RootSignatureVerifier::~RootSignatureVerifier() {}
  204. void RootSignatureVerifier::AllowReservedRegisterSpace(bool bAllow) {
  205. m_bAllowReservedRegisterSpace = bAllow;
  206. }
  207. const char* RangeTypeString(DxilDescriptorRangeType rt)
  208. {
  209. static const char *RangeType[] = {"SRV", "UAV", "CBV", "SAMPLER"};
  210. static_assert(_countof(RangeType) == ((unsigned)DxilDescriptorRangeType::MaxValue + 1),
  211. "otherwise, need to update name array");
  212. return (rt <= DxilDescriptorRangeType::MaxValue) ? RangeType[(unsigned)rt]
  213. : "unknown";
  214. }
  215. const char *VisTypeString(DxilShaderVisibility vis) {
  216. static const char *Vis[] = {"ALL", "VERTEX", "HULL",
  217. "DOMAIN", "GEOMETRY", "PIXEL",
  218. "AMPLIFICATION", "MESH"};
  219. static_assert(_countof(Vis) == ((unsigned)DxilShaderVisibility::MaxValue + 1),
  220. "otherwise, need to update name array");
  221. unsigned idx = (unsigned)vis;
  222. return vis <= DxilShaderVisibility::MaxValue ? Vis[idx] : "unknown";
  223. }
  224. static bool IsDxilShaderVisibility(DxilShaderVisibility v) {
  225. return v <= DxilShaderVisibility::MaxValue;
  226. }
  227. void RootSignatureVerifier::AddRegisterRange(unsigned iRP,
  228. NODE_TYPE nt,
  229. unsigned iDTS,
  230. DxilDescriptorRangeType DescType,
  231. DxilShaderVisibility VisType,
  232. unsigned NumRegisters,
  233. unsigned BaseRegister,
  234. unsigned RegisterSpace,
  235. DiagnosticPrinter &DiagPrinter) {
  236. RegisterRange interval;
  237. interval.space = RegisterSpace;
  238. interval.lb = BaseRegister;
  239. interval.ub = (NumRegisters != UINT_MAX) ? BaseRegister + NumRegisters - 1 : UINT_MAX;
  240. interval.nt = nt;
  241. interval.iDTS = iDTS;
  242. interval.iRP = iRP;
  243. if (!m_bAllowReservedRegisterSpace &&
  244. (RegisterSpace >= DxilSystemReservedRegisterSpaceValuesStart) &&
  245. (RegisterSpace <= DxilSystemReservedRegisterSpaceValuesEnd)) {
  246. if (nt == DESCRIPTOR_TABLE_ENTRY) {
  247. EAT(DiagPrinter << "Root parameter [" << iRP << "] descriptor table entry [" << iDTS
  248. << "] specifies RegisterSpace=" << std::hex << RegisterSpace
  249. << ", which is invalid since RegisterSpace values in the range "
  250. << "[" << std::hex << DxilSystemReservedRegisterSpaceValuesStart
  251. << "," << std::hex << DxilSystemReservedRegisterSpaceValuesEnd
  252. << "] are reserved for system use.\n");
  253. }
  254. else {
  255. EAT(DiagPrinter << "Root parameter [" << iRP
  256. << "] specifies RegisterSpace=" << std::hex << RegisterSpace
  257. << ", which is invalid since RegisterSpace values in the range "
  258. << "[" << std::hex << DxilSystemReservedRegisterSpaceValuesStart
  259. << "," << std::hex << DxilSystemReservedRegisterSpaceValuesEnd
  260. << "] are reserved for system use.\n");
  261. }
  262. }
  263. const RegisterRange *pNode = nullptr;
  264. DxilShaderVisibility NodeVis = VisType;
  265. if (VisType == DxilShaderVisibility::All) {
  266. // Check for overlap with each visibility type.
  267. for (unsigned iVT = kMinVisType; iVT <= kMaxVisType; iVT++) {
  268. pNode = GetRanges((DxilShaderVisibility)iVT, DescType).FindIntersectingInterval(interval);
  269. if (pNode != nullptr)
  270. break;
  271. }
  272. } else {
  273. // Check for overlap with the same visibility.
  274. pNode = GetRanges(VisType, DescType).FindIntersectingInterval(interval);
  275. // Check for overlap with ALL visibility.
  276. if (pNode == nullptr) {
  277. pNode = GetRanges(DxilShaderVisibility::All, DescType).FindIntersectingInterval(interval);
  278. NodeVis = DxilShaderVisibility::All;
  279. }
  280. }
  281. if (pNode != nullptr) {
  282. const int strSize = 132;
  283. char testString[strSize];
  284. char nodeString[strSize];
  285. switch (nt) {
  286. case DESCRIPTOR_TABLE_ENTRY:
  287. StringCchPrintfA(testString, strSize, "(root parameter [%u], visibility %s, descriptor table slot [%u])",
  288. iRP, VisTypeString(VisType), iDTS);
  289. break;
  290. case ROOT_DESCRIPTOR:
  291. case ROOT_CONSTANT:
  292. StringCchPrintfA(testString, strSize, "(root parameter [%u], visibility %s)",
  293. iRP, VisTypeString(VisType));
  294. break;
  295. case STATIC_SAMPLER:
  296. StringCchPrintfA(testString, strSize, "(static sampler [%u], visibility %s)",
  297. iRP, VisTypeString(VisType));
  298. break;
  299. default:
  300. DXASSERT_NOMSG(false);
  301. break;
  302. }
  303. switch (pNode->nt)
  304. {
  305. case DESCRIPTOR_TABLE_ENTRY:
  306. StringCchPrintfA(nodeString, strSize, "(root parameter[%u], visibility %s, descriptor table slot [%u])",
  307. pNode->iRP, VisTypeString(NodeVis), pNode->iDTS);
  308. break;
  309. case ROOT_DESCRIPTOR:
  310. case ROOT_CONSTANT:
  311. StringCchPrintfA(nodeString, strSize, "(root parameter [%u], visibility %s)",
  312. pNode->iRP, VisTypeString(NodeVis));
  313. break;
  314. case STATIC_SAMPLER:
  315. StringCchPrintfA(nodeString, strSize, "(static sampler [%u], visibility %s)",
  316. pNode->iRP, VisTypeString(NodeVis));
  317. break;
  318. default:
  319. DXASSERT_NOMSG(false);
  320. break;
  321. }
  322. EAT(DiagPrinter << "Shader register range of type " << RangeTypeString(DescType)
  323. << " " << testString << " overlaps with another "
  324. << "shader register range " << nodeString << ".\n");
  325. }
  326. // Insert node.
  327. GetRanges(VisType, DescType).Insert(interval);
  328. }
  329. const RootSignatureVerifier::RegisterRange *
  330. RootSignatureVerifier::FindCoveringInterval(DxilDescriptorRangeType RangeType,
  331. DxilShaderVisibility VisType,
  332. unsigned Num,
  333. unsigned LB,
  334. unsigned Space) {
  335. RegisterRange RR;
  336. RR.space = Space;
  337. RR.lb = LB;
  338. RR.ub = LB + Num - 1;
  339. const RootSignatureVerifier::RegisterRange *pRange = GetRanges(DxilShaderVisibility::All, RangeType).FindIntersectingInterval(RR);
  340. if (!pRange && VisType != DxilShaderVisibility::All) {
  341. pRange = GetRanges(VisType, RangeType).FindIntersectingInterval(RR);
  342. }
  343. if (pRange && !pRange->contains(RR)) {
  344. pRange = nullptr;
  345. }
  346. return pRange;
  347. }
  348. static DxilDescriptorRangeType GetRangeType(DxilRootParameterType RPT) {
  349. switch (RPT) {
  350. case DxilRootParameterType::CBV: return DxilDescriptorRangeType::CBV;
  351. case DxilRootParameterType::SRV: return DxilDescriptorRangeType::SRV;
  352. case DxilRootParameterType::UAV: return DxilDescriptorRangeType::UAV;
  353. default:
  354. static_assert(DxilRootParameterType::UAV == DxilRootParameterType::MaxValue,
  355. "otherwise, need to add cases here.");
  356. break;
  357. }
  358. DXASSERT_NOMSG(false);
  359. return DxilDescriptorRangeType::SRV;
  360. }
  361. void RootSignatureVerifier::VerifyRootSignature(
  362. const DxilVersionedRootSignatureDesc *pVersionedRootSignature,
  363. DiagnosticPrinter &DiagPrinter) {
  364. const DxilVersionedRootSignatureDesc *pUpconvertedRS = nullptr;
  365. // Up-convert root signature to the latest RS version.
  366. ConvertRootSignature(pVersionedRootSignature, DxilRootSignatureVersion::Version_1_1, &pUpconvertedRS);
  367. DXASSERT_NOMSG(pUpconvertedRS->Version == DxilRootSignatureVersion::Version_1_1);
  368. // Ensure this gets deleted as necessary.
  369. struct SigGuard {
  370. const DxilVersionedRootSignatureDesc *Orig, *Guard;
  371. SigGuard(const DxilVersionedRootSignatureDesc *pOrig, const DxilVersionedRootSignatureDesc *pGuard)
  372. : Orig(pOrig), Guard(pGuard) { }
  373. ~SigGuard() {
  374. if (Orig != Guard) {
  375. DeleteRootSignature(Guard);
  376. }
  377. }
  378. };
  379. SigGuard S(pVersionedRootSignature, pUpconvertedRS);
  380. const DxilRootSignatureDesc1 *pRootSignature = &pUpconvertedRS->Desc_1_1;
  381. // Flags (assume they are bits that can be combined with OR).
  382. if ((pRootSignature->Flags & ~DxilRootSignatureFlags::ValidFlags) != DxilRootSignatureFlags::None) {
  383. EAT(DiagPrinter << "Unsupported bit-flag set (root signature flags "
  384. << std::hex << (uint32_t)pRootSignature->Flags << ").\n");
  385. }
  386. m_RootSignatureFlags = pRootSignature->Flags;
  387. for (unsigned iRP = 0; iRP < pRootSignature->NumParameters; iRP++) {
  388. const DxilRootParameter1 *pSlot = &pRootSignature->pParameters[iRP];
  389. // Shader visibility.
  390. DxilShaderVisibility Visibility = pSlot->ShaderVisibility;
  391. if (!IsDxilShaderVisibility(Visibility)) {
  392. EAT(DiagPrinter << "Unsupported ShaderVisibility value " << (uint32_t)Visibility
  393. << " (root parameter [" << iRP << "]).\n");
  394. }
  395. DxilRootParameterType ParameterType = pSlot->ParameterType;
  396. switch (ParameterType) {
  397. case DxilRootParameterType::DescriptorTable: {
  398. DescriptorTableVerifier DTV;
  399. DTV.Verify(pSlot->DescriptorTable.pDescriptorRanges,
  400. pSlot->DescriptorTable.NumDescriptorRanges, iRP, DiagPrinter);
  401. for (unsigned iDTS = 0; iDTS < pSlot->DescriptorTable.NumDescriptorRanges; iDTS++) {
  402. const DxilDescriptorRange1 *pRange = &pSlot->DescriptorTable.pDescriptorRanges[iDTS];
  403. unsigned RangeFlags = (unsigned)pRange->Flags;
  404. // Verify range flags.
  405. if (RangeFlags & ~(unsigned)DxilDescriptorRangeFlags::ValidFlags) {
  406. EAT(DiagPrinter << "Unsupported bit-flag set (descriptor range flags "
  407. << (uint32_t)pRange->Flags << ").\n");
  408. }
  409. switch (pRange->RangeType) {
  410. case DxilDescriptorRangeType::Sampler: {
  411. if (RangeFlags & (unsigned)(DxilDescriptorRangeFlags::DataVolatile |
  412. DxilDescriptorRangeFlags::DataStatic |
  413. DxilDescriptorRangeFlags::DataStaticWhileSetAtExecute)) {
  414. EAT(DiagPrinter << "Sampler descriptor ranges can't specify DATA_* flags "
  415. << "since there is no data pointed to by samplers "
  416. << "(descriptor range flags " << (uint32_t)pRange->Flags << ").\n");
  417. }
  418. break;
  419. }
  420. default: {
  421. unsigned NumDataFlags = 0;
  422. if (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataVolatile) { NumDataFlags++; }
  423. if (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataStatic) { NumDataFlags++; }
  424. if (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataStaticWhileSetAtExecute) { NumDataFlags++; }
  425. if (NumDataFlags > 1) {
  426. EAT(DiagPrinter << "Descriptor range flags cannot specify more than one DATA_* flag "
  427. << "at a time (descriptor range flags " << (uint32_t)pRange->Flags << ").\n");
  428. }
  429. if ((RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataStatic) &&
  430. (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DescriptorsVolatile)) {
  431. EAT(DiagPrinter << "Descriptor range flags cannot specify DESCRIPTORS_VOLATILE with the DATA_STATIC flag at the same time (descriptor range flags " << (uint32_t)pRange->Flags << "). "
  432. << "DATA_STATIC_WHILE_SET_AT_EXECUTE is fine to combine with DESCRIPTORS_VOLATILE, since DESCRIPTORS_VOLATILE still requires descriptors don't change during execution. \n");
  433. }
  434. break;
  435. }
  436. }
  437. AddRegisterRange(iRP,
  438. DESCRIPTOR_TABLE_ENTRY,
  439. iDTS,
  440. pRange->RangeType,
  441. Visibility,
  442. pRange->NumDescriptors,
  443. pRange->BaseShaderRegister,
  444. pRange->RegisterSpace,
  445. DiagPrinter);
  446. }
  447. break;
  448. }
  449. case DxilRootParameterType::Constants32Bit:
  450. AddRegisterRange(iRP,
  451. ROOT_CONSTANT,
  452. (unsigned)-1,
  453. DxilDescriptorRangeType::CBV,
  454. Visibility,
  455. 1,
  456. pSlot->Constants.ShaderRegister,
  457. pSlot->Constants.RegisterSpace,
  458. DiagPrinter);
  459. break;
  460. case DxilRootParameterType::CBV:
  461. case DxilRootParameterType::SRV:
  462. case DxilRootParameterType::UAV: {
  463. // Verify root descriptor flags.
  464. unsigned Flags = (unsigned)pSlot->Descriptor.Flags;
  465. if (Flags & ~(unsigned)DxilRootDescriptorFlags::ValidFlags) {
  466. EAT(DiagPrinter << "Unsupported bit-flag set (root descriptor flags " << std::hex << Flags << ").\n");
  467. }
  468. unsigned NumDataFlags = 0;
  469. if (Flags & (unsigned)DxilRootDescriptorFlags::DataVolatile) { NumDataFlags++; }
  470. if (Flags & (unsigned)DxilRootDescriptorFlags::DataStatic) { NumDataFlags++; }
  471. if (Flags & (unsigned)DxilRootDescriptorFlags::DataStaticWhileSetAtExecute) { NumDataFlags++; }
  472. if (NumDataFlags > 1) {
  473. EAT(DiagPrinter << "Root descriptor flags cannot specify more "
  474. << "than one DATA_* flag at a time (root "
  475. << "descriptor flags " << NumDataFlags << ").\n");
  476. }
  477. AddRegisterRange(iRP, ROOT_DESCRIPTOR, (unsigned)-1,
  478. GetRangeType(ParameterType), Visibility, 1,
  479. pSlot->Descriptor.ShaderRegister,
  480. pSlot->Descriptor.RegisterSpace, DiagPrinter);
  481. break;
  482. }
  483. default:
  484. static_assert(DxilRootParameterType::UAV == DxilRootParameterType::MaxValue,
  485. "otherwise, need to add cases here.");
  486. EAT(DiagPrinter << "Unsupported ParameterType value " << (uint32_t)ParameterType
  487. << " (root parameter " << iRP << ")\n");
  488. }
  489. }
  490. for (unsigned iSS = 0; iSS < pRootSignature->NumStaticSamplers; iSS++) {
  491. const DxilStaticSamplerDesc *pSS = &pRootSignature->pStaticSamplers[iSS];
  492. // Shader visibility.
  493. DxilShaderVisibility Visibility = pSS->ShaderVisibility;
  494. if (!IsDxilShaderVisibility(Visibility)) {
  495. EAT(DiagPrinter << "Unsupported ShaderVisibility value " << (uint32_t)Visibility
  496. << " (static sampler [" << iSS << "]).\n");
  497. }
  498. StaticSamplerVerifier SSV;
  499. SSV.Verify(pSS, DiagPrinter);
  500. AddRegisterRange(iSS, STATIC_SAMPLER, (unsigned)-1,
  501. DxilDescriptorRangeType::Sampler, Visibility, 1,
  502. pSS->ShaderRegister, pSS->RegisterSpace, DiagPrinter);
  503. }
  504. }
  505. void RootSignatureVerifier::VerifyShader(DxilShaderVisibility VisType,
  506. const void *pPSVData,
  507. uint32_t PSVSize,
  508. DiagnosticPrinter &DiagPrinter) {
  509. DxilPipelineStateValidation PSV;
  510. IFTBOOL(PSV.InitFromPSV0(pPSVData, PSVSize), E_INVALIDARG);
  511. bool bShaderDeniedByRootSig = false;
  512. switch (VisType) {
  513. case DxilShaderVisibility::Vertex:
  514. if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyVertexShaderRootAccess) != DxilRootSignatureFlags::None) {
  515. bShaderDeniedByRootSig = true;
  516. }
  517. break;
  518. case DxilShaderVisibility::Hull:
  519. if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyHullShaderRootAccess) != DxilRootSignatureFlags::None) {
  520. bShaderDeniedByRootSig = true;
  521. }
  522. break;
  523. case DxilShaderVisibility::Domain:
  524. if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyDomainShaderRootAccess) != DxilRootSignatureFlags::None) {
  525. bShaderDeniedByRootSig = true;
  526. }
  527. break;
  528. case DxilShaderVisibility::Geometry:
  529. if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyGeometryShaderRootAccess) != DxilRootSignatureFlags::None) {
  530. bShaderDeniedByRootSig = true;
  531. }
  532. break;
  533. case DxilShaderVisibility::Pixel:
  534. if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyPixelShaderRootAccess) != DxilRootSignatureFlags::None) {
  535. bShaderDeniedByRootSig = true;
  536. }
  537. break;
  538. case DxilShaderVisibility::Amplification:
  539. if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyAmplificationShaderRootAccess) != DxilRootSignatureFlags::None) {
  540. bShaderDeniedByRootSig = true;
  541. }
  542. break;
  543. case DxilShaderVisibility::Mesh:
  544. if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyMeshShaderRootAccess) != DxilRootSignatureFlags::None) {
  545. bShaderDeniedByRootSig = true;
  546. }
  547. break;
  548. default:
  549. break;
  550. }
  551. bool bShaderHasRootBindings = false;
  552. for (unsigned iResource = 0; iResource < PSV.GetBindCount(); iResource++) {
  553. const PSVResourceBindInfo0 *pBindInfo0 = PSV.GetPSVResourceBindInfo0(iResource);
  554. DXASSERT_NOMSG(pBindInfo0);
  555. unsigned Space = pBindInfo0->Space;
  556. unsigned LB = pBindInfo0->LowerBound;
  557. unsigned UB = pBindInfo0->UpperBound;
  558. unsigned Num = (UB != UINT_MAX) ? (UB - LB + 1) : 1;
  559. PSVResourceType ResType = (PSVResourceType)pBindInfo0->ResType;
  560. switch(ResType) {
  561. case PSVResourceType::Sampler: {
  562. bShaderHasRootBindings = true;
  563. auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::Sampler, VisType, Num, LB, Space);
  564. if(!pCoveringRange) {
  565. EAT(DiagPrinter << "Shader sampler descriptor range (RegisterSpace=" << Space
  566. << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
  567. << ") is not fully bound in root signature.\n");
  568. }
  569. break;
  570. }
  571. case PSVResourceType::SRVTyped:
  572. case PSVResourceType::SRVRaw:
  573. case PSVResourceType::SRVStructured: {
  574. bShaderHasRootBindings = true;
  575. auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::SRV, VisType, Num, LB, Space);
  576. if (pCoveringRange) {
  577. if(pCoveringRange->nt == ROOT_DESCRIPTOR && ResType == PSVResourceType::SRVTyped) {
  578. EAT(DiagPrinter << "A Shader is declaring a resource object as a texture using "
  579. << "a register mapped to a root descriptor SRV (RegisterSpace=" << Space
  580. << ", ShaderRegister=" << LB << "). "
  581. << "SRV or UAV root descriptors can only be Raw or Structured buffers.\n");
  582. }
  583. }
  584. else {
  585. EAT(DiagPrinter << "Shader SRV descriptor range (RegisterSpace=" << Space
  586. << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
  587. << ") is not fully bound in root signature.\n");
  588. }
  589. break;
  590. }
  591. case PSVResourceType::UAVTyped:
  592. case PSVResourceType::UAVRaw:
  593. case PSVResourceType::UAVStructured:
  594. case PSVResourceType::UAVStructuredWithCounter: {
  595. bShaderHasRootBindings = true;
  596. auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::UAV, VisType, Num, LB, Space);
  597. if (pCoveringRange) {
  598. if (pCoveringRange->nt == ROOT_DESCRIPTOR) {
  599. if (ResType == PSVResourceType::UAVTyped) {
  600. EAT(DiagPrinter << "A shader is declaring a typed UAV using a register mapped "
  601. << "to a root descriptor UAV (RegisterSpace=" << Space
  602. << ", ShaderRegister=" << LB << "). "
  603. << "SRV or UAV root descriptors can only be Raw or Structured buffers.\n");
  604. }
  605. if (ResType == PSVResourceType::UAVStructuredWithCounter) {
  606. EAT(DiagPrinter << "A Shader is declaring a structured UAV with counter using "
  607. << "a register mapped to a root descriptor UAV (RegisterSpace=" << Space
  608. << ", ShaderRegister=" << LB << "). "
  609. << "SRV or UAV root descriptors can only be Raw or Structured buffers.\n");
  610. }
  611. }
  612. }
  613. else {
  614. EAT(DiagPrinter << "Shader UAV descriptor range (RegisterSpace=" << Space
  615. << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
  616. << ") is not fully bound in root signature.\n");
  617. }
  618. break;
  619. }
  620. case PSVResourceType::CBV: {
  621. bShaderHasRootBindings = true;
  622. auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::CBV, VisType, Num, LB, Space);
  623. if (!pCoveringRange) {
  624. EAT(DiagPrinter << "Shader CBV descriptor range (RegisterSpace=" << Space
  625. << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
  626. << ") is not fully bound in root signature.\n");
  627. }
  628. break;
  629. }
  630. default:
  631. break;
  632. }
  633. }
  634. if (bShaderHasRootBindings && bShaderDeniedByRootSig) {
  635. EAT(DiagPrinter << "Shader has root bindings but root signature uses a DENY flag "
  636. << "to disallow root binding access to the shader stage.\n");
  637. }
  638. }
  639. BOOL isNaN(const float &a) {
  640. static const unsigned exponentMask = 0x7f800000;
  641. static const unsigned mantissaMask = 0x007fffff;
  642. unsigned u = *(const unsigned *)&a;
  643. return (((u & exponentMask) == exponentMask) && (u & mantissaMask)); // NaN
  644. }
  645. static bool IsDxilTextureAddressMode(DxilTextureAddressMode v) {
  646. return DxilTextureAddressMode::Wrap <= v &&
  647. v <= DxilTextureAddressMode::MirrorOnce;
  648. }
  649. static bool IsDxilComparisonFunc(DxilComparisonFunc v) {
  650. return DxilComparisonFunc::Never <= v && v <= DxilComparisonFunc::Always;
  651. }
  652. // This validation closely mirrors CCreateSamplerStateValidator's checks
  653. void StaticSamplerVerifier::Verify(const DxilStaticSamplerDesc* pDesc,
  654. DiagnosticPrinter &DiagPrinter) {
  655. if (!pDesc) {
  656. EAT(DiagPrinter << "Static sampler: A nullptr pSamplerDesc was specified.\n");
  657. }
  658. bool bIsComparison = false;
  659. switch (pDesc->Filter) {
  660. case DxilFilter::MINIMUM_MIN_MAG_MIP_POINT:
  661. case DxilFilter::MINIMUM_MIN_MAG_POINT_MIP_LINEAR:
  662. case DxilFilter::MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT:
  663. case DxilFilter::MINIMUM_MIN_POINT_MAG_MIP_LINEAR:
  664. case DxilFilter::MINIMUM_MIN_LINEAR_MAG_MIP_POINT:
  665. case DxilFilter::MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
  666. case DxilFilter::MINIMUM_MIN_MAG_LINEAR_MIP_POINT:
  667. case DxilFilter::MINIMUM_MIN_MAG_MIP_LINEAR:
  668. case DxilFilter::MINIMUM_ANISOTROPIC:
  669. case DxilFilter::MAXIMUM_MIN_MAG_MIP_POINT:
  670. case DxilFilter::MAXIMUM_MIN_MAG_POINT_MIP_LINEAR:
  671. case DxilFilter::MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT:
  672. case DxilFilter::MAXIMUM_MIN_POINT_MAG_MIP_LINEAR:
  673. case DxilFilter::MAXIMUM_MIN_LINEAR_MAG_MIP_POINT:
  674. case DxilFilter::MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
  675. case DxilFilter::MAXIMUM_MIN_MAG_LINEAR_MIP_POINT:
  676. case DxilFilter::MAXIMUM_MIN_MAG_MIP_LINEAR:
  677. case DxilFilter::MAXIMUM_ANISOTROPIC:
  678. break;
  679. case DxilFilter::MIN_MAG_MIP_POINT:
  680. case DxilFilter::MIN_MAG_POINT_MIP_LINEAR:
  681. case DxilFilter::MIN_POINT_MAG_LINEAR_MIP_POINT:
  682. case DxilFilter::MIN_POINT_MAG_MIP_LINEAR:
  683. case DxilFilter::MIN_LINEAR_MAG_MIP_POINT:
  684. case DxilFilter::MIN_LINEAR_MAG_POINT_MIP_LINEAR:
  685. case DxilFilter::MIN_MAG_LINEAR_MIP_POINT:
  686. case DxilFilter::MIN_MAG_MIP_LINEAR:
  687. case DxilFilter::ANISOTROPIC:
  688. break;
  689. case DxilFilter::COMPARISON_MIN_MAG_MIP_POINT:
  690. case DxilFilter::COMPARISON_MIN_MAG_POINT_MIP_LINEAR:
  691. case DxilFilter::COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT:
  692. case DxilFilter::COMPARISON_MIN_POINT_MAG_MIP_LINEAR:
  693. case DxilFilter::COMPARISON_MIN_LINEAR_MAG_MIP_POINT:
  694. case DxilFilter::COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
  695. case DxilFilter::COMPARISON_MIN_MAG_LINEAR_MIP_POINT:
  696. case DxilFilter::COMPARISON_MIN_MAG_MIP_LINEAR:
  697. case DxilFilter::COMPARISON_ANISOTROPIC:
  698. bIsComparison = true;
  699. break;
  700. default:
  701. EAT(DiagPrinter << "Static sampler: Filter unrecognized.\n");
  702. }
  703. if (!IsDxilTextureAddressMode(pDesc->AddressU)) {
  704. EAT(DiagPrinter << "Static sampler: AddressU unrecognized.\n");
  705. }
  706. if (!IsDxilTextureAddressMode(pDesc->AddressV)) {
  707. EAT(DiagPrinter << "Static sampler: AddressV unrecognized.\n");
  708. }
  709. if (!IsDxilTextureAddressMode(pDesc->AddressW)) {
  710. EAT(DiagPrinter << "Static sampler: AddressW unrecognized.\n");
  711. }
  712. if (isNaN(pDesc->MipLODBias) || (pDesc->MipLODBias < DxilMipLodBiaxMin) ||
  713. (pDesc->MipLODBias > DxilMipLodBiaxMax)) {
  714. EAT(DiagPrinter << "Static sampler: MipLODBias must be in the "
  715. << "range [" << DxilMipLodBiaxMin << " to " << DxilMipLodBiaxMax
  716. <<"]. " << pDesc->MipLODBias << "specified.\n");
  717. }
  718. if (pDesc->MaxAnisotropy > DxilMapAnisotropy) {
  719. EAT(DiagPrinter << "Static sampler: MaxAnisotropy must be in "
  720. << "the range [0 to " << DxilMapAnisotropy << "]. "
  721. << pDesc->MaxAnisotropy << " specified.\n");
  722. }
  723. if (bIsComparison && !IsDxilComparisonFunc(pDesc->ComparisonFunc)) {
  724. EAT(DiagPrinter << "Static sampler: ComparisonFunc unrecognized.");
  725. }
  726. if (isNaN(pDesc->MinLOD)) {
  727. EAT(DiagPrinter << "Static sampler: MinLOD be in the range [-INF to +INF]. "
  728. << pDesc->MinLOD << " specified.\n");
  729. }
  730. if (isNaN(pDesc->MaxLOD)) {
  731. EAT(DiagPrinter << "Static sampler: MaxLOD be in the range [-INF to +INF]. "
  732. << pDesc->MaxLOD << " specified.\n");
  733. }
  734. }
  735. static DxilShaderVisibility GetVisibilityType(DXIL::ShaderKind ShaderKind) {
  736. switch(ShaderKind) {
  737. case DXIL::ShaderKind::Pixel: return DxilShaderVisibility::Pixel;
  738. case DXIL::ShaderKind::Vertex: return DxilShaderVisibility::Vertex;
  739. case DXIL::ShaderKind::Geometry: return DxilShaderVisibility::Geometry;
  740. case DXIL::ShaderKind::Hull: return DxilShaderVisibility::Hull;
  741. case DXIL::ShaderKind::Domain: return DxilShaderVisibility::Domain;
  742. case DXIL::ShaderKind::Amplification: return DxilShaderVisibility::Amplification;
  743. case DXIL::ShaderKind::Mesh: return DxilShaderVisibility::Mesh;
  744. default: return DxilShaderVisibility::All;
  745. }
  746. }
  747. _Use_decl_annotations_
  748. bool VerifyRootSignatureWithShaderPSV(const DxilVersionedRootSignatureDesc *pDesc,
  749. DXIL::ShaderKind ShaderKind,
  750. const void *pPSVData,
  751. uint32_t PSVSize,
  752. llvm::raw_ostream &DiagStream) {
  753. try {
  754. RootSignatureVerifier RSV;
  755. DiagnosticPrinterRawOStream DiagPrinter(DiagStream);
  756. RSV.VerifyRootSignature(pDesc, DiagPrinter);
  757. RSV.VerifyShader(GetVisibilityType(ShaderKind), pPSVData, PSVSize, DiagPrinter);
  758. } catch (...) {
  759. return false;
  760. }
  761. return true;
  762. }
  763. bool VerifyRootSignature(_In_ const DxilVersionedRootSignatureDesc *pDesc,
  764. _In_ llvm::raw_ostream &DiagStream,
  765. _In_ bool bAllowReservedRegisterSpace) {
  766. try {
  767. RootSignatureVerifier RSV;
  768. RSV.AllowReservedRegisterSpace(bAllowReservedRegisterSpace);
  769. DiagnosticPrinterRawOStream DiagPrinter(DiagStream);
  770. RSV.VerifyRootSignature(pDesc, DiagPrinter);
  771. } catch (...) {
  772. return false;
  773. }
  774. return true;
  775. }
  776. } // namespace hlsl