🎉 Phase 4 vraie validée visuellement : pixels custom plein écran

Capture : docs/phase4-victory-1280x800.png — dégradé ARGB animé 1280x800
écrit par redox-wl-fullscreen-paint, occupant tout l'écran QEMU sans
trace de bootlog, fbcond ou Orbital.

Cause racine du verrou (3 bugs en cascade) :

1. ConsumerHandle local à RedoxOutput::open() → droppé en fin de fn →
   inputd::on_close retirait le VT de self.vts → tous les `inputd -A <vt>`
   ultérieurs retournaient warning "switch to non-existent VT"

2. L'env var VT=N posée par init n'a aucun lien avec le VT alloué par
   inputd. inputd auto-incrémente next_vt_id à partir de 2 (VT 1 réservé
   bootlog). Avec fbbootlogd VT 1 + fbcond VT 2, notre paint = VT 3.

3. Sans le bon VT activé, set_crtc est silencieusement no-op côté
   driver-graphics (lib.rs:575 : `if *vt == self.active_vt { ... }`).

Fixes :
- RedoxOutput stocke `_consumer: ConsumerHandle` pour préserver le VT
- RedoxOutput.vt() lu via fpath sur consumer fd (inputd retourne
  `<scheme>/<vt>`)
- Binary lit output.vt() puis fait inputd -A <vt> avec le bon numéro
- 300ms de sleep pour propagation active_vt avant take_crtc

Validation automatisée : qemu -display none + monitor unix socket +
ncat -U pour sendkey ret + screendump à T+14s + ImageMagick.

Image Redox restaurée à boot Orbital normal après la session.

Phase 4 close. La piste 1 (consume events VT) reste utile pour le
hot-switch propre Ctrl+Alt+Fn mais n'est plus bloquante.

Leyoda 2026 – GPLv3
This commit is contained in:
Votre Nom 2026-05-09 10:46:20 +02:00
parent 5b1e038333
commit 753a30757b
7 changed files with 139 additions and 18 deletions

View file

@ -187,8 +187,84 @@ Même sans visuel, le pipeline est validé par :
- la persistance du buffer `CpuBackedBuffer` (alloc + écriture + sync sans
panic, plusieurs centaines de fois sans fuite mémoire visible)
C'est suffisant pour avancer phase 5 (input backend) et y revenir plus tard
quand on aura un compositor qui consomme les events VT.
## VICTOIRE 2026-05-09 — phase 4 vraie validée visuellement
Capture : ![](phase4-victory-1280x800.png)
L'écran QEMU montre intégralement le dégradé ARGB animé écrit par notre
binaire `redox-wl-fullscreen-paint`, plein écran 1280x800. Aucune trace
de bootlog, fbcond ou fbbootlogd. C'est notre code Rust qui pilote le
framebuffer Redox.
### La cause racine du verrou (3 bugs en cascade)
Bug 1 — **`ConsumerHandle` était local à `RedoxOutput::open()`** et droppé
à la sortie de la fonction. inputd-daemon réagissait avec `on_close` qui
retire le VT de `self.vts`. Tous les `inputd -A <vt>` ultérieurs
retournaient warning "switch to non-existent VT".
Bug 2 — **L'env var `VT=N` posée par init n'a aucun lien avec le VT
réellement alloué par inputd**. inputd auto-incrémente `next_vt_id` à
partir de 2 (VT 1 réservé bootlog). On dénombrait :
- VT 1 = `consumer_bootlog` de fbbootlogd
- VT 2 = consumer de fbcond (lancé par `init.initfs.d/20_fbcond.service`)
- VT 3 = notre consumer
Bug 3 — **Sans le bon VT activé, `set_crtc` est silencieusement no-op**
côté `driver-graphics` (cf `lib.rs:575` : `if *vt == self.active_vt {
self.adapter.set_crtc(...) }`).
### Le fix
```rust
pub struct RedoxOutput {
/// CONSUMER GARDÉ EN VIE : si on le drop, inputd retire notre VT et
/// `inputd -A <vt>` dira "non-existent".
_consumer: ConsumerHandle,
// ...
/// VT alloué par inputd, lu via fpath() sur le consumer fd.
/// (cf `inputd::main.rs:271-281` qui retourne `display.scheme/<vt>`)
vt: usize,
}
```
Et le binaire qui appelle :
```rust
let our_vt = output.vt(); // VT exact alloué par inputd
Command::new("inputd").arg("-A").arg(our_vt.to_string()).status()?;
thread::sleep(Duration::from_millis(300)); // propagation active_vt
output.take_crtc()?; // set_crtc passe la condition
output.present_with_takeover()?; // pixels visibles à l'écran
```
### Validation visuelle automatisée
Méthode reproductible dans le repo :
```bash
qemu-system-x86_64 \
... -vga std -display none \
-monitor unix:/tmp/qmp.sock,server,nowait \
-serial file:/tmp/qemu-serial.log ... &
sleep 2; printf "sendkey ret\n" | ncat -U /tmp/qmp.sock # passe bootloader
sleep 14; printf "screendump /tmp/frame.ppm\n" | ncat -U /tmp/qmp.sock
magick /tmp/frame.ppm /tmp/frame.png # convert
# Lire le PNG pour voir le rendu
```
### Implications pour la suite
Phase 4 entièrement validée. La fondation `RedoxOutput` est utilisable telle
quelle pour :
- Phase 5 (input backend) : ajouter `consumer.read_events()` pour récupérer
les events keyboard/mouse de inputd
- Phase 6 (surfaces shm composées) : composer plusieurs `wl_shm` buffers
dans le `pixels_mut()` de `RedoxOutput`
- Phase 7 (compositor utilisable) : ajouter focus, stacking, damage
tracking au-dessus
La piste 1 du plan (consommer events VT) reste utile à terme pour gérer le
hot-switch propre entre VTs (Ctrl+Alt+Fn), mais n'est plus bloquante pour
afficher.
## Prochaine étape : phase 4 vraie

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB