Skip to content

Commit 7d002f2

Browse files
committed
Add documentation on capability system.
Fixes shader-slang#3454.
1 parent 6dca7e3 commit 7d002f2

16 files changed

+248
-85
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ The Slang system is designed to provide developers of real-time graphics applica
1616

1717
* The Slang compiler can generate code for a wide variety of targets and APIs: D3D12, Vulkan, D3D11, OpenGL, CUDA, and CPU. Slang code can be broadly portable, but still take advantage of the unique features of each platform.
1818

19-
* [Automatic differentiation](https://shader-slang.com/slang/user-guide/08-autodiff.html) as a first-class language feature. Slang can automatically generate both forward and backward derivative propagation code for complex functions that involve arbitrary control flow and dynamic dispatch. This allows users to easily make existing rendering codebases differentiable, or to use Slang as the kernel language in a PyTorch driven machine learning framework via [`slangpy`](https://shader-slang.com/slang/user-guide/a1-02-slangpy.html).
19+
* [Automatic differentiation](https://shader-slang.com/slang/user-guide/autodiff.html) as a first-class language feature. Slang can automatically generate both forward and backward derivative propagation code for complex functions that involve arbitrary control flow and dynamic dispatch. This allows users to easily make existing rendering codebases differentiable, or to use Slang as the kernel language in a PyTorch driven machine learning framework via [`slangpy`](https://shader-slang.com/slang/user-guide/a1-02-slangpy.html).
2020

2121
* Generics and interfaces allow shader specialization to be expressed cleanly without resort to preprocessor techniques or string-pasting. Unlike C++ templates, Slang's generics are checked ahead of time and don't produce cascading error messages that are difficult to diagnose. The same generic shader can be specialized for a variety of different types to produce specialized code ahead of time, or on the fly, completely under application control.
2222

docs/_config.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
theme: jekyll-theme-tactile
1+
theme: jekyll-theme-tactile

docs/scripts/Program.cs

+6
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ public static string Run(string path)
164164
node.sections.Add(sectionStr);
165165
node.sectionShortTitles.Add(maybeGetShortTitle(sectionStr, content, i));
166166
}
167+
if (content[i].StartsWith("permalink:"))
168+
{
169+
var prefixLength = ("permalink:").Length;
170+
var permaPath = content[i].Substring(prefixLength, content[i].Length - prefixLength).Trim();
171+
node.fileID = Path.GetFileName(permaPath);
172+
}
167173
}
168174
if (node.title == null)
169175
{

docs/user-guide/00-introduction.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
layout: user-guide
3+
permalink: /user-guide/introduction
34
---
45

56
Introduction

docs/user-guide/01-get-started.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
layout: user-guide
3+
permalink: /user-guide/get-started
34
---
45

56
# Getting Started with Slang

docs/user-guide/02-conventional-features.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
layout: user-guide
3+
permalink: /user-guide/conventional-features
34
---
45

56
Conventional Language Features

docs/user-guide/03-convenience-features.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
layout: user-guide
3+
permalink: /user-guide/convenience-features
34
---
45

56
# Basic Convenience Features

docs/user-guide/04-modules-and-access-control.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
layout: user-guide
3+
permalink: /user-guide/modules
34
---
45

56
Modules and Access Control

docs/user-guide/05-capabilities.md

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
---
2+
layout: user-guide
3+
permalink: /user-guide/capabilities
4+
---
5+
6+
# Capabilities
7+
8+
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.
9+
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,
10+
Slang exposes operations from all target platforms to allow the user to take maximum advantage on a specific target.
11+
12+
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
13+
available on D3D/HLSL, they will get an error when attempting to compile that code to D3D.
14+
15+
To help the user to maintain compatibility of their shader code on platforms matter to their applications, Slang's type system can now infer and enforce capability requirements
16+
to provide assurance that the shader code will be compatible with the specific set of platforms before compiling for that platform.
17+
18+
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
19+
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
20+
get a diagnostic message directly in their code editor.
21+
22+
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
23+
a `discard` statement, it shall be a type-check error.
24+
25+
## Capability Atoms and Capability Requirements
26+
27+
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,
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+
30+
A capabiltiy **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
31+
capability requirement with the following syntax:
32+
33+
```csharp
34+
[require(spvShaderClockKHR)]
35+
[require(glsl, GL_EXT_shader_realtime_clock)]
36+
[require(hlsl_nvapi)]
37+
uint2 getClock() {...}
38+
```
39+
40+
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:
41+
```
42+
(spvShaderClockKHR | glsl + GL_EXT_shader_realtime_clock | hlsl_nvapi)
43+
```
44+
45+
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.
46+
47+
When evaluating capability requirements, Slang will expand all implications. Therefore the final capability requirement for `getClock` is:
48+
```
49+
spirv_1_0 + SPV_KHR_shader_clock + spvShaderClockKHR
50+
| glsl + _GL_EXT_shader_realtime_clock
51+
| hlsl + hlsl_nvapi
52+
```
53+
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,
54+
or where `nvapi` is available when targeting HLSL.
55+
56+
## Conflicting Capabilities
57+
58+
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
59+
their corresponding group.
60+
61+
If two capability requirements contain different atoms that are conflicting with each other, these two requirements are considered __incompatible__.
62+
For example, requirement `spvShaderClockKHR + fragment` and requirement `spvShaderClockKHR + vertex` are incompatible, because `fragment` conflicts with `vertex`.
63+
64+
## Requirements in Parent Scope
65+
66+
The capability requirement of a decl is always joined with the requirements declared in its parents.
67+
For example:
68+
```csharp
69+
[require(spvShaderClockKHR)]
70+
struct MyType
71+
{
72+
[require(spvShaderClockKHR)]
73+
void method() { ... }
74+
}
75+
```
76+
`MyType.method` has requirement `spvShaderClockKHR + spvShaderClockKHR`.
77+
78+
## Inferrence of Capability Requirements
79+
80+
By default, Slang will infer the capability requirements of a function given its definition, as long as the function has `internal` or `private` visibilty. For example, given:
81+
```csharp
82+
void myFunc()
83+
{
84+
if (getClock().x % 1000 == 0)
85+
discard;
86+
}
87+
```
88+
Slang will automatically deduce that `myFunc` has capability
89+
```
90+
spirv_1_0 + SPV_KHR_shader_clock + spvShaderClockKHR + fragment
91+
| glsl + _GL_EXT_shader_realtime_clock + fragment
92+
| hlsl + hlsl_nvapi + fragment
93+
```
94+
Since `discard` statement requires capability `fragment`.
95+
96+
## Inferrence on target_switch
97+
98+
A `__target_switch` statement will introduce disjunctions in its inferred capabiltiy requirement. For example:
99+
```csharp
100+
void myFunc()
101+
{
102+
__target_switch
103+
{
104+
case spirv: ...;
105+
case hlsl: ...;
106+
}
107+
}
108+
```
109+
The capability requirement of `myFunc` is `(spirv | hlsl)`, meaning that the function can be called from a context where either `spirv` or `hlsl` capability
110+
is available.
111+
112+
## Capability Aliases
113+
114+
To make it easy to specify capabilities on different platforms, Slang also defines many aliases that can be used in `[require]` attributes.
115+
For example, Slang declares:
116+
```
117+
alias sm_6_6 = _sm_6_6
118+
| glsl_spirv_1_5 + sm_6_5
119+
+ GL_EXT_shader_atomic_int64 + atomicfloat2
120+
| spirv_1_5 + sm_6_5
121+
+ GL_EXT_shader_atomic_int64 + atomicfloat2
122+
+ SPV_EXT_descriptor_indexing
123+
| cuda
124+
| cpp;
125+
```
126+
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.
127+
Note that in the above definition, `GL_EXT_shader_atomic_int64` is also an alias that is defined as:
128+
```
129+
alias GL_EXT_shader_atomic_int64 = _GL_EXT_shader_atomic_int64 | spvInt64Atomics;
130+
```
131+
Where `_GL_EXT_shader_atomic_int64` is the atom that represent the true `GL_EXT_shader_atomic_int64` GLSL extension.
132+
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
133+
it can be used in both the contexts of GLSL and SPIRV target.
134+
135+
When aliases are used in a `[require]` attribute, the compiler will expand the alias to evaluate the capability set, and remove all incompatible conjunctions.
136+
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`.
137+
138+
## Validation of Capability Requirements
139+
140+
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
141+
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.
142+
143+
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.

docs/user-guide/05-interfaces-generics.md docs/user-guide/06-interfaces-generics.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
layout: user-guide
3+
permalink: /user-guide/interfaces-generics
34
---
45

56
Interfaces and Generics

docs/user-guide/08-autodiff.md docs/user-guide/07-autodiff.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
layout: user-guide
3+
permalink: /user-guide/autodiff
34
---
45

56
# Automatic Differentiation

docs/user-guide/06-compiling.md docs/user-guide/08-compiling.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
layout: user-guide
3+
permalink: /user-guide/compiling
34
---
45

56
Compiling Code with Slang

docs/user-guide/07-targets.md docs/user-guide/09-targets.md

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
layout: user-guide
3+
permalink: /user-guide/targets
34
---
45

56
Supported Compilation Targets

docs/user-guide/a1-02-slangpy.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ print(output_grad)
153153

154154
`slangpy` also binds the forward-mode version of your kernel (propagate derivatives of inputs to the output) which can be invoked the same way using `module.square.fwd()`
155155

156-
You can refer to [this documentation](08-autodiff.md) for a detailed reference of Slang's automatic differentiation feature.
156+
You can refer to [this documentation](autodiff) for a detailed reference of Slang's automatic differentiation feature.
157157

158158
### Wrapping your kernels as pytorch functions
159159

@@ -451,7 +451,7 @@ in the `inputGradToPropagateTo` tensor. Therefore, after running `boxFilter_bwd`
451451
back propagated derivative values.
452452

453453
Again, to understand all the details of the automatic differentiation system, please refer to the
454-
[Automatic Differentiation](08-autodiff.md) chapter for a detailed explanation.
454+
[Automatic Differentiation](autodiff) chapter for a detailed explanation.
455455

456456
## Manually binding kernels
457457
`[AutoPyBindCUDA]` works for most use cases, but in certain situations, it may be necessary to write the *host* function by hand. The host function can also be written in Slang, and `slangpy` handles its compilation to C++.

0 commit comments

Comments
 (0)