123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871 |
- ///////////////////////////////////////////////////////////////////////////////
- // //
- // DxilRootSignature.cpp //
- // Copyright (C) Microsoft Corporation. All rights reserved. //
- // This file is distributed under the University of Illinois Open Source //
- // License. See LICENSE.TXT for details. //
- // //
- // Provides support for manipulating root signature structures. //
- // //
- ///////////////////////////////////////////////////////////////////////////////
- #include "dxc/DXIL/DxilConstants.h"
- #include "dxc/DxilRootSignature/DxilRootSignature.h"
- #include "dxc/Support/Global.h"
- #include "dxc/Support/WinIncludes.h"
- #include "dxc/Support/WinFunctions.h"
- #include "dxc/Support/FileIOHelper.h"
- #include "dxc/dxcapi.h"
- #include "llvm/Support/raw_ostream.h"
- #include "llvm/IR/DiagnosticPrinter.h"
- #include <string>
- #include <algorithm>
- #include <utility>
- #include <vector>
- #include <set>
- #include <ios>
- #include <assert.h> // Needed for DxilPipelineStateValidation.h
- #include "dxc/DxilContainer/DxilPipelineStateValidation.h"
- #include "DxilRootSignatureHelper.h"
- using namespace llvm;
- using std::string;
- namespace hlsl {
- using namespace root_sig_helper;
- //////////////////////////////////////////////////////////////////////////////
- // Interval helper.
- template <typename T>
- class CIntervalCollection {
- private:
- std::set<T> m_set;
- public:
- const T* FindIntersectingInterval(const T &I) {
- auto it = m_set.find(I);
- if (it != m_set.end())
- return &*it;
- return nullptr;
- }
- void Insert(const T& value) {
- auto result = m_set.insert(value);
- UNREFERENCED_PARAMETER(result);
- #if DBG
- DXASSERT(result.second, "otherwise interval collides with existing in collection");
- #endif
- }
- };
- //////////////////////////////////////////////////////////////////////////////
- // Verifier classes.
- class DescriptorTableVerifier {
- public:
- void Verify(const DxilDescriptorRange1 *pRanges, unsigned NumRanges,
- unsigned iRTS, DiagnosticPrinter &DiagPrinter);
- };
- class StaticSamplerVerifier {
- public:
- void Verify(const DxilStaticSamplerDesc *pDesc, DiagnosticPrinter &DiagPrinter);
- };
- class RootSignatureVerifier {
- public:
- RootSignatureVerifier();
- ~RootSignatureVerifier();
- void AllowReservedRegisterSpace(bool bAllow);
- // Call this before calling VerifyShader, as it accumulates root signature state.
- void VerifyRootSignature(const DxilVersionedRootSignatureDesc *pRootSignature,
- DiagnosticPrinter &DiagPrinter);
- void VerifyShader(DxilShaderVisibility VisType,
- const void *pPSVData,
- uint32_t PSVSize,
- DiagnosticPrinter &DiagPrinter);
- typedef enum NODE_TYPE {
- DESCRIPTOR_TABLE_ENTRY,
- ROOT_DESCRIPTOR,
- ROOT_CONSTANT,
- STATIC_SAMPLER
- } NODE_TYPE;
- private:
- static const unsigned kMinVisType = (unsigned)DxilShaderVisibility::All;
- static const unsigned kMaxVisType = (unsigned)DxilShaderVisibility::MaxValue;
- static const unsigned kMinDescType = (unsigned)DxilDescriptorRangeType::SRV;
- static const unsigned kMaxDescType = (unsigned)DxilDescriptorRangeType::MaxValue;
- struct RegisterRange {
- NODE_TYPE nt;
- unsigned space;
- unsigned lb; // inclusive lower bound
- unsigned ub; // inclusive upper bound
- unsigned iRP;
- unsigned iDTS;
- // Sort by space, then lower bound.
- bool operator<(const RegisterRange& other) const {
- return space < other.space ||
- (space == other.space && ub < other.lb);
- }
- // Like a regular -1,0,1 comparison, but 0 indicates overlap.
- int overlap(const RegisterRange& other) const {
- if (space < other.space) return -1;
- if (space > other.space) return 1;
- if (ub < other.lb) return -1;
- if (lb > other.ub) return 1;
- return 0;
- }
- // Check containment.
- bool contains(const RegisterRange& other) const {
- return (space == other.space) && (lb <= other.lb && other.ub <= ub);
- }
- };
- typedef CIntervalCollection<RegisterRange> RegisterRanges;
- void AddRegisterRange(unsigned iRTS, NODE_TYPE nt, unsigned iDTS,
- DxilDescriptorRangeType DescType,
- DxilShaderVisibility VisType,
- unsigned NumRegisters, unsigned BaseRegister,
- unsigned RegisterSpace, DiagnosticPrinter &DiagPrinter);
- const RegisterRange *FindCoveringInterval(DxilDescriptorRangeType RangeType,
- DxilShaderVisibility VisType,
- unsigned Num,
- unsigned LB,
- unsigned Space);
- RegisterRanges &
- GetRanges(DxilShaderVisibility VisType, DxilDescriptorRangeType DescType) {
- return RangeKinds[(unsigned)VisType][(unsigned)DescType];
- }
- RegisterRanges RangeKinds[kMaxVisType + 1][kMaxDescType + 1];
- bool m_bAllowReservedRegisterSpace;
- DxilRootSignatureFlags m_RootSignatureFlags;
- };
- void DescriptorTableVerifier::Verify(const DxilDescriptorRange1 *pRanges,
- uint32_t NumRanges, uint32_t iRP,
- DiagnosticPrinter &DiagPrinter) {
- bool bHasSamplers = false;
- bool bHasResources = false;
- uint64_t iAppendStartSlot = 0;
- for (unsigned iDTS = 0; iDTS < NumRanges; iDTS++) {
- const DxilDescriptorRange1 *pRange = &pRanges[iDTS];
- switch (pRange->RangeType) {
- case DxilDescriptorRangeType::SRV:
- case DxilDescriptorRangeType::UAV:
- case DxilDescriptorRangeType::CBV:
- bHasResources = true;
- break;
- case DxilDescriptorRangeType::Sampler:
- bHasSamplers = true;
- break;
- default:
- static_assert(DxilDescriptorRangeType::Sampler == DxilDescriptorRangeType::MaxValue,
- "otherwise, need to update cases here");
- EAT(DiagPrinter << "Unsupported RangeType value " << (uint32_t)pRange->RangeType
- << " (descriptor table slot [" << iDTS << "], root parameter [" << iRP << "]).\n");
- }
- // Samplers cannot be mixed with other resources.
- if (bHasResources && bHasSamplers) {
- EAT(DiagPrinter << "Samplers cannot be mixed with other "
- << "resource types in a descriptor table (root "
- << "parameter [" << iRP << "]).\n");
- }
- // NumDescriptors is not 0.
- if (pRange->NumDescriptors == 0) {
- EAT(DiagPrinter << "NumDescriptors cannot be 0 (descriptor "
- << "table slot [" << iDTS << "], root parameter [" << iRP << "]).\n");
- }
- // Range start.
- uint64_t iStartSlot = iAppendStartSlot;
- if (pRange->OffsetInDescriptorsFromTableStart != DxilDescriptorRangeOffsetAppend) {
- iStartSlot = pRange->OffsetInDescriptorsFromTableStart;
- }
- if (iStartSlot > UINT_MAX) {
- EAT(DiagPrinter << "Cannot append range with implicit lower "
- << "bound after an unbounded range (descriptor "
- << "table slot [" << iDTS << "], root parameter [" << iRP << "]).\n");
- }
- // Descriptor range and shader register range overlow.
- if (pRange->NumDescriptors != UINT_MAX) {
- // Bounded range.
- uint64_t ub1 = (uint64_t)pRange->BaseShaderRegister +
- (uint64_t)pRange->NumDescriptors - 1ull;
- if (ub1 > UINT_MAX) {
- EAT(DiagPrinter << "Overflow for shader register range: "
- << "BaseShaderRegister=" << pRange->BaseShaderRegister
- << ", NumDescriptor=" << pRange->NumDescriptors
- << "; (descriptor table slot [" << iDTS
- << "], root parameter [" << iRP << "]).\n");
- }
- uint64_t ub2 = (uint64_t)iStartSlot + (uint64_t)pRange->NumDescriptors - 1ull;
- if (ub2 > UINT_MAX) {
- EAT(DiagPrinter << "Overflow for descriptor range (descriptor "
- << "table slot [" << iDTS << "], root parameter [" << iRP << "])\n");
- }
- iAppendStartSlot = iStartSlot + (uint64_t)pRange->NumDescriptors;
- } else {
- // Unbounded range.
- iAppendStartSlot = 1ull + (uint64_t)UINT_MAX;
- }
- }
- }
- RootSignatureVerifier::RootSignatureVerifier() {
- m_RootSignatureFlags = DxilRootSignatureFlags::None;
- m_bAllowReservedRegisterSpace = false;
- }
- RootSignatureVerifier::~RootSignatureVerifier() {}
- void RootSignatureVerifier::AllowReservedRegisterSpace(bool bAllow) {
- m_bAllowReservedRegisterSpace = bAllow;
- }
- const char* RangeTypeString(DxilDescriptorRangeType rt)
- {
- static const char *RangeType[] = {"SRV", "UAV", "CBV", "SAMPLER"};
- static_assert(_countof(RangeType) == ((unsigned)DxilDescriptorRangeType::MaxValue + 1),
- "otherwise, need to update name array");
- return (rt <= DxilDescriptorRangeType::MaxValue) ? RangeType[(unsigned)rt]
- : "unknown";
- }
- const char *VisTypeString(DxilShaderVisibility vis) {
- static const char *Vis[] = {"ALL", "VERTEX", "HULL",
- "DOMAIN", "GEOMETRY", "PIXEL",
- "AMPLIFICATION", "MESH"};
- static_assert(_countof(Vis) == ((unsigned)DxilShaderVisibility::MaxValue + 1),
- "otherwise, need to update name array");
- unsigned idx = (unsigned)vis;
- return vis <= DxilShaderVisibility::MaxValue ? Vis[idx] : "unknown";
- }
- static bool IsDxilShaderVisibility(DxilShaderVisibility v) {
- return v <= DxilShaderVisibility::MaxValue;
- }
- void RootSignatureVerifier::AddRegisterRange(unsigned iRP,
- NODE_TYPE nt,
- unsigned iDTS,
- DxilDescriptorRangeType DescType,
- DxilShaderVisibility VisType,
- unsigned NumRegisters,
- unsigned BaseRegister,
- unsigned RegisterSpace,
- DiagnosticPrinter &DiagPrinter) {
- RegisterRange interval;
- interval.space = RegisterSpace;
- interval.lb = BaseRegister;
- interval.ub = (NumRegisters != UINT_MAX) ? BaseRegister + NumRegisters - 1 : UINT_MAX;
- interval.nt = nt;
- interval.iDTS = iDTS;
- interval.iRP = iRP;
- if (!m_bAllowReservedRegisterSpace &&
- (RegisterSpace >= DxilSystemReservedRegisterSpaceValuesStart) &&
- (RegisterSpace <= DxilSystemReservedRegisterSpaceValuesEnd)) {
- if (nt == DESCRIPTOR_TABLE_ENTRY) {
- EAT(DiagPrinter << "Root parameter [" << iRP << "] descriptor table entry [" << iDTS
- << "] specifies RegisterSpace=" << std::hex << RegisterSpace
- << ", which is invalid since RegisterSpace values in the range "
- << "[" << std::hex << DxilSystemReservedRegisterSpaceValuesStart
- << "," << std::hex << DxilSystemReservedRegisterSpaceValuesEnd
- << "] are reserved for system use.\n");
- }
- else {
- EAT(DiagPrinter << "Root parameter [" << iRP
- << "] specifies RegisterSpace=" << std::hex << RegisterSpace
- << ", which is invalid since RegisterSpace values in the range "
- << "[" << std::hex << DxilSystemReservedRegisterSpaceValuesStart
- << "," << std::hex << DxilSystemReservedRegisterSpaceValuesEnd
- << "] are reserved for system use.\n");
- }
- }
- const RegisterRange *pNode = nullptr;
- DxilShaderVisibility NodeVis = VisType;
- if (VisType == DxilShaderVisibility::All) {
- // Check for overlap with each visibility type.
- for (unsigned iVT = kMinVisType; iVT <= kMaxVisType; iVT++) {
- pNode = GetRanges((DxilShaderVisibility)iVT, DescType).FindIntersectingInterval(interval);
- if (pNode != nullptr)
- break;
- }
- } else {
- // Check for overlap with the same visibility.
- pNode = GetRanges(VisType, DescType).FindIntersectingInterval(interval);
- // Check for overlap with ALL visibility.
- if (pNode == nullptr) {
- pNode = GetRanges(DxilShaderVisibility::All, DescType).FindIntersectingInterval(interval);
- NodeVis = DxilShaderVisibility::All;
- }
- }
- if (pNode != nullptr) {
- const int strSize = 132;
- char testString[strSize];
- char nodeString[strSize];
- switch (nt) {
- case DESCRIPTOR_TABLE_ENTRY:
- StringCchPrintfA(testString, strSize, "(root parameter [%u], visibility %s, descriptor table slot [%u])",
- iRP, VisTypeString(VisType), iDTS);
- break;
- case ROOT_DESCRIPTOR:
- case ROOT_CONSTANT:
- StringCchPrintfA(testString, strSize, "(root parameter [%u], visibility %s)",
- iRP, VisTypeString(VisType));
- break;
- case STATIC_SAMPLER:
- StringCchPrintfA(testString, strSize, "(static sampler [%u], visibility %s)",
- iRP, VisTypeString(VisType));
- break;
- default:
- DXASSERT_NOMSG(false);
- break;
- }
- switch (pNode->nt)
- {
- case DESCRIPTOR_TABLE_ENTRY:
- StringCchPrintfA(nodeString, strSize, "(root parameter[%u], visibility %s, descriptor table slot [%u])",
- pNode->iRP, VisTypeString(NodeVis), pNode->iDTS);
- break;
- case ROOT_DESCRIPTOR:
- case ROOT_CONSTANT:
- StringCchPrintfA(nodeString, strSize, "(root parameter [%u], visibility %s)",
- pNode->iRP, VisTypeString(NodeVis));
- break;
- case STATIC_SAMPLER:
- StringCchPrintfA(nodeString, strSize, "(static sampler [%u], visibility %s)",
- pNode->iRP, VisTypeString(NodeVis));
- break;
- default:
- DXASSERT_NOMSG(false);
- break;
- }
- EAT(DiagPrinter << "Shader register range of type " << RangeTypeString(DescType)
- << " " << testString << " overlaps with another "
- << "shader register range " << nodeString << ".\n");
- }
- // Insert node.
- GetRanges(VisType, DescType).Insert(interval);
- }
- const RootSignatureVerifier::RegisterRange *
- RootSignatureVerifier::FindCoveringInterval(DxilDescriptorRangeType RangeType,
- DxilShaderVisibility VisType,
- unsigned Num,
- unsigned LB,
- unsigned Space) {
- RegisterRange RR;
- RR.space = Space;
- RR.lb = LB;
- RR.ub = LB + Num - 1;
- const RootSignatureVerifier::RegisterRange *pRange = GetRanges(DxilShaderVisibility::All, RangeType).FindIntersectingInterval(RR);
- if (!pRange && VisType != DxilShaderVisibility::All) {
- pRange = GetRanges(VisType, RangeType).FindIntersectingInterval(RR);
- }
- if (pRange && !pRange->contains(RR)) {
- pRange = nullptr;
- }
- return pRange;
- }
- static DxilDescriptorRangeType GetRangeType(DxilRootParameterType RPT) {
- switch (RPT) {
- case DxilRootParameterType::CBV: return DxilDescriptorRangeType::CBV;
- case DxilRootParameterType::SRV: return DxilDescriptorRangeType::SRV;
- case DxilRootParameterType::UAV: return DxilDescriptorRangeType::UAV;
- default:
- static_assert(DxilRootParameterType::UAV == DxilRootParameterType::MaxValue,
- "otherwise, need to add cases here.");
- break;
- }
- DXASSERT_NOMSG(false);
- return DxilDescriptorRangeType::SRV;
- }
- void RootSignatureVerifier::VerifyRootSignature(
- const DxilVersionedRootSignatureDesc *pVersionedRootSignature,
- DiagnosticPrinter &DiagPrinter) {
- const DxilVersionedRootSignatureDesc *pUpconvertedRS = nullptr;
- // Up-convert root signature to the latest RS version.
- ConvertRootSignature(pVersionedRootSignature, DxilRootSignatureVersion::Version_1_1, &pUpconvertedRS);
- DXASSERT_NOMSG(pUpconvertedRS->Version == DxilRootSignatureVersion::Version_1_1);
- // Ensure this gets deleted as necessary.
- struct SigGuard {
- const DxilVersionedRootSignatureDesc *Orig, *Guard;
- SigGuard(const DxilVersionedRootSignatureDesc *pOrig, const DxilVersionedRootSignatureDesc *pGuard)
- : Orig(pOrig), Guard(pGuard) { }
- ~SigGuard() {
- if (Orig != Guard) {
- DeleteRootSignature(Guard);
- }
- }
- };
- SigGuard S(pVersionedRootSignature, pUpconvertedRS);
- const DxilRootSignatureDesc1 *pRootSignature = &pUpconvertedRS->Desc_1_1;
- // Flags (assume they are bits that can be combined with OR).
- if ((pRootSignature->Flags & ~DxilRootSignatureFlags::ValidFlags) != DxilRootSignatureFlags::None) {
- EAT(DiagPrinter << "Unsupported bit-flag set (root signature flags "
- << std::hex << (uint32_t)pRootSignature->Flags << ").\n");
- }
- m_RootSignatureFlags = pRootSignature->Flags;
- for (unsigned iRP = 0; iRP < pRootSignature->NumParameters; iRP++) {
- const DxilRootParameter1 *pSlot = &pRootSignature->pParameters[iRP];
- // Shader visibility.
- DxilShaderVisibility Visibility = pSlot->ShaderVisibility;
- if (!IsDxilShaderVisibility(Visibility)) {
- EAT(DiagPrinter << "Unsupported ShaderVisibility value " << (uint32_t)Visibility
- << " (root parameter [" << iRP << "]).\n");
- }
- DxilRootParameterType ParameterType = pSlot->ParameterType;
- switch (ParameterType) {
- case DxilRootParameterType::DescriptorTable: {
- DescriptorTableVerifier DTV;
- DTV.Verify(pSlot->DescriptorTable.pDescriptorRanges,
- pSlot->DescriptorTable.NumDescriptorRanges, iRP, DiagPrinter);
- for (unsigned iDTS = 0; iDTS < pSlot->DescriptorTable.NumDescriptorRanges; iDTS++) {
- const DxilDescriptorRange1 *pRange = &pSlot->DescriptorTable.pDescriptorRanges[iDTS];
- unsigned RangeFlags = (unsigned)pRange->Flags;
- // Verify range flags.
- if (RangeFlags & ~(unsigned)DxilDescriptorRangeFlags::ValidFlags) {
- EAT(DiagPrinter << "Unsupported bit-flag set (descriptor range flags "
- << (uint32_t)pRange->Flags << ").\n");
- }
- switch (pRange->RangeType) {
- case DxilDescriptorRangeType::Sampler: {
- if (RangeFlags & (unsigned)(DxilDescriptorRangeFlags::DataVolatile |
- DxilDescriptorRangeFlags::DataStatic |
- DxilDescriptorRangeFlags::DataStaticWhileSetAtExecute)) {
- EAT(DiagPrinter << "Sampler descriptor ranges can't specify DATA_* flags "
- << "since there is no data pointed to by samplers "
- << "(descriptor range flags " << (uint32_t)pRange->Flags << ").\n");
- }
- break;
- }
- default: {
- unsigned NumDataFlags = 0;
- if (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataVolatile) { NumDataFlags++; }
- if (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataStatic) { NumDataFlags++; }
- if (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataStaticWhileSetAtExecute) { NumDataFlags++; }
- if (NumDataFlags > 1) {
- EAT(DiagPrinter << "Descriptor range flags cannot specify more than one DATA_* flag "
- << "at a time (descriptor range flags " << (uint32_t)pRange->Flags << ").\n");
- }
- if ((RangeFlags & (unsigned)DxilDescriptorRangeFlags::DataStatic) &&
- (RangeFlags & (unsigned)DxilDescriptorRangeFlags::DescriptorsVolatile)) {
- 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 << "). "
- << "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");
- }
- break;
- }
- }
- AddRegisterRange(iRP,
- DESCRIPTOR_TABLE_ENTRY,
- iDTS,
- pRange->RangeType,
- Visibility,
- pRange->NumDescriptors,
- pRange->BaseShaderRegister,
- pRange->RegisterSpace,
- DiagPrinter);
- }
- break;
- }
- case DxilRootParameterType::Constants32Bit:
- AddRegisterRange(iRP,
- ROOT_CONSTANT,
- (unsigned)-1,
- DxilDescriptorRangeType::CBV,
- Visibility,
- 1,
- pSlot->Constants.ShaderRegister,
- pSlot->Constants.RegisterSpace,
- DiagPrinter);
- break;
- case DxilRootParameterType::CBV:
- case DxilRootParameterType::SRV:
- case DxilRootParameterType::UAV: {
- // Verify root descriptor flags.
- unsigned Flags = (unsigned)pSlot->Descriptor.Flags;
- if (Flags & ~(unsigned)DxilRootDescriptorFlags::ValidFlags) {
- EAT(DiagPrinter << "Unsupported bit-flag set (root descriptor flags " << std::hex << Flags << ").\n");
- }
- unsigned NumDataFlags = 0;
- if (Flags & (unsigned)DxilRootDescriptorFlags::DataVolatile) { NumDataFlags++; }
- if (Flags & (unsigned)DxilRootDescriptorFlags::DataStatic) { NumDataFlags++; }
- if (Flags & (unsigned)DxilRootDescriptorFlags::DataStaticWhileSetAtExecute) { NumDataFlags++; }
- if (NumDataFlags > 1) {
- EAT(DiagPrinter << "Root descriptor flags cannot specify more "
- << "than one DATA_* flag at a time (root "
- << "descriptor flags " << NumDataFlags << ").\n");
- }
- AddRegisterRange(iRP, ROOT_DESCRIPTOR, (unsigned)-1,
- GetRangeType(ParameterType), Visibility, 1,
- pSlot->Descriptor.ShaderRegister,
- pSlot->Descriptor.RegisterSpace, DiagPrinter);
- break;
- }
- default:
- static_assert(DxilRootParameterType::UAV == DxilRootParameterType::MaxValue,
- "otherwise, need to add cases here.");
- EAT(DiagPrinter << "Unsupported ParameterType value " << (uint32_t)ParameterType
- << " (root parameter " << iRP << ")\n");
- }
- }
- for (unsigned iSS = 0; iSS < pRootSignature->NumStaticSamplers; iSS++) {
- const DxilStaticSamplerDesc *pSS = &pRootSignature->pStaticSamplers[iSS];
- // Shader visibility.
- DxilShaderVisibility Visibility = pSS->ShaderVisibility;
- if (!IsDxilShaderVisibility(Visibility)) {
- EAT(DiagPrinter << "Unsupported ShaderVisibility value " << (uint32_t)Visibility
- << " (static sampler [" << iSS << "]).\n");
- }
- StaticSamplerVerifier SSV;
- SSV.Verify(pSS, DiagPrinter);
- AddRegisterRange(iSS, STATIC_SAMPLER, (unsigned)-1,
- DxilDescriptorRangeType::Sampler, Visibility, 1,
- pSS->ShaderRegister, pSS->RegisterSpace, DiagPrinter);
- }
- }
- void RootSignatureVerifier::VerifyShader(DxilShaderVisibility VisType,
- const void *pPSVData,
- uint32_t PSVSize,
- DiagnosticPrinter &DiagPrinter) {
- DxilPipelineStateValidation PSV;
- IFTBOOL(PSV.InitFromPSV0(pPSVData, PSVSize), E_INVALIDARG);
- bool bShaderDeniedByRootSig = false;
- switch (VisType) {
- case DxilShaderVisibility::Vertex:
- if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyVertexShaderRootAccess) != DxilRootSignatureFlags::None) {
- bShaderDeniedByRootSig = true;
- }
- break;
- case DxilShaderVisibility::Hull:
- if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyHullShaderRootAccess) != DxilRootSignatureFlags::None) {
- bShaderDeniedByRootSig = true;
- }
- break;
- case DxilShaderVisibility::Domain:
- if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyDomainShaderRootAccess) != DxilRootSignatureFlags::None) {
- bShaderDeniedByRootSig = true;
- }
- break;
- case DxilShaderVisibility::Geometry:
- if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyGeometryShaderRootAccess) != DxilRootSignatureFlags::None) {
- bShaderDeniedByRootSig = true;
- }
- break;
- case DxilShaderVisibility::Pixel:
- if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyPixelShaderRootAccess) != DxilRootSignatureFlags::None) {
- bShaderDeniedByRootSig = true;
- }
- break;
- case DxilShaderVisibility::Amplification:
- if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyAmplificationShaderRootAccess) != DxilRootSignatureFlags::None) {
- bShaderDeniedByRootSig = true;
- }
- break;
- case DxilShaderVisibility::Mesh:
- if ((m_RootSignatureFlags & DxilRootSignatureFlags::DenyMeshShaderRootAccess) != DxilRootSignatureFlags::None) {
- bShaderDeniedByRootSig = true;
- }
- break;
- default:
- break;
- }
- bool bShaderHasRootBindings = false;
- for (unsigned iResource = 0; iResource < PSV.GetBindCount(); iResource++) {
- const PSVResourceBindInfo0 *pBindInfo0 = PSV.GetPSVResourceBindInfo0(iResource);
- DXASSERT_NOMSG(pBindInfo0);
- unsigned Space = pBindInfo0->Space;
- unsigned LB = pBindInfo0->LowerBound;
- unsigned UB = pBindInfo0->UpperBound;
- unsigned Num = (UB != UINT_MAX) ? (UB - LB + 1) : 1;
- PSVResourceType ResType = (PSVResourceType)pBindInfo0->ResType;
- switch(ResType) {
- case PSVResourceType::Sampler: {
- bShaderHasRootBindings = true;
- auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::Sampler, VisType, Num, LB, Space);
- if(!pCoveringRange) {
- EAT(DiagPrinter << "Shader sampler descriptor range (RegisterSpace=" << Space
- << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
- << ") is not fully bound in root signature.\n");
- }
- break;
- }
- case PSVResourceType::SRVTyped:
- case PSVResourceType::SRVRaw:
- case PSVResourceType::SRVStructured: {
- bShaderHasRootBindings = true;
- auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::SRV, VisType, Num, LB, Space);
- if (pCoveringRange) {
- if(pCoveringRange->nt == ROOT_DESCRIPTOR && ResType == PSVResourceType::SRVTyped) {
- EAT(DiagPrinter << "A Shader is declaring a resource object as a texture using "
- << "a register mapped to a root descriptor SRV (RegisterSpace=" << Space
- << ", ShaderRegister=" << LB << "). "
- << "SRV or UAV root descriptors can only be Raw or Structured buffers.\n");
- }
- }
- else {
- EAT(DiagPrinter << "Shader SRV descriptor range (RegisterSpace=" << Space
- << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
- << ") is not fully bound in root signature.\n");
- }
- break;
- }
- case PSVResourceType::UAVTyped:
- case PSVResourceType::UAVRaw:
- case PSVResourceType::UAVStructured:
- case PSVResourceType::UAVStructuredWithCounter: {
- bShaderHasRootBindings = true;
- auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::UAV, VisType, Num, LB, Space);
- if (pCoveringRange) {
- if (pCoveringRange->nt == ROOT_DESCRIPTOR) {
- if (ResType == PSVResourceType::UAVTyped) {
- EAT(DiagPrinter << "A shader is declaring a typed UAV using a register mapped "
- << "to a root descriptor UAV (RegisterSpace=" << Space
- << ", ShaderRegister=" << LB << "). "
- << "SRV or UAV root descriptors can only be Raw or Structured buffers.\n");
- }
- if (ResType == PSVResourceType::UAVStructuredWithCounter) {
- EAT(DiagPrinter << "A Shader is declaring a structured UAV with counter using "
- << "a register mapped to a root descriptor UAV (RegisterSpace=" << Space
- << ", ShaderRegister=" << LB << "). "
- << "SRV or UAV root descriptors can only be Raw or Structured buffers.\n");
- }
- }
- }
- else {
- EAT(DiagPrinter << "Shader UAV descriptor range (RegisterSpace=" << Space
- << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
- << ") is not fully bound in root signature.\n");
- }
- break;
- }
- case PSVResourceType::CBV: {
- bShaderHasRootBindings = true;
- auto pCoveringRange = FindCoveringInterval(DxilDescriptorRangeType::CBV, VisType, Num, LB, Space);
- if (!pCoveringRange) {
- EAT(DiagPrinter << "Shader CBV descriptor range (RegisterSpace=" << Space
- << ", NumDescriptors=" << Num << ", BaseShaderRegister=" << LB
- << ") is not fully bound in root signature.\n");
- }
- break;
- }
- default:
- break;
- }
- }
- if (bShaderHasRootBindings && bShaderDeniedByRootSig) {
- EAT(DiagPrinter << "Shader has root bindings but root signature uses a DENY flag "
- << "to disallow root binding access to the shader stage.\n");
- }
- }
- BOOL isNaN(const float &a) {
- static const unsigned exponentMask = 0x7f800000;
- static const unsigned mantissaMask = 0x007fffff;
- unsigned u = *(const unsigned *)&a;
- return (((u & exponentMask) == exponentMask) && (u & mantissaMask)); // NaN
- }
- static bool IsDxilTextureAddressMode(DxilTextureAddressMode v) {
- return DxilTextureAddressMode::Wrap <= v &&
- v <= DxilTextureAddressMode::MirrorOnce;
- }
- static bool IsDxilComparisonFunc(DxilComparisonFunc v) {
- return DxilComparisonFunc::Never <= v && v <= DxilComparisonFunc::Always;
- }
- // This validation closely mirrors CCreateSamplerStateValidator's checks
- void StaticSamplerVerifier::Verify(const DxilStaticSamplerDesc* pDesc,
- DiagnosticPrinter &DiagPrinter) {
- if (!pDesc) {
- EAT(DiagPrinter << "Static sampler: A nullptr pSamplerDesc was specified.\n");
- }
- bool bIsComparison = false;
- switch (pDesc->Filter) {
- case DxilFilter::MINIMUM_MIN_MAG_MIP_POINT:
- case DxilFilter::MINIMUM_MIN_MAG_POINT_MIP_LINEAR:
- case DxilFilter::MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT:
- case DxilFilter::MINIMUM_MIN_POINT_MAG_MIP_LINEAR:
- case DxilFilter::MINIMUM_MIN_LINEAR_MAG_MIP_POINT:
- case DxilFilter::MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
- case DxilFilter::MINIMUM_MIN_MAG_LINEAR_MIP_POINT:
- case DxilFilter::MINIMUM_MIN_MAG_MIP_LINEAR:
- case DxilFilter::MINIMUM_ANISOTROPIC:
- case DxilFilter::MAXIMUM_MIN_MAG_MIP_POINT:
- case DxilFilter::MAXIMUM_MIN_MAG_POINT_MIP_LINEAR:
- case DxilFilter::MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT:
- case DxilFilter::MAXIMUM_MIN_POINT_MAG_MIP_LINEAR:
- case DxilFilter::MAXIMUM_MIN_LINEAR_MAG_MIP_POINT:
- case DxilFilter::MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
- case DxilFilter::MAXIMUM_MIN_MAG_LINEAR_MIP_POINT:
- case DxilFilter::MAXIMUM_MIN_MAG_MIP_LINEAR:
- case DxilFilter::MAXIMUM_ANISOTROPIC:
- break;
- case DxilFilter::MIN_MAG_MIP_POINT:
- case DxilFilter::MIN_MAG_POINT_MIP_LINEAR:
- case DxilFilter::MIN_POINT_MAG_LINEAR_MIP_POINT:
- case DxilFilter::MIN_POINT_MAG_MIP_LINEAR:
- case DxilFilter::MIN_LINEAR_MAG_MIP_POINT:
- case DxilFilter::MIN_LINEAR_MAG_POINT_MIP_LINEAR:
- case DxilFilter::MIN_MAG_LINEAR_MIP_POINT:
- case DxilFilter::MIN_MAG_MIP_LINEAR:
- case DxilFilter::ANISOTROPIC:
- break;
- case DxilFilter::COMPARISON_MIN_MAG_MIP_POINT:
- case DxilFilter::COMPARISON_MIN_MAG_POINT_MIP_LINEAR:
- case DxilFilter::COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT:
- case DxilFilter::COMPARISON_MIN_POINT_MAG_MIP_LINEAR:
- case DxilFilter::COMPARISON_MIN_LINEAR_MAG_MIP_POINT:
- case DxilFilter::COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
- case DxilFilter::COMPARISON_MIN_MAG_LINEAR_MIP_POINT:
- case DxilFilter::COMPARISON_MIN_MAG_MIP_LINEAR:
- case DxilFilter::COMPARISON_ANISOTROPIC:
- bIsComparison = true;
- break;
- default:
- EAT(DiagPrinter << "Static sampler: Filter unrecognized.\n");
- }
- if (!IsDxilTextureAddressMode(pDesc->AddressU)) {
- EAT(DiagPrinter << "Static sampler: AddressU unrecognized.\n");
- }
- if (!IsDxilTextureAddressMode(pDesc->AddressV)) {
- EAT(DiagPrinter << "Static sampler: AddressV unrecognized.\n");
- }
- if (!IsDxilTextureAddressMode(pDesc->AddressW)) {
- EAT(DiagPrinter << "Static sampler: AddressW unrecognized.\n");
- }
- if (isNaN(pDesc->MipLODBias) || (pDesc->MipLODBias < DxilMipLodBiaxMin) ||
- (pDesc->MipLODBias > DxilMipLodBiaxMax)) {
- EAT(DiagPrinter << "Static sampler: MipLODBias must be in the "
- << "range [" << DxilMipLodBiaxMin << " to " << DxilMipLodBiaxMax
- <<"]. " << pDesc->MipLODBias << "specified.\n");
- }
- if (pDesc->MaxAnisotropy > DxilMapAnisotropy) {
- EAT(DiagPrinter << "Static sampler: MaxAnisotropy must be in "
- << "the range [0 to " << DxilMapAnisotropy << "]. "
- << pDesc->MaxAnisotropy << " specified.\n");
- }
- if (bIsComparison && !IsDxilComparisonFunc(pDesc->ComparisonFunc)) {
- EAT(DiagPrinter << "Static sampler: ComparisonFunc unrecognized.");
- }
- if (isNaN(pDesc->MinLOD)) {
- EAT(DiagPrinter << "Static sampler: MinLOD be in the range [-INF to +INF]. "
- << pDesc->MinLOD << " specified.\n");
- }
- if (isNaN(pDesc->MaxLOD)) {
- EAT(DiagPrinter << "Static sampler: MaxLOD be in the range [-INF to +INF]. "
- << pDesc->MaxLOD << " specified.\n");
- }
- }
- static DxilShaderVisibility GetVisibilityType(DXIL::ShaderKind ShaderKind) {
- switch(ShaderKind) {
- case DXIL::ShaderKind::Pixel: return DxilShaderVisibility::Pixel;
- case DXIL::ShaderKind::Vertex: return DxilShaderVisibility::Vertex;
- case DXIL::ShaderKind::Geometry: return DxilShaderVisibility::Geometry;
- case DXIL::ShaderKind::Hull: return DxilShaderVisibility::Hull;
- case DXIL::ShaderKind::Domain: return DxilShaderVisibility::Domain;
- case DXIL::ShaderKind::Amplification: return DxilShaderVisibility::Amplification;
- case DXIL::ShaderKind::Mesh: return DxilShaderVisibility::Mesh;
- default: return DxilShaderVisibility::All;
- }
- }
- _Use_decl_annotations_
- bool VerifyRootSignatureWithShaderPSV(const DxilVersionedRootSignatureDesc *pDesc,
- DXIL::ShaderKind ShaderKind,
- const void *pPSVData,
- uint32_t PSVSize,
- llvm::raw_ostream &DiagStream) {
- try {
- RootSignatureVerifier RSV;
- DiagnosticPrinterRawOStream DiagPrinter(DiagStream);
- RSV.VerifyRootSignature(pDesc, DiagPrinter);
- RSV.VerifyShader(GetVisibilityType(ShaderKind), pPSVData, PSVSize, DiagPrinter);
- } catch (...) {
- return false;
- }
- return true;
- }
- bool VerifyRootSignature(_In_ const DxilVersionedRootSignatureDesc *pDesc,
- _In_ llvm::raw_ostream &DiagStream,
- _In_ bool bAllowReservedRegisterSpace) {
- try {
- RootSignatureVerifier RSV;
- RSV.AllowReservedRegisterSpace(bAllowReservedRegisterSpace);
- DiagnosticPrinterRawOStream DiagPrinter(DiagStream);
- RSV.VerifyRootSignature(pDesc, DiagPrinter);
- } catch (...) {
- return false;
- }
- return true;
- }
- } // namespace hlsl
|