3D graphics in Go.
import "poly.red"Warning: under experiment, expect to break at anytime.
poly.red/gpu is a backend-agnostic GPU abstraction, a WebGPU-style
Device/Queue/Buffer/Pipeline/CommandEncoder API for running compute
and rendering pipelines, with a driver (Metal today) underneath. It is
cgo-free: the Metal/Objective-C runtime is reached through
ebitengine/purego, so it builds with
CGO_ENABLED=0.
Shaders are written in Go and compiled to the backend's shading language by
poly.red/gpu/shader: compute, vertex, and fragment kernels, with varyings,
uniforms, vector math, and control flow.
dev, _ := gpu.Open() // Metal on darwin
defer dev.Close()
// Shaders authored in Go, compiled to MSL.
ks, _ := shader.Compile(`
package kernels
type Vec4 struct{ X, Y, Z, W float32 }
type VOut struct {
Pos Vec4 ` + "`gpu:\"position\"`" + `
Color Vec4
}
//gpu:vertex
func VMain(vid uint, pos []float32, col []float32) VOut {
return VOut{Vec4{pos[vid*2], pos[vid*2+1], 0, 1}, Vec4{col[vid*3], col[vid*3+1], col[vid*3+2], 1}}
}
//gpu:fragment
func FMain(in VOut) Vec4 { return in.Color }
`)
// ... build a render pipeline, render to a texture, read pixels back.See the runnable end-to-end example:
go run ./cmd/gpudemo -o triangle.png # Go shaders -> Metal -> PNG, cgo-freeThe design, decisions, and roadmap live in
docs/gpu-abstraction.md; implementation specs are in
specs/.
| Capability | State |
|---|---|
Device API (buffers, bind groups, compute + render pipelines, passes, textures, samplers) |
working |
| Metal backend (compute + render), cgo-free via purego | working |
| Go→shader compiler (compute + vertex/fragment, varyings, uniforms, vector + matrix math, swizzle, texture sampling, trig, control flow) | working |
Renderer deferred pass fully offloaded to the GPU (render.GPU(dev)): point + directional lights, multi-material, shadow maps (one and many casting lights), ambient occlusion, gamma |
working, CPU-parity verified |
| OpenGL ES + Vulkan backends (cgo-free, via purego): compute through the Device API verified in CI on Mesa (llvmpipe / lavapipe, software, headless); GL also does render-to-texture | working |
| DirectX 12 backend, on-screen windowed present | planned, gated on Windows / a display, not design |
The renderer offloads its full deferred shading pass to the GPU when a device is supplied:
dev, _ := gpu.Open()
img := render.NewRenderer(
render.Camera(cam), render.Size(w, h), render.Scene(s),
render.ShadowMap(true),
render.GPU(dev), // deferred shading (lights, materials, shadows, AO) runs on the GPU
).Render()cgo-free build/test of the Metal GPU stack on darwin:
CGO_ENABLED=0 go test ./gpu ./gpu/mtl ./gpu/shader ./gpu/testsCI runs build + vet + tests on macOS, Linux, and Windows; all three are green.
Windows window present was ported to the modern textured-quad GLES blit so it
builds again; displaying a window there is not yet runtime-verified (see
specs/README.md, Known issues).