From a4a3c4f7e8868b2b7bee8a72abb672065a7254f5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 25 Sep 2022 16:46:13 -0600 Subject: [PATCH] vesad: Support multiple displays --- vesad/src/display.rs | 8 +- vesad/src/framebuffer.rs | 62 +++++++++ vesad/src/main.rs | 56 ++++++-- vesad/src/scheme.rs | 271 +++++++++++++++++++++++---------------- 4 files changed, 275 insertions(+), 122 deletions(-) create mode 100644 vesad/src/framebuffer.rs diff --git a/vesad/src/display.rs b/vesad/src/display.rs index fe04c500ce..2af08415a5 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -47,8 +47,8 @@ impl Display { .as_ptr() }; Display { - width: width, - height: height, + width, + height, offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } } } @@ -63,8 +63,8 @@ impl Display { .as_ptr() }; Display { - width: width, - height: height, + width, + height, offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }, font: FontCollection::from_bytes(FONT).into_font().unwrap(), font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(), diff --git a/vesad/src/framebuffer.rs b/vesad/src/framebuffer.rs new file mode 100644 index 0000000000..f3b879210e --- /dev/null +++ b/vesad/src/framebuffer.rs @@ -0,0 +1,62 @@ +use std::{ + ptr, + slice +}; + +pub struct FrameBuffer { + pub phys: usize, + pub width: usize, + pub height: usize, + pub stride: usize, +} + +impl FrameBuffer { + pub fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self { + Self { + phys, + width, + height, + stride, + } + } + + pub fn parse(var: &str) -> Option { + fn parse_number(part: &str) -> Option { + let (start, radix) = if part.starts_with("0x") { + (2, 16) + } else { + (0, 10) + }; + match usize::from_str_radix(&part[start..], radix) { + Ok(ok) => Some(ok), + Err(err) => { + eprintln!("vesad: failed to parse '{}': {}", part, err); + None + } + } + } + + let mut parts = var.split(','); + let phys = parse_number(parts.next()?)?; + let width = parse_number(parts.next()?)?; + let height = parse_number(parts.next()?)?; + let stride = parse_number(parts.next()?)?; + Some(Self::new(phys, width, height, stride)) + } + + pub unsafe fn map(&mut self) -> syscall::Result<&'static mut [u32]> { + let size = self.stride * self.height; + let virt = syscall::physmap( + self.phys, + size * 4, + syscall::PHYSMAP_WRITE | syscall::PHYSMAP_WRITE_COMBINE + )? as *mut u32; + //TODO: should we clear the framebuffer here? + ptr::write_bytes(virt, 0, size); + + Ok(slice::from_raw_parts_mut( + virt, + size + )) + } +} diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 87b1ef6b90..e2bb636c60 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -9,9 +9,13 @@ use std::io::{Read, Write}; use std::os::unix::io::{RawFd, FromRawFd}; use syscall::{Packet, SchemeMut, EVENT_READ}; -use crate::scheme::{DisplayScheme, HandleKind}; +use crate::{ + framebuffer::FrameBuffer, + scheme::{DisplayScheme, HandleKind} +}; pub mod display; +pub mod framebuffer; pub mod scheme; pub mod screen; @@ -24,7 +28,7 @@ fn main() { } else if arg == "G" { spec.push(true); } else { - println!("vesad: unknown screen type: {}", arg); + eprintln!("vesad: unknown screen type: {}", arg); } } @@ -38,7 +42,7 @@ fn main() { .expect("FRAMEBUFFER_HEIGHT not set"), 16 ).expect("failed to parse FRAMEBUFFER_HEIGHT"); - let physbaseptr = usize::from_str_radix( + let phys = usize::from_str_radix( &env::var("FRAMEBUFFER_ADDR") .expect("FRAMEBUFFER_ADDR not set"), 16 @@ -49,17 +53,48 @@ fn main() { 16 ).expect("failed to parse FRAMEBUFFER_STRIDE"); - println!("vesad: {}x{} stride {} at 0x{:X}", width, height, stride, physbaseptr); + println!("vesad: {}x{} stride {} at 0x{:X}", width, height, stride, phys); - if physbaseptr == 0 { + if phys == 0 { return; } - redox_daemon::Daemon::new(|daemon| inner(daemon, width, height, physbaseptr, stride, &spec)).expect("failed to create daemon"); + + let mut framebuffers = vec![FrameBuffer::new( + phys, + width, + height, + stride, + )]; + + //TODO: ideal maximum number of outputs? + for i in 1..1024 { + match env::var(&format!("FRAMEBUFFER{}", i)) { + Ok(var) => match FrameBuffer::parse(&var) { + Some(fb) => { + println!( + "vesad: framebuffer {}: {}x{} stride {} at 0x{:X}", + i, + fb.width, + fb.height, + fb.stride, + fb.phys + ); + framebuffers.push(fb); + }, + None => { + eprintln!("vesad: framebuffer {}: failed to parse '{}'", i, var); + }, + }, + Err(_err) => break, + }; + } + + redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers, &spec)).expect("failed to create daemon"); } -fn inner(daemon: redox_daemon::Daemon, width: usize, height: usize, physbaseptr: usize, stride: usize, spec: &[bool]) -> ! { +fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[bool]) -> ! { let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); - let mut scheme = DisplayScheme::new(width, height, physbaseptr, stride, &spec); + let mut scheme = DisplayScheme::new(framebuffers, &spec); syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); @@ -102,8 +137,9 @@ fn inner(daemon: redox_daemon::Daemon, width: usize, height: usize, physbaseptr: // Can't use scheme.can_read() because we borrow handles as mutable. // (and because it'd treat O_NONBLOCK sockets differently) - let count = if let HandleKind::Screen(screen_i) = handle.kind { - scheme.screens.get(&screen_i) + let count = if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + scheme.vts.get(&vt_i) + .and_then(|screens| screens.get(&screen_i)) .and_then(|screen| screen.can_read()) .unwrap_or(0) } else { 0 }; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index f08f2782fd..08a88e8c2a 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,16 +1,26 @@ use std::collections::BTreeMap; +use std::convert::TryInto; use std::{mem, ptr, slice, str}; use orbclient::{Event, EventOption}; use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, OldMap, O_NONBLOCK, physmap, physunmap, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, Result, SchemeMut}; -use crate::display::Display; -use crate::screen::{Screen, GraphicScreen, TextScreen}; +use crate::{ + display::Display, + framebuffer::FrameBuffer, + screen::{Screen, GraphicScreen, TextScreen}, +}; + +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +pub struct VtIndex(usize); + +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +pub struct ScreenIndex(usize); #[derive(Clone)] pub enum HandleKind { Input, - Screen(usize), + Screen(VtIndex, ScreenIndex), } #[derive(Clone)] @@ -22,54 +32,45 @@ pub struct Handle { } pub struct DisplayScheme { - width: usize, - height: usize, - physbaseptr: usize, - onscreen: &'static mut [u32], - stride: usize, - active: usize, - pub screens: BTreeMap>, + framebuffers: Vec, + onscreens: Vec<&'static mut [u32]>, + active: VtIndex, + pub vts: BTreeMap>>, next_id: usize, pub handles: BTreeMap, } impl DisplayScheme { - pub fn new(width: usize, height: usize, physbaseptr: usize, stride: usize, spec: &[bool]) -> DisplayScheme { - let onscreen = unsafe { - let size = stride * height; - let onscreen_ptr = physmap( - physbaseptr, - size * 4, - PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE - ).expect("vesad: failed to map framebuffer") as *mut u32; - ptr::write_bytes(onscreen_ptr, 0, size); + pub fn new(mut framebuffers: Vec, spec: &[bool]) -> DisplayScheme { + let mut onscreens = Vec::new(); + for fb in framebuffers.iter_mut() { + onscreens.push(unsafe { + fb.map().expect("vesad: failed to map framebuffer") + }); + } - slice::from_raw_parts_mut( - onscreen_ptr, - size - ) - }; + let mut vts = BTreeMap::>>::new(); - let mut screens: BTreeMap> = BTreeMap::new(); - - let mut screen_i = 1; - for &screen_type in spec.iter() { - if screen_type { - screens.insert(screen_i, Box::new(GraphicScreen::new(Display::new(width, height)))); - } else { - screens.insert(screen_i, Box::new(TextScreen::new(Display::new(width, height)))); + let mut vt_i = 1; + for &vt_type in spec.iter() { + let mut screens = BTreeMap::>::new(); + for fb_i in 0..framebuffers.len() { + let fb = &framebuffers[fb_i]; + screens.insert(ScreenIndex(fb_i), if vt_type { + Box::new(GraphicScreen::new(Display::new(fb.width, fb.height))) + } else { + Box::new(TextScreen::new(Display::new(fb.width, fb.height))) + }); } - screen_i += 1; + vts.insert(VtIndex(vt_i), screens); + vt_i += 1; } DisplayScheme { - width, - height, - physbaseptr, - onscreen, - stride, - active: 1, - screens, + framebuffers, + onscreens, + active: VtIndex(1), + vts, next_id: 0, handles: BTreeMap::new(), } @@ -77,13 +78,15 @@ impl DisplayScheme { pub fn can_read(&self, id: usize) -> Option { if let Some(handle) = self.handles.get(&id) { - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get(&screen_i) { - screen.can_read().or(if handle.flags & O_NONBLOCK == O_NONBLOCK { - Some(0) - } else { - None - }); + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get(&vt_i) { + if let Some(screen) = screens.get(&screen_i) { + screen.can_read().or(if handle.flags & O_NONBLOCK == O_NONBLOCK { + Some(0) + } else { + None + }); + } } } } @@ -92,18 +95,20 @@ impl DisplayScheme { } fn resize(&mut self, width: usize, height: usize, stride: usize) { - println!("Resizing to {}, {} stride {}", width, height, stride); + //TODO: support resizing other outputs? + let fb_i = 0; + println!("Resizing framebuffer {} to {}, {} stride {}", fb_i, width, height, stride); // Unmap old onscreen unsafe { - physunmap(self.onscreen.as_mut_ptr() as usize).expect("vesad: failed to unmap framebuffer"); + physunmap(self.onscreens[fb_i].as_mut_ptr() as usize).expect("vesad: failed to unmap framebuffer"); } // Map new onscreen - self.onscreen = unsafe { + self.onscreens[fb_i] = unsafe { let size = stride * height; let onscreen_ptr = physmap( - self.physbaseptr, + self.framebuffers[fb_i].phys, size * 4, PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE ).expect("vesad: failed to map framebuffer") as *mut u32; @@ -116,15 +121,19 @@ impl DisplayScheme { }; // Update size - self.width = width; - self.height = height; - self.stride = stride; + self.framebuffers[fb_i].width = width; + self.framebuffers[fb_i].height = height; + self.framebuffers[fb_i].stride = stride; // Resize screens - for (screen_i, screen) in self.screens.iter_mut() { - screen.resize(width, height); - if *screen_i == self.active { - screen.redraw(self.onscreen, self.stride); + for (vt_i, screens) in self.vts.iter_mut() { + for (screen_i, screen) in screens.iter_mut() { + if screen_i.0 == fb_i { + screen.resize(width, height); + if *vt_i == self.active { + screen.redraw(self.onscreens[fb_i], self.framebuffers[fb_i].stride); + } + } } } } @@ -150,25 +159,35 @@ impl SchemeMut for DisplayScheme { } } else { let mut parts = path_str.split('/'); - let screen_i = parts.next().unwrap_or("").parse::().unwrap_or(0); - if self.screens.contains_key(&screen_i) { - for cmd in parts { - if cmd == "activate" { - self.active = screen_i; + let mut vt_screen = parts.next().unwrap_or("").split('.'); + let vt_i = VtIndex( + vt_screen.next().unwrap_or("").parse::().unwrap_or(1) + ); + let screen_i = ScreenIndex( + vt_screen.next().unwrap_or("").parse::().unwrap_or(0) + ); + if let Some(screens) = self.vts.get(&vt_i) { + if screens.contains_key(&screen_i) { + for cmd in parts { + if cmd == "activate" { + self.active = vt_i; + } } + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, Handle { + kind: HandleKind::Screen(vt_i, screen_i), + flags: flags, + events: EventFlags::empty(), + notified_read: false + }); + + Ok(id) + } else { + Err(Error::new(ENOENT)) } - - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, Handle { - kind: HandleKind::Screen(screen_i), - flags: flags, - events: EventFlags::empty(), - notified_read: false - }); - - Ok(id) } else { Err(Error::new(ENOENT)) } @@ -195,7 +214,7 @@ impl SchemeMut for DisplayScheme { handle.notified_read = false; - if let HandleKind::Screen(_screen_i) = handle.kind { + if let HandleKind::Screen(_vt_i, _screen_i) = handle.kind { handle.events = flags; Ok(syscall::EventFlags::empty()) } else { @@ -206,9 +225,11 @@ impl SchemeMut for DisplayScheme { fn fmap(&mut self, id: usize, map: &Map) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get(&screen_i) { - return screen.map(map.offset, map.size); + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get(&vt_i) { + if let Some(screen) = screens.get(&screen_i) { + return screen.map(map.offset, map.size); + } } } @@ -228,10 +249,15 @@ impl SchemeMut for DisplayScheme { let path_str = match handle.kind { HandleKind::Input => { - format!("display:input/{}/{}", self.width, self.height) + //TODO: allow inputs associated with other framebuffers? + format!("display:input/{}/{}", self.framebuffers[0].width, self.framebuffers[0].height) }, - HandleKind::Screen(screen_i) => if let Some(screen) = self.screens.get(&screen_i) { - format!("display:{}/{}/{}", screen_i, screen.width(), screen.height()) + HandleKind::Screen(vt_i, screen_i) => if let Some(screens) = self.vts.get(&vt_i) { + if let Some(screen) = screens.get(&screen_i) { + format!("display:{}.{}/{}/{}", vt_i.0, screen_i.0, screen.width(), screen.height()) + } else { + return Err(Error::new(EBADF)); + } } else { return Err(Error::new(EBADF)); } @@ -251,12 +277,17 @@ impl SchemeMut for DisplayScheme { fn fsync(&mut self, id: usize) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get_mut(&screen_i) { - if screen_i == self.active { - screen.sync(self.onscreen, self.stride); + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { + if vt_i == self.active { + screen.sync( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); + } + return Ok(0); } - return Ok(0); } } @@ -266,9 +297,11 @@ impl SchemeMut for DisplayScheme { fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get_mut(&screen_i) { - return screen.read(buf); + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { + return screen.read(buf); + } } } @@ -280,10 +313,15 @@ impl SchemeMut for DisplayScheme { match handle.kind { HandleKind::Input => if buf.len() == 1 && buf[0] >= 0xF4 { - let new_active = (buf[0] - 0xF4) as usize + 1; - if let Some(screen) = self.screens.get_mut(&new_active) { + let new_active = VtIndex((buf[0] - 0xF4) as usize + 1); + if let Some(screens) = self.vts.get_mut(&new_active) { self.active = new_active; - screen.redraw(self.onscreen, self.stride); + for (screen_i, screen) in screens.iter_mut() { + screen.redraw( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); + } } Ok(1) } else { @@ -294,13 +332,13 @@ impl SchemeMut for DisplayScheme { match event.to_option() { EventOption::Key(key_event) => match key_event.scancode { f @ 0x3B ..= 0x44 => { // F1 through F10 - new_active_opt = Some((f - 0x3A) as usize); + new_active_opt = Some(VtIndex((f - 0x3A) as usize)); }, 0x57 => { // F11 - new_active_opt = Some(11); + new_active_opt = Some(VtIndex(11)); }, 0x58 => { // F12 - new_active_opt = Some(12); + new_active_opt = Some(VtIndex(12)); }, _ => () }, @@ -314,25 +352,40 @@ impl SchemeMut for DisplayScheme { }; if let Some(new_active) = new_active_opt { - if let Some(screen) = self.screens.get_mut(&new_active) { + if let Some(screens) = self.vts.get_mut(&new_active) { self.active = new_active; - screen.redraw(self.onscreen, self.stride); + for (screen_i, screen) in screens.iter_mut() { + screen.redraw( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); + } } } else { - if let Some(screen) = self.screens.get_mut(&self.active) { - screen.input(event); + if let Some(screens) = self.vts.get_mut(&self.active) { + //TODO: send input to other screens? Don't want extra events + if let Some(screen) = screens.get_mut(&ScreenIndex(0)) { + screen.input(event); + } } } } Ok(events.len() * mem::size_of::()) }, - HandleKind::Screen(screen_i) => if let Some(screen) = self.screens.get_mut(&screen_i) { - let count = screen.write(buf)?; - if screen_i == self.active { - screen.sync(self.onscreen, self.stride); + HandleKind::Screen(vt_i, screen_i) => if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { + let count = screen.write(buf)?; + if vt_i == self.active { + screen.sync( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); + } + Ok(count) + } else { + Err(Error::new(EBADF)) } - Ok(count) } else { Err(Error::new(EBADF)) } @@ -342,9 +395,11 @@ impl SchemeMut for DisplayScheme { fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get_mut(&screen_i) { - return screen.seek(pos, whence).map(|pos| pos as isize); + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { + return screen.seek(pos, whence).map(|pos| pos as isize); + } } }