Pure Go Shader Compiler
WGSL to SPIR-V. Zero CGO.
Part of the GoGPU ecosystem
v0.4.0 — Compute shaders, atomics, barriers, unused var warnings. ~17K lines of pure Go.
- Pure Go — No CGO, no external dependencies
- WGSL Frontend — Full lexer and parser (140+ tokens)
- IR — Complete intermediate representation (expressions, statements, types)
- Compute Shaders — Storage buffers, workgroup memory,
@workgroup_size - Atomic Operations — atomicAdd, atomicSub, atomicMin, atomicMax, atomicCompareExchangeWeak
- Barriers — workgroupBarrier, storageBarrier, textureBarrier
- Type Inference — Automatic type resolution for all expressions, including
letbindings - Type Deduplication — SPIR-V compliant unique type emission
- Array Initialization —
array(1, 2, 3)shorthand with inferred type and size - Texture Sampling — textureSample, textureLoad, textureStore, textureDimensions
- SPIR-V Backend — Vulkan-compatible bytecode generation with correct type handling
- Warnings — Unused variable detection with
_prefix exception - Validation — Type checking and semantic validation
- CLI Tool —
nagaccommand-line compiler
go get github.com/gogpu/nagapackage main
import (
"fmt"
"log"
"github.com/gogpu/naga"
)
func main() {
source := `
@vertex
fn main(@builtin(vertex_index) idx: u32) -> @builtin(position) vec4<f32> {
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
}
`
// Simple compilation
spirv, err := naga.Compile(source)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Generated %d bytes of SPIR-V\n", len(spirv))
}opts := naga.CompileOptions{
SPIRVVersion: spirv.Version1_3,
Debug: true, // Include debug names
Validate: true, // Enable IR validation
}
spirv, err := naga.CompileWithOptions(source, opts)# Install
go install github.com/gogpu/naga/cmd/nagac@latest
# Compile shader
nagac shader.wgsl -o shader.spv
# With debug info
nagac -debug shader.wgsl -o shader.spv
# Show version
nagac -version// Parse WGSL to AST
ast, err := naga.Parse(source)
// Lower AST to IR
module, err := naga.Lower(ast)
// Validate IR
errors, err := naga.Validate(module)
// Generate SPIR-V
spirvOpts := spirv.Options{Version: spirv.Version1_3, Debug: true}
spirvBytes, err := naga.GenerateSPIRV(module, spirvOpts)naga/
├── wgsl/ # WGSL frontend
│ ├── token.go # Token types (140+)
│ ├── lexer.go # Tokenizer
│ ├── ast.go # AST types
│ ├── parser.go # Recursive descent parser (~1400 LOC)
│ └── lower.go # AST → IR converter (~1100 LOC)
├── ir/ # Intermediate representation
│ ├── ir.go # Core types (Module, Type, Function)
│ ├── expression.go # 33 expression types (~520 LOC)
│ ├── statement.go # 16 statement types (~320 LOC)
│ ├── validate.go # IR validation (~750 LOC)
│ ├── resolve.go # Type inference (~500 LOC) ← NEW
│ └── registry.go # Type deduplication (~100 LOC) ← NEW
├── spirv/ # SPIR-V backend
│ ├── spirv.go # SPIR-V constants and opcodes
│ ├── writer.go # Binary module builder (~670 LOC)
│ └── backend.go # IR → SPIR-V translator (~1800 LOC)
├── naga.go # Public API
└── cmd/nagac/ # CLI tool
- Scalars:
f32,f64,i32,u32,bool - Vectors:
vec2<T>,vec3<T>,vec4<T> - Matrices:
mat2x2<f32>...mat4x4<f32> - Arrays:
array<T, N> - Structs:
struct { ... } - Atomics:
atomic<u32>,atomic<i32> - Textures:
texture_2d<f32>,texture_3d<f32>,texture_cube<f32> - Samplers:
sampler,sampler_comparison
@vertex— Vertex shaders with@builtin(position)output@fragment— Fragment shaders with@location(N)outputs@compute— Compute shaders with@workgroup_size(X, Y, Z)
@builtin(position),@builtin(vertex_index),@builtin(instance_index)@builtin(global_invocation_id)— Compute shader invocation ID@location(N)— Vertex attributes and fragment outputs@group(G) @binding(B)— Resource bindings
var<uniform>— Uniform buffervar<storage, read>— Read-only storage buffervar<storage, read_write>— Read-write storage buffervar<workgroup>— Workgroup shared memory
- Variable declarations:
var,let - Control flow:
if,else,for,while,loop - Loop control:
break,continue - Functions:
return,discard - Assignment:
=,+=,-=,*=,/=
- Math:
sin,cos,tan,exp,log,pow,sqrt,abs,min,max,clamp - Geometric:
dot,cross,length,distance,normalize,reflect - Interpolation:
mix,step,smoothstep - Derivatives:
dpdx,dpdy,fwidth - Atomic:
atomicAdd,atomicSub,atomicMin,atomicMax,atomicAnd,atomicOr,atomicXor,atomicExchange,atomicCompareExchangeWeak - Barriers:
workgroupBarrier,storageBarrier,textureBarrier
- WGSL lexer and parser
- Complete IR (expressions, statements, types)
- IR validation
- SPIR-V binary writer
- SPIR-V backend (types, constants, functions, expressions)
- Control flow (if, loop, break, continue)
- Built-in math functions (GLSL.std.450)
- Public API and CLI tool
- Type inference for all expressions
- Type deduplication (SPIR-V compliant)
- Correct int/float/uint opcode selection
- SPIR-V backend with proper type handling
- 67+ unit tests
- Type inference for
letbindings - Array initialization syntax (
array(1, 2, 3)) - Texture sampling operations (textureSample, textureLoad, textureStore)
- SPIR-V image operations (OpImageSample*, OpImageFetch, OpImageQuery*)
- 124 unit tests
- Better error messages with source locations
- Storage buffers (
var<storage, read>,var<storage, read_write>) - Workgroup shared memory (
var<workgroup>) - Atomic operations (atomicAdd, atomicSub, atomicCompareExchangeWeak, etc.)
- Workgroup barriers (workgroupBarrier, storageBarrier, textureBarrier)
- Unused variable warnings
- 203 unit tests
- GLSL backend output
- Source maps for debugging
- Optimization passes
- Full WGSL specification compliance
- Production-ready stability
- HLSL/MSL backends
- WGSL Specification
- SPIR-V Specification
- naga (Rust) — Original implementation
| Project | Description | Status |
|---|---|---|
| gogpu/gogpu | Pure Go graphics framework | v0.4.0 |
| gogpu/wgpu | Pure Go WebGPU types and HAL | v0.5.0 |
| gogpu/gg | 2D graphics with GPU backend, scene graph, SIMD | v0.9.2 |
| go-webgpu/webgpu | WebGPU FFI bindings | Stable |
We welcome contributions! Areas where help is needed:
- Additional WGSL features (ray tracing, mesh shaders)
- Test cases from real shaders
- GLSL backend implementation
- Documentation improvements
MIT License — see LICENSE for details.
naga — Shaders in Pure Go