Elio is a compiler for GPU compute shaders. You write a compute kernel once in a
small language (.elio), and Elio emits the equivalent shader for several
graphics APIs — WGSL (WebGPU), GLSL (Vulkan / GLES 3.1), and Metal (MSL) — plus
a CPU implementation for platforms that have no compute support at all. It is
built for the GoSX renderer, but the core compiler has no GoSX dependency.
A GPU compute kernel — culling, particle integration, a prefix sum, skinning — has to be written separately for each graphics API: WGSL for WebGPU, GLSL for Vulkan and GLES 3.1, MSL for Metal. WebGL and GLES 2.0 have no compute stage at all, so the same work has to be re-implemented on the CPU there. In GoSX this showed up concretely: the particle integrator existed in four hand-written copies (WebGPU/Go, WebGL/JS, Android/Kotlin, iOS/Swift), and there was no portable path for culling, post-processing, or simulation.
Elio replaces those copies with one source. The same kernel is checked to be
valid on each backend: WGSL is validated with naga, GLSL is compiled to SPIR-V
with glslangValidator, and the CPU implementation is run and its results
compared — see conformance/.
It is one of three related M31 Labs compilers: Selena compiles material/shader source for the rasterization pipeline, Eos compiles ML inference, and Elio compiles per-frame compute. They are separate tools that share the same parser tooling and target the same GPU device.
.elio source ──parse──▶ IR ──┬──▶ WGSL (WebGPU; validated by naga)
├──▶ GLSL (Vulkan / GLES 3.1; glslang → SPIR-V)
├──▶ Metal (MSL)
└──▶ CPU (scalar interpreter; WebGL / GLES 2.0)
go install m31labs.dev/elio/cmd/elio@latest
elio emit wgsl kernel.elio # WGSL to stdout
elio emit glsl kernel.elio # GLSL #version 450 compute
elio emit metal kernel.elio # Metal MSL
elio check kernel.elio # parse-check onlyTypes are spelled in a Go-flavored way to avoid the <…> ambiguity of WGSL
generics: [N]T and []T for fixed and runtime arrays, atomic_u32,
vec2/3/4 (suffix u for unsigned), mat3 / mat4. Bindings, a workgroup
size, and a kernel entry point are declared at the top level; the body is
ordinary imperative code (let / var, if, for, indexing, atomics).
@group(0) @binding(0) uniform cull: CullUniforms;
@group(0) @binding(1) storage read input: []InstanceRecord;
@group(0) @binding(2) storage read_write output: []InstanceRecord;
@group(0) @binding(3) storage read_write drawArgs: [4]atomic_u32;
@workgroup(64) kernel main(gid: global_invocation_id) {
let i = gid.x;
if i >= arrayLength(&input) { return; }
let record = input[i];
let center = record.model[3].xyz;
var inside = true;
for (var p: i32 = 0; p < 6; p = p + 1) {
let plane = cull.planes[p];
if dot(plane.xyz, center) + plane.w < -cull.radius { inside = false; break; }
}
if inside {
let slot = atomicAdd(&drawArgs[1], 1u);
output[slot] = record;
}
}
Elio targets GoSX's render/gpu package rather than a GPU API directly, and
attaches to the renderer through render/compute.ExternalComputePass. A pass
records its dispatch onto the frame's command encoder and publishes the buffers
it produced onto a small resource descriptor (render/compute.GPUResource); the
renderer's draw step then reads those buffers. The InstanceRecord layout
(80 bytes: a mat4 plus a vec4<u32>) matches the engine's existing instanced
draw, so a kernel that writes instance records can drive a draw without changes
to the renderer. examples/cull is a working out-of-tree pass whose shader is
generated by this compiler.
| Path | Role |
|---|---|
ir/ |
the compute IR and sample kernels |
parse/ |
.elio front-end (lexer + recursive-descent parser) |
emit/wgsl/, emit/glsl/, emit/metal/ |
backend emitters |
run/ |
scalar CPU interpreter |
conformance/ |
cross-backend validation (naga + glslang + CPU) |
cmd/elio/ |
the elio CLI |
examples/cull/ |
an out-of-tree GoSX ExternalComputePass |
The compiler is working end to end: parsing, four backends, the CLI, and the GoSX integration point are in place and tested. Planned work:
- Continue hardening the
grammargen/gotreesitterparser shared with Selena and Eos; the former hand-written parser has been retired. - A direct SPIR-V emitter is optional; SPIR-V is reachable today through the
GLSL backend and
glslang. - Run Elio kernels in the GoSX frame on a WebGPU device shared with Eos. The device-sharing interfaces exist on both sides; the dispatch path is the next step.
The name is a counterpart to Selena (the rasterization-side compiler).