summaryrefslogtreecommitdiffstats
path: root/CONTEXT.md
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-01 19:52:05 +0200
committersalmonik <salmonik@tuta.io>2026-08-01 19:52:05 +0200
commit819778f292ee4e1294603b98662e083e49e23463 (patch)
tree8df31b678432d2a89cac8e0d50f271a75a3882b5 /CONTEXT.md
parentrsnix v0.4.0: GUI input foundation — PS/2 mouse + scheduler message queues (diff)
downloadrs-dos-819778f292ee4e1294603b98662e083e49e23463.tar.gz
rs-dos-819778f292ee4e1294603b98662e083e49e23463.zip
rsnix v0.5.0: graphics layer + cursor compositor
The first visible GUI surface: real rect primitives, a single shadow→display push path, and an on-screen mouse cursor that can never race the text surface. gop: - fill_rect + push_rect(x,y,w,h): every raster op rasterises into the RAM shadow, then push_rect copies the rect to the display (write-only, still never read) and composites the cursor on top. blit_glyph and scroll shifts now route through it. - cursor overlay: 12x16 pointer (const-fn built from column lists) drawn white with a black offset outline; position in one AtomicU64 (x:high 32, y:low 32) — unpack masks the low word (a bare 'as usize' cast is a no-op on 64-bit). The cursor never enters the shadow, so erasing is just a shadow push of the old rect. - cursor_redraw after scroll shifts and once at spawn (the vt diff never re-blits idle cells). cursor task (task 2, spawned at boot when a mouse is present): - owns the PS/2 ring; polls every 10 ms, moves the cursor (clamped), tracks buttons, and forwards every event to a task's queue when 'mouse <id>' armed it (the window-manager input path). - /dev/mouse is now a position device (x/y/buttons snapshot); 'mouse' watches the cursor live (prints on change); 'cursor' prints one-shot state; 'gfx' draws a status-bar demo; 'gfx check' is an in-kernel pixel self-test (shadow readback, display readback, cursor overlay purity) — PASS/FAIL per stage. Tests (headless QEMU + monitor injection): - make test-gfx (new): all four compositor checks PASS. - make test-mouse (rewritten): cursor tracks mouse_move deltas, buttons ride along, /dev/mouse snapshot, live watch, real-event queue routing. - make test-msg: task numbering shifted (cursor is task 2; msgrecv is task 3) — updated, still PASS. - make test-disk regression re-passes. 0 build warnings.
Diffstat (limited to 'CONTEXT.md')
-rw-r--r--CONTEXT.md74
1 files changed, 60 insertions, 14 deletions
diff --git a/CONTEXT.md b/CONTEXT.md
index 9ceb81d..bfe0170 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -113,9 +113,10 @@ Workspace version is `a.b.c` (single version for all crates):
113 113
114Bump the workspace version in the root `Cargo.toml` when a change of 114Bump the workspace version in the root `Cargo.toml` when a change of
115that class lands — do not leave the version to drift. Current: 115that class lands — do not leave the version to drift. Current:
116`0.4.0` — the GUI input foundation (PS/2 mouse + scheduler message 116`0.5.0` — the GUI era landed (graphics layer + cursor compositor) as a
117queues) landed as a `b` bump; the GUI era itself is reserved for the 117`b` bump from the 0.4.0 input foundation; a future major GUI overhaul
118`a` bump (1.0.0). 118(graphics windows beyond the text surface) would be the `a` bump
119(1.0.0).
119 120
120## Project layout 121## Project layout
121 122
@@ -426,19 +427,24 @@ Workspace of four crates, all built for the `x86_64-unknown-uefi` target:
426 relative** (`dx` + = right, `dy` + = down — the PS/2 Y-up wire 427 relative** (`dx` + = right, `dy` + = down — the PS/2 Y-up wire
427 convention is negated), buttons decoded; 9-bit sign extension via 428 convention is negated), buttons decoded; 9-bit sign extension via
428 the packet sign bits. 429 the packet sign bits.
429- `fs`: `/dev/mouse` char device — `cat /dev/mouse` drains up to 32 430- `fs`: `/dev/mouse` is now a **position device** — `cat /dev/mouse`
430 pending events (`dx=+N dy=+N buttons=L-R`), reports 431 prints the cursor's current state (`x=N y=N buttons=---`), since
431 `mouse: no PS/2 mouse` / `mouse: no events` otherwise. 432 the cursor task owns the PS/2 ring; `mouse: no PS/2 mouse`
432- shell: `mouse` command streams live events (10 ms poll via 433 otherwise.
433 `sleep_ms`) until ^C. 434- shell: `mouse` **watches the on-screen cursor** (x/y/buttons,
435 printed only on change, 10 ms poll) until ^C; `mouse <id>` also
436 routes every decoded event to that task's queue (`cursor still
437 tracks`, route cleared on exit). `cursor` prints a one-shot state
438 line (the parseable test surface).
434 439
435 Verified in QEMU (`make test-mouse`, headless, via the monitor's 440 Verified in QEMU (`make test-mouse`, headless, via the monitor's
436 `mouse_move`/`mouse_button` HMP commands): boot line `ps2: mouse 441 `mouse_move`/`mouse_button` HMP commands): the cursor starts centred,
437 ready`, `/dev/mouse` drains a pre-consumer move (`8,4`), the live 442 `mouse_move 20 7` moves it +20/+7 (asserted against `cursor` output),
438 stream decodes `mouse_move 20 7` → `dx=+20 dy=+7 buttons=---`, 443 `mouse_button 1` → `buttons=L--`, a held-button move (`-5,-3`)
439 `mouse_button 1` → `buttons=L--`, a held-button move 444 tracks position *and* keeps the button, release clears, `/dev/mouse`
440 (`-5,-3` while L down) → `dx=-5 dy=-3 buttons=L--`, release, 445 reports the same position snapshot, the live `mouse` watch prints the
441 and ^C stops the stream. `make test-disk` regression re-passes. 446 changed line and ^C stops it, and `mouse 3` routes a real move into
447 the msgrecv task's queue. `make test-disk` regression re-passes.
442 448
443✅ **Scheduler message queues (the GUI-era primitive from ADR 0003)** — 449✅ **Scheduler message queues (the GUI-era primitive from ADR 0003)** —
444 every task gets a static 16-slot ring of `TaskMsg` (4 KB in .bss, 450 every task gets a static 16-slot ring of `TaskMsg` (4 KB in .bss,
@@ -475,6 +481,46 @@ Workspace of four crates, all built for the `x86_64-unknown-uefi` target:
475 the shell's never-consumed queue), and `jobs` shows q=0 + task back 481 the shell's never-consumed queue), and `jobs` shows q=0 + task back
476 to `blocked` after draining. `make test-disk` regression re-passes. 482 to `blocked` after draining. `make test-disk` regression re-passes.
477 483
484✅ **Graphics layer + cursor compositor** — the first visible GUI
485 surface: real rect primitives, a shadow→display push path, and an
486 on-screen mouse cursor that never races the text surface:
487
488- `gop`: `fill_rect` + `push_rect(x,y,w,h)` — the **single display
489 write path**. Every raster op rasterises into the RAM shadow
490 first, then `push_rect` copies that rect to the display (write-
491 only; the display is still never *read*) and composites the
492 cursor on top. `blit_glyph` and scroll shifts now route through
493 it, so text redraws can never erase or corrupt the cursor. The
494 cursor lives *only* in the overlay — never in the shadow — which
495 makes save/restore impossible to get wrong: erasing = push the
496 old rect (the shadow simply doesn't contain the cursor there).
497- cursor bitmap: 12×16 pointer built by a const fn from explicit
498 column lists (hand-mangled bit literals were the one real bug
499 this round — twice), drawn white with a black offset outline
500 (+1,+1). Position lives in one `AtomicU64` (x:high 32, y:low 32)
501 so a relaxed load never sees a torn pair — *and* the unpack must
502 mask the low word (a bare `as usize` cast is a no-op on 64-bit
503 and returned the whole packed value).
504- `cursor` task (spawned at boot when the mouse is present, task 2):
505 polls the PS/2 ring every 10 ms, moves the cursor via
506 `cursor_move` (clamped to the screen; erase-old + draw-new are
507 both shadow pushes), tracks buttons, and forwards every event to
508 a task's queue when `mouse <id>` armed it. The cursor is drawn
509 once at spawn (the vt diff never re-blits idle cells) and stays
510 visible because every display write composites it; scrolls
511 re-overlay it after the bulk shift.
512- shell: `gfx` draws a status-bar demo scene (navy strip + RGB
513 boxes); `gfx check` is an in-kernel pixel self-test — draws a red
514 rect, reads it back from the shadow *and* the display, asserts
515 the cursor tip is white on the display but absent from the shadow
516 (overlay purity), and prints PASS/FAIL per stage.
517
518 Verified in QEMU (`make test-gfx`): `fill_rect/shadow: OK`,
519 `display push: OK`, `cursor overlay: OK`, `cursor not in shadow:
520 OK`, `gfx check: PASS`; the demo draws; the cursor tracks injected
521 mouse input (test-mouse) with the overlay intact. `make test-disk`
522 regression re-passes.
523
478## Known issues / perf notes 524## Known issues / perf notes
479 525
480- **Scroll cost** — scrolling still shifts the whole framebuffer (a 526- **Scroll cost** — scrolling still shifts the whole framebuffer (a