DEV Community

Cover image for gogpu/gg: Enterprise 2D Graphics Library in Pure Go
Andrey Kolkov
Andrey Kolkov

Posted on

gogpu/gg: Enterprise 2D Graphics Library in Pure Go

Latest: v0.20.0 β€” Enterprise-grade GPU backend, color emoji, anti-aliased rendering. Part of the 280K+ LOC Pure Go graphics ecosystem.

Previous: GPU Compute Shaders in Pure Go (v0.15.0)

What is gogpu/gg?

gg is a production-grade 2D graphics library for Go, designed to power:

  • IDEs β€” Syntax highlighting, code rendering, UI components
  • Browsers β€” Canvas-like rendering, WebGPU acceleration
  • Professional apps β€” Vector graphics, data visualization, games

Key differentiator: Pure Go. No CGO. No external dependencies. Just go build.

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

Feature Overview

Category Capabilities
Drawing Rectangles, circles, ellipses, arcs, lines, polygons, stars, bezier curves
Paths MoveTo, LineTo, QuadraticTo, CubicTo, ArcTo, Close + fluent PathBuilder
Text TrueType fonts, MSDF rendering, bidirectional text, color emoji
Images PNG/JPEG I/O, 7 pixel formats, affine transforms, mipmaps
Compositing 29 blend modes (Porter-Duff, Advanced, HSL), layer isolation
Rendering Software (CPU), GPU (Vulkan/Metal/DX12), hybrid auto-selection
Performance SIMD optimization, parallel tile rendering, LRU caching

Quick Start

Hello World

package main

import "github.com/gogpu/gg"

func main() {
    dc := gg.NewContext(512, 512)
    defer dc.Close()

    // Clear background
    dc.ClearWithColor(gg.White)

    // Draw anti-aliased circle
    dc.SetHexColor("#3498db")
    dc.DrawCircle(256, 256, 100)
    dc.Fill()

    // Draw stroked rectangle
    dc.SetHexColor("#e74c3c")
    dc.SetLineWidth(3)
    dc.DrawRectangle(156, 156, 200, 200)
    dc.Stroke()

    dc.SavePNG("output.png")
}
Enter fullscreen mode Exit fullscreen mode

Text Rendering

package main

import (
    "github.com/gogpu/gg"
    "github.com/gogpu/gg/text"
)

func main() {
    dc := gg.NewContext(800, 200)
    defer dc.Close()

    dc.ClearWithColor(gg.White)

    // Load font
    source, _ := text.NewFontSourceFromFile("Roboto-Regular.ttf")
    defer source.Close()

    // Render text
    dc.SetFont(source.Face(48))
    dc.SetColor(gg.Black)
    dc.DrawString("Hello, GoGPU!", 50, 100)

    // Centered text
    dc.DrawStringAnchored("Centered Text", 400, 150, 0.5, 0.5)

    dc.SavePNG("text.png")
}
Enter fullscreen mode Exit fullscreen mode

Gradients

dc := gg.NewContext(400, 400)
defer dc.Close()

// Linear gradient
grad := gg.NewLinearGradientBrush(0, 0, 400, 400)
grad.AddColorStop(0, gg.Hex("#ff6b6b"))
grad.AddColorStop(0.5, gg.Hex("#4ecdc4"))
grad.AddColorStop(1, gg.Hex("#45b7d1"))

dc.SetFillBrush(grad)
dc.DrawRectangle(0, 0, 400, 400)
dc.Fill()

dc.SavePNG("gradient.png")
Enter fullscreen mode Exit fullscreen mode

Transforms

dc := gg.NewContext(400, 400)
defer dc.Close()

dc.ClearWithColor(gg.White)

// Save state, transform, draw, restore
dc.Push()
dc.Translate(200, 200)
dc.Rotate(math.Pi / 4)  // 45 degrees
dc.Scale(1.5, 1.5)

dc.SetHexColor("#9b59b6")
dc.DrawRectangle(-50, -50, 100, 100)
dc.Fill()

dc.Pop()  // Restore original state

dc.SavePNG("transform.png")
Enter fullscreen mode Exit fullscreen mode

Canvas API

gg provides a familiar Canvas-like API inspired by HTML5 Canvas and Cairo:

Drawing Primitives

// Rectangles
dc.DrawRectangle(x, y, width, height)
dc.DrawRoundedRectangle(x, y, w, h, radius)

// Circles and ellipses
dc.DrawCircle(cx, cy, radius)
dc.DrawEllipse(cx, cy, rx, ry)
dc.DrawArc(cx, cy, r, startAngle, endAngle)

// Lines
dc.DrawLine(x1, y1, x2, y2)
dc.MoveTo(x, y)
dc.LineTo(x, y)

// Curves
dc.QuadraticTo(cx, cy, x, y)
dc.CubicTo(cx1, cy1, cx2, cy2, x, y)

// Polygons
dc.DrawPolygon(points...)
dc.DrawRegularPolygon(n, cx, cy, r, rotation)
dc.DrawStar(cx, cy, outerR, innerR, points)
Enter fullscreen mode Exit fullscreen mode

Styles

