纯 Go 中的 GPU Compute Shaders:gogpu/gg v0.15.0

发布: (2025年12月26日 GMT+8 10:13)
5 min read
原文: Dev.to

Source: Dev.to

请提供您希望翻译的正文内容(除代码块和 URL 之外的文字),我将把它翻译成简体中文并保留原有的格式。谢谢!

GPU Compute Shaders in Pure Go: gogpu/gg v0.15.0

两天前我们 发布了 gogpu/gg v0.14.0 ,其中加入了 alpha 掩码和流畅的 PathBuilder。是的——仅两天时间,我们的进展非常快。

在查看性能分析时,我们发现了一个问题:

CPU 成为了瓶颈。

我们的 GPU 能在毫秒级渲染数百万像素,但 CPU 却花了大量时间对路径进行细分。这是经典的 2‑D 图形问题:CPU 细分无法扩展。

于是我们把整个光栅化管线迁移到了 GPU 计算着色器。

今天,gogpu/gg v0.15.0 已经发布:2 280 行 WGSL 计算着色器、vello‑style 管线、对复杂场景实现了显著的加速。全部使用 Pure Go 实现。

性能挑战

// Drawing 10 000 circles
ctx := gg.NewContext(800, 600)
for i := 0; i 
) {
    let curve = curves[id.x];

    // Adaptive subdivision based on curvature
    let segments = subdivide_bezier(curve);

    // Write to global buffer (thousands in parallel!)
    for (var i = 0u; i 
) {
    let segment = segments[id.x];
    let bounds   = segment_bounds(segment);

    // Find overlapping tiles
    for (var y = tile_min.y; y 
) {
    let tile_id = (pixel.y / TILE_SIZE) * tile_width + (pixel.x / TILE_SIZE);

    var coverage = 0.0;
    for (var i = 0u; i (color.rgb, saturate(coverage));
}

完美的抗锯齿在 任何 规模下——无锯齿,无 MSAA 开销。

预期性能提升

| Workload | Expected Behaviour |
|----------|---------------------|
| Simple paths (= h.segmentThreshold {        |
|        // GPU path: dispatch compute shaders |
|        h.gpu.Rasterize(coarse, segments, backdrop, scene.FillNonZero) |
|    } else { |
|        // CPU path: software rasterization |
|        h.cpu.RasterizeSegments(segments, backdrop) |
|    } |
if h.segmentCount < h.segmentThreshold {
    // GPU path: dispatch compute shaders
    h.gpu.Rasterize(coarse, segments, backdrop, scene.FillNonZero)
} else {
    // CPU path: software rasterization
    h.cpu.RasterizeSegments(segments, backdrop)
}

为什么? 小路径(...atomic)受支持。

  • 需要特定的内存顺序。
  • 缓冲区布局很重要。
// This works
@group(0) @binding(1) var counts: array>;
atomicAdd(&counts[i], 1u);

// This doesn't
var counts: array; // Not atomic!

调试很棘手——WGSL 验证错误……晦涩难懂。

我们发布的内容

统计

  • 2 280 行代码 WGSL 着色器(8 个着色器文件)
  • 约 20 千行代码 Go 位于 backend/wgpu/
  • 总体测试覆盖率 74 %
  • 0 个 lint 检查问题

着色器文件

backend/wgpu/shaders/
├── flatten.wgsl     # 589 LOC — Bezier curve flattening
├── coarse.wgsl      # 335 LOC — Tile binning with atomics
├── fine.wgsl        # 290 LOC — Per‑pixel coverage
├── blend.wgsl       # 424 LOC — 29 blend modes on GPU
├── composite.wgsl   # 235 LOC — Layer compositing
├── strip.wgsl       # 155 LOC — Sparse strip rendering
├── blit.wgsl        #  43 LOC — Final output blit
└── msdf_text.wgsl   # 209 LOC — MSDF text rendering

Go 实现

backend/wgpu/
├── gpu_flatten.go       # 809 LOC — Flatten pipeline
├── gpu_coarse.go        # 698 LOC — Coarse rasterization
├── gpu_fine.go          # 752 LOC — Fine rasterization
├── sparse_strips_gpu.go # 837 LOC — Hybrid CPU/GPU selection
├── renderer.go          # 822 LOC — Main renderer
├── pipeline.go          # 369 LOC — Pipeline orchestration
├── memory.go            # 413 LOC — GPU memory management
└── ... (40+ files total)

亲自尝试

安装

go get github.com/gogpu/gg@v0.15.0

快速示例

package main

import "github.com/gogpu/gg"

func main() {
    ctx := gg.NewContext(512, 512)
    ctx.ClearWithColor(gg.White)

    // 1 000 circles — GPU backend handles complex scenes efficiently
    ctx.SetColor(gg.Hex("#e74c3c"))
    for i := 0; i   
}

从 CPU 瓶颈到 GPU 并行。从顺序细分到大规模并行计算着色器。

这就是纯 Go 能做到的。

go get github.com/gogpu/gg@v0.15.0

⭐ 如果你觉得有用,请给仓库加星!

GoGPU 之旅系列的一部分

GPU 计算着色器(纯 Go) ← 您在此

Back to Blog

相关文章

阅读更多 »