redox-wayland-compositor/docs/phase6-compositor-core.md
Votre Nom 509aae7769 🎉 Phase 6.3 — display + input + compositor-core intégrés runtime
Captures preuves dans docs/phase6-3-*.png : 4 frames qui prouvent
visuellement que raise change l'ordre Z et que compose_into propage le
résultat à l'écran QEMU :
- default-z.png : 3 surfaces overlap, blue top (créé en dernier)
- red-top.png : sendkey 1 → raise(red) → red couvre vert et bleu
- green-top.png : sendkey 2 → raise(green) → green couvre tout dans sa zone
- blue-top.png : sendkey 3 → raise(blue) → retour visuel à initial

Modifications :

compositor-core (commit dbf3bff → maintenant) :
- + iter_z_order_front_to_back() : utile pour hit testing
- + hit_test(x, y) -> Option<SurfaceId> : trouve la surface visible la
  plus haute qui contient le point
- + 4 tests unitaires : 27 total / 27 pass natif (0.00s)

redox-wl-display :
- + dep redox-wl-compositor-core
- + impl Framebuffer for RedoxOutput (délègue à pixels_mut + width/height)

bin redox-wl-test-compose-static (190 lignes) :
- ouvre RedoxOutput + take_crtc
- crée InputBackend partagé
- 3 surfaces ARGB unies (rouge/vert/bleu) avec overlap centré
- boucle event : '1'/'2'/'3' raise resp. red/green/blue
- clic souris → hit_test puis raise (motion non testé sans usb-tablet)
- ré-render seulement si raise → économie CPU
- present_with_takeover() à chaque iter pour tenir le CRTC

Validation QEMU automatisée : sendkey 1/2/3 + screendump entre chaque.
Les 4 PNG montrent l'ordre Z évoluer correctement.

Image Redox restaurée à boot Orbital normal.

docs/phase6-compositor-core.md : compte-rendu 6.1-6.3 complet,
architecture, dépendances, API, limitations, plan 6.4.

Phase 6.3 close. Reste 6.4 (frontend Wayland : wl_compositor + wl_shm
+ xdg-shell mappés vers compositor-core, damage tracking, frame
callbacks). Estimé 2-3 sessions.

Leyoda 2026 – GPLv3
2026-05-09 12:20:04 +02:00

229 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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<ConsumerHandle> │
│ │ 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<Vec<u32>>, // ARGB8888
pub width: u32,
pub height: u32,
}
pub struct SurfaceState {
pub x: i32,
pub y: i32,
pub buffer: Option<SurfaceBuffer>,
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<F>(&mut self, id: SurfaceId, f: F) -> bool;
pub fn iter_z_order_back_to_front(&self) -> impl Iterator<Item = &Surface>;
pub fn iter_z_order_front_to_back(&self) -> impl Iterator<Item = &Surface>;
pub fn hit_test(&self, x: i32, y: i32) -> Option<SurfaceId>;
pub fn compose_into<F: Framebuffer + ?Sized>(&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.*