// Colors
dc.SetColor(gg.Red)
dc.SetRGB(1.0, 0.5, 0.0)
dc.SetRGBA(1.0, 0.5, 0.0, 0.8)
dc.SetHexColor("#3498db")

// Strokes
dc.SetLineWidth(2.0)
dc.SetLineCap(gg.LineCapRound)    // Butt, Round, Square
dc.SetLineJoin(gg.LineJoinMiter)  // Miter, Round, Bevel
dc.SetDash(5, 3)  // Pattern: 5px on, 3px off

// Fill and stroke
dc.Fill()
dc.Stroke()
dc.FillPreserve()   // Fill but keep path
dc.StrokePreserve() // Stroke but keep path
Enter fullscreen mode Exit fullscreen mode

Clipping

// Clip to circle
dc.DrawCircle(200, 200, 100)
dc.Clip()

// All subsequent drawing is clipped
dc.DrawImage(img, 0, 0)

dc.ResetClip()
Enter fullscreen mode Exit fullscreen mode

Fluent PathBuilder

Build complex paths with method chaining for use with Scene Graph:

import (
    "github.com/gogpu/gg"
    "github.com/gogpu/gg/scene"
)

// Build path with fluent API
path := gg.BuildPath().
    MoveTo(100, 100).
    LineTo(200, 100).
    QuadTo(250, 150, 200, 200).
    CubicTo(150, 250, 100, 250, 50, 200).
    Close().
    Circle(300, 150, 50).
    Star(400, 150, 40, 20, 5).
    RoundRect(50, 250, 100, 80, 10).
    Build()

// Use with scene graph
s := scene.NewScene()
s.Fill(scene.FillNonZero, scene.IdentityAffine(),
    scene.SolidBrush(gg.Hex("#2ecc71")), scene.NewPathShape(path))
Enter fullscreen mode Exit fullscreen mode

Available shape methods:

  • MoveTo, LineTo, QuadTo, CubicTo, Close
  • Circle, Ellipse
  • Rect, RoundRect
  • Polygon, Star

Text Rendering

Font Loading

// From file
source, err := text.NewFontSourceFromFile("font.ttf")

// From bytes
source, err := text.NewFontSourceFromBytes(fontBytes)

// Create face at specific size
face := source.Face(24)  // 24pt
defer source.Close()
Enter fullscreen mode Exit fullscreen mode

Multi-Face (Font Fallback)

// Primary font + emoji fallback
mainFont, _ := text.NewFontSourceFromFile("Roboto.ttf")
emojiFont, _ := text.NewFontSourceFromFile("NotoColorEmoji.ttf")

multiFace, _ := text.NewMultiFace(
    mainFont.Face(16),
    text.NewFilteredFace(emojiFont.Face(16), text.RangeEmoji),
)

dc.SetFont(multiFace)
dc.DrawString("Hello World! πŸŽ‰πŸš€", 50, 100)
Enter fullscreen mode Exit fullscreen mode

Text Layout with Wrapping

opts := text.LayoutOptions{
    MaxWidth:    400,
    WrapMode:    text.WrapWordChar,  // Word-first, char fallback
    Alignment:   text.AlignCenter,
    LineSpacing: 1.2,
}

layout := text.LayoutText(longText, face, 16, opts)

// Render using glyph renderer
renderer := text.NewGlyphRenderer()
outlines := renderer.RenderLayout(layout)

// Or access line metrics directly
for _, line := range layout.Lines {
    // line.Y is the baseline Y position
    // line.Width, line.Ascent, line.Descent available
    // line.Glyphs contains positioned glyphs
}
Enter fullscreen mode Exit fullscreen mode

Color Emoji

gg supports both bitmap (CBDT/CBLC) and vector (COLR/CPAL) color emoji:

// Extract bitmap emoji (Noto Color Emoji)
extractor, _ := emoji.NewCBDTExtractor(cbdtData, cblcData)
glyph, _ := extractor.GetGlyph(glyphID, ppem)
img, _ := png.Decode(bytes.NewReader(glyph.Data))

// Parse vector emoji layers (Segoe UI Emoji)
parser, _ := emoji.NewCOLRParser(colrData, cpalData)
glyph, _ := parser.GetGlyph(glyphID, paletteIndex)
for _, layer := range glyph.Layers {
    // Render each layer with layer.Color
}
Enter fullscreen mode Exit fullscreen mode

Layer Compositing

29 Blend Modes

Porter-Duff: Clear, Src, Dst, SrcOver, DstOver, SrcIn, DstIn, SrcOut, DstOut, SrcAtop, DstAtop, Xor

Advanced: Multiply, Screen, Overlay, Darken, Lighten, ColorDodge, ColorBurn, HardLight, SoftLight, Difference, Exclusion

HSL: Hue, Saturation, Color, Luminosity

dc.PushLayer(gg.BlendMultiply, 0.8)  // Blend mode + opacity

dc.SetHexColor("#e74c3c")
dc.DrawCircle(150, 200, 100)
dc.Fill()

dc.SetHexColor("#3498db")
dc.DrawCircle(250, 200, 100)
dc.Fill()

