Skip to content

fix(ggcanvas): idempotent New() + auto-resize Draw() — prevent per-frame allocation #484

Description

@kolkov

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:

  1. Idempotent New(): per-provider cache — return existing canvas if already created for this provider+size
  2. Auto-resize in Draw(): detect window size change, reallocate pixmap internally
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions