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/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()) } 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 218da3c62f..83bf152367 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,65 +46,47 @@ 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, next_id: AtomicUsize, next_vt_id: AtomicUsize, - vts: BTreeMap, + display: Option, + vts: BTreeSet, super_key: bool, active_vt: Option, has_new_events: bool, - maybe_perform_handoff_to: Option, } 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, has_new_events: false, - maybe_perform_handoff_to: None, } } - 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_key(&new_active) { + if !self.vts.contains(&new_active) { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); - return Ok(()); + return; } log::info!( @@ -120,7 +102,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, @@ -136,8 +118,6 @@ impl InputScheme { } self.active_vt = Some(new_active); - - Ok(()) } } @@ -164,19 +144,42 @@ impl Scheme for InputScheme { vt: target, } } - "handle_early" => { + "handle" | "handle_early" => { let display = path_parts.collect::>().join("."); - Handle::Display { - events: EventFlags::empty(), - pending: Vec::new(), - notified: false, - device: display, - is_earlyfb: true, + + let needs_handoff = match command { + "handle_early" => self.display.is_none(), + "handle" => 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()); + + for handle in self.handles.values_mut() { + match handle { + Handle::Consumer { + needs_handoff, + notified, + .. + } => { + *needs_handoff = true; + *notified = false; + } + _ => continue, + } + } } - } - "handle" => { - let display = path_parts.collect::>().join("."); - self.maybe_perform_handoff_to = Some(display.clone()); + Handle::Display { events: EventFlags::empty(), pending: if let Some(active_vt) = self.active_vt { @@ -192,7 +195,7 @@ impl Scheme for InputScheme { }, notified: false, device: display, - is_earlyfb: false, + is_earlyfb: command == "handle_early", } } "control" => Handle::Control, @@ -213,8 +216,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]); @@ -265,7 +268,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); + + 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::()); @@ -315,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()); } @@ -378,7 +386,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(), @@ -400,12 +408,12 @@ impl Scheme for InputScheme { } if let Some(new_active) = new_active_opt { - self.switch_vt(new_active)?; + self.switch_vt(new_active); } } 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() { @@ -500,55 +508,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() { - 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; - - Some(i) - } else { - None - } - }) - .collect::>(); - - 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; - } - _ => continue, - } - } - } - if !scheme.has_new_events { continue; } @@ -560,7 +519,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 +528,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())?; @@ -635,6 +586,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"); } }