Skip to content

Enterprise API Audit — Public API Cleanup #19

@kolkov

Description

@kolkov

Enterprise API Audit — gpucontext Public API Cleanup

Tracking issue for gpucontext improvements. Sources: @lkmavi audit (Flutter embedding scenario), independent senior-go-architect audit, cross-repo consistency check.

Architecture Context: Why gpucontext exists

gogpu is a shared resource ecosystem — multiple libraries (gg, ui, Born ML, g3d) share a single GPU device/queue created by the app framework. This is fundamentally different from monolithic engines (Flutter, Unity) where the engine owns all GPU resources internally.

Our architectural pattern matches:

  • wgpu-rs ecosystem: wgpu creates device → vello/bevy consume it via shared references
  • Vulkan ecosystem: VkDevice shared across libraries via handle passing
  • Go database/sql: shared sql.DB (concrete) + driver.Driver (SPI interface)

gpucontext is the shared interface contract between producer (gogpu) and consumers (gg, ui, Born ML). It defines what a GPU host must provide (DeviceProvider, WindowProvider, EventSource) without coupling consumers to a specific implementation (wgpu Native Go vs Rust FFI vs Browser).

The original audit used Flutter embedding as the test scenario. Flutter manages its own GPU device internally (host only provides platform hooks) — a different architecture. The audit findings were validated independently of the Flutter scenario, on their own enterprise merits.

✅ Remove Dead Code (verified: zero consumers across ecosystem)

  • Instance interface (webgpu_types.go:70) — zero references in gogpu, gg, ui, g3d
  • Surface interface (webgpu_types.go:62) — zero references anywhere
  • OpenDevice struct (webgpu_types.go:74) — zero references anywhere
  • IMEController interface (events.go:109-120) — zero consumers, zero implementors. Remove until actual need
  • Registry[T] (registry.go, 160 LOC) — zero consumers. gogpu uses different backend selection mechanism. Remove or move to internal

✅ Documentation

  • doc.go consumer list stale — missing ui (major EventSource consumer) and g3d
  • doc.go interface list incomplete — omits GestureEventSource, IMEController, AdapterInfo, etc.
  • NullPlatformProvider doc missing SubpixelLayout: SubpixelNone
  • Add String() methods to Key, MouseButton, Modifiers — all other enums have them, these three don't

💬 Needs Discussion: Button Ordering Mismatch

Button (pointer.go) uses W3C ordering: Left=0, Middle=1, Right=2
MouseButton (events.go) uses: Left=0, Right=1, Middle=2

Middle and Right are swapped between the two types. buttonToMouseButton in gogpu/event_source.go:362 converts, but this is a bug vector.

Options:

  1. Deprecate MouseButton entirely in favor of W3C Button (breaking change)
  2. Keep both but add prominent doc warnings
  3. Align MouseButton to W3C ordering (breaking change)

@lkmavi thoughts?

💬 Needs Discussion: Duplicate Types with ui/event

gpucontext defines Key (83 values), Modifiers (6 flags), MouseButton (5 values).
ui/event defines identical event.Key, event.Modifiers, event.Button.
ui/app/event_bridge.go is 250 lines of pure 1:1 translation.

Naming differs: ModControl (gpucontext) vs ModCtrl (ui).

Options:

  1. ui imports gpucontext types directly (eliminate translation layer)
  2. gpucontext exports canonical types, ui re-exports (type alias)
  3. Keep separate but add compile-time sync assertions

💬 Needs Discussion: Dual AdapterInfo

  • gputypes.AdapterInfo — full (VendorID, DeviceID, Driver info, 8 fields)
  • gpucontext.AdapterInfo — simplified (Name + Type, 2 fields)

Both serve different purposes (gputypes for HAL, gpucontext for abstract provider). Document canonical source or add conversion helper.

💬 Needs Discussion: EventSource Size (ISP)

EventSource has 12 methods (keyboard 3, mouse 4, window 2, IME 3). Every implementor must implement all 12. Consider splitting for v1.0:

  • KeyEventSource (3 methods)
  • MouseEventSource (4 methods)
  • WindowEventSource (2 methods)
  • IMEEventSource (3 methods)

winit has no split (monolithic handler). GTK4/Qt6 do split. What's right for gogpu?

✅ Low Priority (v1.0 planning)

  • Empty interface tokens (Device interface{} etc.) — add sentinel methods for compile-time safety
  • Move 5 unused Null* types (NullEventSource, NullWindowChrome, NullPointerEventSource, NullGestureEventSource, NullScrollEventSource) to test utility. Keep NullWindowProvider + NullPlatformProvider (actively used).

💬 Counter-arguments (open for discussion)

1. EventSource unsubscribe@lkmavi suggested adding unsubscribe for dynamic widget trees. Our research: Flutter uses push model (no subscribe/unsubscribe at embedder boundary), winit has no unsubscribe. GTK4/Qt6 do (they're widget toolkits). Our position: widget-level event routing belongs in ui, not in gpucontext windowing layer. @lkmavi, do you see a concrete use case where gogpu-level unsubscribe is needed that ui can't handle internally?

2. SetTabbingMode in PlatformProvider@lkmavi flagged as ISP violation. Checking code: SetTabbingMode is in gogpu.Config, not in gpucontext.PlatformProvider. PlatformProvider has only cross-platform methods (clipboard, cursor, accessibility). @lkmavi, was this based on a different method or earlier code version?


This is a living tracking issue. Feedback welcome from everyone — especially on the 💬 discussion items. If you use gpucontext as a consumer or have experience with similar shared-interface patterns, your perspective is valuable.

References

  • Independent audit: full interface + consumer analysis across ecosystem
  • Breaking change risk matrix: DeviceProvider=CRITICAL, EventSource=HIGH, IMEController=NONE
  • Zero-value safety: all types verified safe

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions