display: the compositor service — claim, double-buffer, present (D2)

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.
This commit is contained in:
Daniel Samson
2026-07-14 01:26:25 +01:00
parent cd812cc00e
commit 69b018cc32
11 changed files with 411 additions and 34 deletions
+7
View File
@@ -171,6 +171,13 @@ CASES = [
{"name": "display",
"expect": r"DANOS-TEST-RESULT: PASS",
"fail": r"DANOS-TEST-RESULT: FAIL"},
# Display service (D2): the user-space compositor claims the framebuffer, allocates a
# cacheable back buffer, clears it, and presents that composed frame — proving the
# double-buffer path. Matched on the service's own heartbeats (it prints them only
# after the whole claim -> map(WC) -> back-buffer -> present chain succeeds).
{"name": "display-service",
"expect": r"display: online \d+x\d+ pitch \d+[\s\S]*display: presented frame 0",
"fail": r"display: could not|CPU EXCEPTION|KERNEL PANIC"},
# Monotonic clock (clock() syscall source): calibrated, advancing, never backwards.
{"name": "clock",
"expect": r"DANOS-TEST-RESULT: PASS",