Phase 4.1-4.3 : test display backend Redox
Crate redox-wl-test-display-backend qui réutilise le pattern Orbital : inputd::ConsumerHandle::new_vt() → open_display_v2() → V2GraphicsHandle. Comportement vérifié : - compile pour x86_64-unknown-redox sans patch (graphics-ipc, inputd, drm via git deps gitlab.redox-os.org/redox-os/base.git, comme Orbital) - sous redoxer run headless : ConsumerHandle::new_vt() OK, open_display_v2 retourne EINVAL (cohérent avec absence framebuffer) - runtime sur framebuffer (redoxer --gui ou make qemu) : à valider manuellement par le user (la fenêtre QEMU étant interactive) README enrichi avec la marche à suivre pour les tests display (voie A: redoxer exec --gui ; voie B: redoxfs + make qemu). Leyoda 2026 – GPLv3
This commit is contained in:
parent
53e6626231
commit
c6ad583a72
3 changed files with 185 additions and 1 deletions
34
README.md
34
README.md
|
|
@ -27,7 +27,8 @@ fd reçu — pixel-perfect.
|
|||
│ ├── redox-wl-test-poll-multifd/ # primitive 4 : poll() multiplexing + POLLHUP
|
||||
│ ├── redox-wl-poc-pixels/ # POC : datapath shm + SCM_RIGHTS bout en bout
|
||||
│ ├── redox-wl-test-handshake/ # phase 3 : wayland-rs server/client registry
|
||||
│ └── redox-wl-test-shm-pipeline/ # phase 3 : pipeline shm complet validé
|
||||
│ ├── redox-wl-test-shm-pipeline/ # phase 3 : pipeline shm complet validé
|
||||
│ └── redox-wl-test-display-backend/ # phase 4.1 : ouvre display Redox via inputd + V2GraphicsHandle
|
||||
└── (pas de Cargo.toml racine : chaque crate est standalone — voir note ci-dessous)
|
||||
```
|
||||
|
||||
|
|
@ -59,6 +60,37 @@ Pattern attendu en fin d'exécution : `[test-XX] PASS: ...`.
|
|||
> qui fait un fail au link (`undefined reference CMSG_NXTHDR/CMSG_DATA`) parce que le linker host
|
||||
> ne sait pas chaîner librelibc.a du sysroot Redox. `redoxer` configure le linker correctement.
|
||||
|
||||
## Tests qui exigent un vrai framebuffer
|
||||
|
||||
Les binaires qui touchent au display (à partir de `redox-wl-test-display-backend`)
|
||||
ne tourneront pas sous `redoxer run` standard car celui-ci est headless.
|
||||
Deux voies pour les exécuter :
|
||||
|
||||
### Voie A — `redoxer exec --gui` (mini-VM interactive)
|
||||
```bash
|
||||
cd crates/redox-wl-test-display-backend
|
||||
redoxer build --release
|
||||
redoxer exec --gui target/x86_64-unknown-redox/release/redox-wl-test-display-backend
|
||||
```
|
||||
Ouvre une fenêtre QEMU, boote une mini-VM Redox avec framebuffer, lance le binaire.
|
||||
À fermer manuellement quand le test est fini.
|
||||
|
||||
### Voie B — Image complète + `make qemu`
|
||||
Pousser le binaire dans une image Redox bootable via redoxfs-fuse :
|
||||
```bash
|
||||
# Monter l'image
|
||||
sudo modprobe fuse
|
||||
mkdir -p /tmp/redox-mnt
|
||||
redoxfs ~/Projets/Redox/redox-src/build/x86_64/desktop/harddrive.img /tmp/redox-mnt
|
||||
# Copier le binaire
|
||||
sudo cp target/x86_64-unknown-redox/release/redox-wl-test-display-backend /tmp/redox-mnt/usr/bin/
|
||||
# Démonter
|
||||
fusermount -u /tmp/redox-mnt
|
||||
# Booter
|
||||
cd ~/Projets/Redox/redox-src && make qemu audio=no
|
||||
# Dans Redox : login user / password root, puis lancer le binaire
|
||||
```
|
||||
|
||||
## Roadmap
|
||||
|
||||
Voir `REDOX_COSMIC_XWAYLAND_RS_PLAN.md` pour le plan complet 14 phases / 5 ans.
|
||||
|
|
|
|||
11
crates/redox-wl-test-display-backend/Cargo.toml
Normal file
11
crates/redox-wl-test-display-backend/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "redox-wl-test-display-backend"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
drm = "0.15"
|
||||
graphics-ipc = { git = "https://gitlab.redox-os.org/redox-os/base.git" }
|
||||
inputd = { git = "https://gitlab.redox-os.org/redox-os/base.git" }
|
||||
libredox = "0.1"
|
||||
orbclient = "0.3"
|
||||
141
crates/redox-wl-test-display-backend/src/main.rs
Normal file
141
crates/redox-wl-test-display-backend/src/main.rs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
//! Phase 4 — Test display backend Redox.
|
||||
//!
|
||||
//! Premier binaire qui touche au display Redox. Réutilise exactement le pattern
|
||||
//! d'Orbital (cf orbital/src/core/mod.rs et core/display.rs) :
|
||||
//!
|
||||
//! inputd::ConsumerHandle::new_vt()
|
||||
//! └─> open_display_v2()
|
||||
//! └─> graphics_ipc::V2GraphicsHandle::from_file
|
||||
//! └─> drm::Device + drm::control::Device (subset KMS Redox)
|
||||
//!
|
||||
//! Comportement attendu selon environnement :
|
||||
//!
|
||||
//! - sous `redoxer run` (headless, pas de framebuffer) : ConsumerHandle::new_vt()
|
||||
//! ouvre /scheme/input/consumer, mais open_display_v2 va probablement échouer
|
||||
//! parce que vesad/virtio-gpud n'a pas de display à offrir. On capture l'erreur.
|
||||
//!
|
||||
//! - dans une vraie session Redox bootée via `make qemu` (avec framebuffer) :
|
||||
//! le display s'ouvre, on énumère les connecteurs et modes. Si on a au moins
|
||||
//! un display connecté, on alloue un CpuBackedBuffer ARGB et on dessine un
|
||||
//! pattern dedans. Note : on ne fait PAS encore de modeset (pas de set_crtc)
|
||||
//! parce qu'Orbital tient déjà le display. Ce test reste lecture seule à ce
|
||||
//! stade — phase 4 vraie consiste à *prendre la place* d'Orbital.
|
||||
|
||||
use std::io;
|
||||
use std::process::ExitCode;
|
||||
|
||||
use drm::Device as _;
|
||||
use drm::control::{Device as _, connector::State};
|
||||
use graphics_ipc::V2GraphicsHandle;
|
||||
use inputd::ConsumerHandle;
|
||||
|
||||
fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||
println!("[disp] Phase 4 display backend test on Redox");
|
||||
|
||||
// Step 1: open consumer handle (talks to inputd)
|
||||
let consumer = ConsumerHandle::new_vt().map_err(|e| {
|
||||
format!(
|
||||
"ConsumerHandle::new_vt failed (expected in headless redoxer): {e} \
|
||||
(errno {})",
|
||||
io::Error::last_os_error().raw_os_error().unwrap_or(0)
|
||||
)
|
||||
})?;
|
||||
println!("[disp] inputd consumer handle opened");
|
||||
|
||||
// Step 2: open display via inputd's fpath redirection
|
||||
let display_file = consumer.open_display_v2().map_err(|e| {
|
||||
format!(
|
||||
"open_display_v2 failed (expected in headless redoxer): {e}"
|
||||
)
|
||||
})?;
|
||||
println!("[disp] display file opened from inputd path");
|
||||
|
||||
// Step 3: wrap as V2GraphicsHandle (subset DRM Linux)
|
||||
let handle = V2GraphicsHandle::from_file(display_file)?;
|
||||
println!("[disp] V2GraphicsHandle created");
|
||||
|
||||
// Step 4: enumerate connectors
|
||||
let resources = handle.resource_handles()?;
|
||||
let connectors = resources.connectors();
|
||||
println!("[disp] {} connector(s) reported by KMS subset", connectors.len());
|
||||
|
||||
let mut connected_count = 0;
|
||||
for (i, &conn) in connectors.iter().enumerate() {
|
||||
match handle.get_connector(conn, true) {
|
||||
Ok(info) => {
|
||||
let state = info.state();
|
||||
let modes = info.modes();
|
||||
println!(
|
||||
"[disp] #{i} connector {:?}: state={:?}, {} mode(s)",
|
||||
conn,
|
||||
state,
|
||||
modes.len()
|
||||
);
|
||||
if state == State::Connected {
|
||||
connected_count += 1;
|
||||
if let Some(mode) = modes.first() {
|
||||
let (w, h) = mode.size();
|
||||
println!("[disp] first mode: {w}x{h}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("[disp] #{i} connector {:?}: get_connector failed: {e}", conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if connected_count == 0 {
|
||||
return Err("no connected display found".into());
|
||||
}
|
||||
println!("[disp] {connected_count} connected display(s)");
|
||||
|
||||
// Step 5: capabilities probe
|
||||
use drm::DriverCapability;
|
||||
let dumb = handle.get_driver_capability(DriverCapability::DumbBuffer);
|
||||
let cursor_w = handle.get_driver_capability(DriverCapability::CursorWidth);
|
||||
let cursor_h = handle.get_driver_capability(DriverCapability::CursorHeight);
|
||||
println!(
|
||||
"[disp] driver caps: dumb_buffer={:?} cursor={}x{}",
|
||||
dumb,
|
||||
cursor_w.map(|v| v.to_string()).unwrap_or_else(|_| "?".into()),
|
||||
cursor_h.map(|v| v.to_string()).unwrap_or_else(|_| "?".into()),
|
||||
);
|
||||
|
||||
// Step 6: try allocating a CpuBackedBuffer of a small size, paint a pattern,
|
||||
// and destroy it. This validates the buffer pipeline of graphics-ipc without
|
||||
// setting it as scanout (which would require a CRTC takeover from Orbital).
|
||||
use drm::buffer::DrmFourcc;
|
||||
use graphics_ipc::CpuBackedBuffer;
|
||||
let (test_w, test_h) = (64u32, 64u32);
|
||||
let mut buf = CpuBackedBuffer::new(&handle, (test_w, test_h), DrmFourcc::Argb8888, 32)?;
|
||||
println!(
|
||||
"[disp] CpuBackedBuffer allocated {}x{} ARGB8888 (shadow={})",
|
||||
test_w,
|
||||
test_h,
|
||||
buf.has_shadow_buf()
|
||||
);
|
||||
let bytes = buf.shadow_buf();
|
||||
for (i, b) in bytes.iter_mut().enumerate() {
|
||||
*b = (i & 0xFF) as u8;
|
||||
}
|
||||
buf.sync_rect(0, 0, test_w, test_h);
|
||||
println!("[disp] painted test pattern + sync_rect");
|
||||
buf.destroy(&handle)?;
|
||||
println!("[disp] CpuBackedBuffer destroyed");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() -> ExitCode {
|
||||
match run() {
|
||||
Ok(()) => {
|
||||
println!("[disp] PASS: display backend pipeline reachable");
|
||||
ExitCode::SUCCESS
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("[disp] FAIL: {e}");
|
||||
ExitCode::FAILURE
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue