DEV Community

Cover image for GoGPU Enterprise Architecture: Cross-Package GPU Integration with gpucontext
Andrey Kolkov
Andrey Kolkov

Posted on

GoGPU Enterprise Architecture: Cross-Package GPU Integration with gpucontext

Release (January 27, 2026): gogpu v0.12.0 + gg v0.21.0 — Enterprise architecture with gpucontext integration. Shared GPU interfaces enable database/sql-like dependency injection across the ecosystem.

The Problem: Circular Dependencies

As the GoGPU ecosystem grew to 300K lines of Pure Go, we hit a classic enterprise problem:

gogpu/gogpu (windowing, GPU init)
      ↓ depends on
gogpu/gg (2D graphics)
      ↓ depends on
gogpu/wgpu (WebGPU implementation)
      ↓ depends on
gogpu/naga (shader compiler)
Enter fullscreen mode Exit fullscreen mode

The challenge: How can gg receive a GPU device from gogpu without creating circular dependencies? And how will gogpu/ui receive both GPU context AND input events?

The answer: Shared interfaces in a zero-dependency package.


Introducing gpucontext

gogpu/gpucontext is a new package with zero dependencies that defines shared GPU infrastructure:

// gpucontext v0.2.0 — Zero dependencies!
import "github.com/gogpu/gpucontext"
Enter fullscreen mode Exit fullscreen mode

Core Interfaces

Interface Purpose Implemented By
DeviceProvider GPU device + queue access gogpu.App
EventSource Input events for UI gogpu.App
IMEController IME positioning for CJK input gogpu.App (future)

This follows the wgpu-types pattern from Rust — separating type definitions from implementation.


DeviceProvider: The database/sql Pattern

Just like Go's database/sql lets you swap MySQL for Postgres without changing your code, gpucontext.DeviceProvider lets libraries receive GPU resources without knowing the source:

// gpucontext/device_provider.go
type DeviceProvider interface {
    Device() Device           // Create GPU resources
    Queue() Queue             // Submit commands
    SurfaceFormat() TextureFormat  // Match surface format
    Adapter() Adapter         // GPU capabilities (optional)
}
Enter fullscreen mode Exit fullscreen mode

gogpu Implements DeviceProvider

In gogpu v0.12.0, the App now provides GPU context to external libraries:

package main

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

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

    app.OnDraw(func(dc *gogpu.Context) {
        // Get DeviceProvider for external libraries
        provider := app.GPUContextProvider()

        // All non-nil — GPU is ready!
        device := provider.Device()   // gpucontext.Device
        queue := provider.Queue()     // gpucontext.Queue
        adapter := provider.Adapter() // gpucontext.Adapter
        format := provider.SurfaceFormat() // gpucontext.TextureFormat

        // Pass to gg, ui, or any library that accepts DeviceProvider
    })

    app.Run()
}
Enter fullscreen mode Exit fullscreen mode

Key insight: The library receiving DeviceProvider doesn't need to know it came from gogpu. It could come from born-ml/born for ML compute, or a future WebAssembly host.


EventSource: Input Events for UI

Building a GUI toolkit requires more than GPU access — you need input events. The EventSource interface provides platform-independent input delivery:

// gpucontext/events.go
type EventSource interface {
    // Keyboard
    OnKeyPress(func(key Key, mods Modifiers))
    OnKeyRelease(func(key Key, mods Modifiers))
    OnTextInput(func(text string))

    // Mouse
    OnMouseMove(func(x, y float64))
    OnMousePress(func(button MouseButton, x, y float64))
    OnMouseRelease(func(button MouseButton, x, y float64))
    OnScroll(func(dx, dy float64))

    // Window
    OnResize(func(width, height int))
    OnFocus(func(focused bool))

    // IME (Chinese/Japanese/Korean input)
    OnIMECompositionStart(fn func())
    OnIMECompositionUpdate(fn func(state IMEState))
    OnIMECompositionEnd(fn func(committed string))
}
Enter fullscreen mode Exit fullscreen mode

Full IME Support for CJK Input

Enterprise applications must support international users. The IMEState struct provides everything needed for inline composition rendering:

