@compute.toys is a playground for WebGPU compute shaders. Everything here is written in WGSL, which is WebGPU's native shader language. For up-to-date information on WGSL, please see the WGSL draft specification. You can also take a tour of WGSL.
@compute.toys supplies keyboard input, mouse input, selectable input textures, custom values controlled by sliders, and the current frame and elapsed time.
Mouse input can be accessed from the mouse
struct:
mouse.pos: vec2i
mouse.click: i32
Timing information is in the time
struct:
time.frame: u32
time.elapsed: f32
Custom uniforms are in the custom
struct:
custom.my_custom_uniform_0: f32
custom.my_custom_uniform_1: f32
Two selectable textures can be accessed from channel0
and channel1
:
textureSampleLevel(channel0, bilinear, uv, pass, lod)
textureSampleLevel(channel1, bilinear, uv, pass, lod)
Keyboard input can be accessed from the provided keyDown(keycode: u32)
helper function:
keyDown(32) // returns true when the spacebar is pressed
For compute shader input and output @compute.toys provides:
one input texture array pass_in
,
one output storage texture array pass_out
,
and one output screen storage texture screen
.
The shader can write to pass_out
, which will be copied into pass_in
after the current entrypoint has returned. pass_in
will always contain whatever has been written to pass_out
during all of the previous entrypoints. The contents of pass_in
will not change while an entrypoint is running. pass_in
and pass_out
are both texture arrays with 4 texture layers. For example, you can access the third layer of pass_in
at LOD 0
and coordinate (1,1)
by using the built-in helper function:
passLoad(2, vec2i(1,1), 0)
@compute.toys also provides an experimental WGSL preprocessor. It currently allows the use of a handful of basic directives:
#define NAME VALUE
for simple macros (function-like parameter substitution is not yet supported)#include "PATH"
for accessing built-in libraries#workgroup_count ENTRYPOINT X Y Z
for specifying how many workgroups should be dispatched for an entrypoint#dispatch_count ENTRYPOINT N
for dispatching an entrypoint multiple times in a row#storage NAME TYPE
for declaring a storage buffer
Read-write storage buffers can be declared using the #storage
directive. For example, you can create a buffer of atomic counters:
#storage atomic_storage array<atomic<i32>>
You could use WGSL's built-in functions to do atomic operations on this buffer in any order, enabling you to safely perform work across many threads at once and accumulate the result in one place. Note that any writes to read-write storage buffers are immediately visible to subsequent reads (unlike the situation with pass_in
and pass_out
).
The final visual output of every shader is written to the screen storage texture, which displays the result in the canvas on this page.
Debugging assertions are supported with an assert helper function:
assert(0, isfinite(col.x))
assert(1, isfinite(col.y))
Every shader begins with a common prelude. The prelude contains the data inputs and outputs for this shader, as well as a few helper functions and type definitions to make working with @compute.toys a more streamlined and familiar process. Please refer to the prelude for a complete listing of the available data in your shader.
Here are the current contents of this shader's prelude:
alias int = i32;
alias uint = u32;
alias float = f32;
alias int2 = vec2<i32>;
alias int3 = vec3<i32>;
alias int4 = vec4<i32>;
alias uint2 = vec2<u32>;
alias uint3 = vec3<u32>;
alias uint4 = vec4<u32>;
alias float2 = vec2<f32>;
alias float3 = vec3<f32>;
alias float4 = vec4<f32>;
alias bool2 = vec2<bool>;
alias bool3 = vec3<bool>;
alias bool4 = vec4<bool>;
alias float2x2 = mat2x2<f32>;
alias float2x3 = mat2x3<f32>;
alias float2x4 = mat2x4<f32>;
alias float3x2 = mat3x2<f32>;
alias float3x3 = mat3x3<f32>;
alias float3x4 = mat3x4<f32>;
alias float4x2 = mat4x2<f32>;
alias float4x3 = mat4x3<f32>;
alias float4x4 = mat4x4<f32>;
struct Time { frame: uint, elapsed: float, delta: float }
struct Mouse { pos: uint2, click: int }
struct DispatchInfo { id: uint }
struct Custom {
_dummy: float,
};
struct Data {
_dummy: array<u32,1>,
};
@group(0) @binding(2) var<uniform> time: Time;
@group(0) @binding(3) var<uniform> mouse: Mouse;
@group(0) @binding(4) var<uniform> _keyboard: array<vec4<u32>,2>;
@group(0) @binding(5) var<uniform> custom: Custom;
@group(0) @binding(6) var<storage,read> data: Data;
@group(0) @binding(7) var<storage,read_write> _assert_counts: array<atomic<u32>>;
@group(0) @binding(8) var<uniform> dispatch: DispatchInfo;
@group(0) @binding(9) var screen: texture_storage_2d<rgba16float,write>;
@group(0) @binding(10) var pass_in: texture_2d_array<f32>;
@group(0) @binding(11) var pass_out: texture_storage_2d_array<rgba16float,write>;
@group(0) @binding(12) var channel0: texture_2d<f32>;
@group(0) @binding(13) var channel1: texture_2d<f32>;
@group(0) @binding(14) var nearest: sampler;
@group(0) @binding(15) var bilinear: sampler;
@group(0) @binding(16) var trilinear: sampler;
@group(0) @binding(17) var nearest_repeat: sampler;
@group(0) @binding(18) var bilinear_repeat: sampler;
@group(0) @binding(19) var trilinear_repeat: sampler;
fn keyDown(keycode: uint) -> bool {
return ((_keyboard[keycode / 128u][(keycode % 128u) / 32u] >> (keycode % 32u)) & 1u) == 1u;
}
fn assert(index: int, success: bool) {
if (!success) {
atomicAdd(&_assert_counts[index], 1u);
}
}
fn passStore(pass_index: int, coord: int2, value: float4) {
textureStore(pass_out, coord, pass_index, value);
}
fn passLoad(pass_index: int, coord: int2, lod: int) -> float4 {
return textureLoad(pass_in, coord, pass_index, lod);
}
fn passSampleLevelBilinearRepeat(pass_index: int, uv: float2, lod: float) -> float4 {
return textureSampleLevel(pass_in, bilinear, fract(uv), pass_index, lod);
}
Note: Matrix types in WGSL are stored in column-major order. This means a matrix of type
mat2x3<f32>
(akamat2x3f
orfloat2x3
) is constructed from 2 column vectors of typevec3<f32>
(akavec3f
orfloat3
). This is backward from HLSL and convention in mathematics.
functions to import seems are maintained at https://github.com/compute-toys/include/tree/146065171bd09afff4bec5823f0b1d2397d28b51