From 9779d1884eb8e3390763f9faad4dfc6b84c0899a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 14:07:39 +0100 Subject: [PATCH 1/9] inputd: Remove the active vt check before post_fevent No input is added to pending anyway when the vt for the consumer isn't the active vt anyway. --- inputd/src/main.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 218da3c62f..0667fca53e 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -560,7 +560,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { pending, needs_handoff, ref mut notified, - vt, + .. } => { if (!*needs_handoff && pending.is_empty()) || *notified @@ -569,14 +569,6 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { continue; } - let active_vt = scheme.active_vt.unwrap(); - - // The activate VT is not the same as the VT that the consumer is listening to - // for events. - if !*needs_handoff && active_vt != *vt { - continue; - } - // Notify the consumer that we have some events to read. Yum yum. socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; From de0239d3edd558b845dfe3fcd7f19b2ae702c9e8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 15:51:32 +0100 Subject: [PATCH 2/9] inputd: Automatically switch to first vt once created --- graphics/fbbootlogd/src/main.rs | 4 ---- graphics/vesad/src/main.rs | 3 --- inputd/src/main.rs | 5 +++++ 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index ca1c3863df..8584718c5d 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -26,16 +26,12 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { let mut scheme = FbbootlogScheme::new(); - let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); - // This is not possible for now as fbbootlogd needs to open new displays at runtime for graphics // driver handoff. In the future inputd may directly pass a handle to the display instead. //libredox::call::setrens(0, 0).expect("fbbootlogd: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); - inputd_control_handle.activate_vt(1).unwrap(); - loop { let request = match socket .next_request(SignalBehavior::Restart) diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 541ce13d79..3a74ee42e9 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -83,7 +83,6 @@ fn main() { } fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[()]) -> ! { let mut inputd_display_handle = DisplayHandle::new_early("vesa").unwrap(); - let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); for &() in spec.iter() { inputd_display_handle.register_vt().unwrap(); @@ -121,8 +120,6 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( daemon.ready().expect("failed to notify parent"); - inputd_control_handle.activate_vt(1).unwrap(); - let all = [Source::Input, Source::Scheme]; for event in all .into_iter() diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 0667fca53e..97790238d7 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -266,6 +266,11 @@ impl Scheme for InputScheme { let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); log::info!("inputd: created VT #{vt} for {device}"); self.vts.insert(vt, Vt::new(device.clone())); + + if self.active_vt.is_none() { + self.switch_vt(vt)?; + } + Ok(vt) } else if buf.len() % size_of::() == 0 { let copy = core::cmp::min(pending.len(), buf.len() / size_of::()); From a0a8401e8d6a4acf5d3be031d8a5b20e1c8fbc4e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 16:03:24 +0100 Subject: [PATCH 3/9] inputd: Inline a couple of functions --- inputd/src/main.rs | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 97790238d7..ce902a44ed 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -46,25 +46,11 @@ enum Handle { Control, } -impl Handle { - pub fn is_producer(&self) -> bool { - matches!(self, Handle::Producer) - } -} - #[derive(Debug)] struct Vt { display: String, } -impl Vt { - fn new(display: impl Into) -> Self { - Self { - display: display.into(), - } - } -} - struct InputScheme { handles: BTreeMap, @@ -265,7 +251,12 @@ impl Scheme for InputScheme { // Trying to do an empty read creates a new VT. let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); log::info!("inputd: created VT #{vt} for {device}"); - self.vts.insert(vt, Vt::new(device.clone())); + self.vts.insert( + vt, + Vt { + display: device.clone(), + }, + ); if self.active_vt.is_none() { self.switch_vt(vt)?; @@ -410,7 +401,7 @@ impl Scheme for InputScheme { } let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - assert!(handle.is_producer()); + assert!(matches!(handle, Handle::Producer)); if let Some(active_vt) = self.active_vt { for handle in self.handles.values_mut() { @@ -632,6 +623,6 @@ fn main() { _ => panic!("inputd: invalid argument: {}", val), } } else { - redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); + redox_daemon::Daemon::new(daemon_runner).expect("inputd: failed to daemonize"); } } From cd193f2aedea062a5fda195ce02260b8348ec55e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:03:23 +0100 Subject: [PATCH 4/9] inputd: Unconditionally perform handoff for all vts together In preparation for having a single set of graphics drivers for all vts. --- inputd/src/main.rs | 48 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index ce902a44ed..eb6caaadfd 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -162,7 +162,18 @@ impl Scheme for InputScheme { } "handle" => { let display = path_parts.collect::>().join("."); - self.maybe_perform_handoff_to = Some(display.clone()); + let needs_handoff = self.handles.values().all(|handle| { + !matches!( + handle, + Handle::Display { + is_earlyfb: false, + .. + } + ) + }); + if needs_handoff { + self.maybe_perform_handoff_to = Some(display.clone()); + } Handle::Display { events: EventFlags::empty(), pending: if let Some(active_vt) = self.active_vt { @@ -497,46 +508,19 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } if let Some(display) = scheme.maybe_perform_handoff_to.take() { - let early_displays = scheme - .handles - .values() - .filter_map(|handle| match handle { - Handle::Display { - device, - is_earlyfb: true, - .. - } => Some(&**device), - _ => None, - }) - .collect::>(); - let vts = scheme - .vts - .iter_mut() - .filter_map(|(&i, vt)| { - if early_displays.contains(&&*vt.display) { - vt.display = display.clone(); + scheme.has_new_events = true; - scheme.has_new_events = true; - - Some(i) - } else { - None - } - }) - .collect::>(); + for vt in scheme.vts.values_mut() { + vt.display = display.clone(); + } for handle in scheme.handles.values_mut() { match handle { Handle::Consumer { needs_handoff, notified, - vt, .. } => { - if !vts.contains(vt) { - continue; - } - *needs_handoff = true; *notified = false; } From ec442b87a3f109745cc25c76d152dc08fec82f3e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:23:27 +0100 Subject: [PATCH 5/9] inputd: Use a single global display rather than have a per-vt display selection --- inputd/src/main.rs | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index eb6caaadfd..b642d5f8aa 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -12,7 +12,7 @@ //! events are available. use core::mem::size_of; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::mem::transmute; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -46,18 +46,14 @@ enum Handle { Control, } -#[derive(Debug)] -struct Vt { - display: String, -} - struct InputScheme { handles: BTreeMap, next_id: AtomicUsize, next_vt_id: AtomicUsize, - vts: BTreeMap, + display: Option, + vts: BTreeSet, super_key: bool, active_vt: Option, @@ -68,11 +64,13 @@ struct InputScheme { impl InputScheme { fn new() -> Self { Self { + handles: BTreeMap::new(), + next_id: AtomicUsize::new(0), next_vt_id: AtomicUsize::new(1), - handles: BTreeMap::new(), - vts: BTreeMap::new(), + display: None, + vts: BTreeSet::new(), super_key: false, active_vt: None, @@ -88,7 +86,7 @@ impl InputScheme { } } - if !self.vts.contains_key(&new_active) { + if !self.vts.contains(&new_active) { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); return Ok(()); } @@ -106,7 +104,7 @@ impl InputScheme { device, .. } => { - if &self.vts[&new_active].display == &*device { + if self.display.as_deref() == Some(&*device) { pending.push(VtEvent { kind: VtEventKind::Activate, vt: new_active, @@ -152,6 +150,9 @@ impl Scheme for InputScheme { } "handle_early" => { let display = path_parts.collect::>().join("."); + if self.display.is_none() { + self.maybe_perform_handoff_to = Some(display.clone()); + } Handle::Display { events: EventFlags::empty(), pending: Vec::new(), @@ -210,8 +211,8 @@ impl Scheme for InputScheme { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; if let Handle::Consumer { vt, .. } = handle { - let display = self.vts.get(vt).ok_or(SysError::new(EINVAL))?; - let vt = format!("{}:{vt}", display.display); + let display = self.display.as_ref().ok_or(SysError::new(EINVAL))?; + let vt = format!("{}:{vt}", display); let size = core::cmp::min(vt.len(), buf.len()); buf[..size].copy_from_slice(&vt.as_bytes()[..size]); @@ -262,12 +263,7 @@ impl Scheme for InputScheme { // Trying to do an empty read creates a new VT. let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); log::info!("inputd: created VT #{vt} for {device}"); - self.vts.insert( - vt, - Vt { - display: device.clone(), - }, - ); + self.vts.insert(vt); if self.active_vt.is_none() { self.switch_vt(vt)?; @@ -385,7 +381,7 @@ impl Scheme for InputScheme { device, .. } => { - if &self.vts[&self.active_vt.unwrap()].display == &*device { + if self.display.as_ref() == Some(device) { pending.push(VtEvent { kind: VtEventKind::Resize, vt: self.active_vt.unwrap(), @@ -510,9 +506,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { if let Some(display) = scheme.maybe_perform_handoff_to.take() { scheme.has_new_events = true; - for vt in scheme.vts.values_mut() { - vt.display = display.clone(); - } + scheme.display = Some(display.clone()); for handle in scheme.handles.values_mut() { match handle { From f8972400ee7c7a57400eb72e9250ab9d12bbca41 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:36:41 +0100 Subject: [PATCH 6/9] inputd: Move handoff logic to fn open --- inputd/src/main.rs | 56 ++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index b642d5f8aa..44fb836074 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -58,7 +58,6 @@ struct InputScheme { active_vt: Option, has_new_events: bool, - maybe_perform_handoff_to: Option, } impl InputScheme { @@ -75,7 +74,6 @@ impl InputScheme { active_vt: None, has_new_events: false, - maybe_perform_handoff_to: None, } } @@ -151,7 +149,22 @@ impl Scheme for InputScheme { "handle_early" => { let display = path_parts.collect::>().join("."); if self.display.is_none() { - self.maybe_perform_handoff_to = Some(display.clone()); + self.has_new_events = true; + self.display = Some(display.clone()); + + for handle in self.handles.values_mut() { + match handle { + Handle::Consumer { + needs_handoff, + notified, + .. + } => { + *needs_handoff = true; + *notified = false; + } + _ => continue, + } + } } Handle::Display { events: EventFlags::empty(), @@ -173,7 +186,22 @@ impl Scheme for InputScheme { ) }); if needs_handoff { - self.maybe_perform_handoff_to = Some(display.clone()); + self.has_new_events = true; + self.display = Some(display.clone()); + + for handle in self.handles.values_mut() { + match handle { + Handle::Consumer { + needs_handoff, + notified, + .. + } => { + *needs_handoff = true; + *notified = false; + } + _ => continue, + } + } } Handle::Display { events: EventFlags::empty(), @@ -503,26 +531,6 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), } - if let Some(display) = scheme.maybe_perform_handoff_to.take() { - scheme.has_new_events = true; - - scheme.display = Some(display.clone()); - - for handle in scheme.handles.values_mut() { - match handle { - Handle::Consumer { - needs_handoff, - notified, - .. - } => { - *needs_handoff = true; - *notified = false; - } - _ => continue, - } - } - } - if !scheme.has_new_events { continue; } From 085a6e32c60f2e0094e50020b306f88de071a243 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:37:14 +0100 Subject: [PATCH 7/9] inputd: Unify early and non-early handle opening --- inputd/src/main.rs | 51 ++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 44fb836074..adbfe671c4 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -146,45 +146,23 @@ impl Scheme for InputScheme { vt: target, } } - "handle_early" => { + "handle" | "handle_early" => { let display = path_parts.collect::>().join("."); - if self.display.is_none() { - self.has_new_events = true; - self.display = Some(display.clone()); - for handle in self.handles.values_mut() { - match handle { - Handle::Consumer { - needs_handoff, - notified, + let needs_handoff = match command { + "handle_early" => self.display.is_none(), + "handle" => self.handles.values().all(|handle| { + !matches!( + handle, + Handle::Display { + is_earlyfb: false, .. - } => { - *needs_handoff = true; - *notified = false; } - _ => continue, - } - } - } - Handle::Display { - events: EventFlags::empty(), - pending: Vec::new(), - notified: false, - device: display, - is_earlyfb: true, - } - } - "handle" => { - let display = path_parts.collect::>().join("."); - let needs_handoff = self.handles.values().all(|handle| { - !matches!( - handle, - Handle::Display { - is_earlyfb: false, - .. - } - ) - }); + ) + }), + _ => unreachable!(), + }; + if needs_handoff { self.has_new_events = true; self.display = Some(display.clone()); @@ -203,6 +181,7 @@ impl Scheme for InputScheme { } } } + Handle::Display { events: EventFlags::empty(), pending: if let Some(active_vt) = self.active_vt { @@ -218,7 +197,7 @@ impl Scheme for InputScheme { }, notified: false, device: display, - is_earlyfb: false, + is_earlyfb: command == "handle_early", } } "control" => Handle::Control, From 67e9f298043814781117d9be75e9dfdf846af0c0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 18:57:10 +0100 Subject: [PATCH 8/9] inputd: switch_vt is infallible --- inputd/src/main.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index adbfe671c4..83bf152367 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -77,16 +77,16 @@ impl InputScheme { } } - fn switch_vt(&mut self, new_active: usize) -> syscall::Result<()> { + fn switch_vt(&mut self, new_active: usize) { if let Some(active_vt) = self.active_vt { if new_active == active_vt { - return Ok(()); + return; } } if !self.vts.contains(&new_active) { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); - return Ok(()); + return; } log::info!( @@ -118,8 +118,6 @@ impl InputScheme { } self.active_vt = Some(new_active); - - Ok(()) } } @@ -273,7 +271,7 @@ impl Scheme for InputScheme { self.vts.insert(vt); if self.active_vt.is_none() { - self.switch_vt(vt)?; + self.switch_vt(vt); } Ok(vt) @@ -325,7 +323,7 @@ impl Scheme for InputScheme { // SAFETY: We have verified the size of the buffer above. let cmd = unsafe { &*buf.as_ptr().cast::() }; - self.switch_vt(cmd.vt)?; + self.switch_vt(cmd.vt); return Ok(buf.len()); } @@ -410,7 +408,7 @@ impl Scheme for InputScheme { } if let Some(new_active) = new_active_opt { - self.switch_vt(new_active)?; + self.switch_vt(new_active); } } From 39dd9118c07c09544ce584b8757d9676d49166c8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 19:18:52 +0100 Subject: [PATCH 9/9] graphics/fbcond: Handle missing graphics driver at startup --- graphics/fbcond/src/display.rs | 53 ++++++++++++++++++++++------------ graphics/fbcond/src/text.rs | 22 +++++++------- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 8595ec6e9c..5e613c76b0 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,28 +1,39 @@ -use graphics_ipc::legacy::{Damage, DisplayMap, LegacyGraphicsHandle}; +use graphics_ipc::legacy::{Damage, LegacyGraphicsHandle}; use inputd::ConsumerHandle; use std::io; pub struct Display { pub input_handle: ConsumerHandle, - pub display_handle: LegacyGraphicsHandle, - pub map: DisplayMap, + pub map: Option, +} + +pub struct DisplayMap { + display_handle: LegacyGraphicsHandle, + pub inner: graphics_ipc::legacy::DisplayMap, } impl Display { pub fn open_vt(vt: usize) -> io::Result { let input_handle = ConsumerHandle::for_vt(vt)?; - let display_handle = Self::open_display(&input_handle)?; + if let Ok(display_handle) = Self::open_display(&input_handle) { + let map = display_handle + .map_display() + .unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")); - let map = display_handle - .map_display() - .unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")); - - Ok(Self { - input_handle, - display_handle, - map, - }) + Ok(Self { + input_handle, + map: Some(DisplayMap { + display_handle, + inner: map, + }), + }) + } else { + Ok(Self { + input_handle, + map: None, + }) + } } /// Re-open the display after a handoff. @@ -35,14 +46,16 @@ impl Display { match new_display_handle.map_display() { Ok(map) => { - self.map = map; - self.display_handle = new_display_handle; - eprintln!( "fbcond: Mapped new display with size {}x{}", - self.map.width(), - self.map.height() + map.width(), + map.height() ); + + self.map = Some(DisplayMap { + display_handle: new_display_handle, + inner: map, + }); } Err(err) => { eprintln!("failed to resize display: {}", err); @@ -57,6 +70,8 @@ impl Display { } pub fn sync_rects(&mut self, sync_rects: Vec) { - self.display_handle.sync_rects(&sync_rects).unwrap(); + if let Some(map) = &self.map { + map.display_handle.sync_rects(&sync_rects).unwrap(); + } } } diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 02f36377cc..3499316da2 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -120,17 +120,19 @@ impl TextScreen { } pub fn write(&mut self, buf: &[u8]) -> Result { - let damage = self.inner.write( - &mut console_draw::DisplayMap { - offscreen: self.display.map.ptr_mut(), - width: self.display.map.width(), - height: self.display.map.height(), - }, - buf, - &mut self.input, - ); + if let Some(map) = &mut self.display.map { + let damage = self.inner.write( + &mut console_draw::DisplayMap { + offscreen: map.inner.ptr_mut(), + width: map.inner.width(), + height: map.inner.height(), + }, + buf, + &mut self.input, + ); - self.display.sync_rects(damage); + self.display.sync_rects(damage); + } Ok(buf.len()) }