Turn the service into a real compositor. A layer is a server-owned surface (its
own mmap'd cacheable buffer) with a screen position, z-order, and visibility.
Clients create layers, draw into them by command, mark damage, and present; the
compositor repaints only the damaged region — clear to the wallpaper, paint the
visible layers bottom-to-top (z-sorted), flush that rectangle back -> front (WC).
- compositor.zig: the pure, host-tested core — Rect (intersect/unite), Surface,
fillRect, composite (opaque, clipped to a damage rect), blitTile (unaligned-
safe read of a client tile). No syscall/runtime dependency.
- protocol.zig: pack(format, r, g, b) — native pixel encoding for rgbx/bgrx, the
shared colour vocabulary of client and server. Host-tested.
- display.zig: the layer table + create/configure/destroy/fill_rect/blit_tile/
damage/present ops wired onto the compositor, plus a damage-accumulating present.
- Startup self-check: two overlapping layers composited on the real framebuffer,
read back to confirm the overlap shows the top layer and outside shows the
bottom — logs `display: compositor self-check ok`.
Gate: `zig build test` green (compositor + pack), and the display-service case's
self-check passes on hardware. Both new pure modules added to the test loop.
Stand up /system/services/display: a ring-3 process that claims the framebuffer
D1 seeded, maps it write-combining as the front buffer, allocates a cacheable
back buffer, and presents composed frames. The GUI track's compositor, reached
by name over ServiceId.display (= 9).
- protocol.zig: the display wire protocol (info/create_layer/configure_layer/
destroy_layer/fill_rect/blit_tile/damage/present). `info` and a whole-screen
`present` are live; the layer ops fail-stub until D3.
- display.zig: enumerate -> claim -> mmio_map(WC) the LFB, mmap a cacheable back
buffer, clear it and present it (proving the double-buffer path), then serve.
- runtime.display + barrel exports (display, display_protocol): a cached
`.display` client with info()/present(), the runtime.block shape.
- init spawns "display" in boot_services; build.zig wires the protocol onto the
runtime, builds the exe, packs it into the initial-ramdisk, installs it.
mmap fix the back buffer forced: systemMmap was capped at 256 pages (1 MiB) by a
fixed kernel-stack scratch array. Rewrote it to map page-by-page with rollback
(no array) and raised the cap to 8192 pages (32 MiB) — enough for a 4K back
buffer. A real limitation met.
Gate: `python3 test/qemu_test.py display-service` matches the service's own
serial heartbeats (display: online WxH / presented frame 0), printed only after
the full claim -> WC-map -> back-buffer -> present chain. Regression-checked
usermem, heap, init, and D1's display.