## 1. Project Overview & Quickstart (shader-slang/LICENSE)

# LICENSE

Open-source repository shader-slang/LICENSE

### Repository Details
- **Repository:** [shader-slang/LICENSE](https://github.com/shader-slang/LICENSE)
- **Primary Language:** Code

*Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.*

## 2. Official Technical Reference & Guides (shader-slang/shader-slang.github.io)

## File: README.md

# Shader-Slang.com website

This theme is losely based on the Serif theme for Jekyll by [Zerostatic Themes](https://www.zerostatic.io).

## Installation

### Installing Ruby & Jekyll

If this is your first time using Jekyll, please follow the [Jekyll docs](https://jekyllrb.com/docs/installation/) and make sure your local environment (including Ruby) is setup correctly.

### Installing Theme

Download or clone the theme.

To run the theme locally, navigate to the theme directory and run:

```
bundle install
```

To start the Jekyll local development server.

```
bundle exec jekyll serve
```

To build the theme.

```
bundle exec jekyll build
```

### Github Pages

This theme has been tested to work with Github Pages (and Github Project Pages). When using Github Pages you will need to update the `baseurl` in the `_config.yml` otherwise all the css, images and paths will be broken.

For example the site https://shader-slang.com would have `baseurl: "/"`

---

## File: docs/auto-diff-tutorial-1.md

---
title: "Automatic Differentiation Tutorial - 1"
layout: page
permalink: "/docs/auto-diff-tutorial-1"
intro_image_absolute: true
intro_image_hide_on_mobile: false
---

## Introduction to Slang\'s Automatic Differentiation (AutoDiff)

This tutorial explains the automatic differentiation (autodiff) capabilities within the Slang shading language, covering both forward and backward modes, handling custom types, defining custom derivatives and providing example use cases.

To enable autodiff for a function in Slang, you simply mark the function with `[Differentiable]`. This instructs the compiler to automatically generate both **forward mode** and **backward mode** gradient propagation functions for it as long as the function is differentiable. In the following sections, we'll explore how each mode works in theory and practice, starting with forward mode autodiff.

### Forward Mode Differentiation

Given a function $s = square(x, y)$, the goal is to find out how changes of the input parameters will impact the output. To do this, we must compute derivative of $s$ with respect to $x$ and $y$, namely $\frac{\partial s}{\partial x}dx$ and $\frac{\partial s}{\partial y}dy$, so the **forward mode automatic differentiation** computes $fwd(s) = \frac{\partial s}{\partial x}dx + \frac{\partial s}{\partial y}dy$, that is to compute **derivatives** of a function by augmenting each variable in a computation with its **rate of change**.

If we write this derivative calculation into matrix multiplication form, we will have

$$fwd(s) = \begin{bmatrix}\frac{\partial s}{\partial x}\frac{\partial s}{\partial y}\end{bmatrix} \begin{bmatrix}dx\\dy\end{bmatrix}$$

And this matrix $\begin{bmatrix}\frac{\partial s}{\partial x}\frac{\partial s}{\partial y}\end{bmatrix}$ is called the **Jacobian Matrix**. In this simple example, the function $square(x,\, y)$ takes two input values and outputs one value, so it's a $\mathbb{R}^{2}\mathbb{\, \rightarrow R}$ mapping, and the shape of the Jacobian matrix will be $\mathbb{R}^{1 \times 2}$. To be more general, if a function is $\mathbb{R}^{N} \rightarrow \mathbb{R}^{M}$mapping, the shape of its Jacobian matrix will be $\mathbb{R}^{M \times N}$. You can find a more comprehensive explanation of the Jacobian matrix in thi [wiki page](https://en.wikipedia.org/wiki/Jacobian_matrix_and_determinant).


>**Extended Reading:**
>
>You may have questions about what exactly $dx$ (or $dy$) is. The answer is directly related to the name of "forward mode" differentiation. According to our definition above, forward mode differentiation tries to tell us how the output deviates if we give input a change. So $dx$ in this context represents the change in the input $x$. $x$ can be an independent variable where we can just assign a change value (e.g. $dx= 1$) to it. But if $x$ is a function that depends on another input variable, e.g. $x = f(\theta)$, and we want to study how change of $\theta$ impacts the output of $s$, in this scenario, $dx = fwd(x) = \frac{\partial x}{\partial \theta}d\theta$, and we can assign 1 to $d\theta$, so its change will "propagate forward" to $x $, and the rate of change of $x$ will "forward" to $s$. And this is why this computation is called forward mode differentiation, because it keeps forwarding the changs from the input variables all the way down to the output variables.
>Forward mode autodiff aims to compute the **Jacobian Matrix vector product**, which evaluates the derivates of a function's output given the rate of change of its inputs. For example, by plugging a one-hot vector (a binary vector where exactly one element is one) into the Jacobian Matrix vector product, we can get the partial derivative of $s$ with respect to the inputs:
>$$\frac{\partial s}{\partial x}  = \begin{bmatrix}\frac{\partial s}{\partial x}\,\frac{\partial s}{\partial y} \end{bmatrix}\begin{bmatrix}1 \\0\end{bmatrix} \text{  and  }\frac{\partial s}{\partial y} = \begin{bmatrix}\frac{\partial s}{\partial x}\frac{\partial s}{\partial y} \end{bmatrix}\begin{bmatrix}0 \\1\end{bmatrix}$$


Now let us see how to use Slang's autodiff to compute the forward mode derivatives. Consider the function $square(x, y)$ defined as follows:
```hlsl
float square(float x, float y)
{
    return x * x + y * y;
}
```

- 1\.  Mark the function as `[Differentiable]` to tell Slang to automatically generate a forward (and backward) mode derivate propagation function at compile time.
```hlsl
[Differentiable]
float square(float x, float y)
{
    return x * x + y * y;
}
```

- 2\.  Construct a differential pair using `diffPair`. This is Slang's built-in function to create a pair holding both the original (primal) value and its derivative. E.g.

```hlsl
let x_pair = diffPair(3.0f, 1.0f);
```

it means $x=3.0$ and $dx = 1.0$. The value of $x$ is just randomly chosen, and we choose $dx = 1.0$, because we want the coefficient of $\frac{\partial s}{\partial x}$ to be 1 in the forward model computation. Similarly, we can construct differential pair for $y$ as well, so:

```hlsl
let y_pair = diffPair(4.0f, 1.0f);
```

- 3\.  Invoke the forward mode differentiation function by using `fwd_diff`, e.g.

```
let result = fwd_diff(square)(x_pair, y_pair);
```

The result variable is also a differential pair, where the `result.p` is the primal value, which is the result of the $square(x, y)$, and `result.d` is the derivative value which is $\frac{\partial s}{\partial x} + \frac{\partial s}{\partial y}$.

If we combine above steps together, the complete code is as follows:

```hlsl
let x_pair = diffPair(3.0f, 1.0f);
let y_pair = diffPair(4.0f, 1.0f);
let result = fwd_diff(square)(x_pair, y_pair);
printf("dResult = %f\n", result.d);
```

In many applications (e.g. gradient descent), we might be more interested in the partial derivative of a function with respect to each independent variable instead of the sum of all of them. Given the definition of the forward mode, we described above, it's easy to write Slang code to achieve that. Take this $square$ function as example, we can construct the differential pair of $y$ by setting the derivative field to 0:

```hlsl
let y_pair = diffPair(4.0f, 0.0f);
let result = fwd_diff(square)(x_pair, y_pair);
```

such that $dy = 0.0$, this piece of code will calculate $\frac{\partial s}{\partial x}\  = \ \left\lbrack \frac{\partial s}{\partial x}\,\frac{\partial s}{\partial y} \right\rbrack\begin{bmatrix}
1 \\
0
\end{bmatrix}$ , so the `result.d` will equal to $\frac{\partial s}{\partial x}$. Similarly, we can play the same trick to x to get $\frac{\partial s}{\partial y}$. As you may notice, in order to achieve partial derivatives of $s$ w.r.t. to the two parameters $x$ and $y$, we have to invoke forward mode differentiation twice. In real world gradient descent-based applications, the number of parameters is easily very large (e.g. 1 million). This means that we must invoke the forward mode autodiff as many times as the number of parameters to get all the partial derivatives, which is impractical, and this is the known limitation of forward mode differentiation. Therefore, the backward mode differentiation is more frequently used in this scenario, and that's what we will explore next.

### Backward Mode Differentiation

For ease of comparison with forward mode, let's keep using $s = square(x,y)$. Now assume we have a loss function $l=h(s)$. The goal is to compute $\frac{\partial l}{\partial x}$ and $\frac{\partial l}{\partial y}$. Applying the chain rule, we can easily form $\frac{\partial l}{\partial x}=\frac{\partial l}{\partial s}\frac{\partial s}{\partial x}$ and $\frac{\partial l}{\partial y}=\frac{\partial l}{\partial s}\frac{\partial s}{\partial y}$. We can also convert this into matrix multiplication form as:

$$\begin{bmatrix}
\frac{\partial l}{\partial x} \\
\frac{\partial l}{\partial y}
\end{bmatrix}=
\begin{bmatrix}
\frac{\partial l}{\partial s}
\end{bmatrix}
\begin{bmatrix}
\frac{\partial s}{\partial x} \frac{\partial s}{\partial y}
\end{bmatrix}
\text{  or  }
\begin{bmatrix}
\frac{\partial l}{\partial x} \\
\frac{\partial l}{\partial y}
\end{bmatrix}=
\begin{bmatrix}
\frac{\partial l}{\partial s}
\end{bmatrix}
\begin{bmatrix}
\frac{\partial s}{\partial x}\\\frac{\partial s}{\partial y}
\end{bmatrix}^T$$

By using the matrix-multiplication form, it's easy to identify the **Jacobian Matrix,** however this time the formula becomes a **vector-Jacobian Matrix product.** And this is the **backward mode differentiation,** it computes the derivatives by propagating the derivative of output to each input. Interestingly, if we set the vector to all one\'s vector, namely $\begin{bmatrix} \frac{\partial l}{\partial s} \end{bmatrix}=\begin{bmatrix}1\end{bmatrix}$, we will get the derivatives of $s$ w.r.t. to $x$ and $y$:

$$bwd(s)=\begin{bmatrix}1\end{bmatrix}
\begin{bmatrix}
\frac{\partial s}{\partial x}\\\frac{\partial s}{\partial y}
\end{bmatrix}^T,$$
where the right hand-side of this equation is the result of the backward mode differentiation.

Slang's syntax for the backward mode autodiff is similar to forward:

- 1\.  Same as forward mode, mark the function as `[Differentiable]`.

- 2\.  Construct differential pair. However, in backward mode, we will leave the derivative field as 0 because that field is used as output to store the result derivative. Therefore, we will construct it as:

```hlsl
var x_pair = diffPair(3.0f, 0.0f);
var y_pair = diffPair(4.0f, 0.0f);
```

Another thing to notice is we use keyword "var" instead of "let" here because "let" will define the variable as constant, but we need x to be an inout variable so it can store the resulting derivative.

- 3\.  Setting $\frac{\partial l}{\partial s}$ to 1:

```hlsl
let dlds = 1.0f;
```

- 4\.  Invoke backward mode autodiff by using `bwd_diff`, e.g.:

```hlsl
bwd_diff(square)(x_pair, y_pair, dlds);
```

After this call, `x_pair.d` and `y_pair.d` will store the value of $\frac{\partial l}{\partial x}$ and $\frac{\partial l}{\partial y}$, that will be $\frac{\partial s}{\partial x}$ and $\frac{\partial s}{\partial y}$ in this case.

Combine all steps together, the complete code will be:

```hlsl
var x_pair = diffPair(3.0f, 0.0f);
var y_pair = diffPair(4.0f, 0.0f);
let dlds = 1.0f;
let result = bwd_diff(square)(x_pair, y_pair, dlds);
printf("dL/dx = %f, dL/dy = %f\n", x_pair.d, y_pair.d);
```

## AutoDiff with User-Defined Types

After warming up on the autodiff concept, a natural question is "How does autodiff work with user-defined types?". The short answer is using the Slang **Differentiable type system.**

**Differentiable vs. Non-Differentiable Types**:

Slang distinguishes between types that can be differentiated (differentiable) and those that cannot (non-differentiable). Take an example, in a function

```hlsl
float run(int op, float a, float b);
```

`int` type for `op` is a **non-differentiable type**, while `float` type for `a` and `b` is a **differentiable type.** When synthesizing the autodiff functions, Slang will change differentiable types to DifferentialPair and will not change the non-differentiable type. Therefore, the signature of forward mode of function `run` will be

```hlsl
DifferentialPair fwd_diff(run)(int op, DifferentialPair<float> a, DifferentialPair<float> b);
```

and this is why we need to construct DifferentialPair when calling the forward mode differentiation function.

By default, following types are differentiable in Slang:

-   **Scalars:** `float`, `double` and `half`.

-   **Vector/Matrix:** `vector` and `matrix` of `float`, `double` and `half`
    types.

-   **Arrays:** `T[n]` is differentiable if `T` is differentiable**.**

-   **Tuples:** `Tuple<each T>` is differentiable if `T` is differentiable.

To make a custom type differentiable, Slang provides a built-in `IDifferentiable` interface, so that any user-defined types conforming to this interface will be treated as differentiable types. The interface is defined as:

```hlsl
interface IDifferentiable
{
    associatedtype Differential : IDifferentiable
    where Differential.Differential == Differential;
    static Differential dzero();
    static Differential dadd(Differential, Differential);
    static Differential dmul<T : __BuiltinRealType>(T, Differential);
};
```

The interface defines requirements that a type must satisfy to be considered differentiable, such as how to represent zero gradient, how to perform multiplication and add operations on the gradients, and the definition of the type of gradients. Taking the previous square example, let's change the input to a custom struct type `Point` such that

```hlsl
struct Point
{
    float x;
    float y;
}

[Differentiable]
float square(Point p)
{
    return p.x * p.x + p.y * p.y;
}
```

If we don't have any constraints on type `Point`, the signature of the forward mode of `square` is

```hlsl
DifferentialPair fwd_diff(square)(Point p);
```

and there is no derivative calculated for the point because Slang treats `Point` as a non-differentiable type, the result derivative will be 0. In order to make `Point` differentiable, we need to make `Point` conform to
`IDifferentiable`:
```hlsl
struct Point: IDifferentiable
{
    float x;
    float y;
}
```

Now the signature of forward mode of `square` becomes:
```hlsl
DifferentialPair<float> fwd_diff(square)(DifferentialPair p);
```

Thus, we can call the forward mode as:

```hlsl
void main()
{
    let p_pair = diffPair(Point(3.0f, 4.0f), Point(1.0f, 1.0f));
    let result = fwd_diff(square)(p_pair);
    printf("dResult = %f\n", result.d)
}
```

Notice that we never provided the definition of `dzero`/`dadd`/`dmul` required by the `IDifferentiable` interface. This is allowed because the Slang compiler automatically synthesizes these methods even if the user doesn't explicitly provide them.

## Custom Derivatives

No AutoDiff implementation is guaranteed to always produce the most efficient derivative code nor the most numerical stable result, therefore sometimes you may want to provide your own implementation for forward and backward mode gradient propagation functions instead of using the compiler-generated ones. Slang also provides a way to allow implementing the custom derivatives.

For custom forward mode implementation, you can use `[ForwardDerivativeOf(<func>)]` attribute to decorate your own implementation of derivatives, where `<func>` is the original function, e.g.

```hlsl
[ForwardDerivativeOf(square)]
DifferentialPair fwd_square(DifferentialPair<float> x, DifferentialPair<float> y)
{
    return diffPair(square(x.p, y.p), 2.0f * (x.p * x.d + y.p * y.d));
}
```

Alternatively, you can use `[ForwardDerivative(<func>)]` attribute to decorate the original function, where `<func>` is the derivative implementation function, e.g.

```hlsl
[ForwardDerivative(fwd_square)]
float square(float x, float y);

DifferentialPair fwd_square(DifferentialPair<float> x, DifferentialPair<float> y)
{
    return diffPair(square(x.p, y.p), 2.0f * (x.p * x.d + y.p *y.d));
}
```

Similarly, this syntax can also be applied in backward mode, for example:

```hlsl
[BackwardDerivativeOf(square)]
void bwd_square(inout DifferentialPair<float> x_pair, inout DifferentialPair<float> y_pair, float dOut)
{
    x_pair = diffPair(x.p, 2.0f * x.p * dOut);
    y_pair = diffPair(y.p, 2.0f * y.p * dOut);
}
```

And of course, another method:

```hlsl
[BackwardDerivativeOf(bwd_square)]
float square(float x, float y);

void bwd_square(inout DifferentialPair<float> x_pair, inout DifferentialPair<float> y_pair, float dOut)
{
    x_pair = diffPair(x.p, 2.0f * x.p * dOut);
    y_pair = diffPair(y.p, 2.0f * y.p * dOut);
}
```

In those cases, Slang compiler will pick your provided implementations.

### How to propagate derivatives to global buffer storage

In the given example in this tutorial, all the variables used in the functions are just local variables. Consider if the variable `y` in the square function is coming from some global storage, e.g

```hlsl
RWStructuredBuffer<float> g_buffer;

[Differentiable]
float square(float x, int idx)
{
    float y = g_buffer[idx];
    return x * x + y * y;
}
```

Where does the derivative of `y` propagate? In this case, variable `y` is treated as a non-differentiable type as the source of this variable is buffer storage which is a non-differentiable type. So custom derivative implementation is very useful to solve this problem.

- 1\.  First, we can wrap the buffer access into a function which is differentiable

```hlsl
RWStructuredBuffer<float> g_buffer;

float getY(int idx) { return g_buffer[idx]; }

[Differentiable]
float square(float x, int idx)
{
    float getY(idx);
    return x * x + y * y;
}
```

- 2\.  We can provide a custom derivative implementation for this function

```hlsl
RWStructuredBuffer<Atomic<float>> yGradBuffer;

float bwd_getY(int idx, float dOut)
{
    yGradBuffer[idx] += dOut;
}
```

During synthesis of the backward mode of `square` function, when the compiler sees the `getY` call instruction, it will automatically pick its custom backward implementation `bwd_getY`.

### Debugging Trick by Using Custom Derivative Implementation

Since the autodiff synthesization process is totally opaque, the generated code is invisible to users. Though you can specify `"-target hlsl"` to translate the target code to some textual form, the autodiff code is not intended to be easy to read, especially when the original functions are sophisticated. Therefore, debugging the autodiff code could be a challenging task. We provide a debug option to help you check the gradients flow during computation.

Looking at the previous example of the use case of custom derivative implementation, you might be aware that this technique can also be used to watch the intermediate gradients. Given an implementation of `square` as follow:

```hlsl
[Differentiable]
float square(float x, float y)
{
    float a = x * x;
    float b = y * y;
    return a + b;
}
```

Assume we want to check whether the gradient of `b` is calculated correct, we can wrap the computation of `b` into a differentiable function, and defined the custom derivative of this function so that we can print or save the derivative flew into this function, for example:

```hlsl
[Differentiable]
float square(float x, float y)
{
    float a = x * x;
    float b = debugGrad(y * y);
    return a + b;
}

float debugGrad(float x) { return x; }

[BackwardDerivativeOf(debugGrad)]
void debugGradBwd(inout DifferentialPair<float> x_pair, float dOut)
{
    printf("Gradient is %f\n", dOut);
    x_pair = diffPair(x.p, dOut);
}
```

With this custom derivative technique, we can flexibly check if the gradient of `y * y` is computed correctly.

In the next tutorial, we will introduce more details and advanced usages of autodiff by building a simple MLP example from scratch.

---

## File: docs/auto-diff-tutorial-2.md

---
title: "Automatic Differentiation Tutorial - 2"
layout: page
permalink: "/docs/auto-diff-tutorial-2"
intro_image_absolute: true
intro_image_hide_on_mobile: false
---

## What Will We Learn

In the [last tutorial](auto-diff-tutorial-1.md), we explained basic knowledge about Slang's autodiff feature and introduced some advanced techniques about custom derivative implementation and custom differential type.

In this tutorial, we will walk through a real-world example using what we've learned from the last tutorial.

We will learn how to implement a tiny Multi-Layer Perceptron (MLP) to approximate a set of polynomial functions using Slang's automatic differentiation capabilities.

### Problem Setup

- **Input**: Two scalar variables x and y

- **Target Function**: A set of polynomial expressions:

$$f(x,y) = \begin{bmatrix}
f_{1}(x,\, y) =&\frac{(x\, + \, y)}{\left( 1\, + \, y^{2} \right)} \\
f_{2}(x,\, y) =&2x + y \\
f_{3}(x,\, y) =&0.5x^{2} + 1.2y \\
f_{4}(x,\, y) =&x + 0.5y^{2}
\end{bmatrix}$$

- **Network Architecture**: 4 inputs → 16 hidden units → 4 outputs
  - We will encode the 2 inputs $x$ and $y$ into $x$, $y$, $x^2$ and $y^2$.

- **Learning Method**: Simple gradient descent

## 2. Mathematical Formulation

### The Learning Problem

Given a neural network $MLP(x,y;\theta)$ with parameters $\theta$, we want to minimize:

$$L(\theta) = \left| \left| MLP(x,y;\theta) - f(x,y) \right| \right|^{2}$$

Where:

- $MLP(x,y;\theta)$ is our neural network's output
- $f(x,y)$ is the ground truth polynomial set
- $L(\theta)$ is the [mean squared error](https://en.wikipedia.org/wiki/Mean_squared_error)

### The workflow will be

- **Forward Pass**: Compute $MLP(x,y;\theta)$ and $L(\theta)$
- **Backward Pass**: Compute $\frac{\partial L}{\partial\theta}$ (gradients w.r.t. parameters)
- **Parameter Update**: $\theta \leftarrow \theta - \alpha\frac{\partial L}{\partial\theta}$ (gradient descent)

## 3. Forward Pass Architecture Design

### 3.1 Top-Level Network Definition

Our MLP is a composition of two feed-forward layers:

```hlsl
public struct MyNetwork
{
    public FeedForwardLayer<4, 16> layer1; // Input to hidden
    public FeedForwardLayer<16, 4> layer2; // Hidden to output

    internal public MLVec<4> _eval(half x, half y)
    {
        // layer2.eval(layer1.eval());
    }

    public half4 eval(no_diff half x, no_diff half y)
    {
        // construct MLVec<4> from x, y, x^2, y^2
        // call internal _eval
        // convert MLVec<4> to half4
    }
}
```

In our interface method design, we introduce an internal representation of vector type `MLVec<4>` in the network evaluation. And this design choice will help us hide the details about how we are going to perform the arithmetic/logic operations on the vector type, as they are irrelevant to how the network should be designed. For now, you can treat this type as an opaque type, and we will talk about the details in later section. Therefore, in the public method, we will just convert the input to `MLVec`, call the internal `_eval` method, and convert `MLVec` back to a normal vector. And in the internal `_eval` method, we will just chain the evaluations of each layer together.
> Note that we are using `half` type, which is [16-bit floating-point type](external/slang/docs/user-guide/02-conventional-features.md#scalar-types) for better throughput and to reduce memory usage.

### 3.2 Feed-Forward Layer Definition

Each layer performs: $LeakyRelu(Wx+b)$, so we can create a struct to abstract this as follows:

```hlsl
public struct FeedForwardLayer
{
    public NFloat* weights;
    public NFloat* weightsGrad;
    public NFloat* biases;
    public NFloat* biasesGrad;

    public MLVec<OutputSize> eval(MLVec input)
    {
        // out = matrix-multiply-add(input, weight, bias);
        // return leaky_relu(out, alpha);
    }
}
```

The evaluation is very simple, just doing a matrix vector multiplication plus a bias vector, and then performing a LeakyRelu function on it. But note that we use pointers in this struct to reference the parameters (e.g. weight and bias) instead of declaring arrays or even global storage buffers. Because our MLP will be run on the GPU and each evaluation function will be executed per-thread, if we used arrays for each layer, an array would be allocated for each thread and that would explode the GPU memory. For the same reason, we cannot declare a storage buffer directly within the layer struct because each thread would create its own copy of the storage buffer containing identical data, leading to massive memory waste. Instead, we use pointers to reference a single shared global storage buffer.

### 3.3 Vector Type Definition

The `MLVec` type represents vectors:
```hlsl
public struct MLVec
{
    public half data[N];
    public static MLVec<N> fromArray(half[N] values)
    {
        // construct MLVec<N> from values
    }

    public NFloat[N] toArray()
    {
        return data;
    }
}
```
For `MLVec`, we declare two methods to help us convert from and to a normal array.

**Supporting Operations**:

- Matrix-vector multiplication with bias
```hlsl
MLVec<OutputSize> matMulAdd(MLVec input, NFloat* matrix, NFloat* bias);
```
- Transpose version of Matrix-vector multiplication with bias
```hlsl
MLVec<OutputSize> matMulTransposed(MLVec input, NFloat* matrix);
```
- Outer product of two vectors
```hlsl
void outerProductAccumulate(MLVec<M> v0, MLVec<N> v1, NFloat* matrix);
```

The first two operations are straightforward, which is just matrix vector multiplication and its transpose version. The last operation defines an outer product of two vectors, the result will be a matrix, such that $\text{x} \otimes \text{y} = \text{x} \cdot \text{y}^{T}$, where $\text{x}$ and $\text{y}$ are column vectors with the same length.

### 3.4 Loss Function Definition

The loss function measures how far our network output is from the target, since we have already defined the interfaces for the MLP network, we can simply implement the loss function:

```hlsl
public half loss(MyNetwork* network, half x, half y)
{
    let networkResult = network.eval(x, y); // MLP(x,y; θ)
    let gt = groundtruth(x, y);             // target(x,y)
    let diff = networkResult - gt;          // Error vector
    return dot(diff, diff);                 // square of error
}
```

And the `groundtruth` implementation is as trivial as:

```hlsl
public half4 groundtruth(half x, half y)
{
    return
    {
        (x + y) / (1 + y * y),  // f₁(x,y)
        2 * x + y,              // f₂(x,y)
        0.5 * x * x + 1.2 * y,  // f₃(x,y)
        x + 0.5 * y * y,        // f₄(x,y)
    };
}
```

## 4. Backward Pass Design

After implementing the forward pass of the network evaluation, we then need to implement the backward pass. You will see how effortless it is to implement the backward pass with Slang's autodiff. We will start the implementation from the end of the workflow to the beginning, because that's how the direction in which the gradients flow.

### 4.1 Backward Pass of Loss

To implement the backward derivative of loss function, we only need to mark the function as `[Differentiable]` as we learned from [last tutorial](auto-diff-tutorial-1.md#forward-mode-differentiation)

```hlsl
[Differentiable]
public half loss(MyNetwork* network, no_diff half x, no_diff half y)
{
    let networkResult = network->eval(x, y);    // MLP(x,y; θ)
    let gt = no_diff groundtruth(x, y);         // target(x,y)
    let diff = networkResult - gt;              // Error vector
    return dot(diff, diff);                     // square of error
}
```

And from the Slang kernel function, we just need to call the backward mode of the `loss` function like this:
```hlsl
bwd_diff(loss)(network, input.x, input.y, 1.0h);
```

One important thing to notice is that we are using the [`no_diff` attribute](external/slang/docs/user-guide/07-autodiff.html#excluding-parameters-from-differentiation) to decorate the inputs `x` and `y`, as well as `groundtruth` calculation, because in the backward pass, we only care about the result of $\frac{\partial loss}{\partial\theta}$. The `no_diff` attribute just tells Slang to treat the variables or instructions as non-differentiable, so there will be no backward mode instructions generated for those variables or instructions. In this case, since we don't care about the derivative of loss function with respect to the input, therefore we can safely mark them as non-differentiable.

Since `loss` function is differentiable now, every instruction inside this function has to be differentiable except those marked as `no_diff`. Therefore, `network->eval(x, y)` must be differentiable, so next we are going to implement the backward pass for this method.

### 4.2 Automatic Propagation to MLP

Just like the `loss` function, the only thing we need to do for `MyNetwork::eval` in order to use it with autodiff is to mark it as differentiable:
```hlsl
public struct MyNetwork
{
    public FeedForwardLayer<4, 16> layer1; // Input to hidden
    public FeedForwardLayer<16, 4> layer2; // Hidden to output

    [Differentiable]
    internal public MLVec<4> _eval(half x, half y)
    {
        // layer2.eval(layer1.eval());
    }

    [Differentiable]
    public half4 eval(no_diff half x, no_diff half y)
    {
        // construct MLVec<4> from x, y
        // call internal _eval
        // convert MLVec<4> to half4
    }
}
```

## 4.3 Custom Backward Pass for Layers

Following the propagation direction of the gradients, we will next implement the backward derivative of FeedForwardLayer. But here we're going to do something different. Instead of asking Slang to automatically synthesize the backward autodiff for us, we will provide a custom derivative implementation. Because the network parameters and gradients are a buffer storage declared in the layer, we will have to provide a custom derivative to write the gradient back to the global buffer storage. You can reference [propagate derivative to storage buffer](auto-diff-tutorial-1.md#how-to-propagate-derivatives-to-global-buffer-storage) in last tutorial to refresh your memory. Another benefit of providing a custom derivative here is that our layer is just matrix multiplication with bias, and its derivative is quite simple, so there are lots of options to accelerate it with specific hardware (e.g. Nvidia tensor cores). Therefore, it's good practice to implement the custom derivative.

First, let's revisit the mathematical formula, given:

$$Z=W\cdot x+b$$
$$Y=LeakyRelu(Z)$$

Where $W \in R^{m \times n}$, $x \in R^{n}$ and $b \in R^{m}$, the
gradient of $W$, $x$ and $b$ will be:

$$Z=W\cdot x+b$$
$$dZ=dY\cdot(z > 0 ? 1:\alpha)$$
$$dW=dZ\cdot x^{T}$$
$$\text{d}b=\text{d}Z$$
$$dx=W^{T}\cdot dZ$$

Therefore, the implementation should be:
```hlsl
[BackwardDerivativeOf(eval)]
public void evalBwd(inout DifferentialPair<MLVec> x, MLVec<OutputSize> dResult)
{
    let Z = eval(x.p); // Re-compute forward pass to get Z
    // Step 1: Backward through activation function
    // dZ = dY * (Z > 0 ? 1 : alpha)
    for (int i = 0; i < OutputSize; i++)
    {
        if (Z.data[i] < 0.0)
        dResult.data[i] *= 0.01h; // Derivative of leaky ReLU
    }

    // Step 2: Accumulate weight gradients
    // dW = dZ * x^T
    outerProductAccumulate(dResult, x.p, weightsGrad);

    // Step 3: Accumulate bias gradients
    // db = dZ
    for (int i = 0; i < OutputSize; i++)
    {
        NFloat originalValue;
        InterlockedAddF16Emulated(biasesGrad + i, dResult.data[i], originalValue);
    }

    // Step 4: Compute input gradients (for chaining to previous layer)
    // dx = W^T * dZ
    let dx = matMulTransposed(dResult, weights);
    x = {x.p, dx}; // Update differential pair
}
```

The key point in this implementation is that we use atomic add when writing the gradients to the global storage buffer, e.g.:
```hlsl
InterlockedAddF16Emulated(biasesGrad + i, dResult.data[i], originalValue);
```

In the forward pass we already know that the parameters stored in a global storage buffer are shared by all threads, and so are the gradients. Therefore, during the backward pass, each thread will accumulate its gradient data to the shared storage buffer, so we must use atomic add operation to accumulate all the gradients without race conditions.

The implementation of `outerProductAccumulate` and `matMulTransposed` are trivial for-loop multiplication, so we will not show the details in this tutorial. The complete code can be found at [here](https://github.com/shader-slang/neural-shading-s25/tree/main/hardware-acceleration/mlp-training).

### 4.4 Make the vector differentiable

If we just compiled what we have right now, we would get a compile error because `MLVec` is not a differentiable type, so Slang doesn't expect the signature of backward of layer's eval method to be:
```hlsl
public void evalBwd(inout DifferentialPair<MLVec> x, MLVec<OutputSize> dResult)
```

Therefore, we will have to update `MLVec` to make it differentiable:
```hlsl
public struct MLVec : IDifferentiable
{
    public half data[N];

    [Differentiable]
    public static MLVec<N> fromArray(half[N] values){ ... }

    [Differentiable]
    public NFloat[N] toArray(){ ... }
}
```

### 4.5 Parameter Update

After backpropagation, the last step is to update the parameters by the gradients we just computed:
```hlsl
public struct Optimizer
{
    public static const NFloat learningRate = 0.01h; // Step size
    public static void step(inout NFloat param, inout NFloat grad)
    {
        param = param - grad * learningRate;    // gradient descent
        grad = 0.f;                             // Reset gradient for next iteration
    }
}
```

## 5. Putting It All Together

We will create two kernel functions: one for training and another for parameter updating.

The training kernel will be:
```hlsl
[shader("compute")]
[numthreads(256, 1, 1)]
void learnGradient(
    uint32_t tid : SV_DispatchThreadID,
    uniform MyNetwork* network,
    uniform Atomic* lossBuffer,
    uniform float2* inputs,
    uniform uint32_t count)
{
    if (tid >= count) return;

    var input = (half2)inputs[tid];

    // Compute all gradients automatically
    bwd_diff(loss)(network, input.x, input.y, 1.0h);

    // Also compute loss value for monitoring
    let thisLoss = (float)loss(network, input.x, input.y);
    let maxLoss = WaveActiveMax(thisLoss);
    if (WaveIsFirstLane())
    {
        lossBuffer.max(bit_cast(maxLoss));
    }
}
```

The parameter update kernel is:

```hlsl
[shader("compute")]
[numthreads(256, 1, 1)]
void adjustParameters(
    uint32_t tid : SV_DispatchThreadID,
    uniform NFloat* params,
    uniform NFloat* gradients,
    uniform uint32_t count)
{
    if (tid >= count) return;

    // Apply gradient descent
    Optimizer::step(params[tid], gradients[tid]);
}
```

The training process will be a loop that alternately invokes the slang compute kernel `learnGradient` and `adjustParameters`, until the loss converges to an acceptable threshold value.

The host side implementation for this example is not shown, as it is simply boilerplate code to setup the graphics pipeline and allocate buffers for parameters. You can access the [github repo](https://github.com/shader-slang/neural-shading-s25/tree/main/hardware-acceleration/mlp-training) for this example's complete code, which includes the host side implementation. Alternatively, you can use the more powerful tool [SlangPy](https://github.com/shader-slang/slangpy) to run this MLP example without writing any graphics boilerplate code.

---

## File: docs/autodiff-tips-custom-diffs.md

---
title: "Autodiff Tips and Tricks: Custom Derivatives"
layout: page
permalink: "/docs/autodiff-tips-custom-diffs"
intro_image_absolute: true
intro_image_hide_on_mobile: false
---

# Autodiff Tips and Tricks: When to Use Custom Derivatives

Slang's automatic differentiation (autodiff) system is powerful and can handle a wide range of functions. However, there are specific scenarios where defining a custom derivative can be beneficial, offering more control and accuracy. This guide outlines the major examples of when you might want to consider writing your own custom derivative, rather than relying solely on Slang's autodiff capabilities.

# 1\. Opaque Functions

Opaque functions are those where the internal operations are not visible or accessible to Slang's autodiff system. This often occurs with functions that interact with external systems or hardware, such as:

* **Hardware-accelerated texture filtering:** When performing operations like texture filtering, the underlying mathematical process may not be exposed in a way that allows Slang to compute a derivative automatically. In such cases, you would need to define a custom derivative that approximates or accurately represents the sensitivity of the output to the input.

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
[BackwardDerivative(externalFunction_bwd)]
float externalFunction(float x)
{
    // This calls an external library or hardware function
    // that Slang cannot differentiate automatically
    return someExternalLibraryCall(x);
}

void externalFunction_bwd(inout DifferentialPair<float> x, float dOut)
{
    // Approximate the derivative using finite differences
    const float epsilon = 1e-6;
    float fwd = someExternalLibraryCall(x.p + epsilon);
    float bwd = someExternalLibraryCall(x.p - epsilon);
    float derivative = (fwd - bwd) / (2.0 * epsilon);

    x = diffPair(x.p, derivative);
}
```

This example shows one option to handle an opaque function that calls an external library. Since Slang cannot see inside the external function, we can use finite differences to approximate the derivative.

# 2\. Buffer Accesses

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
RWStructuredBuffer<float> myBuffer;
RWStructuredBuffer<Atomic<float>> gradientBuffer;  // Global buffer for gradients

[BackwardDerivative(loadFloat_bwd)]
float loadFloat(uint idx)
{
    return myBuffer[idx];
}

void loadFloat_bwd(uint idx, float dOut)
{
    // Safely accumulate gradient to global buffer using atomic addition
    gradientBuffer[idx] += dOut;
}
```

This example shows one way to handle differentiation of buffer access. The `loadFloat` function reads from a buffer, and its custom derivative `loadFloat_bwd` safely accumulates gradients to a global buffer using atomic operations to avoid race conditions when multiple threads might write to the same location.

# 3\. Numerically Unstable Functions

Numerical stability refers to how well a computation preserves accuracy when faced with small changes in input or when intermediate values become very large or very small. Some complex mathematical functions can be numerically unstable, leading to issues like:

* **Divisions by zero:** Highly complex expressions can inadvertently lead to denominators approaching zero, resulting in undefined or infinite derivatives.  
* **Gradient explosion or vanishing:** In deep learning contexts, gradients can become extremely large (explosion) or extremely small (vanishing), hindering effective optimization.

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
[BackwardDerivative(safeDivide_bwd)]
float safeDivide(float numerator, float denominator)
{
    const float epsilon = 1e-8;
    return numerator / max(denominator, epsilon);
}

void safeDivide_bwd(inout DifferentialPair<float> numerator, inout DifferentialPair<float> denominator, float dOut)
{
    const float epsilon = 1e-8;
    const float maxGradient = 1e6;  // Prevent gradient explosion
    float denomStable = denominator.p + epsilon;
    // Clamp gradients to prevent explosion when denominator is very small
    float dNumerator = clamp(dOut / denomStable, -maxGradient, maxGradient);
    float dDenominator = clamp(-dOut * numerator.p / (denomStable * denomStable), -maxGradient, maxGradient);

    numerator = diffPair(numerator.p, dNumerator);
    denominator = diffPair(denominator.p, dDenominator);
}
```

This example shows how to handle division that could be numerically unstable. The `safeDivide` function adds a small epsilon to prevent division by zero, and its custom derivative clamps the gradients to prevent explosion when the denominator is very small.

# Mixing Custom and Automatic Differentiation

One of the key strengths of Slang's autodiff system is its flexibility. You are not forced to choose between entirely custom derivatives or entirely automatic differentiation. Slang allows you to **mix custom and automatic differentiation**. 

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).

# Approximating Derivatives for Inherently Undifferentiable Functions

While some functions are mathematically discontinuous or opaque, making them undifferentiable in a strict sense, it's often still possible and desirable to define a custom derivative that approximates their behavior or provides a useful "gradient" for optimization purposes. This is particularly crucial in machine learning and computational graphics where such functions are common. Here's how you might approach creating a custom derivative for something that seems inherently undifferentiable:

* **Subgradients for Discontinuous Functions**:  
  For functions with sharp corners or jumps (like ReLU, absolute value, or step functions), the derivative is undefined at specific points. Automatic differentiation systems like Slang's handle these cases using established conventions, but you may want custom behavior. A subgradient is not a unique value but rather a set of possible "slopes" at the non-differentiable point. For example, for ReLU:  
  * If input \> 0, derivative is 1\.  
  * If input \< 0, derivative is 0\.  
  * If input \= 0, the subgradient can be any value between 0 and 1 (inclusive).  
    When implementing a custom derivative, you typically pick a specific value from this subgradient set (e.g., 0 or 0.5) to ensure a deterministic derivative for your autodiff system.  

Slang's autodiff system includes built-in conventions for handling many discontinuous functions that would otherwise be problematic for differentiation. For example, Slang can automatically generate derivatives for the `max()` function even though it's not differentiable at the point where `x = y`. When the inputs are equal, Slang assigns half the gradient to each input, ensuring that gradients flow through both branches of the computation. Similarly, for `clamp()` function, when the input equals the minimum or maximum bounds, Slang propagates the gradient to the input `x` rather than to the `min` or `max` parameters, making a choice that favors the primary input. Similar conventions exist for other discontinuous functions like `min()`, `abs()`, and conditional operations. These conventions are designed to provide sensible gradients that work well in practice, even when the mathematical derivative is undefined at certain points.

* **Finite Difference Approximation**:  
  If you have no analytical way to determine the derivative, you can resort to numerical approximation using finite differences. This method involves evaluating the function at two closely spaced points and calculating the slope between them. While computationally more expensive and potentially less accurate than analytical derivatives, finite differences can provide a workable approximation for opaque or highly complex functions where direct differentiation is impossible. You would implement this calculation in your custom derivative function. See the example in the "Opaque Functions" section above for a practical implementation of this technique.  
* **Surrogate Gradients (for Hard Discontinuities)**:  
  For functions with truly "hard" discontinuities (e.g., a direct lookup in a table based on an index, or a strict "if-else" branching that completely changes the computation), a subgradient or finite difference might not be suitable. In such cases, you might use a surrogate gradient. This involves replacing the undifferentiable part of the computation with a differentiable approximation solely for the purpose of backpropagation.  
  For example, if you have a \`floor()\` operation (which is not differentiable), you might, during the backward pass, pretend it was an identity function (\`x\`) or a smoothed version of it to allow gradients to flow through. The forward pass still uses the exact \`floor()\` operation, but the backward pass uses your custom, differentiable surrogate. This allows the optimization algorithm to still "feel" a gradient and make progress, even if it's not the true mathematical derivative.  
* **Domain-Specific Knowledge and Heuristics**:  
  Sometimes, the best "derivative" for an undifferentiable function comes from understanding the underlying problem and applying domain-specific heuristics. For instance, in rendering, if a function represents a decision boundary (e.g., inside/outside an object), your custom derivative might encode how sensitive that decision is to small changes in input, even if the boundary itself is sharp. This often involves defining a "gradient" that pushes the input towards the desired outcome based on prior knowledge.

When choosing an approximation method, consider the trade-offs between accuracy, computational cost, and how well the approximated derivative guides your optimization or analysis. The goal is to provide a "signal" to the autodiff system that allows it to effectively propagate changes and facilitate whatever computation or optimization you are performing.

---

## File: docs/coming-from-glsl.md

---
title: Migrating to Slang from GLSL
layout: page
permalink: "/docs/coming-from-glsl/"
intro_image_absolute: true
intro_image_hide_on_mobile: false
---

## Overview
This guide provides a reference for migrating GLSL shaders to Slang.

## Type and Syntax Reference

When converting GLSL shaders to Slang, you'll need to translate GLSL types and syntax to their Slang equivalents.

### Scalar Types

| GLSL Type | Slang Type | Description |
|-----------|------------|-------------|
| `float`   | `float`    | 32-bit floating point |
| `float16_t` | `half`   | 16-bit floating point |
| `int`     | `int`      | 32-bit signed integer |
| `uint`    | `uint`     | 32-bit unsigned integer |
| `bool`    | `bool`     | Boolean value |
| `double`  | `double`   | 64-bit floating point |
| `int8_t`  | `int8_t`   | 8-bit signed integer |
| `uint8_t` | `uint8_t`  | 8-bit unsigned integer |
| `int16_t` | `int16_t`  | 16-bit signed integer |
| `uint16_t`| `uint16_t` | 16-bit unsigned integer |
| `int64_t` | `int64_t`  | 64-bit signed integer |
| `uint64_t`| `uint64_t` | 64-bit unsigned integer |

### Vector Types

| GLSL Type | Slang Type | Description |
|-----------|------------|-------------|
| `vec2`    | `float2`   | 2-component float vector |
| `vec3`    | `float3`   | 3-component float vector |
| `vec4`    | `float4`   | 4-component float vector |
| `f16vec2` | `half2`    | 2-component half-precision float vector |
| `f16vec3` | `half3`    | 3-component half-precision float vector |
| `f16vec4` | `half4`    | 4-component half-precision float vector |
| `ivec2`   | `int2`     | 2-component int vector |
| `ivec3`   | `int3`     | 3-component int vector |
| `ivec4`   | `int4`     | 4-component int vector |
| `uvec2`   | `uint2`    | 2-component uint vector |
| `uvec3`   | `uint3`    | 3-component uint vector |
| `uvec4`   | `uint4`    | 4-component uint vector |
| `bvec2`   | `bool2`    | 2-component boolean vector |
| `bvec3`   | `bool3`    | 3-component boolean vector |
| `bvec4`   | `bool4`    | 4-component boolean vector |
| `dvec2`   | `double2`  | 2-component double vector |
| `dvec3`   | `double3`  | 3-component double vector |
| `dvec4`   | `double4`  | 4-component double vector |

### Matrix Types

| GLSL Type | Slang Type | Description |
|-----------|------------|-------------|
| `mat2`    | `float2x2` | 2×2 float matrix |
| `mat3`    | `float3x3` | 3×3 float matrix |
| `mat4`    | `float4x4` | 4×4 float matrix |
| `mat2x3`  | `float2x3` | 2×3 float matrix |
| `mat2x4`  | `float2x4` | 2×4 float matrix |
| `mat3x2`  | `float3x2` | 3×2 float matrix |
| `mat3x4`  | `float3x4` | 3×4 float matrix |
| `mat4x2`  | `float4x2` | 4×2 float matrix |
| `mat4x3`  | `float4x3` | 4×3 float matrix |
| `f16mat2` | `half2x2`  | 2×2 half-precision float matrix |
| `f16mat3` | `half3x3`  | 3×3 half-precision float matrix |
| `f16mat4` | `half4x4`  | 4×4 half-precision float matrix |
| `f16mat2x3` | `half2x3` | 2×3 half-precision float matrix |
| `f16mat2x4` | `half2x4` | 2×4 half-precision float matrix |
| `f16mat3x2` | `half3x2` | 3×2 half-precision float matrix |
| `f16mat3x4` | `half3x4` | 3×4 half-precision float matrix |
| `f16mat4x2` | `half4x2` | 4×2 half-precision float matrix |
| `f16mat4x3` | `half4x3` | 4×3 half-precision float matrix |

### Vector/Matrix Construction

GLSL:

```glsl
vec4 color = vec4(1.0, 0.5, 0.2, 1.0);
mat4 transform = mat4(
    vec4(1.0, 0.0, 0.0, 0.0),
    vec4(0.0, 1.0, 0.0, 0.0),
    vec4(0.0, 0.0, 1.0, 0.0),
    vec4(0.0, 0.0, 0.0, 1.0)
);
```

Slang:

```hlsl
float4 color = float4(1.0, 0.5, 0.2, 1.0);
float4x4 transform = float4x4(
    float4(1.0, 0.0, 0.0, 0.0),
    float4(0.0, 1.0, 0.0, 0.0),
    float4(0.0, 0.0, 1.0, 0.0),
    float4(0.0, 0.0, 0.0, 1.0)
);
```

### Matrix Operations

GLSL:

```glsl
mat4 a, b, c;
vec4 v;

// Matrix multiplication
c = a * b;

// Vector transformation (vector is treated as a row vector)
vec4 transformed = v * a;  // row vector * matrix
```

Slang:

```hlsl
float4x4 a, b, c;
float4 v;

// Matrix multiplication
c = mul(a, b);

// Vector transformation (vector is treated as a column vector)
float4 transformed = mul(a, v);  // matrix * column vector
```

Note: Slang uses the `mul()` function for matrix multiplication rather than the `*` operator. Also, vectors are treated as column vectors in Slang, while they're treated as row vectors in GLSL, so the order of arguments is inverted.

### Shader Inputs and Outputs

GLSL and Slang handle shader inputs and outputs differently. Here's a fragment/pixel shader example:

**GLSL:**
```glsl
// Fragment shader input
in vec2 texCoord;

// Fragment shader output
layout(location = 0) out vec4 fragColor;

void main() {
    // Use texCoord to sample a texture
    fragColor = vec4(texCoord, 0.0, 1.0);
}
```

**Slang (Method 1 - Using structures):**
```hlsl
// Input structure
struct PSInput {
    float2 texCoord : TEXCOORD0;
};

// Output structure
struct PSOutput {
    float4 color : SV_Target0;
};

// Pixel shader using structures
[shader("pixel")]
PSOutput main(PSInput input) {
    PSOutput output;
    
    // Use input.texCoord to sample a texture
    output.color = float4(input.texCoord, 0.0, 1.0);
    
    return output;
}
```

**Slang (Method 2 - Direct parameters):**
```hlsl
// Pixel shader using direct parameters
[shader("pixel")]
float4 main(float2 texCoord : TEXCOORD0) : SV_Target0 {
    // Use texCoord to sample a texture
    return float4(texCoord, 0.0, 1.0);
}
```

Both Slang methods produce the same result, but Method 1 is more organized for complex shaders with many inputs and outputs, while Method 2 is more concise for simple shaders.

### Built-in Variables

GLSL provides built-in variables that can be accessed directly in shaders, while Slang requires these variables to be explicitly declared as inputs or outputs in shader entry point functions. Unlike regular shader inputs and outputs which you define yourself, built-in variables provide access to system values like vertex IDs, screen positions, etc.

#### Example: Minimal Vertex Shader with Built-in Variables

Here's a simplified example showing how built-in variables work in both GLSL and Slang:

**GLSL:**
```glsl
#version 460

// No need to declare gl_VertexID - it's implicitly available

void main() {
    // Access input built-in variable directly
    int vertID = gl_VertexID;
    
    // Set position based on vertex ID
    float x = (vertID == 0) ? -0.5 : ((vertID == 1) ? 0.5 : 0.0);
    float y = (vertID == 2) ? 0.5 : -0.5;
    
    // Set output built-in variable directly
    gl_Position = vec4(x, y, 0.0, 1.0);
}
```

**Slang:**
```hlsl
// Slang: Built-in variables must be explicitly declared in the function signature
[shader("vertex")]
float4 main(uint vertexID : SV_VertexID) : SV_Position {
    // Input built-in is passed as a function parameter
    
    // Calculate position based on vertex ID
    float x = (vertexID == 0) ? -0.5 : ((vertexID == 1) ? 0.5 : 0.0);
    float y = (vertexID == 2) ? 0.5 : -0.5;
    
    // Output built-in is returned from the function
    return float4(x, y, 0.0, 1.0);
}
```

Notice the key differences:
1. In GLSL, `gl_VertexID` (input) and `gl_Position` (output) are accessed directly as global variables
2. In Slang, the input `SV_VertexID` is a function parameter, and the output `SV_Position` is the function return value

For more complex shaders, you can use structures for inputs and outputs as shown in the previous section.

#### Built-in Variables Reference

The following table maps GLSL built-in variables to their corresponding Slang system value semantics across standard shader stages. In GLSL, these variables are accessed directly as globals, while in Slang they must be declared explicitly in function signatures with appropriate semantic annotations.

| GLSL Built-in | Slang System Value |
|---------------|-------------------|
| `gl_BaseInstance` | `SV_StartInstanceLocation` |
| `gl_BaseVertex` | `SV_StartVertexLocation` |
| `gl_BaryCoordEXT` | `SV_Barycentrics` |
| `gl_ClipDistance` | `SV_ClipDistance` |
| `gl_CullDistance` | `SV_CullDistance` |
| `gl_CullPrimitiveEXT` | `SV_CullPrimitive` |
| `gl_DrawID` | `SV_DrawIndex` |
| `gl_FragCoord` | `SV_Position` |
| `gl_FragDepth` | `SV_Depth` |
| `gl_FragStencilRefEXT` | `SV_StencilRef` |
| `gl_FrontFacing` | `SV_IsFrontFace` |
| `gl_FullyCoveredEXT` | `SV_InnerCoverage` |
| `gl_GlobalInvocationID` | `SV_DispatchThreadID` |
| `gl_InstanceID` | `SV_InstanceID` |
| `gl_InvocationID` | `SV_GSInstanceID/SV_OutputControlPointID` |
| `gl_Layer` | `SV_RenderTargetArrayIndex` |
| `gl_LocalInvocationID` | `SV_GroupThreadID` |
| `gl_LocalInvocationIndex` | `SV_GroupIndex` |
| `gl_PointSize` | `SV_PointSize` |
| `gl_Position` | `SV_Position` |
| `gl_PrimitiveID` | `SV_PrimitiveID` |
| `gl_PrimitiveShadingRateEXT` | `SV_ShadingRate` |
| `gl_SampleID` | `SV_SampleIndex` |
| `gl_SampleMask` | `SV_Coverage` |
| `gl_ShadingRateEXT` | `SV_ShadingRate` |
| `gl_SubgroupInvocationID` | `SV_WaveLaneIndex` |
| `gl_SubgroupSize` | `SV_WaveLaneCount` |
| `gl_TessCoord` | `SV_DomainLocation` |
| `gl_TessLevelInner` | `SV_InsideTessFactor` |
| `gl_TessLevelOuter` | `SV_TessFactor` |
| `gl_VertexIndex` | `SV_VertexID` |
| `gl_ViewIndex` | `SV_ViewID` |
| `gl_ViewportIndex` | `SV_ViewportArrayIndex` |
| `gl_WorkGroupID` | `SV_GroupID` |

#### Ray Tracing Built-ins

Ray tracing built-ins in Slang are accessed through function calls rather than system value semantics. The following table maps GLSL ray tracing built-ins to their corresponding Slang functions:

| GLSL Built-in | Slang Function |
|---------------|----------------|
| `gl_HitKindEXT` | `HitKind()` |
| `gl_HitTEXT` | `RayTCurrent()` |
| `gl_InstanceCustomIndexEXT` | `InstanceIndex()` |
| `gl_InstanceID` | `InstanceID()` |
| `gl_LaunchIDEXT` | `DispatchRaysIndex()` |
| `gl_LaunchSizeEXT` | `DispatchRaysDimensions()` |
| `gl_ObjectRayDirectionEXT` | `ObjectRayDirection()` |
| `gl_ObjectRayOriginEXT` | `ObjectRayOrigin()` |
| `gl_RayTmaxEXT` | `RayTCurrent()` |
| `gl_RayTminEXT` | `RayTMin()` |
| `gl_WorldRayDirectionEXT` | `WorldRayDirection()` |
| `gl_WorldRayOriginEXT` | `WorldRayOrigin()` |

### Built-in Functions and Operators

When porting GLSL shaders to Slang, most common mathematical functions (sin, cos, tan, pow, sqrt, abs, etc.) share identical names in both languages. However, there are several important differences to be aware of, listed below:

#### Key Function Differences

| GLSL | Slang | Description |
|------|-------|-------------|
| `mix(x, y, a)` | `lerp(x, y, a)` | Linear interpolation |
| `fract(x)` | `frac(x)` | Fractional part of x |
| `inversesqrt(x)` | `rsqrt(x)` | Inverse square root (1/sqrt) |
| `atan(y, x)` | `atan2(y, x)` | Arc tangent of y/x |
| `dFdx(p)` | `ddx(p)` | Derivative with respect to screen-space x |
| `dFdy(p)` | `ddy(p)` | Derivative with respect to screen-space y |
| `m1 * m2` (matrix multiply) | `mul(m1, m2)` | Matrix multiplication |
| `v * m` (row vector) | `mul(m, v)` (column vector) | Vector-matrix multiplication |

## Control Flow Attributes

Slang provides control flow hint attributes similar to those in the GL_EXT_control_flow_attributes GLSL extension. These attributes provide optimization hints for loops and conditional statements to the driver compiler. Note that these are hints only and may be ignored by the driver compiler.

### Attribute Mapping

| GLSL Attribute | Slang Attribute | Applies To | Description |
|----------------|-----------------|------------|-------------|
| `[[branch]]` | `[branch]` | if/switch | Hint to keep selection control flow (use actual branching) |
| `[[flatten]]` | `[flatten]` | if/switch | Hint to remove selection control flow (evaluate both branches) |
| `[[dont_flatten]]` | `[branch]` | if/switch | Same as branch |
| `[[loop]]` | `[loop]` | loops | Hint to keep loop control flow (against unrolling) |
| `[[unroll]]` | `[unroll]` | loops | Hint to remove or reduce loop control flow (unroll fully) |
| `[[dont_unroll]]` | `[loop]` | loops | Same as loop |

Note: Slang also supports [unroll(N)] for partial unrolling hints.

Note: Slang supports the [ForceUnroll] attribute which unrolls the loop before emitting SPIR-V or other target code.

### Usage Example

**GLSL:**

```glsl
#extension GL_EXT_control_flow_attributes : enable

[[unroll]]
for(int i = 0; i < 8; i++) {
    // loop body
}

[[flatten]]
if(condition) {
    // if body
} else {
    // else body
}
```

**Slang:**

```hlsl
[unroll]
for(int i = 0; i < 8; i++) {
    // loop body
}

[flatten]
if(condition) {
    // if body
} else {
    // else body
}
```

These attributes are applied directly before the control flow statements in both languages.

## Resource Handling

This section covers how to convert GLSL resource declarations to Slang, including different buffer types, textures, and specialized resources.

### Resource Binding Models

Slang supports three different binding syntax options to accommodate both HLSL-style and GLSL-style resource declarations:

#### GLSL Binding Model

```glsl
// GLSL uses binding and set numbers
layout(binding = 0, set = 0) uniform UniformBufferA { ... };
```

#### Slang Binding Models

##### Option 1: HLSL Register Syntax

```hlsl
// Using register semantics with space (equivalent to set)
ConstantBuffer bufferA : register(b0, space0);
```

##### Option 2: GLSL-style Layout Syntax

```hlsl
// Using GLSL-style binding with [[vk::binding(binding, set)]]
[[vk::binding(0, 0)]]
ConstantBuffer bufferA;
```

##### Option 3: Direct GLSL Layout Syntax

```hlsl
// Using layout syntax identical to GLSL
layout(binding = 0, set = 0) ConstantBuffer bufferA;
```

All binding syntax options work the same way for all resource types (ConstantBuffer, Texture2D, RWStructuredBuffer, etc.). The GLSL-style options (2 and 3) can be particularly helpful when porting GLSL shaders without changing the binding model.

### Buffer Types

| Resource Type | GLSL | Slang | Description |
|---------------|------|-------|-------------|
| Uniform Buffer | `uniform Buffer {...}` | `ConstantBuffer<T>` | Read-only constant data |
| Storage Buffer | `buffer Buffer {...}` | `RWStructuredBuffer<T>` | Read-write structured data |
| Read-only Storage Buffer | `readonly buffer Buffer {...}` | `StructuredBuffer<T>` | Read-only structured data |

**Example in GLSL:**
```glsl
#version 460

layout(std140, binding = 0) uniform Params {
    float scale;
};

struct Data {
    vec3 value;
};

layout(std430, binding = 1) buffer Storage {
    Data data;
};

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main() {
    float s = scale;
    data.value *= s;
}
```

**Example in Slang:**
```hlsl
struct Params {
    float scale;
};

layout(binding = 0) ConstantBuffer params;

struct Data {
    float3 value;
};

layout(binding = 1) RWStructuredBuffer<Data> data;

[shader("compute")]
[numthreads(1, 1, 1)]
void main() {
    float s = params.scale;
    data[0].value *= s;
}
```

Key differences to note:
1. Slang uses the `RW` prefix to distinguish read-write resources from read-only ones
2. In Slang, structured buffers must be indexed even for a single element (e.g., `data[0].value`)
3. In Slang, all buffer members are accessed through the buffer variable name (e.g., `params.scale`, `data[0].value`)

### Texture Resources

This section covers the declaration and usage of texture resources in Slang compared to GLSL.

#### Combined Texture Samplers

GLSL:
```glsl
// Texture declaration
layout(binding = 0) uniform sampler2D inputTexture;
layout(location = 0) out vec4 fragColor;

void main() {
    // Simple texture sampling and copy to output
    vec2 uv = gl_FragCoord.xy / vec2(1280.0, 720.0);
    fragColor = texture(inputTexture, uv);
}
```

Slang:
```hlsl
// Texture declaration
layout(binding = 0) Sampler2D inputTexture;

[shader("pixel")]
float4 main(float4 position : SV_Position) : SV_Target0 {
    // Simple texture sampling and return
    float2 uv = position.xy / float2(1280.0, 720.0);
    return inputTexture.Sample(uv);
}
```

**Texture Type Mapping:**

| GLSL Type | Slang Type | Description |
|-----------|------------|-------------|
| `sampler1D` | `Sampler1D` | 1D texture with built-in sampler |
| `sampler2D` | `Sampler2D` | 2D texture with built-in sampler |
| `sampler3D` | `Sampler3D` | 3D texture with built-in sampler |
| `samplerCube` | `SamplerCube` | Cube texture with built-in sampler |
| `sampler2DArray` | `Sampler2DArray` | 2D texture array with built-in sampler |
| `samplerCubeArray` | `SamplerCubeArray` | Cube texture array with built-in sampler |
| `sampler2DShadow` | `Sampler2DShadow` | Shadow sampler for depth comparisons |
| `isampler2D` | `Sampler2D` | Integer 2D texture with built-in sampler |
| `usampler2D` | `Sampler2D` | Unsigned integer 2D texture with built-in sampler |

**Texture Function Mapping (Combined Sampler Approach):**

| GLSL Function | Slang Function | Description |
|---------------|----------------|-------------|
| `texture(sampler, coord)` | `sampler.Sample(coord)` | Basic texture sampling |
| `textureLod(sampler, coord, lod)` | `sampler.SampleLevel(coord, lod)` | Sample with specific mip level |
| `textureGrad(sampler, coord, ddx, ddy)` | `sampler.SampleGrad(coord, ddx, ddy)` | Sample with explicit derivatives |
| `textureOffset(sampler, coord, offset)` | `sampler.SampleOffset(coord, offset)` | Sample with offset |
| `texelFetch(sampler, coord, lod)` | `sampler.Load(int3(coord, lod))` | Direct texel fetch |
| `textureSize(sampler, lod)` | `sampler.GetDimensions(lod, width, height)` | Get texture dimensions |
| `textureGather(sampler, coord)` | `sampler.Gather(coord)` | Gather four texels |
| `textureGatherOffset(sampler, coord, offset)` | `sampler.GatherOffset(coord, offset)` | Gather with offset |

#### Separate Texture Samplers

GLSL:
```glsl
// Declare texture and sampler separately
uniform texture2D colorTexture;
uniform sampler texSampler;

void main() {
    vec2 uv = gl_FragCoord.xy / vec2(1280.0, 720.0);
    // Combine texture and sampler for sampling
    vec4 color = texture(sampler2D(colorTexture, texSampler), uv);
    fragColor = color;
}
```

Slang:
```hlsl
// Declare texture and sampler state separately
Texture2D colorTexture;
SamplerState texSampler;

[shader("pixel")]
float4 main(float4 position : SV_Position) : SV_Target {
    float2 uv = position.xy / float2(1280.0, 720.0);
    // Pass sampler state explicitly to the Sample method
    return colorTexture.Sample(texSampler, uv);
}
```

### Image Resources

This section covers the declaration and usage of image resources in Slang compared to GLSL, including how to perform image load/store operations.

GLSL:
```glsl
// Image declaration
layout(binding = 4, rgba8) uniform image2D outputImage;

layout(local_size_x = 8, local_size_y = 8) in;
void main() {
    // Get the pixel coordinate for this thread
    ivec2 pixelCoord = ivec2(gl_GlobalInvocationID.xy);
    
    // Simple image store operation (set to red color)
    imageStore(outputImage, pixelCoord, vec4(1.0, 0.0, 0.0, 1.0));
}
```

Slang:
```hlsl
// Image declaration
layout(binding = 4) RWTexture2D<float4> outputImage;

[shader("compute")]
[numthreads(8, 8, 1)]
void main(uint3 dispatchThreadID : SV_DispatchThreadID) {
    // Get the pixel coordinate for this thread
    int2 pixelCoord = int2(dispatchThreadID.xy);
    
    // Simple image store operation (set to red color)
    outputImage[pixelCoord] = float4(1.0, 0.0, 0.0, 1.0);
}
```

**Image Type Mapping:**

| GLSL Type | Slang Type | Description |
|-----------|------------|-------------|
| `image1D` | `RWTexture1D<float4>` | 1D read-write image |
| `image2D` | `RWTexture2D<float4>` | 2D read-write image |
| `image3D` | `RWTexture3D<float4>` | 3D read-write image |
| `imageCube` | `RWTextureCube<float4>` | Cube read-write image |
| `image2DArray` | `RWTexture2DArray<float4>` | 2D array read-write image |
| `iimage2D` | `RWTexture2D` | Integer 2D read-write image |
| `uimage2D` | `RWTexture2D` | Unsigned integer 2D read-write image |

**Image Function Mapping:**

| GLSL Function | Slang Function | Description |
|---------------|----------------|-------------|
| `imageLoad(image, coord)` | `image[coord]` or `image.Load(coord)` | Read from image |
| `imageStore(image, coord, value)` | `image[coord] = value` or `image.Store(coord, value)` | Write to image |
| `imageSize(image)` | `image.GetDimensions(width, height)` | Get image dimensions |

## Shader Entry Point Syntax

GLSL and Slang use fundamentally different approaches for shader entry points. While GLSL always uses a `void main()` function with implicit inputs/outputs through global variables, Slang uses explicitly typed entry points with decorators and function parameters/return values.

This section provides a general overview of the entry point pattern differences. Detailed shader stage-specific conversion information will be covered in a later section.

### Core Entry Point Pattern

**GLSL Pattern:**
```glsl
#version 460
// Global inputs (in) and outputs (out)
in type input_name;
out type output_name;

// Global uniforms and resources
uniform type resource_name;

// Always uses void main() with no parameters
void main() {
    // Access inputs and resources directly
    // Write to outputs directly
}
```

**Slang Pattern:**
```hlsl
// Shader type specified by decorator
[shader("stage_type")]

// Explicit inputs as parameters, outputs as return value
return_type main(parameter_type param : semantic) : return_semantic {
    // Access inputs through parameters
    // Return output value explicitly
}
```

### Shader Stage Decorators

| Shader Stage | Slang Decoration |
|--------------|------------------|
| **Vertex** | `[shader("vertex")]` |
| **Hull/Tessellation Control** | `[shader("hull")]` |
| **Domain/Tessellation Evaluation** | `[shader("domain")]` |
| **Geometry** | `[shader("geometry")]` |
| **Pixel/Fragment** | `[shader("pixel")]` |
| **Compute** | `[shader("compute")]` |
| **Amplification/Task** | `[shader("amplification")]` |
| **Mesh** | `[shader("mesh")]` |
| **Ray Generation** | `[shader("raygeneration")]` |
| **Closest Hit** | `[shader("closesthit")]` |
| **Miss** | `[shader("miss")]` |
| **Any Hit** | `[shader("anyhit")]` |
| **Intersection** | `[shader("intersection")]` |
| **Callable** | `[shader("callable")]` |

Note: For detailed conversions of specific shader stages including tessellation, geometry, mesh, and ray tracing shaders, see the "Shader Stage-Specific Conversions" section later in this guide.

## Shader Stage-Specific Conversions

This section provides mappings for each shader stage from GLSL to Slang, focusing on essential declarations, attributes, and stage-specific functionality.

### Vertex Shaders

#### Core Declaration Mapping

**GLSL:**
```glsl
// No special attributes required
void main() {
    gl_Position = /* output position calculation */;
}
```

**Slang:**
```hlsl
[shader("vertex")]
float4 main(float3 position : POSITION) : SV_Position {
    return /* output position calculation */;
}
```

#### Key Conversion Points

- **Declaration**: Add `[shader("vertex")]` decoration

### Fragment/Pixel Shaders

#### Core Declaration Mapping

**GLSL:**
```glsl
// Early depth testing (optional)
layout(early_fragment_tests) in;

// Output color target(s)
layout(location = 0) out vec4 fragColor;

void main() {
    fragColor = /* color calculation */;
}
```

**Slang:**
```hlsl
// Early depth testing (optional)
[earlydepthstencil]
[shader("pixel")]
float4 main(float4 position : SV_Position) : SV_Target0 {
    return /* color calculation */;
}
```

#### Key Conversion Points

- **Declaration**: Add `[shader("pixel")]` decoration
- **Early Z testing**: Use `[earlydepthstencil]` attribute
- **Multiple outputs**: Use a struct with multiple fields with `SV_Target0/1/2` semantics

### Compute Shaders

#### Core Declaration Mapping

**GLSL:**
```glsl
layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
void main() {
    // Access thread ID via gl_GlobalInvocationID
}
```

**Slang:**
```hlsl
[shader("compute")]
[numthreads(8, 8, 1)]
void main(uint3 dispatchThreadID : SV_DispatchThreadID) {
    // Access thread ID via dispatchThreadID parameter
}
```

#### Key Conversion Points

- **Thread group size**: Replace `layout(local_size_x=X...) in` with `[numthreads(X,Y,Z)]`
- **Shared memory**: Replace `shared` with `groupshared`
- **Barriers**: Replace `barrier()` with `GroupMemoryBarrierWithGroupSync()`

### Hull Shader (Tessellation Control)

#### Core Declaration Mapping

**GLSL:**
```glsl
// Patch size specification
layout(vertices = 3) out;

void main() {
    // Set tessellation levels and compute control points
    gl_TessLevelOuter[0] = 1.0;
    // ...
}
```

**Slang:**
```hlsl
struct Vertex { /* user-defined struct */ }

struct ControlPoint { /* user-defined struct */ }

// Hull shader requires multiple attributes and a separate patch constant function
[shader("hull")]
[domain("tri")]
[partitioning("fractional_odd")]
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("PatchConstantFunction")]
ControlPoint main(InputPatch<Vertex, 3> patch, uint cpID : SV_OutputControlPointID) {
    // Compute control points
}

// Separate function for tessellation factors
struct PatchTessFactors {
    float4 tessFactor : SV_TessFactor;
    float2 insideTessFactor : SV_InsideTessFactor;
};

PatchTessFactors PatchConstantFunction(InputPatch<Vertex, 3> patch) {
    // Set tessellation levels
}
```

#### Key Attribute Mappings

| GLSL | Slang | Description |
|------|-------|-------------|
| `layout(vertices = N) out` | `[outputcontrolpoints(N)]` | Number of control points |
| *Implicit* | `[domain("tri/quad/isoline")]` | Patch domain type |
| *Implicit* | `[partitioning("integer/fractional_even/fractional_odd")]` | Tessellation pattern |
| *Implicit* | `[outputtopology("triangle_cw/triangle_ccw/line")]` | Output topology |
| *N/A* | `[patchconstantfunc("FunctionName")]` | Function for tessellation factors |

#### Key Conversion Points

- **Split structure**: Separate the per-control-point calculations from patch-constant calculations
- **Explicit domain/partitioning**: Add required attributes that are implicit in GLSL
- **Patch constants**: Create separate function decorated with `[patchconstantfunc]`
- **Input/Output patches**: Use `InputPatch<T, N>` and return individual control points

### Domain Shader (Tessellation Evaluation)

#### Core Declaration Mapping

**GLSL:**
```glsl
// Domain and tessellation mode
layout(triangles, equal_spacing, ccw) in;

void main() {
    // Use gl_TessCoord to interpolate 
    gl_Position = /* position calculation using gl_TessCoord */;
}
```

**Slang:**
```hlsl
struct ControlPoint { /* user-defined struct */ }

// user-defined struct; must include members with SV_TessFactor and SV_InsideTessFactor semantics
struct PatchTessFactors { }

[shader("domain")]
[domain("tri")]
float4 main(
    PatchTessFactors patchConstants,
    float3 tessCoord : SV_DomainLocation,
    const OutputPatch<ControlPoint, 3> patch
) : SV_Position {
    // Use tessCoord to interpolate
    return /* position calculation using tessCoord */;
}
```

#### Key Attribute Mappings

| GLSL | Slang | Description |
|------|-------|-------------|
| `layout(triangles) in` | `[domain("tri")]` | Patch domain type |
| `layout(equal_spacing) in` | *Set in hull shader* | Tessellation spacing |
| `layout(ccw) in` | *Set in hull shader* | Winding order |

#### Key Conversion Points

- **Domain specification**: Use `[domain("tri/quad/isoline")]` attribute
- **Tessellation coordinates**: Access via `SV_DomainLocation` parameter
- **Control points**: Access via `OutputPatch<T, N>` parameter
- **Patch constants**: Access via a patch constant struct parameter

### Geometry Shader

#### Core Declaration Mapping

**GLSL:**
```glsl
// Set primitive types and max vertices
layout(triangles) in;
layout(triangle_strip, max_vertices = 3) out;

void main() {
    // Process and emit vertices
    EmitVertex();
    EndPrimitive();
}
```

**Slang:**
```hlsl
struct VSOutput { /* user-defined struct */ }

struct GSOutput { /* user-defined struct */ }

[shader("geometry")]
[maxvertexcount(3)]
void main(
    triangle VSOutput input[3], 
    inout TriangleStream<GSOutput> outputStream
) {
    // Process and append vertices
    outputStream.Append(vertex);
    outputStream.RestartStrip();
}
```

#### Key Attribute Mappings

| GLSL | Slang | Description |
|------|-------|-------------|
| `layout(points/lines/triangles) in` | Input parameter prefix (`triangle`) | Input primitive type |
| `layout(points/line_strip/triangle_strip) out` | Output stream type | Output primitive type |
| `layout(max_vertices = N) out` | `[maxvertexcount(N)]` | Maximum output vertices |

#### Key Conversion Points

- **Declaration**: Add `[shader("geometry")]` and `[maxvertexcount(N)]`
- **Input primitives**: Use primitive type prefix on input array parameter
- **Output primitives**: Use appropriate stream type (`PointStream`, `LineStream`, `TriangleStream`)
- **Vertex emission**: Replace `EmitVertex()` with `outputStream.Append(v)`
- **End primitive**: Replace `EndPrimitive()` with `outputStream.RestartStrip()`

### Amplification Shader (Task Shader)

#### Core Declaration Mapping

**GLSL:**
```glsl
#extension GL_EXT_mesh_shader : require

layout(local_size_x = 32) in;

taskPayloadSharedEXT TaskData payload;

void main() {
    // Set mesh shader dispatch count
    EmitMeshTasksEXT(taskCount, 1, 1, payload);
}
```

**Slang:**
```hlsl
struct TaskData { /* user-defined struct */ }

[shader("amplification")]
[numthreads(32, 1, 1)]
void main(
    uint gtid : SV_GroupThreadID,
    out payload TaskData payload
) {
    // Set mesh shader dispatch count
    DispatchMesh(taskCount, 1, 1, payload);
}
```

#### Key Conversion Points

- **Declaration**: Add `[shader("amplification")]` and `[numthreads(X,Y,Z)]` decorations
- **Payload**: Replace `taskPayloadSharedEXT` with output parameter
- **Dispatch**: Replace `EmitMeshTasksEXT` with `DispatchMesh`
- **Thread IDs**: Access thread IDs through function parameters with semantics

### Mesh Shader

#### Core Declaration Mapping

**GLSL:**
```glsl
#extension GL_EXT_mesh_shader : require

layout(local_size_x = 32) in;
layout(triangles, max_vertices = 64, max_primitives = 126) out;

void main() {
    // Set counts
    SetMeshOutputsEXT(vertexCount, primitiveCount);
    
    // Write vertices and primitives
    gl_MeshVerticesEXT[idx].gl_Position = /* vertex position */;
    gl_PrimitiveTriangleIndicesEXT[idx] = uvec3(a, b, c);
}
```

**Slang:**
```hlsl
struct MeshVertex { /* user-defined struct */ }

[shader("mesh")]
[numthreads(32, 1, 1)]
[outputtopology("triangle")]
void main(
    uint gtid : SV_GroupThreadID,
    out vertices MeshVertex verts[64],
    out indices uint3 prims[126]
) {
    // Set counts
    SetMeshOutputCounts(vertexCount, primitiveCount);
    
    // Write vertices and primitives
    verts[idx].position = /* vertex position */;
    prims[idx] = uint3(a, b, c);
}
```

#### Key Attribute Mappings

| GLSL | Slang | Description |
|------|-------|-------------|
| `layout(local_size_x = X) in` | `[numthreads(X, Y, Z)]` | Thread group size |
| `layout(triangles) out` | `[outputtopology("triangle")]` | Output primitive type |
| `layout(max_vertices = N, max_primitives = M) out` | Output parameters | Maximum vertices/primitives |

#### Key Conversion Points

- **Declaration**: Add `[shader("mesh")]` and `[numthreads(X,Y,Z)]` decorations
- **Output topology**: Use `[outputtopology("triangle")]` attribute
- **Vertex/primitive count**: Replace `SetMeshOutputsEXT` with `SetMeshOutputCounts`
- **Vertex access**: Replace `gl_MeshVerticesEXT[idx]` with `verts[idx]`
- **Primitive access**: Replace `gl_PrimitiveTriangleIndicesEXT[idx]` with `prims[idx]`

### Ray Tracing Shaders

#### Ray Generation Shader

**GLSL:**
```glsl
#extension GL_EXT_ray_tracing : require

layout(location = 0) rayPayloadEXT PayloadData payload;

void main() {
    // Launch rays
    traceRayEXT(tlas, flags, mask, sbtOffset, stride, miss, origin, tMin, direction, tMax, 0);
}
```

**Slang:**
```hlsl
struct PayloadData { /* user-defined struct */ }

[shader("raygeneration")]
void main() {
    RayDesc ray;
    ray.Origin = origin;
    ray.Direction = direction;
    ray.TMin = tMin;
    ray.TMax = tMax;
    
    PayloadData payload;
    TraceRay(tlas, flags, mask, sbtOffset, stride, miss, ray, payload);
}
```

#### Closest Hit Shader

**GLSL:**
```glsl
#extension GL_EXT_ray_tracing : require

layout(location = 0) rayPayloadInEXT PayloadData payload;

void main() {
    // Process hit
    payload.hit = true;
}
```

**Slang:**
```hlsl
struct PayloadData { /* user-defined struct */ }

[shader("closesthit")]
void main(inout PayloadData payload, in BuiltInTriangleIntersectionAttributes attr) {
    // Process hit
    payload.hit = true;
}
```

#### Miss Shader

**GLSL:**
```glsl
#extension GL_EXT_ray_tracing : require

layout(location = 0) rayPayloadInEXT PayloadData payload;

void main() {
    // Process miss
    payload.hit = false;
}
```

**Slang:**
```hlsl
struct PayloadData { /* user-defined struct */ }

[shader("miss")]
void main(inout PayloadData payload) {
    // Process miss
    payload.hit = false;
}
```

#### Key Conversion Points

- **Declaration**: Use appropriate decorator for each shader type
- **Ray payload**: Pass as `inout` parameter instead of global variable
- **Ray tracing**: Use `TraceRay` with a `RayDesc` struct
- **Built-ins**: Access through function calls instead of global variables
- **Hit attributes**: Receive via function parameters

---

## File: docs/coming-from-hlsl.md

---
title: Migrating to Slang from HLSL
layout: page
permalink: "/docs/coming-from-hlsl/"
intro_image_absolute: true
intro_image_hide_on_mobile: false
---

### Overview
This guide provides a comprehensive overview of the primary syntax and feature differences between HLSL and Slang. It offers essential adjustments needed for a smooth transition and tips to enhance debugging and performance.

While the languages share similarities, paying close attention to specific syntax and function conventions will ensure a seamless migration of HLSL shaders to Slang.


### Key Syntax and Feature Differences

#### `enum` is scoped in Slang
In HLSL, `enum` is unscoped, which means the enum values can be referred to without the enum's name.
In Slang, `enum` is scoped, requiring explicit reference to the enum's name along with its values.



| HLSL shader | Slang shader |
| --- | --- |
| {% capture somemarkdown %}
```hlsl
enum MyEnum
{
    MyEnum_A,
    MyEnum_B,
    MyEnum_C
};

int MyFunc()
{
    return int(MyEnum_A);
}
```
{% endcapture %}
{{ somemarkdown   markdownify }} | {% capture somemarkdown %}

```hlsl
enum MyEnum
{
    A,
    B,
    C
};

int MyFunc()
{
    return int(MyEnum::A);
}
```
{% endcapture %}
{{ somemarkdown   markdownify }} |



To make `enum` unscoped in Slang, use the `-unscoped-enums` option or add the `[UnscopedEnum]` attribute to explicitly declare an enum as unscoped.
```hlsl
// Slang shader
[UnscopedEnum]
enum MyEnum
{
    MyEnum_A,
    MyEnum_B,
    MyEnum_C
};

int MyFunc()
{
    return int(MyEnum_A);
}
```


#### Member functions are immutable by default
By default, Slang member functions do not allow mutations to `this`. It is as if the member function has the `const` keyword in C/C++.

To mutate `this`, you must explicitly use the `[mutating]` attribute on each function.

This is a significant departure from HLSL, but the compiler will flag any missing keywords with an error.


| HLSL shader | Slang shader |
| --- | --- |
| {% capture somemarkdown %}
```hlsl
struct Counter
{
    int count;
    void increment() { count++; }
};
```
{% endcapture %}
{{ somemarkdown   markdownify }} | {% capture somemarkdown %}
```hlsl
struct Counter
{
    int count;

    [mutating]
    void increment() { count++; }
};
```
{% endcapture %}
{{ somemarkdown   markdownify }} |




#### Forward declaration is not needed and not supported
In Slang, function declarations do not need to precede their usage.

Furthermore, Slang does not support separating the declaration from its definition for member functions. Member functions must be fully defined at the point of declaration.


#### Generics Instead of Templates
Slang does not support a "template" feature like HLSL does.
If your HLSL shaders use templates, they will need to be converted to use generics.
Depending on the complexity, this conversion process is generally straightforward.

When the template argument is a constant integer value, use the `let XX : uint` or `uint XX` syntax as shown below,


| HLSL shader | Slang shader |
| --- | --- |
| {% capture somemarkdown %}
```hlsl
template
uint GetValue(const uint index)
{
    return index % strideX, index / strideY;
}
```
{% endcapture %}
{{ somemarkdown   markdownify }} | {% capture somemarkdown %}

```hlsl
__generic
uint GetValue(const uint index)
{
    return index % strideX, index / strideY;
}
```
{% endcapture %}
{{ somemarkdown   markdownify }} |



When the template argument is a typename, you must use a built-in interface or a custom interface you define.


| HLSL shader | Slang shader |
| --- | --- |
| {% capture somemarkdown %}

```hlsl
template
T max4(T x, T y, T z, T w)
{
    return max(max(x, y), max(z, w));
}
```
{% endcapture %}
{{ somemarkdown   markdownify }} | {% capture somemarkdown %}
```hlsl
__generic // `typename` can be omitted
T max4(T x, T y, T z, T w)
    where T : __BuiltinFloatingPointType
{
    return max(max(x, y), max(z, w));
}
```
{% endcapture %}
{{ somemarkdown   markdownify }} |



For more detailed explanations on defining a custom interface, please refer to the [Slang User's Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/06-interfaces-generics.html).


#### `#pragma` for DXC wouldn't work for Slang

If your HLSL shaders use `#pragma` for the DXC compiler, these will not be compatible with Slang.
You will need to remove these lines or encapsulate them as follows,
```hlsl
#if !COMPILER_SLANG
// Generate vector truncation warnings to errors.
#pragma warning(error: 3206)
#endif // #if !COMPILER_SLANG
```


#### Operator Overloading
Slang supports operator overloading, but it cannot be defined as a member method.



| HLSL shader | Slang shader |
| --- | --- |
| {% capture somemarkdown %}

```hlsl
struct MyStruct
{
    MyStruct operator+(MyStruct rhs)
    {
        MyStruct tmp;
        tmp.value = value + rhs.value;
        return tmp;
    }

    float value;
};
```
{% endcapture %}
{{ somemarkdown   markdownify }} | {% capture somemarkdown %}

```hlsl
struct MyStruct
{
    MyStruct operator_ADD(MyStruct rhs)
    {
        MyStruct tmp;
        tmp.value = value + rhs.value;
        return tmp;
    }

    float value;
};

MyStruct operator+(MyStruct lhs, MyStruct rhs)
{
    return lhs.operator_ADD(rhs);
}
```
{% endcapture %}
{{ somemarkdown   markdownify }} |



For more details, please consult the [Slang User's Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/03-convenience-features.html#operator-overloading)

#### Subscript Operator
Slang uses a different syntax for overloading subscript operator so both reads and writes to a subscript location can be defined.


| HLSL shader | Slang shader |
| --- | --- |
| {% capture somemarkdown %}

```hlsl
struct MyType
{
    float values[12];

    float operator[](int index)
    {
        return values[index];
    }
}
```
{% endcapture %}
{{ somemarkdown   markdownify }} | {% capture somemarkdown %}

```hlsl
struct MyType
{
    float values[12];

    __subscript(int index) -> float
    {
        get { return val[index]; }
        set { val[index] = newValue; }
    }
}
```
{% endcapture %}
{{ somemarkdown   markdownify }} |



For more details, please consult the [Slang User's Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/03-convenience-features.html#subscript-operator).


#### Implicit parameter binding
Slang binds resources based on the shader before Dead-Code-Elimination. This means that even if a uniform parameter is not utilized by the shader, Slang will still assign a resource binding index to it.

This differs from HLSL's behavior, where the DXC compiler removes unused parameters from the compiled shaders. The DXC reflection API then provides information on which parameters are actually being used.

This approach ensures consistent behavior across different variations of the same shader, as Slang does not remove unused parameters during its linking process, maintaining a consistent set of parameters regardless of how the shader was used or linked.


#### `unsigned int` is not supported
Slang does not support type names that use more than one token. As a result, `unsigned int` or `signed int` are not supported. These should be renamed to `uint` or `int` respectively.


#### Buffer Layouts
Slang defaults to std140 for constant buffers and std430 for structured buffers and related.
 - Use `-fvk-use-scalar-layout` to set buffer layout to scalar block layout.
 - Use `-fvk-use-gl-layout` to set std430 layout for raw buffer load/stores

StructuredBuffer and related objects can also take a per resource layout
```hlsl

StructuredBuffer<MyStruct, Std140DataLayout>
StructuredBuffer<MyStruct, Std430DataLayout>
StructuredBuffer<MyStruct, ScalarDataLayout>

```


#### `#pragma pack_matrix()` is not supported
HLSL provides a way to change the matrix packing order with a pragma.

While Slang doesn't support the same pragma syntax, you can achieve the same functionality with `-matrix-layout-column-major` or `-matrix-layout-row-major`.


#### Slang requires more strict type casting
Slang demands more strict type casting, but you can add your own casting functions if needed.
Due to this difference, some casting issues may appear as errors while migrating your HLSL shaders to Slang.


#### SPIR-V target specific functionalities
When you target SPIR-V, there are a few things that the user may want to know. Please check the [Slang User's Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/a2-01-spirv-target-specific.html) for more details.


### Debugging and Performance Tips

When debugging Slang shaders, disabling optimizations can simplify the debugging process. Use -O0 during development, and consider experimenting with [ForceInline] to reduce compile times for performance-critical shaders.


#### `#line` directives
Slang offers a command-line option to emit or suppress `#line` directives when targeting C-like text formats such as HLSL, GLSL, Metal, and WGSL.
When `#line` directives are emitted, they can assist in debugging with shader debugging tools, as these tools can correlate back to the original Slang shader.

For more information, please refer to `LineDirectiveMode` in the [Slang User's Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/08-compiling.html).


#### Experiment with [ForceInline]
`[ForceInline]` is akin to the `inline` keyword in C++, where the body of a function is inlined at the call locations. This typically does not make any observable differences, but we have noticed that using `[ForceInline]` can reduce compile times compared to HLSL compilation with DXC.

This is because the shader optimization step inside DXC involves additional processes to optimize out the `out` or `inout` modifiers. When the function is inlined, these modifiers become redundant, thus reducing compile times.

This characteristic may change in the future, but it is worth experimenting with `[ForceInline]`.

---

## File: docs/compilation-api.md

---
title: Using the Slang Compilation API
layout: page
permalink: "/docs/compilation-api/"
intro_image_absolute: true
intro_image_hide_on_mobile: false
---

## Using the Slang Compilation API

This tutorial explains the flow of calls needed to use the Slang Compilation API. The overall sequence is described in [Basic Compilation](#basic-compilation) followed by a discussion on more advanced topics.

Using the compilation API offers much more control over compilation compared to `slangc`, and with better performance as well. For applications with complex needs, or ones that are sensitive to compilation performance, it is recommneded to use the Compilation API.

The Slang compilation API is provided as a dynamic library. Linking to it, you have access to the compilation API which is organized in a Component Object Model (COM) fashion.  The Slang [User Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/08-compiling.html#using-the-compilation-api) describes Slang's "COM-lite" interface a bit more.

## Table of Contents

* [Basic Compilation](#basic-compilation)
* [Precompiled Modules](#precompiled-modules)
* [Specialization](#specialization)
* [Dynamic Dispatch](#dynamic-dispatch)
* [Diagnostics](#diagnostics)
* [Features Accessible Through Additional Interfaces](#features-accessible-through-additional-interfaces)
* [Post-Compilation Reflection](#post-compilation-reflection)
* [Complete Example](#complete-example)

### Basic Compilation

This is the overall flow needed to compile even the simplest applications.

1. [Create Global Session](#create-global-session)
2. [Create Session](#create-session)
3. [Load Modules](#load-modules)
4. [Query Entry Point(s)](#query-entry-points)
5. [Compose Modules + Entry Points](#compose-modules-and-entry-points)
6. [Link Program](#link)
7. [Get Target Kernel Code](#get-target-kernel-code)

### 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"
#include "slang-com-ptr.h"
#include "slang-com-helper.h"
```

#### 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
    Slang::ComPtr<slang::IGlobalSession> globalSession;
    createGlobalSession(globalSession.writeRef());
```

#### 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.

The `SessionDesc` object holds all the configuration for the Session.

* A list of enabled compilation targets (with their options)
* A list of search paths (for `#include` and `import`)
* A list of pre-defined macros

```cpp
    slang::SessionDesc sessionDesc = {};
```

##### 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
    slang::TargetDesc targetDesc = {};
    targetDesc.format = SLANG_SPIRV;
    targetDesc.profile = globalSession->findProfile("spirv_1_5");

    sessionDesc.targets = &targetDesc;
    sessionDesc.targetCount = 1;
```

##### Preprocessor defines

Slang supports using the preprocessor.
```cpp
    std::array<slang::PreprocessorMacroDesc, 2> preprocessorMacroDesc =
        {
            { "BIAS_VALUE", "1138" },
            { "OTHER_MACRO", "float" }
        };
    sessionDesc.preprocessorMacros = preprocessorMacroDesc.data();
    sessionDesc.preprocessorMacroCount = preprocessorMacroDesc.size();
```

##### 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.

```cpp
    std::array<slang::CompilerOptionEntry, 1> options = 
        {
            {
                slang::CompilerOptionName::EmitSpirvDirectly,
                {slang::CompilerOptionValueKind::Int, 1, 0, nullptr, nullptr}
            }
        };
    sessionDesc.compilerOptionEntries = options.data();
    sessionDesc.compilerOptionEntryCount = options.size();
```

##### Create the session

With a fully populated `SessionDesc`, the session can be created.

```cpp
    Slang::ComPtr<slang::ISession> session;
    globalSession->createSession(sessionDesc, session.writeRef());
```

#### 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.

`ISession::loadModule()` takes a module name and functions like an "import" statement in shader code. If already loaded, the cached result in the session is returned. Otherwise, it scours the search paths defined in the session for a file named `<module_name>.slang`.

`ISession::loadModuleFromSourceString()` essentially loads shader source code directly from memory in the `source` parameter, though it also takes parameters for `moduleName` and `path` which require explanation. `moduleName` gives the blob of source its identifier. It serves the same purpose as the `moduleName` provided to the loadModule() overload, except that Slang won't need go and look for a file on disk with that name. Other modules will still be able to refer to the newly loaded module by this name. `path` is used as a backup key for caching the module in the session, which is only likely to be used if a shader uses path-based import statements, e.g. `import "../mymodule.slang";`. Specifying `nullptr` as `path` effectively causes Slang to cache based only on `moduleName`.

```cpp
    Slang::ComPtr<slang::IModule> slangModule;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        const char* moduleName = "shortest";
        const char* modulePath = "shortest.slang";
        slangModule = session->loadModuleFromSourceString(moduleName, modulePath, shortestShader, diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        if (!slangModule)
        {
            return -1;
        }
    }
```

##### 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

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.

A common way to query an entry-point is by using the `IModule::findEntryPointByName` method, which will search the Module's reflection data and return the one which, for example, has the name "computeMain" as seen below. In order for `findEntryPointByName` to suceed, the entry-point function must be decorated with the shader attribute in source, e.g. `[shader("compute")]`. If the entry-point is not explicitly marked, it's necessary to use the `IModule::findAndCheckEntryPoint` function instead.

`IModule::findAndCheckEntryPoint` is an alternative way to query entry-points from a module, and it works even if the function was not marked with the `[shader]` attribute. Because functions that lack the `[shader]` attribute, are not validated as entry-points during `loadModule`, that skipped validation is performed during `IModule::findAndCheckEntryPoint` instead.

```cpp
    Slang::ComPtr<slang::IEntryPoint> entryPoint;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        slangModule->findEntryPointByName("computeMain", entryPoint.writeRef());
        if (!entryPoint)
        {
            std::cout << "Error getting entry point" << std::endl;
            return -1;
        }
    }
```

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

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.

```cpp
    std::array<slang::IComponentType*, 2> componentTypes =
        {
            slangModule,
            entryPoint
        };

    Slang::ComPtr<slang::IComponentType> composedProgram;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        SlangResult result = session->createCompositeComponentType(
            componentTypes.data(),
            componentTypes.size(),
            composedProgram.writeRef(),
            diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        SLANG_RETURN_ON_FAIL(result);
    }
```

#### Link

Ensure that there are no missing dependencies in the composed program by using `link()`.

```cpp
    Slang::ComPtr<slang::IComponentType> linkedProgram;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        SlangResult result = composedProgram->link(
            linkedProgram.writeRef(),
            diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        SLANG_RETURN_ON_FAIL(result);
    }
```

#### Get Target Kernel Code

Finally, it's time to compile the linked Slang program to the target format.

Calling `IComponentType::getEntryPointCode()` will perform the final compilation to the target language and return an `IBlob` pointer to it. As the name implies, it compiles target code for a single entry-point, identified by the first integer argument, into the target format identified by the second integer argument. The component type must not contain any specialization parameters (it must be fully specialized), and it must not have any unmet requirements (it must be fully linked).

```cpp
    // ... loadModule()

    // ... findEntryPointByName() or findAndCheckEntryPoint()

    // ... createCompositeComponentType()

    // ... link()

    Slang::ComPtr<slang::IBlob> spirvCode;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        SlangResult result = linkedProgram->getEntryPointCode(
            0, // entryPointIndex
            0, // targetIndex
            spirvCode.writeRef(),
            diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        SLANG_RETURN_ON_FAIL(result);
    }
```

Alternatively, there is also a function `IComponentType::getTargetCode()` which will compile all entry-points, which is useful for SPIR-V and Metal targets which support multiple entry-points per shader.

You can skip the `createCompositeComponentType()` where entry-points are identified altogether, and instead directly call `link()` on the Module to pull in its dependencies without having chosen any entry-points. `getTargetCode()` will then return a unified GPU kernel with multiple entry-points.

```cpp
    // ... loadModule()

    // ... link()

    Slang::ComPtr<slang::IBlob> spirvCode;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        SlangResult result = linkedProgram->getTargetCode(
            0, // targetIndex
            spirvCode.writeRef(),
            diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        SLANG_RETURN_ON_FAIL(result);
    }
```

`spirvCode->getBufferPointer()` is then used to access the compiled data, and `spirvCode->getBufferSize()` is its size.

Both methods cache results within the session and will return a pre-compiled blob when given the same request.

About Sessions
--------------

#### 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.

For example, if you import a module `foo` in several other modules, `foo` is only compiled once during the session.

The same is true for target binaries. If you request the same target binary multiple times during a session, Slang will compile only the first time and return a cached result every other time.

It's strongly recommended to use as few session objects as possible in applications (more on that, shortly), as it is much more efficient than always using fresh sessions with empty caches.

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?

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.

The Slang language philosophy with respect to supporting multiple target variations is to specialize using generics and interfaces as opposed to `#define`s. Shader systems designed with preprocessor as the primary means to specialize may find the need to create many sessions. For this, and other reasons, the recommendation is to limit preprocessor usage and use as few session objects as possible to get the best reuse and performance.

Precompiled Modules
-------------------

Modules are loaded into the session as described in [Load Modules](#load-modules). There is processing involved in that, as the raw source code needs to be compiled to the Slang internal representation, IR for short. Once loaded, that module does not need to be recompiled for the duration of the [Session](#about-sessions).

Slang offers the capability to save modules to disk after this initial processing, allowing for faster initial module load times.

API methods for module precompilation are described in the [User Guide](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/10-link-time-specialization.html#using-precompiling-modules-with-the-api).

Specialization
--------------

#### 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

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

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.

Then adding to the entrypoint a generic parameter of `IQuality` type would let you choose between high and low quality modes during link-time.

Given the shader:

```hlsl
RWStructuredBuffer<float> result;

interface IQuality
{
    static float getValue();
};
struct HighQuality : IQuality
{
    static float getValue() { return 100.0; }
}
struct LowQuality : IQuality
{
    static float getValue() { return 1.0; }
}

[shader("compute")]
[numthreads(1,1,1)]
void computeMain<T : IQuality>(uint3 threadId : SV_DispatchThreadID)
{
    result[0] = T::getValue();
}
```

The API needed to select between HighQuality and LowQuality is `specialize()`.
Specialization parameters are specified with the `SpecializationArg` class.

The type that you intend to use for concretization of the entry-point can be found with reflection:

```cpp
    slangModule->getLayout()->findTypeByName("HighQuality")
```

Create the SpecializationArg array to use with specialize():
```cpp
    std::array<slang::SpecializationArg, 1> specializationArgs =
    {
        {
            slang::SpecializationArg::Kind::Type,
            slangModule->getLayout()->findTypeByName("HighQuality")
        }
    };
```

Provide that array to `specialize` on the `ComponentType` that requires specialization.
In this case, the component to specialize is the `entryPoint`.

```cpp
    Slang::ComPtr<slang::IEntryPoint> entryPoint;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        slangModule->findEntryPointByName("computeMain", entryPoint.writeRef());
        if (!entryPoint)
        {
            std::cout << "Error getting entry point" << std::endl;
            return -1;
        }
    }
    Slang::ComPtr<slang::IComponentType> specializedEntryPoint;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        SlangResult result = entryPoint->specialize(
            specializationArgs.data(),
            specializationArgs.size(),
            specializedEntryPoint.writeRef(),
            diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        SLANG_RETURN_ON_FAIL(result);
    }
```

Now instead of composing the unspecialized `entryPoint` into your `CompositeComponentType`, you would add the specialized `specializedEntryPoint` into the compositition.

If you dump output for the compiled shader, you'll see that only "HighQuality" exists in the shader, and `computeMain` now refers directly to `HighQuality_getValue_0` as its call to interact with the quality object. Here's a resulting HLSL target compile:

```hlsl
RWStructuredBuffer<float > result_0 : register(u0);

float HighQuality_getValue_0()
{
    return 100.0;
}

[numthreads(1, 1, 1)]
void computeMain(uint3 threadId_0 : SV_DispatchThreadID)
{
    result_0[int(0)] = HighQuality_getValue_0();
    return;
}
```

Dynamic Dispatch
----------------

In the preceding example [Generics Specialization](#generics-specialization), logic for handling a feature was placed behind an interface `IQuality` which could be implemented as either the structs `HighQuality` or `LowQuality`.

The previous use-case was to produce specialized shaders, but imagine that you prefer to have one "uber-shader" that can handle both qualities. Generics can handle that too, and we'll see later that both techniques (dynamic dispatch, specialization) can be supported with the same Slang shader source code.

Instead of parameterizing the entry-point such that the definition of `T` can be specialized at link time, let's instead provide the type of `T` as an integer uniform and dynamically create an object of the specified type through that enum.

Slang provides the utility function `createDynamicObject()` to do just that. Based on an integer and a blob of initialization data, an object of the desired `IQuality` type will be initialized at runtime.

Here's a shader that uses dynamic dispatch for `getValue()` query.

```hlsl
RWStructuredBuffer<float> result;

interface IQuality
{
    static float getValue();
};
struct HighQuality : IQuality
{
    static float getValue() { return 100.0; }
}
struct LowQuality : IQuality
{
    static float getValue() { return 1.0; }
}

uniform int quality;

[shader("compute")]
[numthreads(1,1,1)]
void computeMain(uint3 threadId : SV_DispatchThreadID)
{
    IQuality q = createDynamicObject(quality, 0);
    result[0] = q.getValue();
})
```

Notice that `computeMain` is not a generic function, but the type of `q` it creates dynamically depends on the value of `quality`.

To compile the shader with support for both `IQuality` implementations, Slang requires info from the developer to know which `IQuality` implementations need to be retained in the dynamic dispatch table for `getValue`.

The mechanism for this is "ITypeConformance". Type Conformances are linkable objects, similar to `IEntryPoint` in that they don't represent shader source, so much as targetting a subset of the shader source that should be included in the final composition. By specifying `ITypeConformance` objects in the createCompositeComponentType() call, you restrict the set of `IQuality` implementations that are supported dynamically in the shader. As part of creating Type Conformances, you also get an opportunity to specify preferred enumeration values for the type conformances, used in the dynamic dispatch. Otherwise, specifying `-1` will permit Slang to choose default values.

```cpp
    enum Quality {
        QUALITY_LOW,
        QUALITY_HIGH,
    };

    Slang::ComPtr<slang::ITypeConformance> highQuality;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        SlangResult result = session->createTypeConformanceComponentType(
            slangModule->getLayout()->findTypeByName("HighQuality"),
            slangModule->getLayout()->findTypeByName("IQuality"),
            highQuality.writeRef(),
            QUALITY_HIGH,
            diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        SLANG_RETURN_ON_FAIL(result);
    }

    Slang::ComPtr<slang::ITypeConformance> lowQuality;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        SlangResult result = session->createTypeConformanceComponentType(
            slangModule->getLayout()->findTypeByName("LowQuality"),
            slangModule->getLayout()->findTypeByName("IQuality"),
            lowQuality.writeRef(),
            QUALITY_LOW,
            diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        SLANG_RETURN_ON_FAIL(result);
    }

    std::array<slang::IComponentType*, 4> componentTypes =
        {
            slangModule,
            entryPoint,
            highQuality,
            lowQuality,
        };

    Slang::ComPtr<slang::IComponentType> composedProgram;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        SlangResult result = session->createCompositeComponentType(
            componentTypes.data(),
            componentTypes.size(),
            composedProgram.writeRef(),
            diagnosticsBlob.writeRef());
        diagnoseIfNeeded(diagnosticsBlob);
        SLANG_RETURN_ON_FAIL(result);
    }
```

This sample opts to specify the enum values for `highQuality` and `lowQuality` because the host application will need to select the dynamic type at runtime via uniform and will need to know which integral value does what.

Now when composing the program, the source code module, the entry-point, and BOTH `IQuality` implementations will be included. 

Here's the HLSL output from compiling the shader with dynamic dispatch:

```hlsl
...

RWStructuredBuffer<float > result_0 : register(u0);

struct GlobalParams_0
{
    int quality_0;
};

cbuffer globalParams_0 : register(b0)
{
    GlobalParams_0 globalParams_0;
}

float HighQuality_getValue_0()
{
    return 100.0;
}

float U_S11specialized11HighQuality8getValuep0pf_wtwrapper_0()
{
    return HighQuality_getValue_0();
}

float LowQuality_getValue_0()
{
    return 1.0;
}

float U_S11specialized10LowQuality8getValuep0pf_wtwrapper_0()
{
    return LowQuality_getValue_0();
}

float U_S11specialized8IQuality8getValuep0pf_0(uint2 _S1)
{
    switch(_S1.x)
    {
    case 1U:
        {
            return U_S11specialized11HighQuality8getValuep0pf_wtwrapper_0();
        }
    default:
        {
            return U_S11specialized10LowQuality8getValuep0pf_wtwrapper_0();
        }
    }
}

[numthreads(1, 1, 1)]
void computeMain(uint3 threadId_0 : SV_DispatchThreadID)
{
    result_0[int(0)] = U_S11specialized8IQuality8getValuep0pf_0(uint2(uint(globalParams_0.quality_0), 0U));
    return;
}
```

Notice in particular the switch case added in the function `float U_S11specialized8IQuality8getValuep0pf_0(uint2 _S1)`.

#### 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.

What if only one type conformance is included?

Slang is smart enough to identify this, and will reduce the dynamic dispatch function's switch statement to a single unconditional call to the selected function! In this way, the same shader source can support both dynamic dispatch OR specialization depending on the way it's compiled.

Let's remove `highQuality` from the composed program, leaving only `lowQuality`.
```cpp
    std::array<slang::IComponentType*, 3> componentTypes =
        {
            slangModule,
            entryPoint,
            lowQuality,
        };
```

With that single tweak, see the change in generated shader:

```hlsl
float U_S11specialized10LowQuality8getValuep0pf_wtwrapper_0()
{
    return LowQuality_getValue_0();
}

float U_S11specialized8IQuality8getValuep0pf_0(uint2 _S1)
{
    return U_S11specialized10LowQuality8getValuep0pf_wtwrapper_0();
}

[numthreads(1, 1, 1)]
void computeMain(uint3 threadId_0 : SV_DispatchThreadID)
{
    result_0[int(0)] = U_S11specialized8IQuality8getValuep0pf_0(uint2(uint(globalParams_0.quality_0), 0U));
    return;
}
```

The switch statement is gone, and now the shader is specialized to supporting only one `IQuality`!


Diagnostics
-----------

Many API methods take an optional `diagnostics` parameter. This is the vehicle for Slang to report specific details about the operation. Not just errors, but warnings or other information too.

After calling, the pointed-to argument will be `nullptr` if there are no diagnostics reported, so it's handy to always print out the API diagnostic info after each operation based on whether `nullptr` was returned or not, not only if the operation failed.

For example, in the following, if `diagnosticsBlob` is anything other than `nullptr` there may be useful information to see there.

```cpp
    Slang::ComPtr<slang::IModule> slangModule;
    {
        Slang::ComPtr<slang::IBlob> diagnosticsBlob;
        slangModule = session->loadModuleFromSourceString("shortest", "shortest.slang", shortestShader, diagnosticsBlob.writeRef());
        if (diagnosticsBlob != nullptr)
        {
            std::cout << (const char*)diagnosticsBlob->getBufferPointer() << std::endl;
        }
        if (!slangModule)
        {
            return -1;
        }
    }
```

Features Accessible Through Additional Interfaces
-------------------------------------------------

Some Slang API features are inaccessible using only the basic `IModule` and `IComponentType` COM pointers that we've used so far.  Getting access to additional features can require querying objects for additional interfaces. Experienced COM users will be familiar with the process.

Let's say there is an `ISample` interface declared in `slang.h` with a method of interest, `InterestingModuleMethod()`. Though `InterestingModuleMethod()` operates on a Module internal to Slang, in order to call it, you need to ask Slang for an `ISample` pointer for the `IModule` that you have. Doing so requires passing in the COM UUID (Universally Unique Identifier) for the interface to the `queryInterface()` method, which is `SLANG_UUID_ISample` for the made up `ISample` interface. It's also fine to call the static `ISample::getTypeGuid()` function to get the value for the UUID parameter.

```cpp
   // Assume `mymodule` is a ComPtr acquired from an earlier step.
   ComPtr mysampleinterface;
   if (mymodule->queryInterface(SLANG_UUID_ISample, ISample.writeref()))
   {
       ISample->InterestingMethod();
   }
   else
   {
       // Helpful diagnostic messages, or turn on fallback behavior perhaps.
   }
```

Note that the application is expected to handle the scenario where the interface cannot be queried successfully. One likely reason could be that the application is running in an environment with an older Slang library. The application may ask Slang for an interface that isn't yet implemented in that version of the library. Whether that is a fatal error or if it just means that a feature is disabled, is up to the application.

Post-Compilation Reflection
---------------------------

Target compilation typically involves the elimination of unused parameters and automatic assignment of bindings. Slang offers a post-compilation reflection interface that answers the question of which parameters remain after optimization, `IMetaData`.

An `IMetaData` interface can be queried from a compiled program. After `getEntryPointCode()` has been called, `getEntryPointMetadata()` with the same `entryPointIndex` and `targetIndex` as was used during compilation will provide the reflection information for that entry-point. Similarly, after `getTargetCode()` has been called for a certain `targetIndex`, calling `getTargetMetadata()` on the same `targetIndex` will return its `IMetaData` reflection interface.

`IMetaData` offers the `isParameterLocationUsed()` method which returns whether a resource parameter at the specified binding location is actually being used in the compiled shader.

```cpp
    bool isUsed = false;
    SlangParameterCategory category = SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT;
    unsigned spaceIndex = 0;
    unsigned registerIndex = 0;
    metadata->isParameterLocationUsed(
        category,
        spaceIndex,
        registerIndex,
        isUsed);
```

See [Using the Reflection API](https://docs.shader-slang.org/en/latest/external/slang/docs/user-guide/09-reflection.html) for more details.

Complete Example
----------------

Save the following to disk at a file named "shortest.cpp":

```
/* Detailed source-code truncated for AI context efficiency. */
```

#### 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.

If any of the above assumptions are wrong in your case, adjust the paths below to match:

```bat
g++ -I./slang/include --std=c++14 shortest.cpp -L./slang/build/Release/lib/ -l:libslang.so
```

#### Run it

```bat
LD_LIBRARY_PATH=slang/build/Release/lib ./a.out
```

---

## File: docs/faq.md

---
title: Frequently Asked Questions
layout: page
permalink: "/docs/faq/"
intro_image_absolute: true
intro_image_hide_on_mobile: false
---

#### Where should I ask questions on Slang?

If you run into any questions with the Slang language, the compilation API or the reflection API, please post it on our [GitHub discussion page](https://github.com/shader-slang/slang/discussions).

#### How do I report a compiler bug?

Please post your issues on our [GitHub issues page](https://github.com/shader-slang/slang/issues).


#### Does Slang use LLVM?

No. The Slang compiler itself is not built on the LLVM tech stack, and does not depend on LLVM.
If you are using Slang to generate textual or SPIRV code, no LLVM binaries are required. If you are using Slang to produce standalone executables or dynamically linked
libraries, then a prebuilt LLVM wrapper library called `slang-llvm` is required.

#### What's the distribution size of Slang?

The Slang compiler binary is around 5-10 MB depending on build configuration and target architecture.

#### Can I add another code generation target to Slang?

Absolutely! Slang is open and everyone is welcomed to contribute! Slang supports two types of targets: textual targets such as HLSL/GLSL/WGSL/C++ or binary targets such as SPIRV. Generally, adding support for textual targets is simpler and a lot of the infrastructure can be reused between the targets. We recently added support for Metal and WGSL, and more backends can be added following the similar process. Please create a discussion thread on the [Slang GitHub repo](https://github.com/shader-slang/slang/discussions) to start working with the dev team on adding a new target.

---

## File: docs/feature_matureness.md

---
title: Slang Feature Matureness
layout: page
permalink: "/docs/feature_matureness/"
intro_image_absolute: true
intro_image_hide_on_mobile: false
---

The table below shows the matureness of each Slang feature.

There are four types of Status:
- Stable: feature is stable and mature, and is documented by the language spec.
- Public Review: feature is implemented and tested by the community, and is now under public review and ready to be marked as stable and become part of the language spec.
- Experimental: feature is implemented and being tested by early adopters. Features in this stage are subject to change or removal at any time.  


| Feature | Status | Notes |
| --- | --- | --- |
| Attributes and user defined attributes | Stable |  |
| Auto variable type inference | Stable |  |
| HLSL syntax | Stable | Some known gaps around specific intrinsics; templates intentionally left out |
| enum types | Stable |  |
| Extension | Stable |  |
| Intellisense | Stable |  |
| Modules (import) | Stable | Being widely adopted in many code bases and haven't seen true quality issues reported for a long while. There are issues reported for quality of life improvements, but not about implementation defects. |
| Namespaces | Stable |  |
| Operator Overload | Stable |  |
| Optional<T> | Stable |  |
| ParameterBlock<T> | Stable |  |
| Properties | Stable | No issues found or reported in the last year. (this is to establish reference, many features not listed will fall in this category) |
| Raytracing | Stable |  |
| Reflection | Stable |  |
| User-defined operator[] (with multi parameter support) | Stable |  |
| Vulkan Interop (scalar layout, -fvk-* options) | Stable |  |
| Associated types for static dispatch | Experimental | Has been there for a long while with a lot of user code adoption |
| Autodiff (first-order) | Experimental | Adopted by many large scale code bases (3000+ lines of code), have not seen correctness issues for a long period. There are requests for unimplemented features. Improvements, enhancements and refactors are known and planned. |
| Autodiff (higher-order) | Experimental | Implemented and adopted in 2 different codebases. Known holes in design, and has not been widely adopted or exercised so its quality maybe significantly lower. |
| Builtin generic interfaces and operator overloads for generic code | Experimental | There isn't bugs or quality issues, and a lot of user code is depending on this, but we don't have good test coverage to build the confidence that it will provide good user experience. |
| Capabilities | Experimental | Implementation not done. |
| GLSL Compatibility | Experimental | Lightly adopted in MKL's mini examples, and a subset of CTS. Need more detailed scope and more time to test its quality. |
| Generic existential types | Experimental | Not being used or tested much |
| Generic interface as generic constraints | Experimental | Not widely adopted, test coverage are not comprehensive but the basic feature works. Known limitations in implementation that we need to spec out for now. |
| Geometry Shader (spirv direct) | Experimental | Still seeing bug reports from time to time, but likely more mature than Mesh Shader due to the long time it exists |
| Link time specialization | Experimental | Adopted by one user library and tested with several user applications. No issues has been filed in last two weeks. There are known gaps in implementation but our users are not running into them. |
| Mesh Shader (spirv-direct) | Experimental | Still seeing bugs from time to time, not thoroughly tested. |
| Multi-entrypoint (spirv direct) | Experimental | Being adopted in many codebases including Valve's, still seeing bug reports from time to time, need time to verify its quality |
| Multi-file Modules (__include) | Experimental | Implemented and tested with several different configurations. However, not fully tested with precompiled modules. No user code is adopting this feature. |
| Non-generic Interface as generic constraints | Experimental | The basis of stdlib and widely adopted in user codebase. This is the most basic use of interface types and has been working well. |
| Non-generic existential types (dynamic dispatch) | Experimental | Nontrivial adoption, a lot of test coverage. But syntax around existential types may change. |
| Non-generic existential types (static dispatch) | Experimental | Syntax around existential types may change. |
| Obfuscation | Experimental | Implemented a long while ago and adopted by OV, not seeing bug reports but they may be broken with latest language developments and lack of sufficient testing, especially when used in tendum with precompiled modules and link time specialization. |
| Precompiled Modules (serialization / up-to-date-ness verification) | Experimental | Adopted by one user library and tested with serveral applications. |
| SPIRV Debug | Experimental | Bug rate stablized, and has been working well. But need more adoption or testing to receive a higher matureness rating. |
| SPIRV Pointers | Experimental | Adopted by many users, and address many corner case issues reported by the user. Related bug rate is converging to 0. |
| Uniformity Analysis | Experimental | Implemented the first version, tested with 2 unit tests, no actual user code exercising it, not thoroughly tested, unlikely to work out of box when it gets actual use but expected to mature within 2 weeks in close iteration loop with adopting users. |
| `as` and `is` operators | Experimental |  |
| `reinterpret<T>` | Experimental |  |
{:.table}

---

## File: docs/first-slang-shader.md

---
title: Your first Slang shader
layout: page
permalink: "/docs/first-slang-shader"
intro_image_absolute: true
intro_image_hide_on_mobile: false
---

In this tutorial, we demonstrate how to write a simple compute shader in Slang that adds numbers from two buffers and writes the results into a third buffer. To start, create a text file named `hello-world.slang` in any directory, and paste the following content in the newly created file:

```hlsl
// hello-world.slang
StructuredBuffer<float> buffer0;
StructuredBuffer<float> buffer1;
RWStructuredBuffer<float> result;

[shader("compute")]
[numthreads(1,1,1)]
void computeMain(uint3 threadId : SV_DispatchThreadID)
{
    uint index = threadId.x;
    result[index] = buffer0[index] + buffer1[index];
}
```

> #### Note ####
> Slang has official language extension support for both [Visual Studio](https://marketplace.visualstudio.com/items?itemName=shader-slang.slang-vs-extension) and [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=shader-slang.slang-language-extension). The extensions are powered by the Slang compiler to support a wide range of
> assisting features including auto-completion, function signature hinting, semantic highlighting and more.

As you can see, `hello-world.slang` is no different from a normal HLSL shader file. In fact, Slang is compatible with most HLSL code you would write. On top of HLSL, Slang has added many new language and compiler features that simplifies various tasks with shader code, which we will cover in future chapters. For now we will demonstrate one key feature of Slang: cross-compiling to different platforms.

Slang supports compiling shaders into many different targets including Direct3D 11, Direct3D 12, Vulkan, CUDA and C++ (for execution on CPU). You can run `slangc` with the following command line to compile `hello-world.slang` into Vulkan SPIR-V:

```bat
.\slangc.exe hello-world.slang -profile glsl_450 -target spirv -o hello-world.spv -entry computeMain
```

If you would like to see the equivalent GLSL of the generated SPIR-V code, simply change the `-target` argument to `glsl`:
```bat
.\slangc.exe hello-world.slang -profile glsl_450 -target glsl -o hello-world.glsl -entry computeMain
```

The resulting `hello-world.glsl` generated by `slangc` is shown below:
```glsl
// hello-world.glsl (generated by slangc)
#version 450
layout(row_major) uniform;
layout(row_major) buffer;

#line 2 0
layout(std430, binding = 0) readonly buffer _S1 {
    float _data[];
} buffer0_0;

#line 3
layout(std430, binding = 1) readonly buffer _S2 {
    float _data[];
} buffer1_0;

#line 4
layout(std430, binding = 2) buffer _S3 {
    float _data[];
} result_0;

layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main()
{

#line 10
    uint index_0 = gl_GlobalInvocationID.x;
    float _S4 = ((buffer0_0)._data[(index_0)]);

#line 11
    float _S5 = ((buffer1_0)._data[(index_0)]);

#line 11
    float _S6 = _S4 + _S5;

#line 11
    ((result_0)._data[(index_0)]) = _S6;

#line 8
    return;
}
```
> #### Note ####
> You can check out how this hello world shader compiles to different targets on [Slang Playground](/slang-playground/?target=SPIRV&code=eJyFjz0LwjAQhvf7FUenih9V3Iw6SBcHFxUdSpHYpDYQE8mHFsT_bu2Hm3g33fM-B3dRhAWXUg8f2kg2spKqC-yc8ZnzhrOVz3Nu5rnU1C3xXE9j8keYENgefymGWy8dAUhsQRk3YZDp6807HvRSSJS_usJwymw4GVRdsbsWDFtnQ4UKvVBuio22ZjjD3eEUC3ujLiv2DY178ASs6uOiUIyXuPiujEpSh80pSR2nVd6-14F-904LCLzedkNpAg).


As you can see, things are being translated just as expected to GLSL: the HLSL `StructuredBuffer` and `RWStructuredBuffer` types are mapped to shader storage objects and the `[numthreads]` attribute are translated into proper `layout(...) in` qualifier on the `main` entry-point.

Note that in the generated GLSL code, all shader parameters are qualified with explicit binding layouts. This is because Slang provides a guarantee that all parameters will have fixed bindings regardless of shader optimization. Without generating explicit binding layout qualifiers, the downstream compiler in the driver may change the binding of a parameter depending on whether any preceding parameters are eliminated during optimization passes. In practice, this causes a pain in application code, where developers will need to rely on run-time reflection to determine the binding location of a compiled shader kernel. The issue gets harder to manage when the application also needs to deal with shader specializations. Since Slang will always generate explicit binding locations in its output on all targets as if no parameters are eliminated, the user is assured that parameters always gets a deterministic binding location without having to write any manual binding qualifiers in the Slang code themselves. In fact, we strongly encourage users not to qualify their Slang code with explicit binding qualifiers and let the Slang compiler do its work to properly lay out parameters. This is best practice to maintain code modularity and avoid potential binding location conflicts between different shader modules.

## The full example

The full Vulkan example that sets up and runs the `hello-world.slang` shader in located in the [/examples/hello-world](https://github.com/shader-slang/slang/tree/master/examples/hello-world) directory of the Slang repository. The example code initializes a Vulkan context and runs the compiled SPIR-V code. The example code demonstrates how to use the Slang API to load and compile shaders.

## Further Reading

See how to write vertex and fragment shaders in this [Slang Playground Demo](/slang-playground/?target=SPIRV&code=eJyVU01r20AQvetXDD7Z4MqJm0OJUh_iXHoIDdgEijFlI41tkdWu2J11bUr_e2c_vJHpqUKg1czozXszT7MZrA-tBTyJrpcIDXZaWTKC0MJB_wLSHNu1CuGIhvAEQjWwM2LfoSKwB9GgAT6ac69bRbYsZgmSbwG17vpW4iet5PnSZApWAx3QoK9RGrSj3hGj6s7HoZfivDfaqSag_dAOaqHAWQzp0TKCjuDNEWnlOaY-nB-I8dzb3Y4bMVUSZo-eX8HyXE3wGvQUvwvgaye1oM_Qa9tSq1U1DCptOiEHoTm4Y1X8yUjPPC3TCpmweAwg5Bs2eo0ncga_qQZPVc5FvOvcB9iqRoUJaRVCXNU8Oq_j4dJpAV062Yib0OZPQPFkN7fzL9sh8FJ0aMRQ793pDrpjH4pehOE8Yz5KXb8_BBYLsP5RFUvvCaEosYhIC16Kf1bFKozbrIg5gR28VB_D_u7oqnUeNdzD6vXny_8NfhONNx5FU44m28J3SB59Fq0ax_XywNlak9Q61ES3RdR4LjOXr9A5OY66Sh7NNLEdB5hcN4Xb8mYyucKIZBkhlg65pwp3zFkvw2cM8q5UpjRUdvnHvLY0skso6vNaoro4wnUweFIqkS5O4KZhjWV2RnzNDtrcbMt__bqtMlCtpTYMkwDKuO_xcNPTLGxypSx86oX9Be1nf3g).