# Phase 6 — Compositor core : résultats > Document produit le 2026-05-09 dans le cadre du plan directeur > `REDOX_COSMIC_XWAYLAND_RS_PLAN.md`. > > **Périmètre 6.1-6.3** : structures core, pipeline de composition, > intégration runtime display + input + composition. > > **Hors scope (6.4)** : frontend Wayland (wl_compositor / wl_shm / > xdg-shell), damage tracking, frame callbacks. ## Verdict 6.1-6.3 **✅ Cœur compositor fonctionnel et intégré.** - 27 tests unitaires sur `compositor-core` (12 structures + 11 composition + 4 hit_test) - `RedoxOutput` impl `Framebuffer` → composition directe dans le framebuffer Redox - Bin d'intégration `redox-wl-test-compose-static` qui combine display + input + compositor Captures preuves : | Frame | Z-order (bottom → top) | PNG | |---|---|---| | Initial (3 surfaces créées) | red, green, blue | `phase6-3-default-z.png` | | Après `sendkey 1` (raise red) | green, blue, red | `phase6-3-red-top.png` | | Après `sendkey 2` (raise green) | blue, red, green | `phase6-3-green-top.png` | | Après `sendkey 3` (raise blue) | red, green, blue | `phase6-3-blue-top.png` | Chaque pression de touche déclenche `registry.raise(id)` puis `registry.compose_into(&mut output)` puis `output.present_with_takeover()`, le tout dans le même binaire qui consomme aussi les events via `InputBackend`. ## Architecture finale 6.3 ``` ┌──────────────────────────────────────────────────┐ │ redox-wl-test-compose-static (binaire) │ │ │ │ RedoxOutput ──────┐ │ │ (display) │ │ │ │ │ Arc │ │ │ impl Framebuffer│ │ │ │ ▼ │ │ │ InputBackend ──> InputEvent │ │ │ │ │ │ ▼ ▼ │ │ SurfaceRegistry ◄── (raise, hit_test, modify) │ │ │ │ │ │ compose_into(&mut output) │ │ ▼ │ │ pixels écrits dans le framebuffer Redox │ │ │ │ │ └──> present_with_takeover │ └──────────────────────────────────────────────────┘ ``` **Dépendances** (graph propre, pas de cycle) : ``` redox-wl-compositor-core ← lib pure Rust, sans dep externe ▲ ├──── redox-wl-display (impl Framebuffer for RedoxOutput) │ └──── redox-wl-test-compose-static (bin) ▲ └──── redox-wl-input (lib) ``` ## API publique 6.1-6.3 ### Types core ```rust pub struct SurfaceId(u64); pub struct SurfaceBuffer { pub pixels: Arc>, // ARGB8888 pub width: u32, pub height: u32, } pub struct SurfaceState { pub x: i32, pub y: i32, pub buffer: Option, pub visible: bool, } pub struct Surface { /* id, current, pending */ } impl Surface { pub fn id(&self) -> SurfaceId; pub fn current(&self) -> &SurfaceState; pub fn pending(&self) -> &SurfaceState; pub fn pending_mut(&mut self) -> &mut SurfaceState; pub fn commit(&mut self); } ``` ### `SurfaceRegistry` ```rust pub struct SurfaceRegistry { /* ... */ } impl SurfaceRegistry { pub fn create(&mut self) -> SurfaceId; pub fn destroy(&mut self, id: SurfaceId) -> bool; pub fn raise(&mut self, id: SurfaceId); pub fn get(&self, id: SurfaceId) -> Option<&Surface>; pub fn get_mut(&mut self, id: SurfaceId) -> Option<&mut Surface>; pub fn commit(&mut self, id: SurfaceId) -> bool; pub fn modify_pending(&mut self, id: SurfaceId, f: F) -> bool; pub fn iter_z_order_back_to_front(&self) -> impl Iterator; pub fn iter_z_order_front_to_back(&self) -> impl Iterator; pub fn hit_test(&self, x: i32, y: i32) -> Option; pub fn compose_into(&self, target: &mut F); } ``` ### Trait `Framebuffer` ```rust pub trait Framebuffer { fn width(&self) -> u32; fn height(&self) -> u32; fn pixels_mut(&mut self) -> &mut [u32]; } ``` Implémenté pour `RedoxOutput` dans `redox-wl-display`. Le bin d'intégration peut faire `registry.compose_into(&mut output)` directement. ## Tests unitaires (27 total, 0.00s natif) | Catégorie | # | Couverture | |---|---|---| | Surface registry | 6 | create/destroy/raise (idempotent, unknown, etc.) | | Pending/current state | 2 | modification + commit + isolation | | Composition | 9 | empty, fullscreen, partiel, clipping (4 bords), invisible, sans buffer, z-order, current vs pending | | Hit testing | 4 | topmost, skip invisible, after raise, hors écran | | End-to-end | 2 | iter z-order, workflow compositor typique | | **Buffer construction** | 1 | `new_filled` produit bonne taille + couleur | Compile aussi pour `x86_64-unknown-redox` (pure Rust, aucune dep system). ## Méthode validation runtime ```bash # Build cd crates/redox-wl-test-compose-static && redoxer build --release # Push dans image mount image via redoxfs cp binary into /usr/bin/ modify init.d/20_orbital → nowait VT=2 redox-wl-test-compose-static clear init.d/30_console unmount # Boot QEMU headless avec capture qemu ... -display none -monitor unix:/tmp/qmp.sock,... sleep 2 && sendkey ret # bootloader sleep 13 # boot complete screendump /tmp/frame-1.ppm # initial state sendkey 1 && sleep 1 && screendump frame-2.ppm # red top sendkey 2 && sleep 1 && screendump frame-3.ppm # green top sendkey 3 && sleep 1 && screendump frame-4.ppm # blue top ``` Les 4 captures sont visibles dans `docs/phase6-3-*.png`. ## Limitations / hors scope ### Pas de damage tracking Chaque `compose_into()` rerend les surfaces complètement. Pour 3 surfaces ARGB de ~400x300, c'est ~720 KiB recopiés à chaque event. Acceptable (on est largement sous le ms côté CPU). À reconsidérer en 6.4 quand `wl_surface.damage_buffer` arrivera côté frontend. ### Pas de blending alpha `compose_into` overwrite les pixels. Une surface ARGB avec α<255 est traitée comme opaque (l'alpha est ignoré au niveau de la copie). Pour Wayland natif on aura besoin de blending pour les decorations côté client transparentes. Reportable à 6.4 ou 6.5. ### Pas de cursor visible Le bin d'intégration ne dessine pas de curseur. Le pointeur souris QEMU n'apparaît donc pas à l'écran. Hit-test fonctionne (on a vu les events `PointerButton`) mais sans feedback visuel. Add à phase 7 (curseur stable). ### Hit-test au clic non testé visuellement Le test runtime utilise les touches '1'/'2'/'3' pour raise. Les events `PointerMotion` n'arrivent pas dans la config QEMU minimale (pas de `-device usb-tablet`). Le hit-test fonctionne sur les coords qu'on garde côté binaire ; à valider avec un vrai input mouse en 7. ## Code source ``` crates/redox-wl-compositor-core/ # lib pure Rust (450 lignes + 27 tests) ├── Cargo.toml └── src/lib.rs crates/redox-wl-display/ # MODIFIÉ ├── Cargo.toml # + dep redox-wl-compositor-core └── src/lib.rs # + impl Framebuffer for RedoxOutput crates/redox-wl-test-compose-static/ # bin d'intégration (190 lignes) ├── Cargo.toml └── src/main.rs ``` ## Suite phase 6.4 - Ajouter dep `wayland-server` au futur `redox-wl-wayland-frontend` - Mapper `wl_compositor.create_surface` → `registry.create()` - Mapper `wl_shm_pool.create_buffer` → wrapper sur mmap'd region - Mapper `wl_surface.attach` → `state.buffer = Some(...)` - Mapper `wl_surface.commit` → `registry.commit(id)` - Mapper `wl_surface.damage_buffer` → suivi pour optimiser `compose_into` - Mapper `wl_surface.frame` → callback après `present` - Tester avec un client Wayland simple (par ex. `weston-info` ou un client de test custom utilisant `wayland-client`) Estimé 2-3 sessions de 2h. --- *Fin du document de phase 6.1-6.3.*