dc.PopLayer()  // Composite layer
Enter fullscreen mode Exit fullscreen mode

Alpha Masks

// Create mask from shape
dc.DrawCircle(200, 200, 100)
dc.Fill()
mask := dc.AsMask()

// Apply mask to new context
dc2 := gg.NewContext(400, 400)
dc2.SetMask(mask)
dc2.DrawImage(backgroundImage, 0, 0)  // Only visible through mask
Enter fullscreen mode Exit fullscreen mode

Scene Graph (Retained Mode)

For complex, frequently-updated scenes:

import (
    "github.com/gogpu/gg"
    "github.com/gogpu/gg/scene"
)

s := scene.NewScene()

// Build scene graph with layer compositing
s.PushLayer(scene.BlendNormal, 1.0, nil)  // blend, alpha, clip

s.Fill(scene.FillNonZero, scene.IdentityAffine(),
    scene.SolidBrush(gg.Red), scene.NewCircleShape(150, 200, 100))

s.Fill(scene.FillNonZero, scene.IdentityAffine(),
    scene.SolidBrush(gg.Blue), scene.NewCircleShape(250, 200, 100))

s.PopLayer()

// Render to pixmap
renderer := scene.NewRenderer(width, height)
renderer.Render(s)
Enter fullscreen mode Exit fullscreen mode

Benefits:

  • GPU-optimized command batching
  • Efficient dirty region tracking
  • Parallel tile rendering

Backend Architecture

gg supports three rendering backends:

Backend Package Description Use Case
Native backend/native/ Pure Go via gogpu/wgpu Default, zero deps
Rust backend/rust/ wgpu-native FFI Max performance
Software backend/software/ CPU rasterizer Fallback
import "github.com/gogpu/gg/backend"

// Auto-select best available
b := backend.Default()

// Explicit selection
b := backend.Get(backend.BackendNative)
b := backend.Get(backend.BackendRust)     // Requires -tags rust
b := backend.Get(backend.BackendSoftware)
Enter fullscreen mode Exit fullscreen mode

GPU Backend Features (v0.20.0)

  • Command Encoder β€” State machine for GPU command recording
  • Texture Management β€” Lazy views with sync.Once
  • Buffer Mapping β€” Async with device polling
  • Pipeline Cache β€” FNV-1a descriptor hashing
  • Compute Shaders β€” WGSL shaders for path rasterization

Performance

Benchmarks

Operation Time Notes
sRGB β†’ Linear 0.16ns 260x faster than math.Pow
LayerCache.Get 90ns Thread-safe LRU
DirtyRegion.Mark 10.9ns Lock-free atomic
MSDF lookup <10ns Zero-allocation
Path iteration 438ns iter.Seq, 0 allocs

Optimizations

  • SIMD β€” Vectorized color operations
  • Parallel rendering β€” Tile-based multi-threaded rasterization
  • LRU caching β€” Glyph cache, texture cache, layer cache
  • GPU compute β€” Path flattening, tile binning, coverage calculation

Anti-Aliased Rendering

v0.19.0 introduced professional-grade anti-aliasing using the tiny-skia algorithm:

// AA is enabled by default
dc.Fill()

// Disable AA for performance
dc.FillNoAA()
Enter fullscreen mode Exit fullscreen mode

Implementation:

  • 4x supersampling with coverage accumulation
  • AlphaRuns β€” RLE-encoded sparse alpha buffer
  • SIMD batch blending for 16 pixels at a time
  • Same algorithm as Chrome, Android, Flutter

The GoGPU Ecosystem

gg is part of a complete Pure Go graphics stack:

Project Version LOC Description
gogpu/gg v0.20.0 ~122K 2D graphics (this library)
gogpu/wgpu v0.10.1 ~95K Pure Go WebGPU
gogpu/naga v0.8.4 ~33K WGSL shader compiler
gogpu/gogpu v0.11.1 ~28K Graphics framework

Total: ~280K lines of Pure Go.


Design Principles

  1. Pure Go β€” No CGO, easy cross-compilation, single binary
  2. GPU-First β€” Designed for GPU acceleration from day one
  3. Production-Ready β€” Enterprise-grade error handling, logging
  4. API Stability β€” Semantic versioning, deprecation policy

Inspired By

  • vello (Rust) β€” GPU compute shaders, sparse strips
  • tiny-skia (Rust) β€” Anti-aliasing, stroke expansion
  • kurbo (Rust) β€” Path algorithms
  • peniko (Rust) β€” Brush/paint system
  • skrifa/swash (Rust) β€” Font parsing, color emoji

Installation

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

Requirements: Go 1.25+

Build Tags

# Default: Native + Software backends
go build ./...

# With Rust backend (requires wgpu-native)
go build -tags rust ./...

# Software only
go build -tags nogpu ./...
Enter fullscreen mode Exit fullscreen mode

Examples

Complete Examples

Run Examples

cd examples/basic
go run main.go
Enter fullscreen mode Exit fullscreen mode

Documentation


Links


122K lines. Pure Go. Production-ready 2D graphics.

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

Star the repo if you find it useful!


Part of the GoGPU Journey series

Top comments (0)