type IMEState struct {
    Composing       bool   // Currently composing?
    CompositionText string // e.g., "nihon" → "日本"
    CursorPos       int    // Cursor within composition
    SelectionStart  int    // Selection range
    SelectionEnd    int
}
Enter fullscreen mode Exit fullscreen mode

Using EventSource

app := gogpu.NewApp(gogpu.DefaultConfig())

// Get event source
events := app.EventSource()

// Register callbacks
events.OnKeyPress(func(key gpucontext.Key, mods gpucontext.Modifiers) {
    if key == gpucontext.KeyEscape {
        app.Quit()
    }
})

events.OnMousePress(func(btn gpucontext.MouseButton, x, y float64) {
    fmt.Printf("Click at (%.0f, %.0f)\n", x, y)
})

events.OnIMECompositionUpdate(func(state gpucontext.IMEState) {
    // Render composition text inline
    renderIMEPreview(state.CompositionText, state.CursorPos)
})

app.Run()
Enter fullscreen mode Exit fullscreen mode

gg Enterprise Architecture

gg v0.21.0 introduces two new packages that leverage gpucontext:

core/ — CPU Rendering Primitives

Independent of GPU, contains pure algorithms:

gg/core/
├── fixed.go          # Fixed-point math (FDot6, FDot16)
├── edge.go           # Line/curve edges
├── edge_builder.go   # Path → edges conversion
├── analytic_filler.go # Anti-aliased rendering
└── alpha_runs.go     # RLE coverage storage
Enter fullscreen mode Exit fullscreen mode

Key principle: CPU rendering code is separate from GPU code, following Skia/Vello architecture patterns.

render/ — GPU Integration Layer

Bridges gg to host applications via gpucontext:

// gg/render/device.go
type DeviceHandle = gpucontext.DeviceProvider

// gg/render/gpu_renderer.go
// gg receives device from host, doesn't create its own
func NewGPURenderer(handle DeviceHandle) (*GPURenderer, error) {
    if handle == nil {
        return nil, errors.New("render: nil device handle")
    }
    return &GPURenderer{
        handle:           handle,
        softwareFallback: NewSoftwareRenderer(),
    }, nil
}
Enter fullscreen mode Exit fullscreen mode

Architecture:

              User Application
                    │
     ┌──────────────┼──────────────┐
     │              │              │
     ▼              ▼              ▼
  gogpu.App    gg.Context     gg.Scene
  (windowing)  (immediate)    (retained)
     │              │              │
     └──────────────┼──────────────┘
                    │
                    ▼
            gg/render package
     ┌──────────────┼──────────────┐
     │              │              │
     ▼              ▼              ▼
 DeviceHandle  RenderTarget    Renderer
 (GPU access)    (output)     (execution)
                    │
                    ▼
            gg/core package
          (CPU rasterization)
Enter fullscreen mode Exit fullscreen mode

Building gogpu/ui: The Path Forward

With gpucontext providing GPU access AND input events, gogpu/ui can now be built as a pure consumer:

// Future gogpu/ui integration
package main

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

func main() {
    app := gogpu.NewApp(gogpu.DefaultConfig())

    // ui receives BOTH GPU context AND events
    uiRoot := ui.New(
        app.GPUContextProvider(), // GPU for rendering
        app.EventSource(),        // Input for interaction
    )

    uiRoot.Add(
        ui.Box(
            ui.Text("Hello, GoGPU!").Font(ui.Title),
            ui.Button("Click Me").OnClick(func() {
                fmt.Println("Clicked!")
            }),
        ).Padding(16).Gap(12),
    )

    app.OnDraw(func(dc *gogpu.Context) {
        uiRoot.Render()
    })

    app.Run()
}
Enter fullscreen mode Exit fullscreen mode

UI Architecture Goals

Feature Implementation
Signals-based reactivity Fine-grained updates, O(affected) not O(n)
Tailwind-style API Type-safe styling, AI-friendly
Enterprise features Docking, virtualization, accessibility
Cross-platform Desktop (gogpu), Web (WASM), Mobile (WebView)

The Ecosystem Today

