Skip to content

gogpu/gogpu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

172 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

GoGPU Logo

GoGPU

Pure Go GPU Computing Ecosystem
GPU power, Go simplicity. Zero CGO.

CI codecov Go Reference Go Report Card License Latest Release Go Version Stars


Overview

GoGPU is a GPU computing framework for Go that provides a high-level API for graphics and compute operations. It supports dual backends: a high-performance Rust backend (wgpu-native) and a pure Go backend for zero-dependency builds.

Key Features

Category Capabilities
Backends Rust (wgpu-native) or Pure Go (gogpu/wgpu)
Graphics API Runtime selection: Vulkan, DX12, Metal, GLES, Software
Platforms Windows (Vulkan/DX12/GLES), Linux X11/Wayland (Vulkan/GLES), macOS (Metal)
Rendering Event-driven three-state model (idle/animating/continuous), zero-copy surface rendering
Graphics Windowing, input handling, texture loading, frameless windows
Compute Full compute shader support
Window Chrome Frameless windows with custom title bars, DWM shadow, hit-test regions
HiDPI Per-monitor DPI, WM_DPICHANGED, logical/physical coordinate split
Integration DeviceProvider, WindowProvider, PlatformProvider, WindowChrome, SurfaceView
Logging Structured logging via log/slog, silent by default
Build Zero CGO with Pure Go backend

Installation

go get github.com/gogpu/gogpu

Requirements:

  • Go 1.25+
  • CGO_ENABLED=0 (Pure Go FFI requires CGO disabled)

Zero dependencies — just works:

CGO_ENABLED=0 go run .

Note: On macOS and some Linux distros, CGO is enabled by default. Always set CGO_ENABLED=0 when building GoGPU projects.


Quick Start

package main

import (
    "github.com/gogpu/gogpu"
    "github.com/gogpu/gogpu/gmath"
)

func main() {
    app := gogpu.NewApp(gogpu.DefaultConfig().
        WithTitle("Hello GoGPU").
        WithSize(800, 600))

    app.OnDraw(func(dc *gogpu.Context) {
        dc.DrawTriangleColor(gmath.DarkGray)
    })

    app.Run()
}

Result: A window with a rendered triangle in approximately 20 lines of code, compared to 480+ lines of raw WebGPU.


Backend Selection

GoGPU supports two WebGPU implementations, selectable at compile time or runtime.

Build Tags

# Pure Go backend (default, zero dependencies)
go build ./...

# Enable Rust backend (requires wgpu-native shared library)
go build -tags rust ./...

Runtime Selection

// Auto-select best available (default)
app := gogpu.NewApp(gogpu.DefaultConfig())

// Explicit Rust backend
app := gogpu.NewApp(gogpu.DefaultConfig().WithBackend(gogpu.BackendRust))

// Explicit Pure Go backend
app := gogpu.NewApp(gogpu.DefaultConfig().WithBackend(gogpu.BackendGo))
Backend Build Tag Library Use Case
Native Go (default) gogpu/wgpu Zero dependencies, simple deployment
Rust -tags rust wgpu-native via FFI Maximum performance (all platforms)

Note: Rust backend requires wgpu-native DLL.

Graphics API Selection

Backend (Rust/Native) and Graphics API (Vulkan/DX12/Metal/GLES) are independent choices:

// Force Vulkan on Windows (instead of auto-detected default)
app := gogpu.NewApp(gogpu.DefaultConfig().
    WithGraphicsAPI(gogpu.GraphicsAPIVulkan))

// Force DirectX 12 on Windows
app := gogpu.NewApp(gogpu.DefaultConfig().
    WithGraphicsAPI(gogpu.GraphicsAPIDX12))

// Force GLES (useful for testing or compatibility)
app := gogpu.NewApp(gogpu.DefaultConfig().
    WithGraphicsAPI(gogpu.GraphicsAPIGLES))

// Software backend — no GPU required, always available
// Windows: renders to screen via GDI. Linux/macOS: headless.
app := gogpu.NewApp(gogpu.DefaultConfig().
    WithGraphicsAPI(gogpu.GraphicsAPISoftware))
Graphics API Platforms Constant
Auto All (default) gogpu.GraphicsAPIAuto
Vulkan Windows, Linux gogpu.GraphicsAPIVulkan
DX12 Windows gogpu.GraphicsAPIDX12
Metal macOS gogpu.GraphicsAPIMetal
GLES Windows, Linux gogpu.GraphicsAPIGLES
Software All (no GPU needed) gogpu.GraphicsAPISoftware

