DxilRootSignatureValidator.cpp 35 KB

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