Project Version LOC Description
gogpu/gg v0.21.0 ~143K 2D graphics + core/render packages
gogpu/wgpu v0.10.2 ~95K Pure Go WebGPU
gogpu/naga v0.8.4 ~33K Shader compiler
gogpu/gogpu v0.12.0 ~29K GPU framework + gpucontext integration
gogpu/gpucontext v0.2.0 ~1K Shared interfaces (zero deps)
gogpu/ui GUI toolkit (in design)

Total: ~300K lines of Pure Go. No CGO. No Rust required. Just go build.


Dependency Graph

┌─────────────────────────────────────────────────────────────┐
│                    Your Application                         │
├─────────────────────────────────────────────────────────────┤
│    gogpu/ui (future)    │   born-ml/born   │   Your App     │
├─────────────────────────────────────────────────────────────┤
│                  gogpu/gg (2D Graphics)                     │
│              core/ (CPU)    render/ (GPU integration)       │
├─────────────────────────────────────────────────────────────┤
│              gogpu/gogpu (Graphics Framework)               │
│         Windowing, Input, GPU Init, DeviceProvider          │
├─────────────────────────────────────────────────────────────┤
│    gogpu/gpucontext (Shared Interfaces — ZERO DEPS)         │
│      DeviceProvider, EventSource, IME, WebGPU types         │
├─────────────────────────────────────────────────────────────┤
│                  gogpu/wgpu (Pure Go WebGPU)                │
├─────────────────────────────────────────────────────────────┤
│            Vulkan  │  Metal  │  DX12  │  GLES               │
└─────────────────────────────────────────────────────────────┘
Enter fullscreen mode Exit fullscreen mode

Try It

# Get the latest versions
go get github.com/gogpu/gogpu@v0.12.0
go get github.com/gogpu/gg@v0.21.0
go get github.com/gogpu/gpucontext@v0.2.0
Enter fullscreen mode Exit fullscreen mode

Complete Example

package main

import (
    "fmt"

    "github.com/gogpu/gogpu"
    "github.com/gogpu/gogpu/gmath"
    "github.com/gogpu/gpucontext"
)

func main() {
    app := gogpu.NewApp(gogpu.DefaultConfig().
        WithTitle("gpucontext Integration Demo").
        WithSize(800, 600))

    // Setup event handling
    events := app.EventSource()
    events.OnKeyPress(func(key gpucontext.Key, mods gpucontext.Modifiers) {
        fmt.Printf("Key: %d, Mods: %d\n", key, mods)
    })

    events.OnMousePress(func(btn gpucontext.MouseButton, x, y float64) {
        fmt.Printf("Click at (%.0f, %.0f)\n", x, y)
    })

    app.OnDraw(func(dc *gogpu.Context) {
        // Verify DeviceProvider
        provider := app.GPUContextProvider()
        if provider != nil && provider.Device() != nil {
            // GPU ready — can pass to gg or other libraries
        }

        // Draw demo triangle (red) on CornflowerBlue background
        dc.DrawTriangleColor(gmath.CornflowerBlue)
    })

    app.Run()
}
Enter fullscreen mode Exit fullscreen mode

What's Next

Q1 2026: Stabilization

  • Comprehensive benchmarks across all backends
  • Memory optimization and GPU submission batching
  • Documentation and tutorials

Q2 2026: gogpu/ui Foundation

  • Widget system with signals-based reactivity
  • Layout engine (flexbox-inspired)
  • Theme system with accessibility support

Q3 2026: gogpu/ui Enterprise Features

  • Docking and workspace management
  • Virtualized lists for large datasets
  • AccessKit integration for screen readers

Join the Discussion

We're making architectural decisions right now. Your input shapes the future of Go graphics:


Links


Enterprise-grade GPU integration. Pure Go. Zero CGO. Zero circular dependencies.

go get github.com/gogpu/gogpu@v0.12.0
Enter fullscreen mode Exit fullscreen mode

Star the repos if you find them useful!


Part of the GoGPU Journey series:

  1. GoGPU: A Pure Go Graphics Library
  2. From Idea to 100K Lines in Two Weeks
  3. GPU Compute Shaders in Pure Go
  4. Enterprise GPU Backend v0.20.0
  5. Enterprise Architecture v0.21.0 ← You are here

Top comments (0)