summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArielG-NV <159081215+ArielG-NV@users.noreply.github.com>2024-08-28 15:06:23 -0400
committerGitHub <noreply@github.com>2024-08-28 12:06:23 -0700
commit65240d074b4ddec55e56962ebf8de46207bcf5fa (patch)
treefa887d3de8ab55c7498eae2d5bf61966818135a1
parent638e5fb000d4e242a91e8b653da4a72daec0efda (diff)
Allow capabilities to be used with `[shader("...")]` (#4928)
* Allow capabilities to be used with `[shader("...")]` Fixes: #4917 Changes: 1. Allow using capabilities instead of `Stage`s with `EntryPointAttribute`. 2. When resolving capabilities for an entrypoint+profile (per entrypoint) in `resolveStageOfProfileWithEntryPoint` add our `EntryPointAttribute` and resolved capability 3. Added tests and some capabilities related clean-up * fix a warning made by a mistake in syntax * change fineStageByName to assume it is passed a stage without a '_' * test with and without prefix '_' * cleanup some profiles and reprisentation to work better with 'Stage' and 'Profile' This use case is why we need to clean all profile-usage into `CapabilityName`s directly. * change how we compare * only change profiles * let all capabilities be resolved by 'shader' profile for now * fix warning checks I accidently broke * meshshading_internal to _meshshading --------- Co-authored-by: Yong He <yonghe@outlook.com>
-rw-r--r--docs/command-line-slangc-reference.mdbin78354 -> 78338 bytes
-rw-r--r--source/slang/slang-ast-modifier.h16
-rw-r--r--source/slang/slang-capabilities.capdef98
-rw-r--r--source/slang/slang-check-decl.cpp19
-rw-r--r--source/slang/slang-check-modifier.cpp42
-rw-r--r--source/slang/slang-check-shader.cpp17
-rw-r--r--source/slang/slang-compiler.cpp24
-rw-r--r--source/slang/slang-diagnostic-defs.h7
-rw-r--r--source/slang/slang-profile.h4
-rw-r--r--source/slang/slang.cpp2
-rw-r--r--tests/language-feature/capability/explicit-shader-stage-1.slang8
-rw-r--r--tests/language-feature/capability/explicit-shader-stage-2.slang11
-rw-r--r--tests/language-feature/capability/explicit-shader-stage-3.slang8
-rw-r--r--tests/language-feature/capability/explicit-shader-stage-4.slang24
-rw-r--r--tests/language-feature/capability/explicit-shader-stage-5.slang25
-rw-r--r--tests/language-feature/capability/explicit-shader-stage-6.slang25
-rw-r--r--tests/language-feature/capability/explicit-shader-stage-7.slang40
-rw-r--r--tests/language-feature/capability/explicit-shader-stage-8.slang14
-rw-r--r--tests/language-feature/capability/explicit-shader-stage-9.slang25
19 files changed, 314 insertions, 95 deletions
diff --git a/docs/command-line-slangc-reference.md b/docs/command-line-slangc-reference.md
index b7cef7a53..a6df65ab2 100644
--- a/docs/command-line-slangc-reference.md
+++ b/docs/command-line-slangc-reference.md
Binary files differ
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h
index 14e945e25..8c9cb484f 100644
--- a/source/slang/slang-ast-modifier.h
+++ b/source/slang/slang-ast-modifier.h
@@ -924,17 +924,15 @@ class InstanceAttribute : public Attribute
int32_t value;
};
-// A `[shader("stageName")]` attribute, which marks an entry point
-// to be compiled, and specifies the stage for that entry point
-class EntryPointAttribute : public Attribute
+// A `[shader("stageName")]`/`[shader("capability")]` attribute which
+// marks an entry point for compiling. This attribute also specifies
+// the 'capabilities' implicitly supported by an entry point
+class EntryPointAttribute : public Attribute
{
SLANG_AST_CLASS(EntryPointAttribute)
-
- // The resolved stage that the entry point is targetting.
- //
- // TODO: This should be an accessor that uses the
- // ordinary `args` list, rather than side data.
- Stage stage;
+
+ // The resolved capailities for our entry point.
+ CapabilitySet capabilitySet;
};
// A `[__vulkanRayPayload(location)]` attribute, which is used in the
diff --git a/source/slang/slang-capabilities.capdef b/source/slang/slang-capabilities.capdef
index 220e4a424..de44c98a5 100644
--- a/source/slang/slang-capabilities.capdef
+++ b/source/slang/slang-capabilities.capdef
@@ -172,40 +172,14 @@ def compute : stage;
def hull : stage;
def domain : stage;
def geometry : stage;
-def raygen : stage;
-def intersection : stage;
-def anyhit : stage;
-def closesthit: stage;
-def miss : stage;
-def mesh : stage;
-def amplification : stage;
-def callable : stage;
-alias any_stage = vertex | fragment | compute | hull | domain | geometry
- | raygen | intersection | anyhit | closesthit | miss | mesh
- | amplification | callable
- ;
-
-// shader stage alias's
-alias pixel = fragment;
-alias raygeneration = raygen;
-alias tesscontrol = hull;
-alias tesseval = domain;
-alias amplification_mesh = amplification | mesh;
-alias raytracing_stages = raygen | intersection | anyhit | closesthit | miss | callable;
-alias anyhit_closesthit = anyhit | closesthit;
-alias raygen_closesthit_miss = raygen | closesthit | miss;
-alias anyhit_closesthit_intersection = anyhit | closesthit | intersection;
-alias anyhit_closesthit_intersection_miss = anyhit | closesthit | intersection | miss;
-alias raygen_closesthit_miss_callable = raygen | closesthit | miss | callable;
-alias compute_tesscontrol_tesseval = compute | tesscontrol | tesseval;
-alias compute_fragment = compute | fragment;
-alias compute_fragment_geometry_vertex = compute | fragment | geometry | vertex;
-alias domain_hull = domain | hull;
-alias raytracingstages_fragment = raytracing_stages | fragment;
-alias raytracingstages_compute = raytracing_stages | compute;
-alias raytracingstages_compute_amplification_mesh = raytracingstages_compute | amplification_mesh;
-alias raytracingstages_compute_fragment = raytracing_stages | compute_fragment;
-alias raytracingstages_compute_fragment_geometry_vertex = raytracing_stages | compute_fragment_geometry_vertex;
+def _raygen : stage;
+def _intersection : stage;
+def _anyhit : stage;
+def _closesthit: stage;
+def _callable : stage;
+def _miss : stage;
+def _mesh : stage;
+def _amplification : stage;
// SPIRV extensions.
@@ -403,7 +377,7 @@ alias GL_NV_shader_invocation_reorder = _GL_NV_shader_invocation_reorder + _GL_E
alias GL_NV_shader_subgroup_partitioned = _GL_NV_shader_subgroup_partitioned | spvGroupNonUniformPartitionedNV;
alias GL_NV_shader_texture_footprint = _GL_NV_shader_texture_footprint | spvImageFootprintNV;
-// Define feature names
+// Define feature names not reliant on shader stages
alias nvapi = hlsl_nvapi;
alias raytracing = GL_EXT_ray_tracing | _sm_6_3 | cuda;
@@ -413,20 +387,66 @@ alias rayquery = GL_EXT_ray_query | _sm_6_3;
alias raytracing_motionblur = raytracing + motionblur | cuda;
alias ser_motion = ser + motionblur;
alias shaderclock = GL_EXT_shader_realtime_clock | hlsl_nvapi | cpp | cuda;
-alias meshshading_internal = GL_EXT_mesh_shader | _sm_6_5 | metal;
-alias meshshading = amplification_mesh + meshshading_internal;
+alias _meshshading = GL_EXT_mesh_shader | _sm_6_5 | metal;
alias fragmentshaderinterlock = _GL_ARB_fragment_shader_interlock | hlsl_nvapi | spvFragmentShaderPixelInterlockEXT;
alias atomic64 = GL_EXT_shader_atomic_int64 | _sm_6_6 | cpp | cuda;
alias atomicfloat = GL_EXT_shader_atomic_float | _sm_6_0 + hlsl_nvapi | cpp | cuda;
alias atomicfloat2 = GL_EXT_shader_atomic_float2 | _sm_6_6 + hlsl_nvapi | cpp | cuda;
alias fragmentshaderbarycentric = GL_EXT_fragment_shader_barycentric | _sm_6_1;
alias shadermemorycontrol = glsl | _spirv_1_0 | _sm_5_0;
-alias shadermemorycontrol_compute = raytracingstages_compute + shadermemorycontrol;
-alias subpass = fragment + _sm_6_0 | fragment + any_gfx_target;
alias waveprefix = _sm_6_5 | _cuda_sm_7_0 | GL_KHR_shader_subgroup_arithmetic;
alias bufferreference = GL_EXT_buffer_reference;
alias bufferreference_int64 = bufferreference + GL_EXT_shader_explicit_arithmetic_types_int64;
+// non-internal shader stages
+
+alias pixel = fragment;
+
+alias tesscontrol = hull;
+alias tesseval = domain;
+
+alias _raygeneration = _raygen;
+alias raygen = _raygen + raytracing;
+alias raygeneration = _raygeneration + raytracing;
+alias intersection = _intersection + raytracing;
+alias anyhit = _anyhit + raytracing;
+alias closesthit = _closesthit + raytracing;
+alias callable = _callable + raytracing;
+alias miss = _miss + raytracing;
+
+alias mesh = _mesh + _meshshading;
+alias amplification = _amplification + _meshshading;
+
+// shader stage groups
+
+alias any_stage = vertex | fragment | compute | hull | domain | geometry
+ | raygen | intersection | anyhit | closesthit | miss | mesh
+ | amplification | callable
+ ;
+alias amplification_mesh = amplification | mesh;
+alias raytracing_stages = raygen | intersection | anyhit | closesthit | miss | callable;
+alias anyhit_closesthit = anyhit | closesthit;
+alias raygen_closesthit_miss = raygen | closesthit | miss;
+alias anyhit_closesthit_intersection = anyhit | closesthit | intersection;
+alias anyhit_closesthit_intersection_miss = anyhit | closesthit | intersection | miss;
+alias raygen_closesthit_miss_callable = raygen | closesthit | miss | callable;
+alias compute_tesscontrol_tesseval = compute | tesscontrol | tesseval;
+alias compute_fragment = compute | fragment;
+alias compute_fragment_geometry_vertex = compute | fragment | geometry | vertex;
+alias domain_hull = domain | hull;
+alias raytracingstages_fragment = raytracing_stages | fragment;
+alias raytracingstages_compute = raytracing_stages | compute;
+alias raytracingstages_compute_amplification_mesh = raytracingstages_compute | amplification_mesh;
+alias raytracingstages_compute_fragment = raytracing_stages | compute_fragment;
+alias raytracingstages_compute_fragment_geometry_vertex = raytracing_stages | compute_fragment_geometry_vertex;
+
+// Define feature names reliant on shader stages
+
+alias meshshading = amplification_mesh + _meshshading;
+
+alias shadermemorycontrol_compute = raytracingstages_compute + shadermemorycontrol;
+alias subpass = fragment + _sm_6_0 | fragment + any_gfx_target;
+
// Define what each shader model means on different targets.
// spirv profile
diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp
index 3bd6bd327..190433e2f 100644
--- a/source/slang/slang-check-decl.cpp
+++ b/source/slang/slang-check-decl.cpp
@@ -10644,6 +10644,7 @@ namespace Slang
void SemanticsDeclCapabilityVisitor::visitFunctionDeclBase(FunctionDeclBase* funcDecl)
{
+ // If the function is an entrypoint and specifies a target stage, add the capabilities to our function capabilities.
_dispatchCapabilitiesVisitorOfFunctionDecl(this, funcDecl,
[this, funcDecl](SyntaxNode* node, const CapabilitySet& nodeCaps, SourceLoc refLoc)
{
@@ -10657,30 +10658,12 @@ namespace Slang
auto declaredCaps = getDeclaredCapabilitySet(funcDecl);
- if (!declaredCaps.isEmpty())
- {
- // If the function is an entrypoint, add the stage to declaredCaps.
- if (auto entryPointAttr = funcDecl->findModifier<EntryPointAttribute>())
- {
- auto stageCaps = CapabilitySet(Profile(entryPointAttr->stage).getCapabilityName());
- if (declaredCaps.isIncompatibleWith(stageCaps))
- {
- maybeDiagnose(getSink(), this->getOptionSet(), DiagnosticCategory::Capability, funcDecl->loc, Diagnostics::stageIsIncompatibleWithCapabilityDefinition, funcDecl, stageCaps, declaredCaps);
- }
- else
- {
- declaredCaps.join(stageCaps);
- }
- }
- }
-
auto vis = getDeclVisibility(funcDecl);
// If 0 capabilities were annotated on a function, capabilities are inferred from the function body
if (declaredCaps.isEmpty())
{
declaredCaps = funcDecl->inferredCapabilityRequirements;
- return;
}
else
{
diff --git a/source/slang/slang-check-modifier.cpp b/source/slang/slang-check-modifier.cpp
index 705d0bb3b..d7f879c51 100644
--- a/source/slang/slang-check-modifier.cpp
+++ b/source/slang/slang-check-modifier.cpp
@@ -548,19 +548,47 @@ namespace Slang
{
SLANG_ASSERT(attr->args.getCount() == 1);
- String stageName;
- if (!checkLiteralStringVal(attr->args[0], &stageName))
+ String capNameString;
+ if (!checkLiteralStringVal(attr->args[0], &capNameString))
{
return false;
}
- auto stage = findStageByName(stageName);
- if (stage == Stage::Unknown)
+ CapabilityName capName = findCapabilityName(capNameString.getUnownedSlice());
+ if (capName != CapabilityName::Invalid)
{
- getSink()->diagnose(attr->args[0], Diagnostics::unknownStageName, stageName);
- }
+ if (isInternalCapabilityName(capName))
+ maybeDiagnose(getSink(), this->getOptionSet(), DiagnosticCategory::Capability, attr, Diagnostics::usingInternalCapabilityName, attr, capName);
+
+ // Ensure this capability only defines 1 stage per target, else diagnose an error.
+ // This is a fatal error, do not allow toggling this error off.
+ entryPointAttr->capabilitySet = CapabilitySet(capName);
+ HashSet<CapabilityAtom> stageToBeUsed;
+ for (auto& targetSet : entryPointAttr->capabilitySet.getCapabilityTargetSets())
+ {
+ for(auto& stageSet : targetSet.second.shaderStageSets)
+ stageToBeUsed.add(stageSet.first);
+ }
- entryPointAttr->stage = stage;
+ // TODO: Once profiles are removed in favor for `CapabilitySet`s we will beable to use more complex relationships,
+ // Until then we have an artificial limit that any capabilites used inside '[shader(...)]' must only specify 1 stage type
+ // uniformly across targets.
+ if (stageToBeUsed.getCount() > 1)
+ {
+ List<CapabilityAtom> atomsToPrint;
+ atomsToPrint.reserve(stageToBeUsed.getCount());
+ for (auto i : stageToBeUsed)
+ atomsToPrint.add(i);
+ getSink()->diagnose(attr, Diagnostics::capabilityHasMultipleStages, capNameString, atomsToPrint);
+ }
+ return entryPointAttr;
+ }
+ else
+ {
+ // always diagnose this error since nothing can compile with an invalid capability
+ getSink()->diagnose(attr, Diagnostics::unknownCapability, capNameString);
+ return false;
+ }
}
else if ((as<DomainAttribute>(attr)) ||
(as<MaxTessFactorAttribute>(attr)) ||
diff --git a/source/slang/slang-check-shader.cpp b/source/slang/slang-check-shader.cpp
index 99205e522..3a1e4c7f6 100644
--- a/source/slang/slang-check-shader.cpp
+++ b/source/slang/slang-check-shader.cpp
@@ -557,7 +557,7 @@ namespace Slang
for (auto target : linkage->targets)
{
auto targetCaps = target->getTargetCaps();
- auto stageCapabilitySet = CapabilitySet(entryPoint->getProfile().getCapabilityName());
+ auto stageCapabilitySet = entryPoint->getProfile().getCapabilityName();
targetCaps.join(stageCapabilitySet);
if (targetCaps.isIncompatibleWith(entryPointFuncDecl->inferredCapabilityRequirements))
{
@@ -613,20 +613,23 @@ namespace Slang
if (auto entryPointAttr = entryPointFuncDecl->findModifier<EntryPointAttribute>())
{
auto entryPointProfileStage = entryPointProfile.getStage();
- // Ensure every target is specifying the same stage as an entry` point
+ auto entryPointStage = getStageFromAtom(entryPointAttr->capabilitySet.getTargetStage());
+
+ // Ensure every target is specifying the same stage as an entry-point
// if a profile+stage was set, else user will not be aware that their
// code is requiring `fragment` on a `vertex` shader
for (auto target : targets)
{
auto targetProfile = target->getOptionSet().getProfile();
auto profileStage = targetProfile.getStage();
- if (profileStage != Stage::Unknown && profileStage != entryPointAttr->stage)
- maybeDiagnose(sink, optionSet, DiagnosticCategory::Capability, entryPointAttr, Diagnostics::entryPointAndProfileAreIncompatible, entryPointFuncDecl, entryPointAttr->stage, targetProfile.getName());
+ if (profileStage != Stage::Unknown && profileStage != entryPointStage)
+ maybeDiagnose(sink, optionSet, DiagnosticCategory::Capability, entryPointAttr, Diagnostics::entryPointAndProfileAreIncompatible, entryPointFuncDecl, entryPointStage, targetProfile.getName());
}
if (entryPointProfileStage == Stage::Unknown)
- entryPointProfile.setStage(entryPointAttr->stage);
- else if (entryPointProfileStage != Stage::Unknown && entryPointProfileStage != entryPointAttr->stage)
- maybeDiagnose(sink, optionSet, DiagnosticCategory::Capability, entryPointFuncDecl, Diagnostics::specifiedStageDoesntMatchAttribute, entryPointFuncDecl->getName(), entryPointProfileStage, entryPointAttr->stage);
+ entryPointProfile = Profile(entryPointStage);
+ else if (entryPointProfileStage != Stage::Unknown && entryPointProfileStage != entryPointStage)
+ maybeDiagnose(sink, optionSet, DiagnosticCategory::Capability, entryPointFuncDecl, Diagnostics::specifiedStageDoesntMatchAttribute, entryPointFuncDecl->getName(), entryPointProfileStage, entryPointStage);
+ entryPointProfile.additionalCapabilities.add(entryPointAttr->capabilitySet);
return true;
}
return false;
diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp
index f5b7ff428..428532658 100644
--- a/source/slang/slang-compiler.cpp
+++ b/source/slang/slang-compiler.cpp
@@ -361,7 +361,7 @@ namespace Slang
return lookUp(UnownedTerminatedStringSlice(name));
}
- List<CapabilityName> Profile::getCapabilityName()
+ CapabilitySet Profile::getCapabilityName()
{
List<CapabilityName> result;
switch (getVersion())
@@ -378,7 +378,11 @@ namespace Slang
default:
break;
}
- return result;
+
+ CapabilitySet resultSet = CapabilitySet(result);
+ for(auto i : this->additionalCapabilities)
+ resultSet.join(i);
+ return resultSet;
}
char const* Profile::getName()
@@ -451,21 +455,21 @@ namespace Slang
return Stage::Fragment;
case CapabilityAtom::compute:
return Stage::Compute;
- case CapabilityAtom::mesh:
+ case CapabilityAtom::_mesh:
return Stage::Mesh;
- case CapabilityAtom::amplification:
+ case CapabilityAtom::_amplification:
return Stage::Amplification;
- case CapabilityAtom::anyhit:
+ case CapabilityAtom::_anyhit:
return Stage::AnyHit;
- case CapabilityAtom::closesthit:
+ case CapabilityAtom::_closesthit:
return Stage::ClosestHit;
- case CapabilityAtom::intersection:
+ case CapabilityAtom::_intersection:
return Stage::Intersection;
- case CapabilityAtom::raygen:
+ case CapabilityAtom::_raygen:
return Stage::RayGeneration;
- case CapabilityAtom::miss:
+ case CapabilityAtom::_miss:
return Stage::Miss;
- case CapabilityAtom::callable:
+ case CapabilityAtom::_callable:
return Stage::Callable;
default:
SLANG_UNEXPECTED("unknown stage atom");
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index d23ae8a3e..b35acd2c3 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -390,8 +390,8 @@ DIAGNOSTIC(30604, Error, useOfLessVisibleType, "'$0' references less visible typ
DIAGNOSTIC(36005, Error, invalidVisibilityModifierOnTypeOfDecl, "visibility modifier is not allowed on '$0'.")
// Capability
-DIAGNOSTIC(36100, Error, conflictingCapabilityDueToUseOfDecl, "'$0' requires capability '$1' that is conflicting with the '$2''s current capability requirement '$3'.")
-DIAGNOSTIC(36101, Error, conflictingCapabilityDueToStatement, "statement requires capability '$0' that is conflicting with the '$1''s current capability requirement '$2'.")
+DIAGNOSTIC(36100, Error, conflictingCapabilityDueToUseOfDecl, "'$0' requires capability '$1' that is conflicting with the '$2's current capability requirement '$3'.")
+DIAGNOSTIC(36101, Error, conflictingCapabilityDueToStatement, "statement requires capability '$0' that is conflicting with the '$1's current capability requirement '$2'.")
DIAGNOSTIC(36102, Error, conflictingCapabilityDueToStatementEnclosingFunc, "statement requires capability '$0' that is conflicting with the current function's capability requirement '$1'.")
DIAGNOSTIC(36103, Warning, missingCapabilityRequirementOnPublicDecl, "public symbol '$0' is missing capability requirement declaration, the symbol is assumed to require inferred capabilities '$1'.")
DIAGNOSTIC(36104, Error, useOfUndeclaredCapability, "'$0' uses undeclared capability '$1'.")
@@ -404,9 +404,10 @@ DIAGNOSTIC(36109, Error, invalidTargetSwitchCase, "'$0' cannot be used as a targ
DIAGNOSTIC(36110, Error, stageIsIncompatibleWithCapabilityDefinition, "'$0' is defined for stage '$1', which is incompatible with the declared capability set '$2'.")
DIAGNOSTIC(36111, Error, unexpectedCapability, "'$0' resolves into a disallowed `$1` Capability.")
DIAGNOSTIC(36112, Warning, entryPointAndProfileAreIncompatible, "'$0' is defined for stage '$1', which is incompatible with the declared profile '$2'.")
-DIAGNOSTIC(36113, Warning, usingInternalCapabilityName, "'$0' resolves into a '_Internal' `_$1' Capability, use '$1' instead.")
+DIAGNOSTIC(36113, Warning, usingInternalCapabilityName, "'$0' resolves into a '_Internal' '_$1' Capability, use '$1' instead.")
DIAGNOSTIC(36114, Warning, incompatibleWithPrecompileLib, "Precompiled library requires '$0', has `$1`, implicitly upgrading capabilities.")
DIAGNOSTIC(36115, Error, incompatibleWithPrecompileLibRestrictive, "Precompiled library requires '$0', has `$1`.")
+DIAGNOSTIC(36116, Error, capabilityHasMultipleStages, "Capability '$0' is targeting stages '$1', only allowed to use 1 unique stage here.")
// Attributes
diff --git a/source/slang/slang-profile.h b/source/slang/slang-profile.h
index d07a4555f..04d4f5112 100644
--- a/source/slang/slang-profile.h
+++ b/source/slang/slang-profile.h
@@ -113,7 +113,9 @@ namespace Slang
static Profile lookUp(char const* name);
char const* getName();
- List<CapabilityName> getCapabilityName();
+ CapabilitySet getCapabilityName();
+
+ List<CapabilitySet> additionalCapabilities;
RawVal raw = Unknown;
};
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index aa114e44d..23e25249d 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -1749,7 +1749,7 @@ CapabilitySet TargetRequest::getTargetCaps()
// If the user specified a explicit profile, we should pull
// a corresponding atom representing the target version from the profile.
- CapabilitySet profileCaps = CapabilitySet(optionSet.getProfile().getCapabilityName());
+ CapabilitySet profileCaps = optionSet.getProfile().getCapabilityName();
bool isGLSLTarget = false;
switch(getTarget())
diff --git a/tests/language-feature/capability/explicit-shader-stage-1.slang b/tests/language-feature/capability/explicit-shader-stage-1.slang
new file mode 100644
index 000000000..f8d7d8380
--- /dev/null
+++ b/tests/language-feature/capability/explicit-shader-stage-1.slang
@@ -0,0 +1,8 @@
+//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry main -allow-glsl -profile sm_5_0
+
+//CHECK: main
+[shader("fragment")]
+float4 main()
+{
+ return float4(1.0f);
+}
diff --git a/tests/language-feature/capability/explicit-shader-stage-2.slang b/tests/language-feature/capability/explicit-shader-stage-2.slang
new file mode 100644
index 000000000..b4c6d3cfe
--- /dev/null
+++ b/tests/language-feature/capability/explicit-shader-stage-2.slang
@@ -0,0 +1,11 @@
+//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry main -allow-glsl -profile sm_5_0
+//TEST:SIMPLE(filecheck=CHECK_IGNORE_CAPS): -target hlsl -entry main -allow-glsl -profile sm_5_0 -ignore-capabilities
+
+//CHECK: error 36107: entrypoint 'main' does not support compilation target 'hlsl' with stage 'fragment'
+//CHECK_IGNORE_CAPS-NOT: error 36100
+[shader("fragment")]
+float4 main()
+{
+ memoryBarrierAtomicCounter();
+ return float4(1.0f);
+}
diff --git a/tests/language-feature/capability/explicit-shader-stage-3.slang b/tests/language-feature/capability/explicit-shader-stage-3.slang
new file mode 100644
index 000000000..5bf143134
--- /dev/null
+++ b/tests/language-feature/capability/explicit-shader-stage-3.slang
@@ -0,0 +1,8 @@
+//TEST:SIMPLE(filecheck=CHECK): -target hlsl -stage vertex -entry main -allow-glsl -profile sm_5_0
+
+//CHECK: warning 38006
+[shader("fragment")]
+float4 main()
+{
+ return float4(1.0f);
+}
diff --git a/tests/language-feature/capability/explicit-shader-stage-4.slang b/tests/language-feature/capability/explicit-shader-stage-4.slang
new file mode 100644
index 000000000..80ad2c206
--- /dev/null
+++ b/tests/language-feature/capability/explicit-shader-stage-4.slang
@@ -0,0 +1,24 @@
+//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry main -allow-glsl -profile sm_5_0
+
+// We do not error since `shader("raygeneration")` implicitly adds raytracing capabilities to our compile
+//CHECK: main
+struct RayPayload
+{
+ uint data;
+};
+
+uniform RaytracingAccelerationStructure sceneBVH;
+RWStructuredBuffer<uint> outputBuffer;
+[shader("raygeneration")]
+void main()
+{
+ RayDesc ray;
+ ray.Origin = float3(0,0,0);
+ ray.Direction = float3(0,0,0);
+ ray.TMin = 0.001;
+ ray.TMax = 10000.0;
+ RayPayload payload = {};
+ TraceRay(sceneBVH, RAY_FLAG_NONE, ~0, 0, 0, 0, ray, payload);
+
+ outputBuffer[0] = payload.data;
+}
diff --git a/tests/language-feature/capability/explicit-shader-stage-5.slang b/tests/language-feature/capability/explicit-shader-stage-5.slang
new file mode 100644
index 000000000..0c2cd2bd4
--- /dev/null
+++ b/tests/language-feature/capability/explicit-shader-stage-5.slang
@@ -0,0 +1,25 @@
+//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry main -allow-glsl -profile sm_6_5
+
+// Our code compiles here since we specify profile sm_6_5 (supports raytracing)
+//CHECK: warning 36113
+//CHECK: main
+struct RayPayload
+{
+ uint data;
+};
+
+uniform RaytracingAccelerationStructure sceneBVH;
+RWStructuredBuffer<uint> outputBuffer;
+[shader("_raygen")]
+void main()
+{
+ RayDesc ray;
+ ray.Origin = float3(0,0,0);
+ ray.Direction = float3(0,0,0);
+ ray.TMin = 0.001;
+ ray.TMax = 10000.0;
+ RayPayload payload = {};
+ TraceRay(sceneBVH, RAY_FLAG_NONE, ~0, 0, 0, 0, ray, payload);
+
+ outputBuffer[0] = payload.data;
+}
diff --git a/tests/language-feature/capability/explicit-shader-stage-6.slang b/tests/language-feature/capability/explicit-shader-stage-6.slang
new file mode 100644
index 000000000..4884c7b85
--- /dev/null
+++ b/tests/language-feature/capability/explicit-shader-stage-6.slang
@@ -0,0 +1,25 @@
+//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry main -allow-glsl -profile sm_5_0
+
+// Our code does not warn here since we specify profile 'sm_5_0' and a raygen shader.
+// raygen implicitly uses "raygen + raytracing" capabilities
+//CHECK: warning 36113
+struct RayPayload
+{
+ uint data;
+};
+
+uniform RaytracingAccelerationStructure sceneBVH;
+RWStructuredBuffer<uint> outputBuffer;
+[shader("_raygen")]
+void main()
+{
+ RayDesc ray;
+ ray.Origin = float3(0,0,0);
+ ray.Direction = float3(0,0,0);
+ ray.TMin = 0.001;
+ ray.TMax = 10000.0;
+ RayPayload payload = {};
+ TraceRay(sceneBVH, RAY_FLAG_NONE, ~0, 0, 0, 0, ray, payload);
+
+ outputBuffer[0] = payload.data;
+}
diff --git a/tests/language-feature/capability/explicit-shader-stage-7.slang b/tests/language-feature/capability/explicit-shader-stage-7.slang
new file mode 100644
index 000000000..729214cb8
--- /dev/null
+++ b/tests/language-feature/capability/explicit-shader-stage-7.slang
@@ -0,0 +1,40 @@
+//TEST:SIMPLE(filecheck=CHECK_PASS): -target spirv -entry main -allow-glsl -profile sm_5_0
+//TEST:SIMPLE(filecheck=CHECK_WARN): -target spirv -entry main -allow-glsl -profile sm_5_0 -DWARN
+
+// Our code will stillwarn about spirv version being below 'spirv 1.3'. This is Because we are still using `Profile` internally.
+// 'Profile' is an issue which needs to be refactored out since it only stores the info in a single integer through 'profileRaw'
+//CHECK_PASS: warning 50011
+//
+// Our code does not warn about capabilities here since we specify profile 'sm_5_0' and a 'ser_motion_raygen' shader.
+// 'ser_motion_raygen' implicitly uses "raygen + raytracing_motion + ser" capabilities.
+//CHECK_PASS: main
+
+// On the contrary, our code will warn without 'ser_motion_raygen'.
+//CHECK_WARN: warning 41012
+//CHECK_WARN: warning 50011
+
+
+struct RayPayload
+{
+ uint data;
+};
+
+uniform RaytracingAccelerationStructure sceneBVH;
+RWStructuredBuffer<uint> outputBuffer;
+#ifndef WARN
+[shader("ser_motion_raygen")]
+#else
+[shader("raygen")]
+#endif
+void main()
+{
+ RayDesc ray;
+ ray.Origin = float3(0,0,0);
+ ray.Direction = float3(0,0,0);
+ ray.TMin = 0.001;
+ ray.TMax = 10000.0;
+ RayPayload payload = {};
+ TraceMotionRay(sceneBVH, RAY_FLAG_NONE, ~0, 0, 0, 0, ray, 0, payload);
+
+ outputBuffer[0] = payload.data;
+}
diff --git a/tests/language-feature/capability/explicit-shader-stage-8.slang b/tests/language-feature/capability/explicit-shader-stage-8.slang
new file mode 100644
index 000000000..48afacc3d
--- /dev/null
+++ b/tests/language-feature/capability/explicit-shader-stage-8.slang
@@ -0,0 +1,14 @@
+//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry main -allow-glsl -profile sm_5_0
+// CHECK: error 36116
+struct RayPayload
+{
+ uint data;
+};
+
+uniform RaytracingAccelerationStructure sceneBVH;
+RWStructuredBuffer<uint> outputBuffer;
+[shader("compute_fragment")]
+void main()
+{
+ outputBuffer[0] = 0;
+}
diff --git a/tests/language-feature/capability/explicit-shader-stage-9.slang b/tests/language-feature/capability/explicit-shader-stage-9.slang
new file mode 100644
index 000000000..a37498022
--- /dev/null
+++ b/tests/language-feature/capability/explicit-shader-stage-9.slang
@@ -0,0 +1,25 @@
+//TEST:SIMPLE(filecheck=CHECK): -target hlsl -entry main -allow-glsl -stage raygeneration -profile sm_6_5
+
+// Our code compiles here since 'raygeneration' stage implies 'raygen+raytracing' capabilities
+//CHECK-NOT: warning 36113
+//CHECK: main
+struct RayPayload
+{
+ uint data;
+};
+
+uniform RaytracingAccelerationStructure sceneBVH;
+RWStructuredBuffer<uint> outputBuffer;
+
+void main()
+{
+ RayDesc ray;
+ ray.Origin = float3(0,0,0);
+ ray.Direction = float3(0,0,0);
+ ray.TMin = 0.001;
+ ray.TMax = 10000.0;
+ RayPayload payload = {};
+ TraceRay(sceneBVH, RAY_FLAG_NONE, ~0, 0, 0, 0, ray, payload);
+
+ outputBuffer[0] = payload.data;
+}