DxilRootSignatureValidator.cpp 34 KB

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