Resource Management

GPU resources are automatically cleaned up on shutdown when registered with TrackResource:

canvas, _ := ggcanvas.New(provider, 800, 600)
app.TrackResource(canvas) // auto-closed on shutdown, no OnClose needed

Resources are closed in LIFO (reverse) order after GPU idle, before device destruction. The shutdown sequence is: WaitIdle → tracked resources → OnClose → Renderer.Destroy().

ggcanvas auto-registration: When created via a provider that implements ResourceTracker (like App), ggcanvas auto-registers — no TrackResource call needed.

GC safety net: Textures use runtime.AddCleanup as a fallback — if you forget Destroy(), the GC will eventually clean up GPU resources. This is a safety net, not a replacement for explicit cleanup.


Texture Loading

// Load from file (PNG, JPEG)
tex, err := renderer.LoadTexture("sprite.png")
defer tex.Destroy()

// Create from Go image
img := image.NewRGBA(image.Rect(0, 0, 128, 128))
tex, err := renderer.NewTextureFromImage(img)

// With custom filtering options
opts := gogpu.TextureOptions{
    MagFilter:    gputypes.FilterModeNearest,  // Crisp pixels
    AddressModeU: gputypes.AddressModeRepeat,  // Tiling
}
tex, err := renderer.LoadTextureWithOptions("tile.png", opts)

DeviceProvider Interface

GoGPU exposes GPU resources through the DeviceProvider interface for integration with external libraries:

type DeviceProvider interface {
    Device() hal.Device              // HAL GPU device (type-safe Go interface)
    Queue() hal.Queue                // HAL command queue
    SurfaceFormat() gputypes.TextureFormat
}

// Usage
provider := app.DeviceProvider()
device := provider.Device()   // hal.Device — 30+ methods with error returns
queue := provider.Queue()     // hal.Queue — Submit, WriteBuffer, ReadBuffer

Cross-Package Integration (gpucontext)

For integration with external libraries like gogpu/gg, use the standard gpucontext interfaces:

import "github.com/gogpu/gpucontext"

// Get gpucontext.DeviceProvider for external libraries
provider := app.GPUContextProvider()
device := provider.Device()   // gpucontext.Device interface
queue := provider.Queue()     // gpucontext.Queue interface
format := provider.SurfaceFormat() // gpucontext.TextureFormat

// Get gpucontext.EventSource for UI frameworks
events := app.EventSource()
events.OnKeyPress(func(key gpucontext.Key, mods gpucontext.Modifiers) {
    // Handle keyboard input
})
events.OnMousePress(func(button gpucontext.MouseButton, x, y float64) {
    // Handle mouse click
})

This enables enterprise-grade dependency injection between packages without circular imports.

HalProvider (Direct GPU Access)

For GPU accelerators that need low-level HAL access (compute shaders, buffer readback):

import "github.com/gogpu/gpucontext"

provider := app.GPUContextProvider()

// Type-assert to HalProvider for direct HAL access
if hp, ok := provider.(gpucontext.HalProvider); ok {
    halDevice := hp.HalDevice() // hal.Device for compute pipelines
    halQueue := hp.HalQueue()   // hal.Queue for command submission
}

Used by gogpu/gg GPU SDF accelerator for compute shader dispatch on shared device.

SurfaceView (Zero-Copy Rendering)

For direct GPU rendering without CPU readback:

app.OnDraw(func(dc *gogpu.Context) {
    view := dc.SurfaceView() // Current frame's GPU texture view
    // Pass to ggcanvas.RenderDirect() for zero-copy compositing
})

This eliminates the GPU→CPU→GPU round-trip when integrating with gg/ggcanvas.

Window & Platform Integration

App implements gpucontext.WindowProvider and gpucontext.PlatformProvider for UI frameworks:

// Window geometry and DPI
w, h := app.Size()              // logical points (DIP)
fw, fh := app.PhysicalSize()    // physical pixels (framebuffer)
scale := app.ScaleFactor()      // 1.0 = standard, 2.0 = Retina/HiDPI

// Clipboard
text, _ := app.ClipboardRead()
app.ClipboardWrite("copied text")

// Cursor management
app.SetCursor(gpucontext.CursorPointer)  // hand cursor
app.SetCursor(gpucontext.CursorText)     // I-beam for text input

// System preferences
if app.DarkMode() { /* switch to dark theme */ }
if app.ReduceMotion() { /* disable animations */ }
if app.HighContrast() { /* increase contrast */ }
fontMul := app.FontScale() // user's font size preference

