yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
07f21ee31
master
layout: user-guide permalink: /user-guide/capabilities
Capabilities
One of the biggest challenges in maintaining cross-platform shader code is to manage the differences in hardware capabilities across different GPUs, graphics APIs, and shader stages. Each graphics API or shader stage may expose operations that are not available on other platforms. Instead of restricting Slang's features to the lowest common denominator of different platforms, Slang exposes operations from all target platforms to allow the user to take maximum advantage on a specific target.
A consequence of this approach is that the user is now responsible for maintaining compatibility of their code. For example, if the user writes code that uses a Vulkan extension currently not available on D3D/HLSL, they will get an error when attempting to compile that code to D3D.
To help the user to maintain compatibility of their shader code on platforms that matter to their applications, Slang's type system can now infer and enforce capability requirements to provide assurance that the shader code will be compatible with the specific set of platforms before compiling for that platform.
For example, Texture2D.SampleCmp is available on D3D and Vulkan, but not available on CUDA. If the user is intended to write cross-platform code that targets CUDA, they will
receive a type-checking error when attempting to use SampleCmp before the code generation stage of compilation. When using Slang's intellisense plugin, the programmer should
get a diagnostic message directly in their code editor.
As another example, discard is a statement that is only meaningful when used in fragment shaders. If a vertex shader contains a discard statement or calling a function that contains
a discard statement, it shall be a type-check error.
Capability Atoms and Capability Requirements
Slang models code generation targets, shader stages, API extensions and hardware features as distinct capability atoms. For example, GLSL_460 is a capability atom that stands for the GLSL 460 code generation target,
compute is an atom that represents the compute shader stage, _sm_6_7 is an atom representing the shader model 6.7 feature set in D3D, SPV_KHR_ray_tracing is an atom representing the SPV_KHR_ray_tracing SPIR-V extension, and spvShaderClockKHR is an atom for the ShaderClockKHR SPIRV capability. For a complete list of capabilities supported by the Slang compiler, check the capability definition file.
A capability requirement can be a single capability atom, a conjunction of capability atoms, or a disjunction of conjunction of capability atoms. A function can declare its capability requirement with the following syntax:
[ require ( spvShaderClockKHR )] [ require ( glsl , GL_EXT_shader_realtime_clock )] [ require ( hlsl_nvapi )] uint2 getClock () { ...}
Each [require] attribute declares a conjunction of capability atoms, and all [require] attributes form the final requirement of the getClock() function as a disjunction of capabilities:
(spvShaderClockKHR | glsl + GL_EXT_shader_realtime_clock | hlsl_nvapi)
A capability can imply other capabilities. Here spvShaderClockKHR is a capability that implies SPV_KHR_shader_clock, which represents the SPIRV SPV_KHR_shader_clock extension, and the SPV_KHR_shader_clock capability implies spirv_1_0, which stands for the spirv code generation target.
When evaluating capability requirements, Slang will expand all implications. Therefore the final capability requirement for getClock is:
spirv_1_0 + SPV_KHR_shader_clock + spvShaderClockKHR | glsl + _GL_EXT_shader_realtime_clock | hlsl + hlsl_nvapi
Which means the function can be called from locations where the spvShaderClockKHR capability is available (when targeting SPIRV), or where the GL_EXT_shader_realtime_clock extension is available when targeting GLSL,
or where nvapi is available when targeting HLSL.
Conflicting Capabilities
Certain groups of capabilities are mutually exclusive such that only one capability in the group is allowed to exist. For example, all stage capabilities are mutual exclusive: a requirement for both fragment and vertex is impossible to satisfy. Currently, capabilities that model different code generation targets (e.g. hlsl, glsl) or different shader stages (vertex, fragment, etc.) are mutually exclusive within
their corresponding group.
If two capability requirements contain different atoms that are conflicting with each other, these two requirements are considered incompatible.
For example, requirement spvShaderClockKHR + fragment and requirement spvShaderClockKHR + vertex are incompatible, because fragment conflicts with vertex.
Capabilities Between Parent and Members
The capability requirement of a member is always merged with the requirements declared in its parent(s). If the member declares requirements for additional compilation targets, they are added to the requirement set as a separate disjunction. For example, given:
[ require ( glsl )] [ require ( hlsl )] struct MyType { [ require ( hlsl , hlsl_nvapi )] [ require ( spirv )] static void method () { ... } }
MyType.method will have requirement glsl | hlsl + hlsl_nvapi | spirv.
The [require] attribute can also be used on module declarations, so that the requirement will
apply to all members within the module. For example:
[ require ( glsl )] [ require ( hlsl )] [ require ( spirv )] module myModule ; // myFunc has requirement glsl|hlsl|spirv publicvoid myFunc() { }
Capabilities Between Subtype and Supertype
For inheritance/implementing-interfaces the story is a bit different.
We require that the subtype (Foo1) have a subset of capabilities to the supertype (IFoo1).
For example:
[ require ( sm_4_0 )] interface IFoo1 { } [ require ( sm_6_0 )] struct Foo1 : IFoo1 { }
We error here since Foo1 is not a subset to IFoo1. Foo1 has sm_6_0, which includes capabilities sm_4_0 does not have.
[ require ( sm_6_0 )] interface IFoo2 { } [ require ( sm_4_0 )] interface IFoo1 { } [ require ( sm_4_0 )] struct Foo1 : IFoo1 , IFoo2 { }
We do not error here since IFoo2 and IFoo1 are supersets to Foo1.
Additionally, any supertype to subtype relationship must share the same shader stage and shader target support.
// Error, Foo1 is missing `spirv` [ require ( hlsl )] [ require ( spirv )] interface IFoo1 { } [ require ( hlsl )] struct Foo1 : IFoo1 { } // Error, IFoo1 is missing `hlsl` [ require ( hlsl )] interface IFoo1 { } [ require ( hlsl )] [ require ( spirv )] struct Foo1 : IFoo1 { }
Capabilities Between Requirement and Implementation
We require that all requirement capabilities are supersets of their implementation (only required if capabilities are explicitly annotated).
public interface IAtomicAddable_Pass { public static void atomicAdd ( RWByteAddressBuffer buf , uint addr , This value ); } public extension int64_t : IAtomicAddable_Pass{ public static void atomicAdd ( RWByteAddressBuffer buf , uint addr , int64_t value ) { buf . InterlockedAddI64 ( addr , value ); } } public interface IAtomicAddable_Error { [ require ( glsl , sm_4_0 )] public static void atomicAdd ( RWByteAddressBuffer buf , uint addr , This value ); } public extension uint : IAtomicAddable_Error{ // Error: implementation has superset of capabilites, sm_6_0 vs. sm_4_0 // Note: sm_6_0 is inferred from `InterlockedAddI64` public static void atomicAdd ( RWByteAddressBuffer buf , uint addr , int64_t value ) { buf . InterlockedAddI64 ( addr , value ); } }
Requirment and implementation must also share the same shader stage and shader target support.
public interface IAtomicAddable_Error { [ require ( glsl )] [ require ( hlsl )] public static void atomicAdd ( RWByteAddressBuffer buf , uint addr , This value ); } public extension uint : IAtomicAddable_Error{ [ require ( glsl )] // Error, missing `hlsl` public static void atomicAdd ( RWByteAddressBuffer buf , uint addr , int64_t value ) { buf . InterlockedAddI64 ( addr , value ); } } public interface IAtomicAddable_Error { [ require ( glsl )] public static void atomicAdd ( RWByteAddressBuffer buf , uint addr , This value ); } public extension uint : IAtomicAddable_Error{ [ require ( glsl )] [ require ( hlsl )] // Error, has additional capability `hlsl` public static void atomicAdd ( RWByteAddressBuffer buf , uint addr , int64_t value ) { buf . InterlockedAddI64 ( addr , value ); } }
Capabilities of Functions
Inference of Capability Requirements
By default, Slang will infer the capability requirements of a function given its definition, as long as the function has internal or private visibility. For example, given:
void myFunc () { if ( getClock (). x % 1000 == 0 ) discard ; }
Slang will automatically deduce that myFunc has capability
spirv_1_0 + SPV_KHR_shader_clock + spvShaderClockKHR + fragment | glsl + _GL_EXT_shader_realtime_clock + fragment | hlsl + hlsl_nvapi + fragment
Since discard statement requires capability fragment.
Inference on target_switch
A __target_switch statement will introduce disjunctions in its inferred capability requirement. For example:
void myFunc () { __target_switch { case spirv : ...; case hlsl : ...; } }
The capability requirement of myFunc is (spirv | hlsl), meaning that the function can be called from a context where either spirv or hlsl capability
is available.
Capability Incompatabilities
The function declaration must be a superset of the capabilities the function body uses for any shader stage/target the function declaration implicitly/explicitly requires.
[ require ( sm_5_0 )] public void requires_sm_5_0 () { } [ require ( sm_4_0 )] public void logic_sm_5_0_error () // Error, missing `sm_5_0` support { requires_sm_5_0 (); } public void logic_sm_5_0__pass () // Pass, no requirements { requires_sm_5_0 (); } [ require ( hlsl , vertex )] public void logic_vertex () { } [ require ( hlsl , fragment )] public void logic_fragment () { } [ require ( hlsl , vertex , fragment )] public void logic_stage_pass_1 () // Pass, `vertex` and `fragment` supported { __stage_switch { case vertex : logic_vertex(); case fragment : logic_fragment(); } } [ require ( hlsl , vertex , fragment , mesh , hull , domain )] public void logic_many_stages () { } [ require ( hlsl , vertex , fragment )] public void logic_stage_pass_2 () // Pass, function only requires that the body implements the stages `vertex` & `fragment`, the rest are irelevant { logic_many_stages (); } [ require ( hlsl , any_hit )] public void logic_stage_fail_1 () // Error, function requires `any_hit`, body does not support `any_hit` { logic_many_stages (); }
Capability Aliases
To make it easy to specify capabilities on different platforms, Slang also defines many aliases that can be used in [require] attributes.
For example, Slang declares in slang-capabilities.capdef:
alias sm_6_6 = _sm_6_6
| glsl_spirv_1_5 + sm_6_5
+ GL_EXT_shader_atomic_int64 + atomicfloat2
| spirv_1_5 + sm_6_5
+ GL_EXT_shader_atomic_int64 + atomicfloat2
+ SPV_EXT_descriptor_indexing
| cuda
| cpp;
So user code can write [require(sm_6_6)] to mean that the function requires shader model 6.6 on D3D or equivalent set of GLSL/SPIRV extensions when targeting GLSL or SPIRV.
Note that in the above definition, GL_EXT_shader_atomic_int64 is also an alias that is defined as:
alias GL_EXT_shader_atomic_int64 = _GL_EXT_shader_atomic_int64 | spvInt64Atomics;
Where _GL_EXT_shader_atomic_int64 is the atom that represent the true GL_EXT_shader_atomic_int64 GLSL extension.
The GL_EXT_shader_atomic_int64 alias is defined as a disjunction of _GL_EXT_shader_atomic_int64 and the Int64Atomics SPIRV capability so that
it can be used in both the contexts of GLSL and SPIRV target.
When aliases are used in a [require] attribute, the compiler will expand the alias to evaluate the capability set, and remove all incompatible conjunctions.
For example, [require(hlsl, sm_6_6)] will be evaluated to (hlsl+_sm_6_6) because all other conjunctions in sm_6_6 are incompatible with hlsl.
Validation of Capability Requirements
Slang requires all public methods and interface methods to have explicit capability requirements declarations. Omitting capability declaration on a public method means that the method does not require any specific capability. Functions with explicit requirement declarations will be verified by the compiler to ensure that it does not use any capability beyond what is declared.
Slang recommends but does not require explicit declaration of capability requirements for entrypoints. If explicit capability requirements are declared on an entrypoint, they will be used to validate the entrypoint the same way as other public methods, providing assurance that the function will work on all intended targets. If an entrypoint does not define explicit capability requirements, Slang will infer the requirements, and only issue a compiler error when the inferred capability is incompatible with the current code generation target.
1--- 2layout : user-guide 3permalink : /user-guide/capabilities 4--- 5 6# Capabilities 7 8One of the biggest challenges in maintaining cross-platform shader code is to manage the differences in hardware capabilities across different GPUs, graphics APIs, and shader stages. 9Each graphics API or shader stage may expose operations that are not available on other platforms. Instead of restricting Slang's features to the lowest common denominator of different platforms, 10Slang exposes operations from all target platforms to allow the user to take maximum advantage on a specific target. 11 12A consequence of this approach is that the user is now responsible for maintaining compatibility of their code. For example, if the user writes code that uses a Vulkan extension currently not 13available on D3D/HLSL, they will get an error when attempting to compile that code to D3D. 14 15To help the user to maintain compatibility of their shader code on platforms that matter to their applications, Slang's type system can now infer and enforce capability requirements 16to provide assurance that the shader code will be compatible with the specific set of platforms before compiling for that platform. 17 18For example, `Texture2D.SampleCmp` is available on D3D and Vulkan, but not available on CUDA. If the user is intended to write cross-platform code that targets CUDA, they will 19receive a type-checking error when attempting to use `SampleCmp` before the code generation stage of compilation. When using Slang's intellisense plugin, the programmer should 20get a diagnostic message directly in their code editor. 21 22As another example, `discard` is a statement that is only meaningful when used in fragment shaders. If a vertex shader contains a `discard` statement or calling a function that contains 23a `discard` statement, it shall be a type-check error. 24 25## Capability Atoms and Capability Requirements 26 27Slang models code generation targets, shader stages, API extensions and hardware features as distinct capability atoms. For example, `GLSL_460` is a capability atom that stands for the GLSL 460 code generation target, 28`compute` is an atom that represents the compute shader stage, `_sm_6_7` is an atom representing the shader model 6.7 feature set in D3D, `SPV_KHR_ray_tracing` is an atom representing the `SPV_KHR_ray_tracing` SPIR-V extension, and `spvShaderClockKHR` is an atom for the `ShaderClockKHR` SPIRV capability. For a complete list of capabilities supported by the Slang compiler, check the [capability definition file](https://github.com/shader-slang/slang/blob/master/source/slang/slang-capabilities.capdef). 29 30A capability **requirement** can be a single capability atom, a conjunction of capability atoms, or a disjunction of conjunction of capability atoms. A function can declare its 31capability requirement with the following syntax: 32 33``` csharp 34[require(spvShaderClockKHR)] 35[require(glsl, GL_EXT_shader_realtime_clock)] 36[require(hlsl_nvapi)] 37uint2 getClock() {...} 38``` 39 40Each `[require]` attribute declares a conjunction of capability atoms, and all `[require]` attributes form the final requirement of the `getClock()` function as a disjunction of capabilities: 41``` 42(spvShaderClockKHR | glsl + GL_EXT_shader_realtime_clock | hlsl_nvapi) 43``` 44 45A capability can __imply__ other capabilities. Here `spvShaderClockKHR` is a capability that implies `SPV_KHR_shader_clock`, which represents the SPIRV `SPV_KHR_shader_clock` extension, and the `SPV_KHR_shader_clock` capability implies `spirv_1_0`, which stands for the spirv code generation target. 46 47When evaluating capability requirements, Slang will expand all implications. Therefore the final capability requirement for `getClock` is: 48``` 49spirv_1_0 + SPV_KHR_shader_clock + spvShaderClockKHR 50| glsl + _GL_EXT_shader_realtime_clock 51| hlsl + hlsl_nvapi 52``` 53Which means the function can be called from locations where the `spvShaderClockKHR` capability is available (when targeting SPIRV), or where the `GL_EXT_shader_realtime_clock` extension is available when targeting GLSL, 54or where `nvapi` is available when targeting HLSL. 55 56## Conflicting Capabilities 57 58Certain groups of capabilities are mutually exclusive such that only one capability in the group is allowed to exist. For example, all stage capabilities are mutual exclusive: a requirement for both `fragment` and `vertex` is impossible to satisfy. Currently, capabilities that model different code generation targets (e.g. `hlsl`, `glsl`) or different shader stages (`vertex`, `fragment`, etc.) are mutually exclusive within 59their corresponding group. 60 61If two capability requirements contain different atoms that are conflicting with each other, these two requirements are considered __incompatible__. 62For example, requirement `spvShaderClockKHR + fragment` and requirement `spvShaderClockKHR + vertex` are incompatible, because `fragment` conflicts with `vertex`. 63 64## Capabilities Between Parent and Members 65 66The capability requirement of a member is always merged with the requirements declared in its parent(s). If the member declares requirements for additional compilation targets, they are added to the requirement set as a separate disjunction. 67For example, given: 68``` csharp 69[require(glsl)] 70[require(hlsl)] 71struct MyType 72{ 73[require(hlsl, hlsl_nvapi)] 74[require(spirv)] 75static void method() { ... } 76} 77``` 78`MyType.method` will have requirement `glsl | hlsl + hlsl_nvapi | spirv`. 79 80The `[require]` attribute can also be used on module declarations, so that the requirement will 81apply to all members within the module. For example: 82``` csharp 83[require(glsl)] 84[require(hlsl)] 85[require(spirv)] 86module myModule; 87 88// myFunc has requirement glsl|hlsl|spirv 89public void myFunc() 90{ 91} 92``` 93 94## Capabilities Between Subtype and Supertype 95 96For inheritance/implementing-interfaces the story is a bit different. 97We require that the subtype (`Foo1`) have a subset of capabilities to the supertype (`IFoo1`). 98 99For example: 100``` csharp 101[require(sm_4_0)] 102interface IFoo1 103{ 104} 105[require(sm_6_0)] 106struct Foo1 : IFoo1 107{ 108} 109``` 110We error here since `Foo1` is not a subset to `IFoo1`. `Foo1` has `sm_6_0`, which includes capabilities `sm_4_0` does not have. 111 112``` csharp 113[require(sm_6_0)] 114interface IFoo2 115{ 116} 117[require(sm_4_0)] 118interface IFoo1 119{ 120} 121[require(sm_4_0)] 122struct Foo1 : IFoo1, IFoo2 123{ 124} 125``` 126We do not error here since `IFoo2` and `IFoo1` are supersets to `Foo1`. 127 128Additionally, any supertype to subtype relationship must share the same shader stage and shader target support. 129 130``` csharp 131// Error, Foo1 is missing `spirv` 132[require(hlsl)] 133[require(spirv)] 134interface IFoo1 135{ 136} 137[require(hlsl)] 138struct Foo1 : IFoo1 139{ 140} 141 142// Error, IFoo1 is missing `hlsl` 143[require(hlsl)] 144interface IFoo1 145{ 146} 147[require(hlsl)] 148[require(spirv)] 149struct Foo1 : IFoo1 150{ 151} 152``` 153 154## Capabilities Between Requirement and Implementation 155 156We require that all requirement capabilities are supersets of their implementation (only required if capabilities are explicitly annotated). 157 158``` csharp 159public interface IAtomicAddable_Pass 160{ 161public static void atomicAdd(RWByteAddressBuffer buf, uint addr, This value); 162} 163public extension int64_t : IAtomicAddable_Pass 164{ 165public static void atomicAdd(RWByteAddressBuffer buf, uint addr, int64_t value) { buf.InterlockedAddI64(addr, value); } 166} 167 168public interface IAtomicAddable_Error 169{ 170[require(glsl, sm_4_0)] 171public static void atomicAdd(RWByteAddressBuffer buf, uint addr, This value); 172} 173public extension uint : IAtomicAddable_Error 174{ 175// Error: implementation has superset of capabilites, sm_6_0 vs. sm_4_0 176// Note: sm_6_0 is inferred from `InterlockedAddI64` 177public static void atomicAdd(RWByteAddressBuffer buf, uint addr, int64_t value) { buf.InterlockedAddI64(addr, value); } 178} 179``` 180 181Requirment and implementation must also share the same shader stage and shader target support. 182 183``` csharp 184public interface IAtomicAddable_Error 185{ 186[require(glsl)] 187[require(hlsl)] 188public static void atomicAdd(RWByteAddressBuffer buf, uint addr, This value); 189} 190public extension uint : IAtomicAddable_Error 191{ 192[require(glsl)] // Error, missing `hlsl` 193public static void atomicAdd(RWByteAddressBuffer buf, uint addr, int64_t value) { buf.InterlockedAddI64(addr, value); } 194} 195 196public interface IAtomicAddable_Error 197{ 198[require(glsl)] 199public static void atomicAdd(RWByteAddressBuffer buf, uint addr, This value); 200} 201public extension uint : IAtomicAddable_Error 202{ 203[require(glsl)] 204[require(hlsl)] // Error, has additional capability `hlsl` 205public static void atomicAdd(RWByteAddressBuffer buf, uint addr, int64_t value) { buf.InterlockedAddI64(addr, value); } 206} 207``` 208 209## Capabilities of Functions 210 211### Inference of Capability Requirements 212 213By default, Slang will infer the capability requirements of a function given its definition, as long as the function has `internal` or `private` visibility. For example, given: 214``` csharp 215void myFunc() 216{ 217if (getClock().x % 1000 == 0) 218discard; 219} 220``` 221Slang will automatically deduce that `myFunc` has capability 222``` 223spirv_1_0 + SPV_KHR_shader_clock + spvShaderClockKHR + fragment 224| glsl + _GL_EXT_shader_realtime_clock + fragment 225| hlsl + hlsl_nvapi + fragment 226``` 227Since `discard` statement requires capability `fragment`. 228 229### Inference on target_switch 230 231A `__target_switch` statement will introduce disjunctions in its inferred capability requirement. For example: 232``` csharp 233void myFunc() 234{ 235__target_switch 236{ 237case spirv: ...; 238case hlsl: ...; 239} 240} 241``` 242The capability requirement of `myFunc` is `(spirv | hlsl)`, meaning that the function can be called from a context where either `spirv` or `hlsl` capability 243is available. 244 245### Capability Incompatabilities 246 247The function declaration must be a superset of the capabilities the function body uses **for any shader stage/target the function declaration implicitly/explicitly requires**. 248 249``` csharp 250[require(sm_5_0)] 251public void requires_sm_5_0() 252{ 253 254} 255[require(sm_4_0)] 256public void logic_sm_5_0_error() // Error, missing `sm_5_0` support 257{ 258requires_sm_5_0(); 259} 260 261public void logic_sm_5_0__pass() // Pass, no requirements 262{ 263requires_sm_5_0(); 264} 265 266[require(hlsl, vertex)] 267public void logic_vertex() 268{ 269 270} 271[require(hlsl, fragment)] 272public void logic_fragment() 273{ 274 275} 276[require(hlsl, vertex, fragment)] 277public void logic_stage_pass_1() // Pass, `vertex` and `fragment` supported 278{ 279__stage_switch 280{ 281case vertex: 282logic_vertex(); 283case fragment: 284logic_fragment(); 285} 286} 287 288[require(hlsl, vertex, fragment, mesh, hull, domain)] 289public void logic_many_stages() 290{ 291 292} 293[require(hlsl, vertex, fragment)] 294public void logic_stage_pass_2() // Pass, function only requires that the body implements the stages `vertex` & `fragment`, the rest are irelevant 295{ 296logic_many_stages(); 297} 298 299[require(hlsl, any_hit)] 300public void logic_stage_fail_1() // Error, function requires `any_hit`, body does not support `any_hit` 301{ 302logic_many_stages(); 303} 304``` 305 306## Capability Aliases 307 308 To make it easy to specify capabilities on different platforms, Slang also defines many aliases that can be used in `[require]` attributes. 309For example, Slang declares in `slang-capabilities.capdef`: 310``` 311alias sm_6_6 = _sm_6_6 312| glsl_spirv_1_5 + sm_6_5 313+ GL_EXT_shader_atomic_int64 + atomicfloat2 314| spirv_1_5 + sm_6_5 315+ GL_EXT_shader_atomic_int64 + atomicfloat2 316+ SPV_EXT_descriptor_indexing 317| cuda 318| cpp; 319``` 320So user code can write `[require(sm_6_6)]` to mean that the function requires shader model 6.6 on D3D or equivalent set of GLSL/SPIRV extensions when targeting GLSL or SPIRV. 321Note that in the above definition, `GL_EXT_shader_atomic_int64` is also an alias that is defined as: 322``` 323alias GL_EXT_shader_atomic_int64 = _GL_EXT_shader_atomic_int64 | spvInt64Atomics; 324``` 325Where `_GL_EXT_shader_atomic_int64` is the atom that represent the true `GL_EXT_shader_atomic_int64` GLSL extension. 326The `GL_EXT_shader_atomic_int64` alias is defined as a disjunction of `_GL_EXT_shader_atomic_int64` and the `Int64Atomics` SPIRV capability so that 327it can be used in both the contexts of GLSL and SPIRV target. 328 329When aliases are used in a `[require]` attribute, the compiler will expand the alias to evaluate the capability set, and remove all incompatible conjunctions. 330For example, `[require(hlsl, sm_6_6)]` will be evaluated to `(hlsl+_sm_6_6)` because all other conjunctions in `sm_6_6` are incompatible with `hlsl`. 331 332## Validation of Capability Requirements 333 334Slang requires all public methods and interface methods to have explicit capability requirements declarations. Omitting capability declaration on a public method means that the method does not require any 335specific capability. Functions with explicit requirement declarations will be verified by the compiler to ensure that it does not use any capability beyond what is declared. 336 337Slang recommends but does not require explicit declaration of capability requirements for entrypoints. If explicit capability requirements are declared on an entrypoint, they will be used to validate the entrypoint the same way as other public methods, providing assurance that the function will work on all intended targets. If an entrypoint does not define explicit capability requirements, Slang will infer the requirements, and only issue a compiler error when the inferred capability is incompatible with the current code generation target.