summaryrefslogtreecommitdiff
path: root/source/slang/slang-capability.cpp
diff options
context:
space:
mode:
authorArielG-NV <159081215+ArielG-NV@users.noreply.github.com>2024-06-12 16:38:23 -0400
committerGitHub <noreply@github.com>2024-06-12 13:38:23 -0700
commit8813c610562b1c30222ec3ef0734ef601d43b617 (patch)
treeb012aa178a52a0313ce9deab31006556a2637011 /source/slang/slang-capability.cpp
parent7447fcafa71440336f553d6e0af21b12fc74d138 (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.cpp144
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)