Ebiten-Style Input Polling

For game loops, use the polling-based Input API:

import "github.com/gogpu/gogpu/input"

app.OnUpdate(func(dt float64) {
    inp := app.Input()

    // Keyboard
    if inp.Keyboard().JustPressed(input.KeySpace) {
        player.Jump()
    }
    if inp.Keyboard().Pressed(input.KeyLeft) {
        player.MoveLeft(dt)
    }

    // Mouse
    x, y := inp.Mouse().Position()
    if inp.Mouse().JustPressed(input.MouseButtonLeft) {
        player.Shoot(x, y)
    }
})

All input methods are thread-safe and work with the frame-based update loop.

Event-Driven Rendering

GoGPU uses a three-state rendering model for optimal power efficiency:

State Condition CPU Usage Latency
Idle No activity 0% (blocks on OS events) <1ms wakeup
Animating Active animation tokens VSync (~60fps) Smooth
Continuous ContinuousRender=true 100% (game loop) Immediate
// Event-driven mode (default for UI apps)
app := gogpu.NewApp(gogpu.DefaultConfig().
    WithContinuousRender(false))

// Start animation — renders at VSync while token is alive
token := app.StartAnimation()
// ... animation runs at 60fps ...
token.Stop() // Loop returns to idle (0% CPU)

// Request single-frame redraw from any goroutine
app.RequestRedraw()

Multiple animation tokens can be active simultaneously. The loop renders continuously until all tokens are stopped.

Resource Cleanup

Use OnClose to release GPU resources before the renderer is destroyed:

app.OnClose(func() {
    if canvas != nil {
        _ = canvas.Close()
        canvas = nil
    }
})

if err := app.Run(); err != nil {
    log.Fatal(err)
}

OnClose runs on the render thread before Renderer.Destroy(), ensuring textures, bind groups, and pipelines are released while the device is still alive.


Compute Shaders

Full compute shader support via HAL interfaces:

// Create compute pipeline via HAL device
pipeline, _ := device.CreateComputePipeline(&hal.ComputePipelineDescriptor{
    Layout:     pipelineLayout,
    Module:     shaderModule,
    EntryPoint: "main",
})

// Create storage buffers
inputBuffer, _ := device.CreateBuffer(&hal.BufferDescriptor{
    Size:  dataSize,
    Usage: gputypes.BufferUsageStorage | gputypes.BufferUsageCopyDst,
})

// Dispatch compute work via command encoder
encoder, _ := device.CreateCommandEncoder()
encoder.BeginEncoding("compute")
pass := encoder.BeginComputePass(&hal.ComputePassDescriptor{})
pass.SetPipeline(pipeline)
pass.SetBindGroup(0, bindGroup, nil)
pass.Dispatch(workgroupsX, 1, 1)
pass.End()
cmdBuf := encoder.EndEncoding()
queue.Submit([]hal.CommandBuffer{cmdBuf}, nil, 0)

Logging

GoGPU uses log/slog for structured logging, silent by default:

import "log/slog"

// Enable info-level logging
gogpu.SetLogger(slog.Default())

// Enable debug-level logging for full diagnostics
gogpu.SetLogger(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
    Level: slog.LevelDebug,
})))

// Get current logger
logger := gogpu.Logger()

Log levels: Debug (texture creation, pipeline state), Info (backend selected, adapter info), Warn (resource cleanup errors).


Architecture

GoGPU uses multi-thread architecture (Ebiten/Gio pattern) for professional responsiveness:

  • Main thread: Window events only (Win32/Cocoa/X11 message pump)
  • Render thread: All GPU operations (device, swapchain, commands)

This ensures windows never show "Not Responding" during heavy GPU operations.

User Application
       │
       ▼
┌─────────────────────────────────────────────────────────┐
│                      gogpu.App                          │
│    Multi-Thread: Events (main) + Render (dedicated)     │
└─────────────────────────────────────────────────────────┘
       │
       ▼
┌─────────────────────────────────────────────────────────┐
│                    gogpu.Renderer                       │
│  Uses hal.Device / hal.Queue directly (Go interfaces)   │
└─────────────────────────────────────────────────────────┘
       │
       ├─────────────────┐
       ▼                 ▼
┌─────────────┐  ┌─────────────┐
│  gogpu/wgpu │  │  Platform   │
│ (Pure Go    │  │  Windowing  │
│  WebGPU)    │  │ Win32/Cocoa │
└──────┬──────┘  └─────────────┘
       │
 ┌─────┴─────┬─────┬─────┬─────────┐
 ▼           ▼     ▼     ▼         ▼
