๐Ÿ“š gogpu/gg - Awesome Go Library for Images

Go Gopher mascot for gogpu/gg

GPU-accelerated 2D rendering with Canvas-like API, zero CGO (part of [GoGPU](https://github.com/gogpu) pure Go graphics ecosystem)

๐Ÿท๏ธ Images
๐Ÿ“‚ Images
โญ 0 stars
View on GitHub ๐Ÿ”—

Detailed Description of gogpu/gg

gg

2D Graphics Library for Go
Pure Go | GPU Accelerated | Production Ready

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

Part of the GoGPU ecosystem


Overview

gg is a 2D graphics library for Go designed to power IDEs, browsers, and graphics-intensive applications. Built with modern patterns inspired by vello and tiny-skia, it delivers production-grade rendering with zero CGO dependencies.

Six-Tier GPU Rendering: SDF shapes, convex polygons, stencil+cover paths, MSDF text, Vello compute pipeline, glyph mask cache
Six-tier GPU rendering: SDF shapes, convex polygons, stencil+cover paths, MSDF text, Vello compute, and glyph mask cache. Pure Go, Vulkan/DX12/GLES backends, zero CGO. (source)

Key Features

CategoryCapabilities
RenderingImmediate and retained mode, six-tier GPU acceleration (SDF, Convex, Stencil+Cover, MSDF Text, Compute, Glyph Mask), Vello analytic AA, GPU scissor rect clipping, CPU fallback
ShapesRectangles, circles, ellipses, arcs, bezier curves, polygons, stars
TextTrueType fonts, MSDF + glyph mask dual-strategy rendering, TextMode auto-selection, DPI-aware HiDPI text, ClearType LCD subpixel rendering, font hinting (auto-hinter), transform-aware CPU text (scale/rotate/shear), glyph outline caching, emoji support, bidirectional text, HarfBuzz shaping
Compositing29 blend modes (Porter-Duff, Advanced, HSL), layer isolation, alpha masks (per-shape, per-layer, luminance, post-process)
Images7 pixel formats, PNG/JPEG/WebP I/O, mipmaps, affine transforms
SVGFull SVG renderer (gg/svg): parse + render SVG XML with color override for theming, SVG path data parser (ParseSVGPath), transform-aware FillPath/StrokePath
Vector ExportRecording system with PDF and SVG backends
RasterizerSmart per-path algorithm selection (scanline, 4ร—4 tiles, 16ร—16 tiles, SDF, compute), text-aware area-based routing
PerformanceTile-based parallel rendering, LRU caching

Installation

go get github.com/gogpu/gg

Requirements: Go 1.25+


Quick Start

package main

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

func main() {
    // Create drawing context
    dc := gg.NewContext(512, 512)
    defer dc.Close()

    dc.ClearWithColor(gg.White)

    // Draw shapes
    dc.SetHexColor("#3498db")
    dc.DrawCircle(256, 256, 100)
    dc.Fill()

    // Render text
    source, _ := text.NewFontSourceFromFile("arial.ttf")
    defer source.Close()

    dc.SetFont(source.Face(32))
    dc.SetColor(gg.Black)
    dc.DrawString("Hello, GoGPU!", 180, 260)

    dc.SavePNG("output.png")
}

Rendering

Software Rendering (Default)

The CPU rasterizer automatically selects the optimal algorithm per-path:

AlgorithmTilesBest For
AnalyticFiller (scanline)โ€”Simple paths, small shapes (< 32px)
SparseStrips4ร—4Complex paths, CPU/SIMD workloads
TileCompute16ร—16Extreme complexity (10K+ segments)
dc := gg.NewContext(800, 600)
defer dc.Close()

// Auto-selection (default) โ€” optimal algorithm per-path
dc.DrawCircle(400, 300, 100)
dc.Fill()

// Force specific algorithm for benchmarking
dc.SetRasterizerMode(gg.RasterizerSparseStrips)

GPU Acceleration (Optional)

gg supports optional GPU acceleration through the GPUAccelerator interface with a six-tier rendering pipeline:

TierMethodBest For
SDFSigned Distance FieldCircles, ellipses, rectangles, rounded rects
ConvexDirect vertex emissionConvex polygons, single draw call
Stencil+CoverFan tessellation + stencil bufferArbitrary complex paths, EvenOdd/NonZero fill
MSDF TextMulti-channel Signed Distance FieldDynamic/animated text, resolution-independent
Compute9-stage Vello compute pipelineFull scenes with many paths (GPU parallel rasterization)
Glyph MaskCPU-rasterized R8 alpha atlasStatic UI text โ‰ค48px, pixel-perfect quality

Tiers 1โ€“4, 6 use a render-pass pipeline; Tier 5 uses compute shaders dispatched via PipelineMode (Auto/RenderPass/Compute). Text auto-selection routes horizontal text โ‰ค48px to Glyph Mask (Skia/Chrome pattern), else MSDF.

When no GPU is registered, rendering uses the high-quality CPU rasterizer (default).

import (
    "github.com/gogpu/gg"
    _ "github.com/gogpu/gg/gpu" // opt-in GPU acceleration
)

func main() {
    // GPU automatically used when available, falls back to CPU
    dc := gg.NewContext(800, 600)
    defer dc.Close()

    dc.DrawCircle(400, 300, 100)
    dc.Fill() // tries GPU first, falls back to CPU transparently
}

For zero-copy rendering directly to a GPU surface (e.g., in a gogpu window), use ggcanvas.Canvas.RenderDirect โ€” see the gogpu integration example. The example uses event-driven rendering with AnimationToken for power-efficient VSync (0% CPU when idle).

Custom Pixmap

// Use existing pixmap
pm := gg.NewPixmap(800, 600)
dc := gg.NewContext(800, 600, gg.WithPixmap(pm))

Architecture

                        gg (Public API)
                             โ”‚
         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
         โ”‚                   โ”‚                   โ”‚
   Immediate Mode       Retained Mode        Resources
   (Context API)        (Scene Graph)     (Images, Fonts)
         โ”‚                   โ”‚                   โ”‚
         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                             โ”‚
              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
              โ”‚                             โ”‚
         CPU Raster                   GPUAccelerator
      (always available)            (opt-in via gg/gpu)
              โ”‚                             โ”‚
    internal/raster              โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                                 โ”‚          โ”‚          โ”‚
                           Render Pass   MSDF Text   Compute
                          (Tiers 1-3)   (Tier 4)   (Tier 5)

Rendering Structure

ComponentLocationDescription
CPU Rasterinternal/raster/Scanline analytic AA (hybrid: Vello coverage + Skia/tiny-skia edge infrastructure)
Tile Rasterizersinternal/gpu/ (4ร—4), internal/gpu/tilecompute/ (16ร—16)SparseStrips + TileCompute, both ported from Vello
GPU Acceleratorinternal/gpuSix-tier GPU pipeline (SDF, Convex, Stencil+Cover, MSDF Text, Compute, Glyph Mask)
GPU + Tilesgpu/Opt-in via import _ "github.com/gogpu/gg/gpu" (GPU + tile rasterizers)
Tiles Onlyraster/Opt-in via import _ "github.com/gogpu/gg/raster" (CPU-only tiles)
SoftwareRoot gg packageDefault CPU renderer with smart algorithm selection

Core APIs

Immediate Mode (Context)

Canvas-style drawing with transformation stack:

dc := gg.NewContext(800, 600)
defer dc.Close()

// Transforms
dc.Push()
dc.Translate(400, 300)
dc.Rotate(math.Pi / 4)
dc.DrawRectangle(-50, -50, 100, 100)
dc.SetRGB(0.2, 0.5, 0.8)
dc.Fill()
dc.Pop()

// Bezier paths
dc.MoveTo(100, 100)
dc.QuadraticTo(200, 50, 300, 100)
dc.CubicTo(350, 150, 350, 250, 300, 300)
dc.SetLineWidth(3)
dc.Stroke()

Fluent Path Builder

Type-safe path construction with method chaining:

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).
    Build()

dc.SetPath(path)
dc.Fill()

Retained Mode (Scene Graph)

GPU-optimized scene graph for complex applications:

import "github.com/gogpu/gg/render"

s := render.NewScene()

s.SetFillColor(color.RGBA{R: 255, A: 200})
s.Circle(150, 200, 100)
s.Fill()

s.SetFillColor(color.RGBA{B: 255, A: 200})
s.Circle(250, 200, 100)
s.Fill()

renderer := render.NewSoftwareRenderer()
target := render.NewPixmapTarget(800, 600)
renderer.Render(target, s)

Text Rendering

Full Unicode support with font fallback and optional HarfBuzz-level shaping:

// Font composition
mainFont, _ := text.NewFontSourceFromFile("Roboto.ttf")
emojiFont, _ := text.NewFontSourceFromFile("NotoEmoji.ttf")
defer mainFont.Close()
defer emojiFont.Close()

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

dc.SetFont(multiFace)
dc.DrawString("Hello World! Nice day!", 50, 100)

// Optional: enable HarfBuzz shaping for ligatures, kerning, complex scripts
shaper := text.NewGoTextShaper()
text.SetShaper(shaper)
defer text.SetShaper(nil)

// Text layout with wrapping
opts := text.LayoutOptions{
    MaxWidth:  400,
    WrapMode:  text.WrapWordChar,
    Alignment: text.AlignCenter,
}
layout := text.LayoutText("Long text...", face, opts)

Transform-Aware Text

Text rendering respects the full transformation matrix (scale, rotation, shear):

dc.SetFont(source.Face(24))
dc.SetRGB(0, 0, 0)

// Scaled text โ€” rendered at device resolution (no pixelation)
dc.Push()
dc.Scale(2, 2)
dc.DrawString("2x Scale", 50, 50)
dc.Pop()

// Rotated text โ€” glyph outlines converted to vector paths
dc.Push()
dc.Translate(200, 200)
dc.Rotate(math.Pi / 6) // 30 degrees
dc.DrawString("Rotated", 0, 0)
dc.Pop()

Text rendering strategy is selectable per-Context via SetTextMode():

ModeStrategyBest for
TextModeAutoAuto-select (default)General use
TextModeMSDFGPU MSDF atlasGames, animations, real-time scaling
TextModeVectorGlyph outlines as pathsUI labels, quality-critical text
TextModeBitmapCPU bitmap rasterizationPNG/PDF export, static text

The CPU text pipeline uses a three-tier strategy (modeled after Skia/Cairo/Vello): translation-only โ†’ bitmap, uniform scale โ‰ค256px โ†’ bitmap at device size, everything else โ†’ glyph outlines as vector paths with cached outlines via GlyphCache.

Color Emoji

Full color emoji support with CBDT/CBLC (bitmap) and COLR/CPAL (vector) formats:

COLR Color Palette
175 colors from Segoe UI Emoji COLR/CPAL palette

// Extract color emoji from font
extractor, _ := emoji.NewCBDTExtractor(cbdtData, cblcData)
glyph, _ := extractor.GetGlyph(glyphID, ppem)
img, _ := png.Decode(bytes.NewReader(glyph.Data))

// Parse COLR/CPAL vector layers
parser, _ := emoji.NewCOLRParser(colrData, cpalData)
glyph, _ := parser.GetGlyph(glyphID, paletteIndex)
for _, layer := range glyph.Layers {
    // Render each layer with layer.Color
}

See examples/color_emoji/ for a complete example.

Layer Compositing

29 blend modes with isolated layers:

dc.PushLayer(gg.BlendOverlay, 0.7)

dc.SetRGB(1, 0, 0)
dc.DrawCircle(150, 200, 100)
dc.Fill()

dc.SetRGB(0, 0, 1)
dc.DrawCircle(250, 200, 100)
dc.Fill()

dc.PopLayer()

Alpha Masks

Per-shape masking โ€” each draw individually masked:

// Create a circular mask
dc.DrawCircle(200, 200, 100)
mask := dc.AsMask() // capture path as mask (before Fill!)
dc.ClearPath()

// Apply mask: only the circle area is visible
dc.SetMask(mask)
dc.SetRGB(0, 0, 1)
dc.DrawRectangle(0, 0, 400, 400)
dc.Fill() // blue only inside the circle

Per-layer masking โ€” mask an entire group of draws:

mask := gg.NewMask(400, 400)
// ... fill mask with desired shape ...

dc.PushMaskLayer(mask)
dc.DrawCircle(100, 100, 50)
dc.Fill()
dc.DrawRectangle(200, 200, 80, 80)
dc.Fill()
dc.PopLayer() // entire layer masked, then composited

Recording & Vector Export

Record drawing operations and export to PDF or SVG:

import (
    "github.com/gogpu/gg/recording"
    _ "github.com/gogpu/gg-pdf" // Register PDF backend
    _ "github.com/gogpu/gg-svg" // Register SVG backend
)

// Create recorder
rec := recording.NewRecorder(800, 600)

// Draw using familiar API
rec.SetColor(gg.Blue)
rec.DrawCircle(400, 300, 100)
rec.Fill()

// Finish recording and play back to a raster backend
r := rec.FinishRecording()
backend := raster.NewBackend()
r.Playback(backend)
backend.SaveToFile("output.png")

Why "Context" Instead of "Canvas"?

The drawing type is named Context following industry conventions:

LibraryDrawing Type
HTML5 CanvasCanvasRenderingContext2D
Cairocairo_t (context)
Apple CoreGraphicsCGContext
piet (Rust)RenderContext

In HTML5, Canvas is the element while Context performs drawing (canvas.getContext("2d")). The Context contains drawing state and provides the drawing API.

Convention: dc for drawing context, ctx for context.Context:

dc := gg.NewContext(512, 512) // dc = drawing context

Performance

OperationTimeNotes
sRGB to Linear0.16ns260x faster than math.Pow
LayerCache.Get90nsThread-safe LRU
DirtyRegion.Mark10.9nsLock-free atomic
MSDF lookup<10nsZero-allocation
Path iteration23nsSOA Iterate(), 0 allocs
FillRect77ยตs0 allocs (zero-alloc pipeline)
FillCircle r1002ms0 allocs (zero-alloc pipeline)
Gradient ColorAt33ns0 allocs (pre-sorted stops)

Ecosystem

gg is part of the GoGPU ecosystem.

ProjectDescription
gogpu/gogpuGPU framework with windowing and input
gogpu/wgpuPure Go WebGPU implementation
gogpu/nagaShader compiler (WGSL to SPIR-V, MSL, GLSL)
gogpu/gg2D graphics (this repo)
gogpu/gg-pdfPDF export backend for recording
gogpu/gg-svgSVG export backend for recording
gogpu/uiGUI toolkit (planned)

Documentation

Articles


Contributing

Contributions welcome! See CONTRIBUTING.md for guidelines.

Priority areas:

  • API feedback and testing
  • Examples and documentation
  • Performance benchmarks
  • Cross-platform testing

License

MIT License โ€” see LICENSE for details.


gg โ€” 2D Graphics for Go