Problem
New users naturally write ggcanvas.New() inside OnDraw (every frame), causing:
- 7.3 MB pixmap allocation per frame (1080p)
- ~440 MB/s GC pressure at 60 FPS
- GPU texture leaks (previous Canvas never Close()'d)
Discovered by Pavel Tišnovský in root.cz tutorial (Part 3, ~40 min read, 12 interactive examples).
Enterprise reference
SDL, Qt, Skia, Flutter, Gio — all prevent per-frame context recreation structurally, not via documentation.
Proposed fix (Option D)
// ggcanvas.New() becomes idempotent: same provider → cached canvas
canvas, _ := ggcanvas.New(provider, w, h)
app.OnDraw(func(dc *gogpu.Context) {
canvas.Draw(func(cc *gg.Context) { // auto-resize if window changed
cc.DrawCircle(100, 100, 50)
cc.Fill()
})
})
Changes needed:
- Idempotent New(): per-provider cache — return existing canvas if already created for this provider+size
- Auto-resize in Draw(): detect window size change, reallocate pixmap internally
- No architecture violation: gg stays independent from gogpu (ARCH-008 preserved)
Why not Flutter/Gio pattern (OnDraw passes *gg.Context):
gogpu and gg do NOT depend on each other (shared resource ecosystem). gogpu must work without gg (wgpu direct, g3d, Born ML). Making OnDraw pass *gg.Context would couple gogpu → gg.
Problem
New users naturally write
ggcanvas.New()insideOnDraw(every frame), causing:Discovered by Pavel Tišnovský in root.cz tutorial (Part 3, ~40 min read, 12 interactive examples).
Enterprise reference
SDL, Qt, Skia, Flutter, Gio — all prevent per-frame context recreation structurally, not via documentation.
Proposed fix (Option D)
Changes needed:
Why not Flutter/Gio pattern (OnDraw passes *gg.Context):
gogpu and gg do NOT depend on each other (shared resource ecosystem). gogpu must work without gg (wgpu direct, g3d, Born ML). Making OnDraw pass *gg.Context would couple gogpu → gg.