Vulkan     DX12  Metal  GLES   Software

Package Structure

Package Purpose
gogpu (root) App, Config, Context, Renderer, Texture
gpu/ Backend selection (HAL-based)
gpu/types/ BackendType, GraphicsAPI enums
gpu/backend/rust/ Rust backend via wgpu-native FFI (opt-in, -tags rust)
gpu/backend/native/ HAL backend creation (Vulkan/Metal selection)
gmath/ Vec2, Vec3, Vec4, Mat4, Color
window/ Window configuration
input/ Keyboard and mouse input
internal/platform/ Platform-specific windowing
internal/thread/ Multi-thread rendering (RenderLoop)

Platform Support

Windows

Native Win32 windowing with Vulkan, DirectX 12, GLES, and Software backends.

Linux

X11 and Wayland support with Vulkan, GLES, and Software (headless) backends.

  • X11 — pure Go X11 protocol with libX11 loaded via goffi for Vulkan surface creation. Multi-touch input via XInput2 wire protocol.
  • Wayland — pure Go Wayland protocol (object dispatch) with libwayland-client via goffi for Vulkan surfaces. Server-side decorations via zxdg_decoration_manager_v1. Tested on WSLg, GNOME, KDE, sway.

macOS

Pure Go Cocoa implementation via goffi Objective-C runtime, with Metal and Software (headless) backends:

internal/platform/darwin/
├── application.go   # NSApplication lifecycle
├── window.go        # NSWindow, NSView management
├── surface.go       # CAMetalLayer integration
└── objc.go          # Objective-C runtime via goffi

Note: macOS Cocoa requires UI operations on the main thread. GoGPU handles this automatically.


Ecosystem

Project Description
gogpu/gogpu GPU framework (this repo)
gogpu/gpucontext Shared interfaces (DeviceProvider, WindowProvider, PlatformProvider, EventSource)
gogpu/gputypes Shared WebGPU types (TextureFormat, BufferUsage, Limits)
gogpu/wgpu Pure Go WebGPU implementation
gogpu/naga Shader compiler (WGSL to SPIR-V, MSL, GLSL)
gogpu/gg 2D graphics library
gogpu/ui GUI toolkit (planned)
go-webgpu/webgpu wgpu-native FFI bindings
go-webgpu/goffi Pure Go FFI library

Documentation

Articles


Contributing

Contributions welcome! See GitHub Discussions to share ideas and ask questions.

Priority areas:

  • Platform testing (macOS, Linux X11/Wayland, Windows DX12)
  • Documentation and examples
  • Performance benchmarks
  • Bug reports
git clone https://github.com/gogpu/gogpu
cd gogpu
go build ./...
go test ./...

Acknowledgments

Professor Ancha Baranova — This project would not have been possible without her invaluable help and support.

Inspiration

Contributors

Contributor Contributions
@ppoage macOS ARM64 (Apple Silicon) support — 3 merged PRs across gogpu, wgpu, and naga with ~3,500 lines of code. Made Metal backend work on M1/M4
@JanGordon Documentation fix (wgpu)

Community Champions

Champion Contributions
@darkliquid · Andrew Montgomery Linux platform hero — 3 bug reports, 13+ comments with detailed stack traces and diagnostics. His persistence uncovered the critical goffi stack spill bug affecting all Linux/macOS users
@i2534 Most prolific gg tester — 7 bug reports covering alpha blending, patterns, transforms, and line joins. Shaped the quality of the 2D renderer
@qq1792569310 · luomo Early stress-tester — 3 issues and 9 comments. Found memory leak and event system bugs that improved framework stability
@rcarlier · Richard Carlier Cross-platform tester — 4 issues across gg and ui. Active tester of text rendering, image handling, and UI on macOS Apple Silicon (M3)
@amortaza · Afshin Mortazavi-Nia Architecture contributor — deep multi-week engagement in gg+gogpu integration discussions. Author of go-bellina UI library
@cyberbeast · Sandesh Gade macOS Tahoe debugger — thorough Metal backend debugging on Apple M2 Max with detailed diagnostics
@crsolver UI architecture advisor — significant input on the UI toolkit RFC with 8+ discussion comments
@neurlang Wayland expert — author of neurlang/wayland, provided expert consultation on Wayland protocol issues

Early Adopters

These developers tested GoGPU on Day 1 — when nothing worked and every platform was broken. Their bug reports shaped the project:


License

MIT License — see LICENSE for details.


GoGPU — Building the GPU computing ecosystem Go deserves