display: layer client API + the display-demo client (D4)

Drive the compositor from a separate process, proving the pipeline end to end.

- runtime.display: a Layer handle (fill / blitTile / configure / damage /
  destroy), createLayer, and a color(r,g,b) helper that caches the mode and
  packs via protocol.pack. Coordinates are signed over the u32 wire fields
  (@bitCast both ways), so a layer may sit or move partly off-screen.
- system/services/display-demo: the input-source analog for the compositor — a
  full-screen wallpaper, a rectangle it slides back and forth (moved by
  configure each frame, so the damage-driven present repaints old + new), and a
  cursor. Presents in a loop paced by runtime.time. Wired into build + initrd.

Fix this surfaced: protocol.message_maximum was 4096, but the kernel caps every
IPC message at MESSAGE_MAXIMUM = 256, so replyWait rejected the oversized receive
buffer with -E2BIG and the serve loop had been spinning since D2 (invisibly, as
those gates matched init-time heartbeats). Set it to 256; blit_tile is now
explicitly a small-tile path (larger bitmaps are the deferred shm surface).

Gate: `python3 test/qemu_test.py display-demo` — the demo drives frames of
motion through the layer client API and logs `display-demo: ok`. Regression:
zig build test, display (D1), display-service (D2/D3), and default zig build.
This commit is contained in:
Daniel Samson
2026-07-14 01:56:37 +01:00
parent f9cf0007c5
commit 105203b447
8 changed files with 253 additions and 17 deletions
+6 -4
View File
@@ -54,10 +54,12 @@ pub const Reply = extern struct {
reserved2: u32 = 0,
};
/// Sized to hold a modest `blit_tile` payload (a cursor / glyph-cell tile) inline on top
/// of the header, not just the fixed messages — the compositor's receive/reply buffers
/// (`runtime.service.run`) are this big.
pub const message_maximum: usize = 4096;
/// The IPC message size — the kernel caps every message at `MESSAGE_MAXIMUM` (256 bytes,
/// system/kernel/ipc-synchronous.zig), so this matches it (a larger receive/reply buffer
/// is rejected with -E2BIG). A `blit_tile` therefore carries only a *small* tile inline —
/// `maximum_payload` bytes = up to 54 pixels, enough for a cursor or small sprite; larger
/// bitmaps are the deferred shared-memory surface path (docs/display.md).
pub const message_maximum: usize = 256;
pub const request_size: usize = @sizeOf(Request);
pub const reply_size: usize = @sizeOf(Reply);
pub const maximum_payload: usize = message_maximum - request_size;