Pure Go Shader Compiler
WGSL to SPIR-V, MSL, GLSL, and HLSL. Zero CGO.
Part of the GoGPU ecosystem
naga is a shader compiler written entirely in Go. It compiles WGSL (WebGPU Shading Language) to multiple backend formats without requiring CGO or external dependencies.
| Category | Capabilities |
|---|---|
| Input | Full WGSL parser (120+ tokens) |
| Outputs | SPIR-V, MSL, GLSL, HLSL |
| Compute | Storage buffers, workgroups, atomics, barriers |
| Build | Zero CGO, single binary |
- Pure Go — No CGO, no external dependencies
- WGSL Frontend — Full lexer and parser (120+ 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
- Swizzle Operations — Full vector swizzle support (
.xyz,.rgba,.xxyy, etc.) - Function Calls —
OpFunctionCallsupport for modular WGSL shaders with helper functions - SPIR-V Backend — Vulkan-compatible bytecode generation with correct type handling
- MSL Backend — Metal Shading Language output for macOS/iOS
- GLSL Backend — OpenGL Shading Language for OpenGL 3.3+, ES 3.0+
- HLSL Backend — High-Level Shading Language for DirectX 11/12
- Type Conversions — Scalar constructors
f32(x),u32(y),i32(z)with correct SPIR-V opcodes - Warnings — Unused variable detection with
_prefix exception - Validation — Type checking and semantic validation
- CLI Tool —
nagaccommand-line compiler
go get github.com/gogpu/nagaRequirements: Go 1.25+
package 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# SPIR-V disassembler (debugging shader compilation)
go install github.com/gogpu/naga/cmd/spvdis@latest
spvdis shader.spv
# Texture shader compile tool (testing)
go install github.com/gogpu/naga/cmd/texture_compile@latest
texture_compile shader.wgsl// Parse and lower WGSL to IR (shared across all backends)
ast, _ := naga.Parse(source)
module, _ := naga.Lower(ast)
// Generate SPIR-V (Vulkan)
spirvBytes, _ := naga.GenerateSPIRV(module, spirv.Options{})
// Generate MSL (Metal)
mslCode, _, _ := msl.Compile(module, msl.DefaultOptions())
// Generate GLSL (OpenGL)
glslCode, _, _ := glsl.Compile(module, glsl.DefaultOptions())
// Generate HLSL (DirectX)
hlslCode, _, _ := hlsl.Compile(module, hlsl.DefaultOptions())// 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 (120+)
│ ├── lexer.go # Tokenizer
│ ├── ast.go # AST types
│ ├── parser.go # Recursive descent parser (~1400 LOC)
│ └── lower.go # AST → IR converter (~2500 LOC)
├── ir/ # Intermediate representation
│ ├── ir.go # Core types (Module, Type, Function)
│ ├── expression.go # 24 expression types (~520 LOC)
│ ├── statement.go # 16 statement types (~320 LOC)
│ ├── validate.go # IR validation (~750 LOC)
│ ├── resolve.go # Type inference (~500 LOC)
│ └── registry.go # Type deduplication (~100 LOC)
├── spirv/ # SPIR-V backend
│ ├── spirv.go # SPIR-V constants and opcodes
│ ├── writer.go # Binary module builder (~670 LOC)
│ └── backend.go # IR → SPIR-V translator (~3700 LOC)
├── msl/ # MSL backend (Metal)
│ ├── backend.go # Public API, Options, Compile()
│ ├── writer.go # MSL code writer
│ ├── types.go # Type generation (~400 LOC)
│ ├── expressions.go # Expression codegen (~1175 LOC)
│ ├── statements.go # Statement codegen (~350 LOC)
│ ├── functions.go # Entry points and functions (~500 LOC)
│ └── keywords.go # MSL/C++ reserved words
├── glsl/ # GLSL backend (OpenGL)
│ ├── backend.go # Public API
│ ├── writer.go # GLSL code writer
│ ├── types.go # Type generation
│ ├── expressions.go # Expression codegen
│ ├── statements.go # Statement codegen
│ └── keywords.go # Reserved word escaping
├── hlsl/ # HLSL backend (DirectX)
│ ├── backend.go # Public API, Options, Compile()
│ ├── writer.go # HLSL code writer (~400 LOC)
│ ├── types.go # Type generation (~500 LOC)
│ ├── expressions.go # Expression codegen (~1100 LOC)
│ ├── statements.go # Statement codegen (~600 LOC)
│ ├── storage.go # Buffer/atomic operations (~500 LOC)
│ ├── functions.go # Entry points with semantics (~500 LOC)
│ └── keywords.go # HLSL reserved words
├── naga.go # Public API
└── cmd/
├── nagac/ # CLI compiler
├── spvdis/ # SPIR-V disassembler
└── texture_compile/ # Texture shader testing
- Scalars:
f16,f32,i32,u32,bool - Vectors:
vec2<T>,vec3<T>,vec4<T> - Matrices:
mat2x2<f32>...mat4x4<f32> - Arrays:
array<T, N>,array<T>(runtime-sized, storage buffers) - 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,const - Control flow:
if,else,for,while,loop,switch,case,default - Loop control:
break,continue - Functions:
return,discard - Assignment:
=,+=,-=,*=,/=
- Math:
abs,min,max,clamp,saturate,sign,fma,modf,frexp,ldexp,quantizeToF16 - Trigonometric:
sin,cos,tan,asin,acos,atan,atan2,sinh,cosh,tanh,asinh,acosh,atanh - Angle:
radians,degrees - Exponential:
exp,exp2,log,log2,pow,sqrt,inverseSqrt - Decomposition:
ceil,floor,round,fract,trunc - Geometric:
dot,cross,length,distance,normalize,faceForward,reflect,refract,outerProduct - Interpolation:
mix,step,smoothstep - Matrix:
transpose,determinant,inverse - Relational:
all,any,isnan,isinf - Bit:
countTrailingZeros,countLeadingZeros,countOneBits,reverseBits,extractBits,insertBits,firstTrailingBit,firstLeadingBit - Packing:
pack4x8snorm,pack4x8unorm,pack2x16snorm,pack2x16unorm,pack2x16float,pack4xI8,pack4xU8,pack4xI8Clamp,pack4xU8Clamp,unpack4x8snorm,unpack4x8unorm,unpack2x16snorm,unpack2x16unorm,unpack2x16float,unpack4xI8,unpack4xU8 - Selection:
select - Derivatives:
dpdx,dpdy,fwidth,dpdxCoarse,dpdyCoarse,fwidthCoarse,dpdxFine,dpdyFine,fwidthFine - Atomic:
atomicAdd,atomicSub,atomicMin,atomicMax,atomicAnd,atomicOr,atomicXor,atomicExchange,atomicCompareExchangeWeak - Barriers:
workgroupBarrier,storageBarrier,textureBarrier - Array:
arrayLength
Current Version: See CHANGELOG.md for release history.
| Backend | Status | Target Platform |
|---|---|---|
| SPIR-V | ✅ Stable | Vulkan |
| MSL | ✅ Stable | Metal (macOS/iOS) |
| GLSL | ✅ Stable | OpenGL 3.3+, ES 3.0+ |
| HLSL | ✅ Stable | DirectX 11/12 |
See ROADMAP.md for detailed development plans.
- WGSL Specification
- SPIR-V Specification
- naga (Rust) — Original implementation
naga is the shader compiler for the GoGPU ecosystem.
| Project | Description |
|---|---|
| gogpu/gogpu | GPU framework with windowing and input |
| gogpu/wgpu | Pure Go WebGPU implementation |
| gogpu/naga | Shader compiler (this repo) |
| gogpu/gg | 2D graphics library |
| gogpu/ui | GUI toolkit (planned) |
- ROADMAP.md — Development milestones
- CHANGELOG.md — Release notes
- pkg.go.dev — API reference
We welcome contributions! Areas where help is needed:
- Additional WGSL features
- Test cases from real shaders
- Backend optimizations
- Documentation improvements
MIT License — see LICENSE for details.
naga — Shaders in Pure Go