Skip to content

Releases: gogpu/compose

v0.2.0 — Mailbox Frame Delivery

19 May 09:14
735b66e

Choose a tag to compare

Added

  • Server.Snapshot() — returns latest frame from each connected module. Designed for compositor render tick pattern (Android BufferQueue / Vulkan MAILBOX semantics).
  • Frame.Sequence — monotonic frame counter mapped from wire protocol header, for change detection.
  • Per-module mailbox — each module's latest frame is stored server-side. Intermediate frames silently overwritten (latest-frame-wins).

Push-based delivery officially supported

Modules can call PublishFrame() at any time without waiting for OnFrameRequest. The server accepts and stores frames unconditionally. Both push and pull patterns coexist on the same connection — no mode negotiation needed.

// Compositor render tick (new pattern):
frames := srv.Snapshot()
for id, frame := range frames {
    compositor.Blit(id, frame)
}

// Push module (sends whenever data changes):
client.PublishFrame(compose.Frame{Pixels: rgba, Width: 400, Height: 120})

// Pull module (renders only when asked — unchanged from v0.1.0):
client.OnFrameRequest(func() {
    client.PublishFrame(renderClock())
})

Architecture

Based on research across 9 production compositors (Wayland, Android SurfaceFlinger, Chromium viz, Flutter, PipeWire, Windows DWM, macOS Core Animation, Vulkan MAILBOX, X11). See ADR-002.

Backward compatible

No wire protocol changes. No handshake changes. OnFrame callback still fires on every receipt. Existing v0.1.0 code works unchanged.

v0.1.0 — First Release

17 May 09:21
df08c56

Choose a tag to compare

compose v0.1.0

First release of gogpu/compose — Pure Go multi-process composition library.

Highlights

  • Unix socket transport — cross-platform (Linux, macOS, Windows AF_UNIX)
  • Wire protocol v1 — 64-byte fixed header, cache-line aligned, zero-alloc encode/decode
  • LZ4 compression — 2.9 GB/s, 99.6% compression on GUI pixels
  • Pull-based flow control — Wayland frame callback pattern, adaptive rate reduction
  • Hot-plug — modules connect/disconnect/crash without compositor restart
  • Public APIcompose.Listen(), compose.Dial(), Frame, functional options

Metrics

Metric Value
Total LOC ~9,000
Tests 220+
Coverage ~98%
Packages 6 (1 public + 5 internal)
Lint (30+ linters) 0 issues
CI Ubuntu + macOS + Windows
Dependencies 1 (pierrec/lz4/v4)

Quick Start

// Compositor
srv, _ := compose.Listen("/tmp/compose.sock")
srv.OnFrame(func(f compose.Frame) { /* blit pixels */ })

// Module
client, _ := compose.Dial("/tmp/compose.sock", compose.WithName("clock"))
client.PublishFrame(compose.Frame{Pixels: rgba, Width: 400, Height: 120})

Architecture

compose/                    # Public API (13 symbols)
└── internal/
    ├── protocol/           # Wire format (100% coverage)
    ├── codec/              # Raw + LZ4 (97% coverage)
    ├── conn/               # Module lifecycle (98.9% coverage)
    ├── flow/               # Pacing (100% coverage)
    └── transport/socket/   # Unix sockets (95.1% coverage)

What's Next

  • Phase 2: Reference examples (compositor + clock + notification binaries)
  • Phase 3: Shared memory transport (zero-copy, triple-buffer)
  • Phase 4: Delta frames, compression negotiation