defnotmid

Projects / 03

oksl

SkSL in plain Odin. A compiler for Skia runtime-effect shaders that emits SPIR-V, MSL and a CPU program, so nobody needs a shader compiler installed.

  • Odin
  • MIT
  • core: only
  • SPIR-V · MSL · CPU
  • Shadertoy in
Source on GitHub ↗
27 seconds of oksl, music included: the title glitched by SkSL reading a live text group, a shader typed in and rendering beside its source, a raymarched SDF and a Shadertoy tunnel. Rendered with onimite, whose shader layers oksl compiles.

By the numbers

test shaders match, GPU vs CPU
17 / 17
15 within 1/255; the other two differ only at threshold edges
targets from one source
3
SPIR-V for Vulkan, MSL for Metal, a CPU program
shader compilers to install
0
the compiler depends on Odin's core: only
SkSL programs a frame
18
onimite's shader_mode example, one of them Shadertoy

Parity from tools/gpu_parity (2026-10-10, SDL_GPU on Vulkan, RX 9070 XT, against the CPU interpreter); program count from onimite's BENCHMARK.md.

What's in it

  1. 01SkSL as Skia takes it

    half4 main(float2 coord), uniforms, uniform shader children sampled with .eval, structs, arrays, matrices and the GLSL ES 3 built-ins.

  2. 02Shadertoy in

    GLSL from Shadertoy is rewritten to SkSL as fframes does it, a text rewrite rather than a second parser, with errors reported on the original lines.

  3. 03SPIR-V and MSL

    SPIR-V 1.0 for Vulkan and MSL for Metal, laid out for SDL_GPU's bindings, plus a committed layer vertex shader.

  4. 04A CPU interpreter that keeps up

    Every function inlines into one flat program over 16 SoA lanes (four 2x2 quads). One switch per instruction, never per lane, and arithmetic runs as loops the compiler vectorizes.

  5. 05GPU semantics on the CPU

    Divergent control flow runs under execution masks, helper lanes keep dFdx/dFdy correct, and integer division, mod and shifts match the GPU.

  6. 06Reflection

    A std140 uniform block with the Shadertoy built-ins at fixed offsets; Module.uniforms reports every user uniform's offset, size and stride.

  7. 07Useful errors

    line:column messages, several per compile, and clear diagnostics for what SkSL leaves out: no preprocessor, no discard, no sampler2D.

  8. 08Data-oriented

    Tokens, syntax, symbols and types are flat arrays of plain structs referenced by integer ids. A compile allocates from one arena, released by destroy.

Not yet

  • Fragment shaders only, and no Shadertoy multipass buffers.
  • No struct uniforms, arrays of arrays, switch, or colorFilter / blender children.
  • MSL is compiled and tested on macOS only; Windows runs SDL_GPU's Vulkan driver (no DXIL).

Use it

uniform float3 iResolution;
uniform float iTime;
uniform float uKick;

half4 main(float2 coord) {
    float2 uv = (coord - 0.5 * iResolution.xy) / iResolution.y;
    float r = length(uv);
    float a = atan(uv.y, uv.x);
    float w = sin(18.0 * r - 4.0 * iTime + 3.0 * sin(3.0 * a));
    float ring = 0.012 / abs(r - 0.3 - 0.04 * w - 0.06 * uKick);
    half3 col = 0.5 + 0.5 * cos(iTime + 6.0 * r + half3(0, 2, 4));
    col *= smoothstep(-0.3, 1.0, w) * (1.1 - r);
    col += ring * half3(0.7, 1.0, 0.25);
    return half4(col, 1.0);
}

The family