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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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