diff --git a/.github/workflows/sphinx-build-test.yml b/.github/workflows/sphinx-build-test.yml index de0e6a18..07d1ca6c 100644 --- a/.github/workflows/sphinx-build-test.yml +++ b/.github/workflows/sphinx-build-test.yml @@ -29,7 +29,7 @@ jobs: cd docs # Run Sphinx build to catch issues # -D build_toctree=True enables toctree processing to verify all docs are included - python -m sphinx -b html . _build/html + python -m sphinx -W -b html . _build/html - name: Check for broken links to external sites run: | diff --git a/docs/autodiff-tips-custom-diffs.md b/docs/autodiff-tips-custom-diffs.md index 388c79bd..16a1e1d3 100644 --- a/docs/autodiff-tips-custom-diffs.md +++ b/docs/autodiff-tips-custom-diffs.md @@ -1,7 +1,7 @@ --- -title: Autodiff Tips and Tricks: Custom Derivatives +title: Autodiff Tips and Tricks - Custom Derivatives layout: page -description: Autodiff Tips and Tricks: Custom Derivatives +description: Autodiff Tips and Tricks - Custom Derivatives permalink: "/docs/autodiff-tips-custom-diffs" intro_image_absolute: true intro_image_hide_on_mobile: false @@ -19,7 +19,8 @@ Opaque functions are those where the internal operations are not visible or acce For these functions, since the autodiff system cannot "see" inside to compute the derivative, providing a custom derivative allows you to still incorporate them into your differentiable computations. -```slang + +```hlsl [BackwardDerivative(externalFunction_bwd)] float externalFunction(float x) { @@ -46,7 +47,8 @@ This example shows one option to handle an opaque function that calls an externa Functions whose output depends on values retrieved from memory based on an input (e.g., accessing an RWStructuredBuffer on the GPU, or reading from a raw pointer CPU-side) introduce side-effects that automatic differentiation struggles to handle. This can include things like race conditions or ambiguous derivative write-back locations. Additionally, the lookup index itself is non-continuous. Therefore, custom derivatives are often necessary to accurately represent "change" at these points, potentially involving subgradients or specific approximations. -```slang + +```hlsl RWStructuredBuffer myBuffer; RWStructuredBuffer> gradientBuffer; // Global buffer for gradients @@ -74,7 +76,8 @@ Numerical stability refers to how well a computation preserves accuracy when fac By defining a custom derivative, you can implement more robust numerical methods that mitigate these issues, ensuring that your derivatives are well-behaved and do not lead to computational errors or poor training performance. This might involve re-parameterizations or specialized derivative formulas. -```slang + +```hlsl [BackwardDerivative(safeDivide_bwd)] float safeDivide(float numerator, float denominator) { @@ -104,7 +107,7 @@ One of the key strengths of Slang's autodiff system is its flexibility. You are This means you can address just the parts of your function stack that truly need custom derivatives (e.g., the opaque or numerically unstable sections) while still leveraging Slang's powerful autodiff for the rest of your computations. This hybrid approach offers the best of both worlds: the convenience and efficiency of automatic differentiation where it's most effective, and the precision and control of custom derivatives where they are absolutely necessary. -For examples of this in practice, take a look at some of the [experiments]() in our SlangPy samples repository. In particular, you can see a user-defined custom derivative function invoking bwd\_diff() to make use of automatic differentiation for the functions it calls out to in the [differentiable splatting experiment](https://github.com/shader-slang/slangpy-samples/blob/main/experiments/diff-splatting/diffsplatting2d.slang#L512). +For examples of this in practice, take a look at some of the [experiments](https://github.com/shader-slang/slangpy-samples/blob/main/experiments) in our SlangPy samples repository. In particular, you can see a user-defined custom derivative function invoking bwd\_diff() to make use of automatic differentiation for the functions it calls out to in the [differentiable splatting experiment](https://github.com/shader-slang/slangpy-samples/blob/main/experiments/diff-splatting/diffsplatting2d.slang#L512). # Approximating Derivatives for Inherently Undifferentiable Functions diff --git a/docs/compilation-api.md b/docs/compilation-api.md index 29f09240..aafab5d9 100644 --- a/docs/compilation-api.md +++ b/docs/compilation-api.md @@ -26,7 +26,7 @@ The Slang compilation API is provided as a dynamic library. Linking to it, you h * [Post-Compilation Reflection](#post-compilation-reflection) * [Complete Example](#complete-example) -### Basic Compilation +## Basic Compilation This is the overall flow needed to compile even the simplest applications. @@ -38,8 +38,8 @@ This is the overall flow needed to compile even the simplest applications. 6. [Link Program](#link) 7. [Get Target Kernel Code](#get-target-kernel-code) -### Step-by-step -#### Includes +## Step-by-step +### Includes The main header file is `slang.h`, though you also need `slang-com-ptr.h` to have the definition of Slang::ComPtr used throughout the API. `slang-com-helper.h` is nice to have, since it provides helpers for checking API return values and otherwise using COM. ```cpp #include "slang.h" @@ -47,7 +47,7 @@ The main header file is `slang.h`, though you also need `slang-com-ptr.h` to hav #include "slang-com-helper.h" ``` -#### Create Global Session +### Create Global Session The global API call to `createGlobalSession` is always going to be the first runtime step, since it establishes a connection to the Slang API implementation. ```cpp @@ -55,7 +55,7 @@ The global API call to `createGlobalSession` is always going to be the first run createGlobalSession(globalSession.writeRef()); ``` -#### Create Session +### Create Session To read more about what sessions are all about, see [About Sessions](#about-sessions). Creating a session sets the configuration for what you are going to do with the API. @@ -69,7 +69,7 @@ The `SessionDesc` object holds all the configuration for the Session. slang::SessionDesc sessionDesc = {}; ``` -##### List of enabled compilation targets +#### List of enabled compilation targets Here, only one target is enabled, `spirv_1_5`. You can enable more targets, for example, if you need to be able to compile the same source to DXIL as well as SPIRV. ```cpp @@ -81,7 +81,7 @@ Here, only one target is enabled, `spirv_1_5`. You can enable more targets, for sessionDesc.targetCount = 1; ``` -##### Preprocessor defines +#### Preprocessor defines Slang supports using the preprocessor. ```cpp @@ -94,7 +94,7 @@ Slang supports using the preprocessor. sessionDesc.preprocessorMacroCount = preprocessorMacroDesc.size(); ``` -##### Compiler options +#### Compiler options Here is where you can specify Session-wide options. Check the [User Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/08-compiling.html#compiler-options) for info on available options. @@ -110,7 +110,7 @@ Here is where you can specify Session-wide options. Check the [User Guide](https sessionDesc.compilerOptionEntryCount = options.size(); ``` -##### Create the session +#### Create the session With a fully populated `SessionDesc`, the session can be created. @@ -119,7 +119,7 @@ With a fully populated `SessionDesc`, the session can be created. globalSession->createSession(sessionDesc, session.writeRef()); ``` -#### Load Modules +### Load Modules Modules are the granularity of shader source code that can be compiled in Slang. When using the compilation API, there are two main functions to consider. @@ -142,11 +142,11 @@ Modules are the granularity of shader source code that can be compiled in Slang. } ``` -##### Life Time of Modules +#### Life Time of Modules Modules are owned by the slang Session. Once loaded, they are valid as long as the Session is valid. -#### Query Entry Points +### Query Entry Points Slang shaders may contain many entry points, and it's necessary to be able to identify them programatically in the Compilation API in order to select which entry points to compile. @@ -170,7 +170,7 @@ A common way to query an entry-point is by using the `IModule::findEntryPointByN It is also possible to query entry-points by index, and work backwards to check the name of the entry-points that are returned at different indices. Check the [User Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/09-reflection.html#program-reflection) for info. -#### Compose Modules and Entry Points +### Compose Modules and Entry Points Up to this point, modules have been loaded, and entry points have been identified, but to move forward with defining a GPU program, the relevant subset need to be selected for _composition_ into a unified program. @@ -194,7 +194,7 @@ Up to this point, modules have been loaded, and entry points have been identifie } ``` -#### Link +### Link Ensure that there are no missing dependencies in the composed program by using `link()`. @@ -210,7 +210,7 @@ Ensure that there are no missing dependencies in the composed program by using ` } ``` -#### Get Target Kernel Code +### Get Target Kernel Code Finally, it's time to compile the linked Slang program to the target format. @@ -266,7 +266,7 @@ Both methods cache results within the session and will return a pre-compiled blo About Sessions -------------- -#### What's a session? +### What's a session? A session is a scope for caching and reuse. As you use the Slang API, the session caches everything that is loaded in it. @@ -278,7 +278,7 @@ It's strongly recommended to use as few session objects as possible in applicati Using long-lived sessions with Slang API is a big advantage over compiling with the standalone `slangc` compiler executable, since each invocation of `slangc` creates a new session object by necessity. -#### When do I need a new Session? +### When do I need a new Session? A session does have some global state in it which currently makes it unable to cache and reuse artifacts, namely, the `#define` configurations. Unique combinations of preprocessor `#defines` used in your shaders will require unique session objects. @@ -296,16 +296,16 @@ API methods for module precompilation are described in the [User Guide](https:// Specialization -------------- -#### Link-time Constants +### Link-time Constants This form of specialization involves placing relevant constant definitions in a separate Module that can be selectively included. For example, if you have two variants of a shader that differ in constants that they use, you can create two different Modules for the constants, one for each variant. When composing one variant or the other, just select the right constants module in createCompositeComponentType(). This is described also in the [User Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/10-link-time-specialization.html#link-time-constants) -#### Link-time Types +### Link-time Types Similar to Link-time Constants. This form of specialization simply puts different versions of user types in separate modules so that the needed implementation can be selected when creating the CompositeComponentType. [User Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/10-link-time-specialization.html#link-time-types) -#### Generics Specialization +### Generics Specialization Say you have a shader that has a feature in it that can be in one of two states, "High Quality" and "Low Quality". One way to support both modes of operation is to use generics. Put the logic for the two modes into two structs, both conforming to an interface (e.g. `IQuality`) that can be consistently used by callers. @@ -569,7 +569,7 @@ void computeMain(uint3 threadId_0 : SV_DispatchThreadID) Notice in particular the switch case added in the function `float U_S11specialized8IQuality8getValuep0pf_0(uint2 _S1)`. -#### Supporting both specialization and dynamic dispatch +### Supporting both specialization and dynamic dispatch In the prior example, `HighQuality` and `LowQuality` are both supported in a single uber-shader, compiled to support dynamic dispatch on the call to `getValue()`. To achieve this, two `ITypeConformance` objects were added to the composite component. @@ -813,7 +813,7 @@ int main() } ``` -#### Compile it (g++ directions) +### Compile it (g++ directions) * Assumes Slang is installed in the current directory at `slang`. * Assumes program is saved to "shortest.cpp". * Assumes a release build of Slang. @@ -824,7 +824,7 @@ If any of the above assumptions are wrong in your case, adjust the paths below t g++ -I./slang/include --std=c++14 shortest.cpp -L./slang/build/Release/lib/ -l:libslang.so ``` -#### Run it +### Run it ```bat LD_LIBRARY_PATH=slang/build/Release/lib ./a.out diff --git a/docs/conf.py b/docs/conf.py index 85a108be..f922ace6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -172,7 +172,7 @@ def setup(app): myst_title_to_header = True # Suppress specific warnings -suppress_warnings = ["myst.header", "myst.xref_missing", "myst.xref_ambiguous"] +suppress_warnings = ["myst.header", "myst.xref_ambiguous"] linkcheck_anchors = False linkcheck_ignore = [