display: layer stack + damage-driven compositor (D3)

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.
This commit is contained in:
Daniel Samson
2026-07-14 01:39:04 +01:00
parent 69b018cc32
commit f9cf0007c5
6 changed files with 498 additions and 56 deletions
+19 -13
View File
@@ -94,23 +94,29 @@ fault cases, since a lone blocking service can't reschedule the in-kernel test c
poll). Regression-checked: `usermem`, `heap` (the `mmap` rewrite), `init` (the boot-list
addition), and D1's `display` all still pass.
## D3 — Layer stack + compositor + damage present
## D3 — Layer stack + compositor + damage present ✅
The heart: composite an ordered layer stack, present only what changed.
- [ ] A layer table (fixed capacity, like the input service's subscriber table): each
layer = rect, z-order, visible flag, a server-owned surface (`mmap` cacheable).
- [ ] Implement `create_layer` / `configure_layer` / `destroy_layer`, `fill_rect`,
`blit_tile` (inline tile in the IPC message), `damage`.
- [ ] `composite()`: walk layers bottom-to-top, paint dirty regions into the back buffer
(clip to layer rect ∩ damage; handle `rgbx`/`bgrx`; step by `pitch`).
- [ ] `present()`: flush merged damage rects back → front (sequential WC writes).
- [ ] Host tests (`zig build test`): layer clipping, damage-rect merge, and a
`blit`/`fill` against a fake in-memory framebuffer for both pixel formats and a
`pitch > width*4` case.
- [x] A layer table (16 slots): each `Layer` = position, z, visible, a server-owned
`mmap`'d surface (freed on `destroy_layer`). `damage` accumulates the dirty screen
region since the last present.
- [x] `create_layer` / `configure_layer` (damages old + new footprints) / `destroy_layer`,
`fill_rect`, `blit_tile` (reads the inline tile from the IPC payload, unaligned-safe),
`damage`, `present`.
- [x] Pure, host-tested [compositor.zig](../system/services/display/compositor.zig): `Rect`
(intersect/unite), `Surface`, `fillRect`, `composite` (opaque, clipped to a damage
rect), `blitTile`. `present` clears the damaged region to the wallpaper, paints the
visible layers bottom-to-top (z-sorted), and flushes just that rect back → front (WC).
Colour packing (rgbx/bgrx) is `protocol.pack`, also host-tested.
- [x] Host tests (`zig build test`, green): rect intersect/unite, `fillRect` clipping +
`stride > width` padding, `composite` overlap-shows-top + damage clipping, `blitTile`
unaligned read + clipping, and `pack` for both pixel formats.
**Gate:** `zig build test` green for the compositor unit tests; an in-service self-check
composites two overlapping layers and the overlap shows the top layer's colour.
**Gate (met):** `zig build test` green for the compositor + pack unit tests, **and** the
`display-service` case's startup self-check composites two overlapping layers on the real
framebuffer and reads back the composited pixels — overlap = top layer, outside = bottom
layer — logging `display: compositor self-check ok` (matched by the harness).
## D4 — Client API + the demo client