redox-wayland-compositor/docs/existing-redox-gui.md
Votre Nom 53e6626231 Initial commit: phases 1-3 du portage Wayland Rust pour Redox OS
Plan directeur 14 phases / 5 ans (REDOX_COSMIC_XWAYLAND_RS_PLAN.md).

Phase 1 — Audit Redox (docs/existing-redox-gui.md, 486 lignes) :
- Orbital, graphics-ipc (API DRM compatible Linux subset KMS), inputd, vesad
- relibc support : AF_UNIX, SCM_RIGHTS, shm_open, mmap, poll
- 3 manques identifiés : memfd_create, keymap XKB, AT-SPI

Phase 2 — Validation primitives sur Redox via redoxer (5 tests + 1 POC) :
- test-unix-socket : SOCK_STREAM Wayland-shaped roundtrip
- test-fd-passing : SCM_RIGHTS mono-process (artefact kernel)
- test-fd-passing-fork : SCM_RIGHTS multi-process (validation Wayland critique)
- test-shm-open : shm_open + mmap + persistance + unlink
- test-poll-multifd : poll() multiplexing + POLLHUP
- poc-pixels : datapath shm + SCM_RIGHTS bout en bout (10000 pixels ARGB)

Phase 3 — wayland-rs sur Redox (compile + runtime) :
- wayland-{scanner,backend,server,client} compilent pour x86_64-unknown-redox
  sans patch upstream (rustix supporte Redox via libc backend)
- test-handshake : server/client wl_registry handshake roundtrip
- test-shm-pipeline : pipeline complet (ListeningSocket Unix réel + fd passing
  via wl_shm.create_pool + wl_shm_pool + wl_buffer + wl_surface + commit +
  serveur lit pixels via fd reçu, validation pixel-perfect)

Verdict phase 3 : wayland-rs upstream est viable sur Redox out-of-the-box,
le port "Wayland sur Redox" est désormais un problème de compositor à écrire,
pas de stack à porter.

Prérequis build : redoxer (pas cargo direct, car CMSG_NXTHDR/CMSG_DATA
ne sont pas linkés autrement vers librelibc.a).

Leyoda 2026 – GPLv3
2026-05-08 17:41:55 +02:00

19 KiB

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) :

main()
  └─ orbital()
       ├─ lit env "VT" (passé par inputd au boot)
       ├─ Orbital::open_display()           ← ouvre display via inputd
       ├─ exec "inputd -A <vt>"             ← 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 :

EventQueue<Source>
  ├─ 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) :

open("/scheme/orbital/<flags>/<x>/<y>/<w>/<h>/<title>")
  → 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 :

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

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) :

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 :

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::KeyEventwl_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 :

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

~/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.