diff options
| author | ArielG-NV <159081215+ArielG-NV@users.noreply.github.com> | 2024-06-12 16:38:23 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-12 13:38:23 -0700 |
| commit | 8813c610562b1c30222ec3ef0734ef601d43b617 (patch) | |
| tree | b012aa178a52a0313ce9deab31006556a2637011 /source/slang/slang-capability.cpp | |
| parent | 7447fcafa71440336f553d6e0af21b12fc74d138 (diff) | |
Capability System: Implicit capability upgrade warning/error (#4241)
* capability upgrade warning/error
adjusted implementation + tests to support a warning/error if capabilities are implicitly upgraded and test accordingly.
* add glsl profile caps
* add GLSL and HLSL capabilities to the associated capability
* syntax error in capdef
* only error if user explicitly enables capabilities
1. changed testing infrastructure to not set a `profile` explicitly,
2. Added tests to be sure this works as intended with user API and with slangc command line
* Change capability atom definitions and how Slang manages them to fix errors
1. most `glsl_spirv` version atoms have been removed from `.capdef`, instead we will translate `spirv` version atoms into `glsl_spirv` since there is no point in writing the same code twice in `.capdef` files to define `spirv` versions.
2. add spirv version, and hlsl sm version (and equivlent) capability dependencies
3. removed some stage requirments which were set on objects, keep the wrapper capabilities. I am keeping the wrapper capabilities since I am unaware on if there are stage limitations (spec says code in practice does not work).
* check internal version instead of version profile (_spirv_1_5 vs. spirv_1_5)
* remove unused OpCapability. adjust SPIRV version'ing again for glsl_spirv
* apply workaround for glslang bug with rayquery usage
* ensure capabilities targetted by a profile and added together by a user are valid
* remove additions to `spirv_1_*` wrapper
* spirv_* -> glsl_spirv fix
* fix bug where incompatable profiles would cause invalid target caps
* try to avoid joining invalid capabilities
* fix the warning/error & printing
* run through tests to fix capability system and test mistakes
many mistakes were mesh shaders doing `-profile glsl_450+spirv_1_4`. This is not allowed for a few reasons
1. the test tooling does not handle arguments the same as `slangc`
2. glsl_450 core profile does not support mesh shaders, nor does spirv_1_4. sm_6_5 does work in this senario
* set some sm_4_1 intrinsics to sm_4_0
* replace `GLSL_` defs with `glsl_`
* swap the unsupported render-test syntax for working syntax
* set d3d11/d3d12 profile defaults
this is required since sm version changes compiled code & behavior
* adjusted nvapi capabilities with atomics + d3d11 set to use sm_5_0 as per default
* cleanup
* address review
* incorrect styling
* change `bitscanForward` to work as intended on 32 bit targets
---------
Co-authored-by: Yong He <yonghe@outlook.com>
Diffstat (limited to 'source/slang/slang-capability.cpp')
| -rw-r--r-- | source/slang/slang-capability.cpp | 144 |
1 files changed, 113 insertions, 31 deletions
diff --git a/source/slang/slang-capability.cpp b/source/slang/slang-capability.cpp index 21b2641b4..2c3069f61 100644 --- a/source/slang/slang-capability.cpp +++ b/source/slang/slang-capability.cpp @@ -100,16 +100,16 @@ bool isDirectChildOfAbstractAtom(CapabilityAtom name) return _getInfo(name).abstractBase != CapabilityName::Invalid; } -bool isTargetVersionAtom(CapabilityName name) +bool isTargetVersionAtom(CapabilityAtom name) { - if (name >= CapabilityName::spirv_1_0 && name <= getLatestSpirvAtom()) + if (name >= CapabilityAtom::_spirv_1_0 && name <= getLatestSpirvAtom()) return true; - if (name >= CapabilityName::metallib_2_3 && name <= getLatestMetalAtom()) + if (name >= CapabilityAtom::metallib_2_3 && name <= getLatestMetalAtom()) return true; return false; } -bool isSpirvExtensionAtom(CapabilityName name) +bool isSpirvExtensionAtom(CapabilityAtom name) { return UnownedStringSlice(_getInfo(name).name).startsWith("SPV_"); } @@ -124,26 +124,26 @@ CapabilityName findCapabilityName(UnownedStringSlice const& name) return result; } -CapabilityName getLatestSpirvAtom() +inline CapabilityAtom getLatestSpirvAtom() { - static CapabilityName result = CapabilityName::Invalid; - if (result == CapabilityName::Invalid) + static CapabilityAtom result = CapabilityAtom::Invalid; + if (result == CapabilityAtom::Invalid) { - CapabilitySet latestSpirvCapSet = CapabilitySet(CapabilityName::spirv_latest); + CapabilitySet latestSpirvCapSet = CapabilitySet(CapabilityName::_spirv_latest); auto latestSpirvCapSetElements = latestSpirvCapSet.getAtomSets()->getElements<CapabilityAtom>(); - result = (CapabilityName)latestSpirvCapSetElements[latestSpirvCapSetElements.getCount() - 2]; //-1 gets shader stage + result = asAtom(latestSpirvCapSetElements[latestSpirvCapSetElements.getCount() - 2]); //-1 gets shader stage } return result; } -CapabilityName getLatestMetalAtom() +CapabilityAtom getLatestMetalAtom() { - static CapabilityName result = CapabilityName::Invalid; - if (result == CapabilityName::Invalid) + static CapabilityAtom result = CapabilityAtom::Invalid; + if (result == CapabilityAtom::Invalid) { CapabilitySet latestMetalCapSet = CapabilitySet(CapabilityName::metallib_latest); auto latestMetalCapSetElements = latestMetalCapSet.getAtomSets()->getElements<CapabilityAtom>(); - result = (CapabilityName)latestMetalCapSetElements[latestMetalCapSetElements.getCount() - 2]; //-1 gets shader stage + result = asAtom(latestMetalCapSetElements[latestMetalCapSetElements.getCount() - 2]); //-1 gets shader stage } return result; } @@ -175,7 +175,7 @@ CapabilityAtom getTargetAtomInSet(const CapabilityAtomSet& atomSet) auto iter = out.begin(); if (iter == out.end()) return CapabilityAtom::Invalid; - return (CapabilityAtom)*iter; + return asAtom(*iter); } CapabilityAtom getStageAtomInSet(const CapabilityAtomSet& atomSet) @@ -186,7 +186,7 @@ CapabilityAtom getStageAtomInSet(const CapabilityAtomSet& atomSet) auto iter = out.begin(); if (iter == out.end()) return CapabilityAtom::Invalid; - return (CapabilityAtom)*iter; + return asAtom(*iter); } template<CapabilityName keyholeAtomToPermuteWith> @@ -201,11 +201,11 @@ void CapabilitySet::addPermutationsOfConjunctionForEachInContainer(CapabilityAto if constexpr (keyholeAtomToPermuteWith == CapabilityName::target) { - addConjunction(conjunctionPermutation, (CapabilityAtom)atom, knownStageAtom); + addConjunction(conjunctionPermutation, asAtom(atom), knownStageAtom); } else if constexpr (keyholeAtomToPermuteWith == CapabilityName::stage) { - addConjunction(conjunctionPermutation, knownTargetAtom, (CapabilityAtom)atom); + addConjunction(conjunctionPermutation, knownTargetAtom, asAtom(atom)); } else { @@ -394,17 +394,25 @@ bool CapabilitySet::implies(CapabilityAtom atom) const return this->implies(tmpSet); } -bool CapabilitySet::implies(CapabilitySet const& other, const bool onlyRequireSingleImply) const +CapabilitySet::ImpliesReturnFlags CapabilitySet::_implies(CapabilitySet const& otherSet, ImpliesFlags flags) const { // x implies (c | d) only if (x implies c) and (x implies d). - for (const auto& otherTarget : other.m_targetSets) + bool onlyRequireSingleImply = ((int)flags & (int)ImpliesFlags::OnlyRequireASingleValidImply); + int flagsCollected = (int)CapabilitySet::ImpliesReturnFlags::NotImplied; + + if (otherSet.isEmpty()) + return CapabilitySet::ImpliesReturnFlags::Implied; + + for (const auto& otherTarget : otherSet.m_targetSets) { auto thisTarget = this->m_targetSets.tryGetValue(otherTarget.first); if (!thisTarget) { + if (onlyRequireSingleImply) + continue; // 'this' lacks a target 'other' has. - return false; + return CapabilitySet::ImpliesReturnFlags::NotImplied; } for (const auto& otherStage : otherTarget.second.shaderStageSets) @@ -412,31 +420,44 @@ bool CapabilitySet::implies(CapabilitySet const& other, const bool onlyRequireSi auto thisStage = thisTarget->shaderStageSets.tryGetValue(otherStage.first); if (!thisStage) { + if (onlyRequireSingleImply) + continue; // 'this' lacks a stage 'other' has. - return false; + return CapabilitySet::ImpliesReturnFlags::NotImplied; } // all stage sets that are in 'other' must be contained by 'this' - if(thisStage->atomSet) + if (thisStage->atomSet) { auto& thisStageSet = thisStage->atomSet.value(); - if(otherStage.second.atomSet) - { - if (!onlyRequireSingleImply) + if (otherStage.second.atomSet) + { + auto contained = thisStageSet.contains(otherStage.second.atomSet.value()); + if (!onlyRequireSingleImply && !contained) { - if (!thisStageSet.contains(otherStage.second.atomSet.value())) - return false; + return CapabilitySet::ImpliesReturnFlags::NotImplied; } - else + else if (onlyRequireSingleImply && contained) { - if (thisStageSet.contains(otherStage.second.atomSet.value())) - return true; + return CapabilitySet::ImpliesReturnFlags::Implied; } } } } } - return !onlyRequireSingleImply; + if (!onlyRequireSingleImply) + flagsCollected |= (int)CapabilitySet::ImpliesReturnFlags::Implied; + + return (CapabilitySet::ImpliesReturnFlags)flagsCollected; +} + +bool CapabilitySet::implies(CapabilitySet const& other) const +{ + return (int)_implies(other, ImpliesFlags::None) & (int)CapabilitySet::ImpliesReturnFlags::Implied; +} +CapabilitySet::ImpliesReturnFlags CapabilitySet::atLeastOneSetImpliedInOther(CapabilitySet const& other) const +{ + return _implies(other, ImpliesFlags::OnlyRequireASingleValidImply); } void CapabilityTargetSet::unionWith(const CapabilityTargetSet& other) @@ -827,6 +848,53 @@ bool CapabilitySet::checkCapabilityRequirement(CapabilitySet const& available, C return true; } +/// Converts spirv version atom to the glsl_spirv equivlent. If not possible, Invalid is returned +inline CapabilityName maybeConvertSpirvVersionToGlslSpirvVersion(CapabilityName& atom) +{ + if (atom >= CapabilityName::_spirv_1_0 && asAtom(atom) <= getLatestSpirvAtom()) + { + return (CapabilityName)((Int)CapabilityName::glsl_spirv_1_0 + ((Int)atom - (Int)CapabilityName::_spirv_1_0)); + } + return CapabilityName::Invalid; +} + +void CapabilitySet::addSpirvVersionFromOtherAsGlslSpirvVersion(CapabilitySet& other) +{ + if (auto* otherTargetSet = other.m_targetSets.tryGetValue(CapabilityAtom::spirv)) + { + auto* thisTargetSet = m_targetSets.tryGetValue(CapabilityAtom::glsl); + if (!thisTargetSet) + return; + + for (auto& otherStageSet : otherTargetSet->shaderStageSets) + { + if (!otherStageSet.second.atomSet) + continue; + + auto* thisStageSet = thisTargetSet->shaderStageSets.tryGetValue(otherStageSet.first); + if (!thisStageSet || !thisStageSet->atomSet) + continue; + + CapabilityAtomSet::Iterator otherAtom = otherStageSet.second.atomSet->begin(); + while (otherAtom != otherStageSet.second.atomSet->end()) + { + otherAtom++; + auto otherAtomName = (CapabilityName)*otherAtom; + if (otherAtomName > (CapabilityName)getLatestSpirvAtom()) + { + otherAtom = otherStageSet.second.atomSet->end(); + continue; + } + auto maybeConvertedSpirvVersionAtom = maybeConvertSpirvVersionToGlslSpirvVersion(otherAtomName); + if (maybeConvertedSpirvVersionAtom == CapabilityName::Invalid) + continue; + + thisStageSet->atomSet->add((UInt)maybeConvertedSpirvVersionAtom); + } + } + } +} + void printDiagnosticArg(StringBuilder& sb, const CapabilitySet& capSet) { bool isFirstSet = true; @@ -864,6 +932,20 @@ void printDiagnosticArg(StringBuilder& sb, CapabilityName name) sb << _getInfo(name).name; } +void printDiagnosticArg(StringBuilder& sb, List<CapabilityAtom>& list) +{ + sb << "{"; + auto count = list.getCount(); + for(Index i = 0; i < count; i++) + { + printDiagnosticArg(sb, list[i]); + if (i + 1 != count) + sb << ", "; + } + sb << "}"; +} + + #ifdef UNIT_TEST_CAPABILITIES #define CHECK_CAPS(inData) SLANG_ASSERT(inData>0) |
