DxilRootSignatureValidator.cpp 35 KB

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