🎉🎉🎉 Phase 6.4 — Wayland complet : un client externe affiche ses pixels
Capture preuve : docs/phase6-4-wayland-client-surface.png — pattern ARGB 320x240 écrit par un binaire client Wayland externe affiché par notre compositor sur le framebuffer Redox dans QEMU. Crates ajoutés : redox-wl-wayland-frontend (lib, ~430 lignes) : - WaylandFrontend struct avec SurfaceRegistry intégré + Display<Self> + ListeningSocket - bind_absolute(path), accept_pending_clients(), dispatch_clients(), flush_clients(), notify_frame_done() - ShmPool : mmap + munmap on drop - BufferData : Arc<Mutex<ShmPool>> + offset/w/h/stride/format - SurfaceData : Arc<...> qui contient SurfaceId + pending_buffer + pending_frame_callbacks - Dispatch impls : wl_compositor v5, wl_shm v1 (advertise ARGB+XRGB), wl_shm_pool, wl_buffer, wl_surface (attach/damage/commit/frame/destroy), wl_callback, wl_region (no-op) Sémantique commit : copy-on-commit (lit pixels via mmap, copie dans SurfaceBuffer owned). Plus simple que de garder le mmap vivant. Au commit, raise auto la surface (politique simple). redox-wl-compositor (bin, ~150 lignes) : - ouvre RedoxOutput + InputBackend partagé - bind WaylandFrontend sur /tmp/redox-wl-comp.sock - export WAYLAND_DISPLAY env var - boucle main 30 fps : accept clients → dispatch → input → render → notify_frame_done → flush - Esc = exit propre redox-wl-test-client-shm (bin, ~170 lignes) : - attente du socket compositor (50 retries × 100ms) - Connection::from_backend après UnixStream::connect - Dispatch handlers minimal pour wl_registry, compositor, shm, pool, buffer, surface - shm_open + ftruncate + mmap + pattern ARGB déterministe (orange + bandes diagonales) - shm.create_pool(fd) + pool.create_buffer + compositor.create_surface - surface.attach + damage_buffer + commit - reste connecté 25s pour qu'on capture l'écran Validation runtime : compositor en init VT=2, client lancé en parallèle via 30_console. Logs serial montrent toute la séquence : [client] globals : compositor=true shm=true [client] shm créé, peint 320x240 ARGB [client] surface attach + damage + commit envoyés [comp] tick=30 surfaces=1 elapsed=1.2s [comp] tick=510 surfaces=1 elapsed=20.7s ← surface persiste 20+s PNG capturée à T+12s montre la surface du client visible sur le framebuffer. Position (0,0) parce que xdg-shell absent (placement absent). Reportable phase 7. Image Redox restaurée à boot Orbital normal. docs/phase6-4-wayland-frontend.md : compte-rendu complet, archi, sémantique commit, limitations, plan phase 7. Phase 6 entièrement close. Le compositor naissant fonctionne avec un vrai client Wayland externe sur Redox. Leyoda 2026 – GPLv3
This commit is contained in:
parent
509aae7769
commit
8a897d975d
8 changed files with 1098 additions and 0 deletions
BIN
docs/phase6-4-wayland-client-surface.png
Normal file
BIN
docs/phase6-4-wayland-client-surface.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7 KiB |
171
docs/phase6-4-wayland-frontend.md
Normal file
171
docs/phase6-4-wayland-frontend.md
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
# Phase 6.4 — Frontend Wayland : un client externe affiche ses pixels
|
||||
|
||||
> Document produit le 2026-05-09 dans le cadre du plan directeur
|
||||
> `REDOX_COSMIC_XWAYLAND_RS_PLAN.md`.
|
||||
>
|
||||
> **Scope** : un client Wayland externe (process séparé, code Rust pur
|
||||
> via wayland-rs) se connecte au compositor binaire, lui envoie un
|
||||
> buffer shm peint, et le compositor l'affiche.
|
||||
|
||||
## Verdict
|
||||
|
||||
**✅ Pipeline Wayland complet sur Redox, end-to-end, par-dessus
|
||||
notre stack `compositor-core` + `redox-wl-display` + `redox-wl-input`.**
|
||||
|
||||
Capture preuve :  — le pattern
|
||||
ARGB 320x240 visible dans le coin haut-gauche est écrit par le client
|
||||
externe et affiché par le compositor sur le display Redox.
|
||||
|
||||
## Architecture finale 6.4
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────┐ ┌─────────────────────────────┐
|
||||
│ redox-wl-compositor (bin) │ │ redox-wl-test-client-shm │
|
||||
│ │ │ (bin séparé) │
|
||||
│ ┌────────────────┐ │ │ │
|
||||
│ │ RedoxOutput │ │ │ - shm_open + pattern ARGB │
|
||||
│ └────┬───────────┘ │ │ - wl_compositor │
|
||||
│ │ Arc<ConsumerHandle> │ │ - wl_shm │
|
||||
│ ▼ │ │ - wl_shm_pool.create │
|
||||
│ ┌────────────────┐ │ │ - wl_buffer │
|
||||
│ │ InputBackend │ │ │ - wl_surface.attach │
|
||||
│ └────────────────┘ │ │ - wl_surface.commit │
|
||||
│ │ │ │
|
||||
│ ┌────────────────┐ │ └─────────────┬───────────────┘
|
||||
│ │WaylandFrontend │ │ │ Unix socket
|
||||
│ │ - registry │ ◄────────────────┼──────────────────┘ + SCM_RIGHTS
|
||||
│ │ (compositor- │ │
|
||||
│ │ core) │ │
|
||||
│ │ - Display<Self>│ │
|
||||
│ │ - Listener │ │
|
||||
│ └────────┬───────┘ │
|
||||
│ │ compose_into │
|
||||
│ ▼ │
|
||||
│ framebuffer Redox → écran │
|
||||
└──────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## Globaux exposés
|
||||
|
||||
| Global | Version | Comportement |
|
||||
|---|---|---|
|
||||
| `wl_compositor` | 5 | `create_surface` → `registry.create()` ; `create_region` no-op |
|
||||
| `wl_shm` | 1 | advertise `Argb8888` + `Xrgb8888` ; `create_pool(fd, size)` → mmap immédiat |
|
||||
| `wl_shm_pool` | — | `create_buffer` → `BufferData` (offset/w/h/stride/format) ; `resize` no-op (TODO) |
|
||||
| `wl_buffer` | — | (pas de request à traiter, juste destroy implicite) |
|
||||
| `wl_surface` | 5 | `attach`, `damage`/`damage_buffer` (no-op tracking 6.4), `commit`, `frame`, `destroy` |
|
||||
| `wl_callback` | — | utilisé pour `wl_surface.frame` ; `done` envoyé par `notify_frame_done` |
|
||||
| `wl_region` | — | no-op (pas d'input region utilisée) |
|
||||
|
||||
## Sémantique commit Wayland implémentée
|
||||
|
||||
Quand un client envoie `wl_surface.commit` :
|
||||
|
||||
1. Récupération du `BufferData` attaché en pending (via `wl_surface.attach`)
|
||||
2. Lecture des pixels du shm via `mmap` côté serveur
|
||||
3. Création d'un `SurfaceBuffer` (Arc<Vec<u32>>) côté `compositor-core`
|
||||
4. `registry.modify_pending(id, |s| s.buffer = Some(...))`
|
||||
5. `registry.commit(id)` — pending → current
|
||||
6. `registry.raise(id)` — politique simple : dernière surface commitée passe au top
|
||||
7. Frame callbacks pending → queue globale, traité au `notify_frame_done` après le prochain present
|
||||
|
||||
**Approche "copy on commit"** : on copie les pixels du shm vers un Vec<u32>
|
||||
owned. Plus simple que de garder une référence vivante au mmap qui peut
|
||||
être unmappé par le client à tout moment. Coût ≈ 320×240×4 = 300 KiB par
|
||||
commit pour notre client de test, négligeable.
|
||||
|
||||
## Validation runtime
|
||||
|
||||
Configuration :
|
||||
```toml
|
||||
# init.d/20_orbital → nowait VT=2 redox-wl-compositor
|
||||
# init.d/30_console → nowait redox-wl-test-client-shm
|
||||
```
|
||||
|
||||
Le compositor démarre, expose le socket `/tmp/redox-wl-comp.sock`, le
|
||||
client a une boucle de connexion qui retry 50× × 100 ms et finit par
|
||||
se connecter quand le socket apparaît.
|
||||
|
||||
Logs capturés via /scheme/debug → serial QEMU stdio :
|
||||
|
||||
```
|
||||
[comp] Phase 6.4 — compositor Wayland démarrage
|
||||
[comp] display 1280x800, VT=3
|
||||
[comp] CRTC pris
|
||||
[comp] Wayland socket : /tmp/redox-wl-comp.sock
|
||||
[client] connect to compositor
|
||||
[client] globals : compositor=true shm=true
|
||||
[client] shm créé, peint 320x240 ARGB
|
||||
[client] surface attach + damage + commit envoyés
|
||||
[comp] tick=30 surfaces=1 elapsed=1.2s
|
||||
...
|
||||
[comp] tick=510 surfaces=1 elapsed=20.7s ← surface persiste 20s
|
||||
```
|
||||
|
||||
## Limitations / hors scope
|
||||
|
||||
### Pas de placement (xdg-shell absent)
|
||||
La surface du client est affichée à `(0, 0)` parce qu'aucun protocole
|
||||
de placement n'est implémenté. Pour des fenêtres positionnables /
|
||||
redimensionnables, il faudra `xdg_wm_base` + `xdg_toplevel` (phase 7
|
||||
ou plus tard).
|
||||
|
||||
### Pas de damage tracking effectif
|
||||
`wl_surface.damage` et `damage_buffer` sont reçus mais ignorés. Chaque
|
||||
frame recompose tout. Pour 1-3 surfaces de petite taille c'est
|
||||
imperceptible ; à optimiser quand on aura beaucoup de surfaces.
|
||||
|
||||
### Pas de wl_buffer.release explicite
|
||||
Le `release` Wayland indique au client qu'il peut réutiliser un buffer.
|
||||
Notre approche copy-on-commit rend ce protocole inutile (on n'a plus
|
||||
besoin du shm après commit). Mais des clients sophistiqués pourraient
|
||||
attendre `release` avant d'écrire à nouveau — à vérifier au cas par cas.
|
||||
|
||||
### Pas de seat / input vers les clients
|
||||
`wl_seat`, `wl_keyboard`, `wl_pointer` ne sont pas exposés. Les events
|
||||
input sont seulement consommés côté compositor (pour Esc=quit). Phase
|
||||
7 ajoutera la propagation des events vers la surface focalisée.
|
||||
|
||||
### Pas de subcompositor
|
||||
`wl_subcompositor` non exposé. Pas critique pour des clients simples.
|
||||
|
||||
## Code source
|
||||
|
||||
```
|
||||
crates/redox-wl-wayland-frontend/ # lib (~430 lignes)
|
||||
├── Cargo.toml
|
||||
└── src/lib.rs # WaylandFrontend, Dispatch impls
|
||||
|
||||
crates/redox-wl-compositor/ # bin (~150 lignes)
|
||||
├── Cargo.toml
|
||||
└── src/main.rs # boucle main display+input+frontend
|
||||
|
||||
crates/redox-wl-test-client-shm/ # bin (~170 lignes)
|
||||
├── Cargo.toml
|
||||
└── src/main.rs # client wayland-rs qui peint + commit
|
||||
```
|
||||
|
||||
## Suite phase 7
|
||||
|
||||
Si on veut un compositor utilisable au quotidien, il manque (par
|
||||
ordre de priorité) :
|
||||
|
||||
1. **xdg-shell** (`xdg_wm_base` + `xdg_toplevel` + `xdg_surface`) →
|
||||
placement, redimensionnement, fermeture propre, titres de fenêtres
|
||||
2. **wl_seat + wl_keyboard + wl_pointer** → propager les events input
|
||||
vers la surface focalisée. Décision XKB à prendre (porter
|
||||
libxkbcommon / impl Rust pur / strings minimales).
|
||||
3. **Curseur software** → afficher le pointeur souris à l'écran (le
|
||||
compositor en a déjà la position via InputBackend, mais ne le
|
||||
dessine pas)
|
||||
4. **Gestion focus + raise on click** → utiliser hit_test +
|
||||
wl_seat.keyboard_enter/leave events
|
||||
5. **Damage tracking effectif** → réduire le coût de composition
|
||||
6. **Clipboard** → wl_data_device_manager
|
||||
7. **Multiple clients simultanés**, fermeture propre, recover sur crash client
|
||||
|
||||
Estimé phase 7 complète : 5-8 sessions.
|
||||
|
||||
---
|
||||
|
||||
*Fin du document de phase 6.4.*
|
||||
Loading…
Add table
Add a link
Reference in a new issue