# Audit Phase 1 — Existant Redox GUI > Document produit le 2026-05-08 dans le cadre du plan directeur > `REDOX_COSMIC_XWAYLAND_RS_PLAN.md` (phase 1 : audit avant code). > > **Périmètre** : comprendre l'architecture graphique actuelle de Redox > (Orbital + drivers + primitives) pour calibrer le portage Wayland. ## Résumé exécutif Redox dispose **déjà d'une fondation graphique plus mûre que prévu** : - **Une API DRM compatible Linux** (subset KMS) exposée via `graphics-ipc` et utilisée par Orbital - **Plusieurs drivers** : VESA firmware (`vesad`), virtio-gpu (`virtio-gpud`), Intel HD (`ihdgd`) - **Un input multiplexer** (`inputd`) qui gère VT switching, keymaps, producteurs/consommateurs - **Orbital** très compact (~3900 lignes Rust) qui valide le pattern serveur-clients via scheme Côté primitives système, **l'essentiel de ce que Wayland exige est déjà là** : - AF_UNIX sockets via le scheme `chan:` ✅ - `sendmsg`/`recvmsg` avec **SCM_RIGHTS implémenté** (fd passing) ✅ - `shm_open` via `/scheme/shm/` ✅ - `mmap MAP_SHARED` ✅ - `poll`/`epoll` ✅ - ⚠️ `memfd_create` : numéro syscall défini mais implémentation à vérifier **Conclusion** : la phase 2 (primitives OS) du plan directeur sera moins lourde que craint. La majorité des briques existent — il faudra surtout valider le comportement par tests dédiés. --- ## 1. Architecture Orbital ### 1.1 Point d'entrée et boot `orbital/src/main.rs` (82 lignes) : ```text main() └─ orbital() ├─ lit env "VT" (passé par inputd au boot) ├─ Orbital::open_display() ← ouvre display via inputd ├─ exec "inputd -A " ← s'enregistre comme handler du VT ├─ Config::from_path("/ui/orbital.toml") ├─ OrbitalScheme::new(displays, config) └─ orbital.run(scheme, login_cmd) ← event loop principal ``` **Note séquence de boot** : c'est `inputd` qui orchestre l'ouverture du display au moment où le VT s'active. Orbital ne touche pas directement aux drivers graphiques — il passe par inputd qui lui retourne un fd `/scheme/.../v2/...`. ### 1.2 Event loop (`core/mod.rs`, 662 lignes) Architecture deux-fd : ```text EventQueue ├─ Scheme fd (clients Orbital) → SchemeSync trait └─ Input fd (depuis inputd consumer) → ConsumerHandleEvent::Events ``` **Patterns clés** : - Utilise `event::EventQueue` (crate `redox_event`) — équivalent Redox de `wl_event_loop` Wayland ou `epoll` Linux - Chaque source a son fd, multiplexé en édge-triggered READ - Les requests scheme bloquantes sont stockées dans `delayed: VecDeque` puis réveillées quand un input arrive (équivalent du `wl_display_dispatch_pending` Wayland) **Réutilisable pour le compositor Wayland** : - Le pattern EventQueue avec sources typées (`user_data!` macro) est exactement ce qu'il faut pour le compositor Wayland - Le mécanisme `delayed` pour les reads bloquants est réutilisable tel quel ### 1.3 Protocole `orbital:` (le scheme) Implémenté dans `core/mod.rs::OrbitalHandler::SchemeSync` et `scheme.rs` (1721 lignes). **API client** (ce qu'un client appelle pour ouvrir une fenêtre) : ```text open("/scheme/orbital//////") → returns window_fd write(window_fd, "T,nouveau titre") → titre write(window_fd, "S,800,600") → resize write(window_fd, "P,100,200") → position write(window_fd, "Y,0,0,800,600,...") → damage rectangles write(window_fd, "F,t,1") → flag transparent on read(window_fd, &mut events) → pull events (clavier, souris, ...) mmap_prep(window_fd, ...) → obtient un buffer mmap zero-copy fsync(window_fd) → commit (équivalent wl_surface.commit) ``` **Concepts à transposer en Wayland** : | Orbital | Équivalent Wayland | |---|---| | open() avec path verbeux | `xdg_surface` + `xdg_toplevel` configure | | write("S,...") resize | `xdg_toplevel.configure` + ack | | write("Y,...") damage | `wl_surface.damage_buffer` | | mmap_prep | `wl_shm_pool.create_buffer` + `wl_surface.attach` | | fsync | `wl_surface.commit` | | read events | event queue Wayland | **Limites du protocole Orbital** : - API basée sur strings dans les writes — pas type-safe, pas de versioning - Une seule sémantique d'extension (préfixes "A","D","F","M","P","S","T","Y") - Pas de négociation de capabilities côté serveur - Buffer mmap'é direct — moins flexible que `wl_shm_pool` mais plus rapide ### 1.4 Composition (`compositor.rs`, 281 lignes) Compositor logiciel CPU pur : - `Image::roi_mut()` pour écrire dans le framebuffer - `Color` ARGB8888 - Damage rectangles propagés aux clients via `Y,...` - Curseur SW si pas de hardware cursor disponible (cf `core/display.rs:140` `set_client_capability(CursorPlaneHotspot, true)`) **Réutilisable directement** : la logique damage tracking + composition CPU est exactement ce qu'il faut pour la phase 6-7 du plan (`wl_shm` + composition). --- ## 2. Stack graphique Redox ### 2.1 API `graphics-ipc` (la lib commune) `base/drivers/graphics/graphics-ipc/src/lib.rs` (127 lignes). **Découverte critique** (commentaire ligne 13-15) : > *The v2 graphics API allows creating framebuffers on the fly, using them for > page flipping and handles all displays using a single fd. This is basically > a subset of the Linux DRM interface with a couple of custom ioctls in the > place of the KMS ioctls that are missing.* **Conséquence** : Redox a une **API DRM compatible Linux** (subset KMS). La crate Rust `drm` upstream fonctionne directement sur Redox. API exposée : ```rust V2GraphicsHandle::from_file(file) ├─ resource_handles() ← liste connectors/encoders/CRTCs ├─ get_connector(handle, force_probe) ├─ get_encoder(handle) ├─ create_dumb_buffer(size, fourcc, bpp) ├─ map_dumb_buffer(buffer) ← mmap CPU-accessible ├─ add_framebuffer(buffer, depth, bpp) ├─ set_crtc(crtc, fb, position, connectors, mode) ├─ dirty_framebuffer(fb, &[ClipRect]) ← damage flush ├─ move_cursor / set_cursor2 └─ destroy_* ``` `CpuBackedBuffer` (lignes 46-127) : - Wrapper sur `DumbBuffer` DRM - Optionnel : shadow buffer host (write-combining mitigation) - `sync_rect()` pour copier shadow → on-screen par damage **Implications pour le portage Wayland** : 1. Pas besoin de réinventer le display backend — l'API DRM existe 2. Peut être utilisée telle quelle par un compositor Wayland Rust 3. `CpuBackedBuffer::shadow_buf()` retourne `&mut [u8]` — exactement le format SHM que Wayland attend pour la composition ### 2.2 Drivers graphiques disponibles Localisation : `base/drivers/graphics/`. | Driver | Cible | Statut | Notes | |---|---|---|---| | **`vesad`** (133 + 275 lignes) | VESA framebuffer firmware (BIOS/UEFI) | Stable | Lit FRAMEBUFFER_* env, support multi-FB | | **`virtio-gpud`** (615 + 528 lignes) | virtio-gpu (QEMU/KVM) | Actif | C'est ce qui tourne sur ton image desktop | | **`ihdgd`** | Intel HD Graphics | Actif | Driver natif HW | | `fbcond` | Console framebuffer | — | Texte console | | `fbbootlogd` | Boot log framebuffer | — | Affichage early boot | | `console-draw` | Helpers dessin console | — | Lib commune | | `driver-graphics` | Couche d'abstraction commune (`GraphicsScheme`) | — | C'est elle qui exporte `display.<driver>` | Tous publient leur scheme sous forme `display.<nom>` (ex: `display.vesa`). ### 2.3 Chemin d'ouverture du display ```text Orbital └─> ConsumerHandle::new_vt() // /scheme/input/consumer └─> open_display_v2() └─> fpath() pour récupérer le path complet └─> open("/scheme/.../v2/<display>") // fd graphics-ipc v2 └─> V2GraphicsHandle::from_file ``` C'est `inputd` qui détient la connaissance du driver graphique actif et expose un chemin standard. Orbital ne hard-code pas `vesa` ou `virtio-gpu` — il demande à inputd. **Implication pour le compositor Wayland** : suivre le même pattern. Demander à `inputd` quel display est associé au VT, ouvrir le fd retourné, le wrapper en `V2GraphicsHandle`. Pas de hardcode de driver. ### 2.4 `vesad` — le chemin firmware framebuffer `base/drivers/graphics/vesad/src/main.rs` (133 lignes). **Bootstrap** (lignes 19-44) : ```rust FRAMEBUFFER_WIDTH // hex string, ex "780" → 1920 FRAMEBUFFER_HEIGHT // ex "438" → 1080 FRAMEBUFFER_ADDR // adresse physique du FB fournie par firmware FRAMEBUFFER_STRIDE // bytes par ligne ``` Le bootloader (UEFI/BIOS) place ces variables avant de chainer vers le kernel. `vesad` mappe l'adresse physique en mémoire userspace et expose le FB via `GraphicsScheme`. **Fallback bootloader env** (lignes 60-84) : `vesad` lit `/scheme/sys/env` pour `FRAMEBUFFER1`, `FRAMEBUFFER2`, ... — support multi-écran natif au boot si le firmware en remonte plusieurs. **Implication** : pour la phase 4 du plan (backend display), partir de `vesad` comme chemin de validation initial = sûr et simple. virtio-gpud est plus puissant mais plus complexe (gpu commandes, virgl optionnel). --- ## 3. Stack input ### 3.1 `inputd` — le multiplexer `base/drivers/inputd/src/{lib.rs,main.rs}` (211 + 663 lignes). **Schemes exposés** : | Path | Pour | Rôle | |---|---|---| | `/scheme/input/consumer` | Orbital, futur compositor | reçoit les events triés (orbclient::Event) | | `/scheme/input/consumer_bootlog` | bootlog | events early-boot | | `/scheme/input/producer` | drivers ps2d, usbhidd | écrit des events bruts | | `/scheme/input/control` | gestion VT/keymap | active VT, change keymap | | `/scheme/input/handle/<scheme>` | délégation à un autre scheme | déléguer un VT à un autre serveur | | `/scheme/input/handle_early/<scheme>` | idem mais avant init VT | bootlog, etc. | **API ConsumerHandle** : ```rust let h = ConsumerHandle::new_vt()?; let display_fd = h.open_display_v2()?; // ← ouvre le display de ce VT let evt_fd = h.event_handle(); // ← fd à mettre dans EventQueue match h.read_events(&mut events)? { ConsumerHandleEvent::Events(slice) => /* traite events */, ConsumerHandleEvent::Handoff => /* VT change, on perd le contrôle */, } ``` Le **handoff via `ESTALE`** est crucial : quand le VT switch (Ctrl-Alt-F2), inputd retourne ESTALE — Orbital sait qu'il doit se mettre en veille proprement. Le compositor Wayland devra gérer la même sémantique. ### 3.2 Drivers input `base/drivers/input/` : - `ps2d` — clavier/souris PS/2 (legacy + KVM) - `usbhidd` — HID USB (clavier, souris, tablette) Tous écrivent vers `/scheme/input/producer`. inputd dédoublonne, séquence, attribue au VT actif, transmet au consumer. ### 3.3 Format d'event `orbclient::Event` (struct C-compatible) — défini dans la crate `orbclient`. Types : `KeyEvent`, `MouseEvent`, `MouseRelativeEvent`, `ButtonEvent`, `ScrollEvent`, `FocusEvent`, `QuitEvent`, etc. **Pour Wayland** : - Mapping `orbclient::KeyEvent` → `wl_keyboard.key` : direct - Codes de touches : `orbclient` utilise des scancodes — il faudra traduire vers les **keycodes XKB** que Wayland attend - ⚠️ **xkb keymap** : à concevoir, voir section 5 --- ## 4. Primitives OS pour Wayland (relibc) Vérifications effectuées dans `~/Projets/Redox/relibc/src/`. ### 4.1 Sockets Unix (AF_UNIX) `platform/redox/socket.rs` : - AF_UNIX **bind/connect** : implémenté via syscall direct (commentaire ligne 69 : *"bind/connect with AF_UNIX were replaced with SYS_CALL"*) - Path encoding : `chan:<path>` (ligne 177 : `buf.starts_with(b"chan:")`) - SOCK_STREAM ✅ et SOCK_DGRAM ✅ supportés - Compatible avec l'usage Wayland (`$XDG_RUNTIME_DIR/wayland-N`) ### 4.2 fd passing — `sendmsg` / `recvmsg` avec SCM_RIGHTS **🟢 Critique** : `platform/redox/socket.rs` : - Lignes 272 et 447 : `(SOL_SOCKET, SCM_RIGHTS)` traité dans cmsghdr - Lignes 835 et 924 : `recvmsg` / `sendmsg` implémentés en interne C'est **le pré-requis n°1** du plan (risque majeur 1) — il est rempli. Il faut quand même écrire des tests dédiés en phase 2 pour valider : - Passage simple de fd entre deux processus - Multiple fds dans un même cmsg - Passage d'un fd shm + lecture côté receveur ### 4.3 Mémoire partagée — `shm_open` + mmap **`shm_open`** : `header/sys_mman/mod.rs:185` : ```rust pub unsafe extern "C" fn shm_open(name, oflag, mode) -> c_int { // traduit "/foo" → "/scheme/shm/foo" puis open() classique } ``` Mécanisme : un scheme dédié `/scheme/shm/` sert de namespace (équivalent `/dev/shm` Linux mais via le scheme system). **`mmap MAP_SHARED`** : présent (`header/sys_mman/mod.rs`). Tous les buffers DRM dumb sont déjà mappés ainsi par `graphics-ipc`. ### 4.4 ⚠️ `memfd_create` - Numéro syscall défini : `__NR_memfd_create = 319` (x86_64) - **Implémentation** : pas vue dans la sortie grep — probablement absente ou stub - **Impact pour Wayland** : libwayland-client moderne préfère `memfd_create` pour les shm pools (pas de path needed). Fallback : `shm_open` avec nom unique → fonctionne, juste un peu plus verbeux À traiter en phase 2 : - Soit implémenter `memfd_create` au-dessus de `shm_open + shm_unlink` - Soit ajouter une couche `cfg(target_os = "redox")` côté `wayland-client` qui force le path shm_open ### 4.5 Event loop / poll - `header/poll/mod.rs` : `poll()` POSIX disponible - `header/sys_select/mod.rs` : `select` POSIX - `header/sys_epoll/mod.rs` : `epoll_*` (probablement émulé sur Redox via l'EventQueue native — à vérifier) - **Native Redox** : `redox_event::EventQueue` — utilisé par Orbital, plus idiomatique. Pour le compositor Rust pur, autant l'utiliser directement plutôt que de passer par poll() POSIX. --- ## 5. Manques identifiés (à traiter dans le plan) ### 5.1 Pas de keymap XKB sur Redox Wayland exige que le serveur envoie un keymap XKB au client (`wl_keyboard.keymap` event, format `XKB_V1`). Or : - Redox utilise des scancodes orbclient - Pas de `xkbcommon` packagé sur Redox (à confirmer en cherchant la recette) - Pas de fichiers de keymap XKB système **À traiter en phase 5 (backend input)** : - Option A : porter `libxkbcommon` (C, ~10k loc) - Option B : utiliser la crate Rust `xkb` (wrapper xkbcommon, dépend du C) - Option C : implémenter un sous-ensemble XKB en Rust (plus long mais cohérent avec l'esprit du projet) Recommandation : **Option C** mais avec scope minimal (US layout + variantes basiques) au début. La crate `xkeysym` peut servir de base. ### 5.2 Pas d'AT-SPI / dbus pour l'accessibilité - Phase 11 du plan vise navigation clavier + métadata d'accessibilité - Sur Linux, AT-SPI transporte ces métadata via dbus - Dbus existe sur Redox mais portage limité ; AT-SPI n'est pas porté - À concevoir : protocole Redox simple d'accessibilité, ou wayland-protocols custom (text-input-v3 comme point de départ) ### 5.3 GPU userspace driver manquant - vesad et virtio-gpud existent mais pas de DRM driver "GPU complet" hors virtio - Mesa3D Redox = LLVMpipe seulement (CPU) - Phase 12 du plan = GPU expérimental — restera CPU pour le MVP - À documenter : aucune accélération hardware n'est garantie pour les phases 0-11 ### 5.4 Pas de session manager / VT API stable - Sur Linux : `logind` / `seatd` gèrent les VT et l'accès aux devices - Sur Redox : `inputd` joue un rôle similaire mais pas équivalent - Pour Smithay (phase 13), il faudra un backend session Redox basé sur inputd --- ## 6. Ce qui est réutilisable directement | Composant Redox actuel | Usage dans le compositor Wayland | |---|---| | `redox_event::EventQueue` | Boucle principale du compositor | | `redox-scheme::SchemeSync` | Si on choisit aussi de publier un scheme `wayland:` | | `graphics-ipc::V2GraphicsHandle` | Backend display (phase 4) — direct | | `graphics-ipc::CpuBackedBuffer` | wl_shm composition (phase 6) — direct | | `inputd::ConsumerHandle` | Backend input (phase 5) — direct | | `orbital/src/compositor.rs` damage tracking | Référence pour notre damage logic (phase 6-7) | | `orbital/src/scheme.rs` focus + raccourcis | Référence pour focus management (phase 7) | | `redox-log` | Logging | | Crate `drm` upstream | Si on veut adresser DRM directement | --- ## 7. Décisions recommandées pour la suite ### Phase 2 (primitives OS) — peut être réduite Plutôt que d'auditer toutes les primitives, **se limiter à des tests dédiés** : 1. Test fd passing : 2 processus, l'un crée un memfd-like, l'autre le mappe 2. Test Unix socket SOCK_STREAM avec messages Wayland-shaped (header binaire) 3. Test event loop multi-fd avec signaux POSIX 4. Test concurrent shm_open/mmap depuis plusieurs processus Si les 4 tests passent, on a la garantie que `wayland-rs` peut tourner. Estimation : **1 mois à 2h/jour** au lieu des 6 mois initialement budgétés. ### Phase 3 (port wayland-rs) — à découper `wayland-rs` upstream a peu de deps OS-specifiques dans son crate `wayland-backend`. Ordre suggéré : 1. `wayland-scanner` (génération code XML → Rust) : pure logic, devrait marcher tel quel 2. `wayland-backend` : couche socket — vérifier le `cfg(unix)` vs ajout d'un `cfg(target_os = "redox")` 3. `wayland-server` : haut niveau — devrait fonctionner si backend OK 4. `wayland-client` : symétrique ### Phase 4 (display backend) — voie rapide possible `V2GraphicsHandle` est si proche de l'API DRM Linux qu'on peut s'inspirer directement de `core/display.rs` d'Orbital pour le RedoxOutput. **Estimation : 2 mois à 2h/jour** (au lieu des 6 mois si on partait de zéro). --- ## 8. Repos clonés localement pour la suite ```text ~/Projets/Redox/ ├── orbital/ ← référence compositor (gitlab.redox-os.org/redox-os/orbital) ├── base/ ← drivers + graphics-ipc + inputd (gitlab.redox-os.org/redox-os/base) ├── relibc/ ← libc Redox, primitives POSIX (--depth 1) ├── redox-src/ ← repo umbrella, ~/Projets/Redox/redox-src/build/x86_64/desktop/harddrive.img └── docs/existing-redox-gui.md ← ce document ``` Sources additionnelles à cloner si on creuse plus : - `redox-os/wayland-rs-redox-fork` *(à créer le moment venu)* - `redox-os/drivers` *(déjà inclus dans base/drivers/)* - `Smithay/smithay` *(plus tard, phase 13)* --- ## 9. Documents à produire ensuite Selon le plan directeur (section "Documents A Produire Ensuite") : | Document | Quand | Contenu | |---|---|---| | `redox-wayland-primitives.md` | Phase 2, après tests | Résultats des 4 tests dédiés + conclusions | | `compositor-architecture.md` | Phase 3-4 | Crates, traits, flux de données | | `display-backend-redox.md` | Phase 4 | Détails RedoxOutput + dirty_framebuffer flow | | `input-backend-redox.md` | Phase 5 | Mapping orbclient → Wayland + XKB strategy | | `software-rendering-and-gpu-roadmap.md` | Phase 4 + 12 | CPU paths + GPU horizon | | `accessibility-roadmap.md` | Phase 11 | Décisions sans AT-SPI | | `orbital-migration.md` | Phase 8-9 | Comment porter winit/softbuffer/clients | | `cosmic-smithay-roadmap.md` | Phase 13 | Quand y aller, dépendances bloquantes | | `x11-compat-rust-roadmap.md` | Phase 14 | Projet séparé | --- *Fin de l'audit phase 1.*