#68

Fleet: GPU effects on the shared surface

Openbettercleveropened 3d ago

GPU effects (#51: CRT, bloom, cursor trail, custom WGSL through setEffects) render only on a terminal's own canvas. A terminal on a shared-surface pool (Fleet, #54) rejects setEffects, so a Fleet page cannot use them.

Plan

Apply effects once per worker surface. The worker already keeps a retained backing texture of the whole canvas, and it currently copies that texture to the canvas every frame. With effects on, the post-process passes read the backing directly and write the canvas instead of copying it. This costs one composite pass per worker frame, plus two half-resolution blur passes for bloom and one pass for a custom shader. It does not depend on the terminal count.

The other option was effects per terminal inside the shared pass. Each terminal would need its own scene texture and blur targets, which is about 1,000 extra textures and 3–4 passes per terminal per frame at 1,000 terminals. That is too costly for Fleet. Any effect that needs per-terminal state (the cursor trail, which follows one cursor) is not available on a shared surface and is ignored there.

With effects off, the surface keeps its current path exactly: the backing is copied to the canvas, and no extra textures, passes or texture usages are created.

Acceptance criteria

  • pool.setEffects(effects | null) (shared pools; additive API) applies CRT, bloom and a custom WGSL shader to every worker surface. It rejects with compiler messages for an invalid shader and keeps the previous effects. pool.effects reads the current setting. The cursor trail is documented as unsupported on shared surfaces.
  • With effects off, no effect textures or passes exist, and the backing keeps its original usages, so the frame path is unchanged.
  • Areas outside the terminals stay transparent over the page: CRT curvature outside the tube and custom-shader output outside terminal coverage are transparent, never opaque black.
  • Animated shaders keep presenting frames while no terminal changes.
  • The native app's demo shaders (synthwave, glitch, rain, shockwave, hologram, warp, matrix) are ported to demo/effects/ and compile against the browser prelude.
  • demo/fleet.html has an effects selector, usable in both main-thread and worker-fed modes.
  • Measured headed at 120 Hz on the M5 Max with 1,000 terminals: effects off, CRT + bloom, and CRT + bloom + synthwave, recording p10, CPU, GPU-completed updates, RSS, load and power.
  • Unit tests for the pool-level effect plumbing. Existing suites stay green, and both the libghostty and xterm-compatible profiles keep working.

Stacked on #67's branch (perf/fleet-1000-60fps).

Activity

0

No activity yet.