纯 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) ← 您在此