TGSL (TypeGPU Shading Language) is a subset of JavaScript used to define functions that run on the GPU via TypeGPU.
It works by transpiling JavaScript into a compact AST format, called tinyest,
which is then used to generate equivalent WGSL.
Instead of using a WGSL code string, you can pass TGSL to the tgpu function shell as an argument instead.
Functions from the WGSL standard library (distance, arrayLength, workgroupBarrier, etc.) are accessible through the typegpu/std endpoint.
The package also includes functions for vector and matrix operators (add, eq, lt…).
TGSL-implemented functions can also be invoked on the CPU, as along as they do not use any GPU-exclusive functionalities, like buffers or textures (regardless of whether they are marked as “kernel” or not).
TGSL limitations —
For a function to be valid TGSL, it must consist only of supported JS syntax (again, see tinyest-for-wgsl repository), possibly including references to bound buffers, constant variables defined outside of the function, other TGSL functions etc.
This means that, for example, console.log() calls will not work on the GPU.
Differences between JS on the CPU and GPU —
TGSL is developed to work on the GPU the same as on the CPU as much as possible,
however because of the fundamental differences between the JavaScript and WGSL languages, it is not guaranteed to always be the case.
Currently the biggest known difference is that vectors, matrices and structs are treated as reference types in JavaScript and value types in WGSL.
That is, on the WGSL side, the assignment operator copies the value instead of the reference, and two different vectors can be equal to each other if only they store the same values, unlike in JS, where they need to point to the same reference.
To somehow alleviate this issue, when passing arguments to tgpu functions on JS side, we perform a deep copy of them (note that in WGSL arguments are immutable by default).
When using TGSL on the GPU, the behavior is that of WGSL, not JS, as one would expect.
Therefore some WGSL knowledge is still required, even when opting out for TGSL.
.value —
Objects that have different types on the CPU and on the GPU (like buffers, layouts, slots etc.) need to be accessed via the value property in TGSL functions (or the $ property alias).
This is different from how they appear in WGSL-implemented ones.
Allocates memory on the GPU, allows passing data between host and shader.
Read-only on the GPU, optimized for small data. For a general-purpose buffer,
use
TgpuRoot.createBuffer
.
@param ― typeSchema The type of data that this buffer will hold.
@param ― initial The initial value of the buffer. (optional)
createUniform(
import d
d.
const vec4f: d.Vec4f
export vec4f
Schema representing vec4f - a vector with 4 elements of type f32.
Also a constructor function for this vector value.
Operators —
JavaScript does not support operator overloading.
This means that, while you can still use operators for numbers,
you have to use supplementary functions from typegpu/std (add, mul, eq, lt, ge…) for operations involving vectors and matrices.
When to use TGSL instead of WGSL —
Writing the code using TGSL has a few significant advantages.
It allows defining utils only once and using them both as a kernel and host functions,
as well as enables complete syntax highlighting and autocomplete in TypeGPU function definitions, leading to a better developer UX.
However, it sometimes might be better to choose WGSL for certain functions.
Since JavaScript doesn’t support operator overloading, functions including complex matrix operations can be more readable in WGSL.
Writing WGSL becomes a necessity whenever TGSL does not support some feature or standard library function quite yet.
Luckily, you don’t have to choose one or the other for the entire project. It is possible to mix and match WGSL and TGSL at every step of the way.