diff --git a/vesad/src/display.rs b/vesad/src/display.rs index c07e6bcf90..fe04c500ce 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -24,7 +24,6 @@ static FONT_ITALIC: &'static [u8] = include_bytes!("../res/DejaVuSansMono-Obliqu pub struct Display { pub width: usize, pub height: usize, - pub onscreen: &'static mut [u32], pub offscreen: &'static mut [u32], #[cfg(feature="rusttype")] pub font: Font<'static>, @@ -38,7 +37,7 @@ pub struct Display { impl Display { #[cfg(not(feature="rusttype"))] - pub fn new(width: usize, height: usize, onscreen: usize) -> Display { + pub fn new(width: usize, height: usize) -> Display { let size = width * height; let offscreen = unsafe { @@ -50,13 +49,12 @@ impl Display { Display { width: width, height: height, - onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } } } #[cfg(feature="rusttype")] - pub fn new(width: usize, height: usize, onscreen: usize) -> Display { + pub fn new(width: usize, height: usize) -> Display { let size = width * height; let offscreen = unsafe { Global @@ -67,7 +65,6 @@ impl Display { Display { width: width, height: height, - onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, 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(), @@ -124,9 +121,6 @@ impl Display { self.width = width; self.height = height; - let onscreen = self.onscreen.as_mut_ptr(); - self.onscreen = unsafe { slice::from_raw_parts_mut(onscreen, size) }; - unsafe { Global.deallocate(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; } else { @@ -268,7 +262,7 @@ impl Display { } /// Copy from offscreen to onscreen - pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize) { + pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize, onscreen: &mut [u32], stride: usize) { let start_y = cmp::min(self.height, y); let end_y = cmp::min(self.height, y + h); @@ -276,13 +270,10 @@ impl Display { let len = (cmp::min(self.width, x + w) - start_x) * 4; let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize; + let mut onscreen_ptr = onscreen.as_mut_ptr() as usize; - let stride = self.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - onscreen_ptr += offset; + offscreen_ptr += (y * self.width + start_x) * 4; + onscreen_ptr += (y * stride + start_x) * 4; let mut rows = end_y - start_y; while rows > 0 { @@ -293,8 +284,8 @@ impl Display { len ); } - offscreen_ptr += stride; - onscreen_ptr += stride; + offscreen_ptr += self.width * 4; + onscreen_ptr += stride * 4; rows -= 1; } } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index fa3778cce6..87b1ef6b90 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -7,7 +7,7 @@ use std::{env, process, ptr}; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::{RawFd, FromRawFd}; -use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE}; +use syscall::{Packet, SchemeMut, EVENT_READ}; use crate::scheme::{DisplayScheme, HandleKind}; @@ -43,24 +43,23 @@ fn main() { .expect("FRAMEBUFFER_ADDR not set"), 16 ).expect("failed to parse FRAMEBUFFER_ADDR"); + let stride = usize::from_str_radix( + &env::var("FRAMEBUFFER_STRIDE") + .expect("FRAMEBUFFER_STRIDE not set"), + 16 + ).expect("failed to parse FRAMEBUFFER_STRIDE"); - println!("vesad: {}x{} at 0x{:X}", width, height, physbaseptr); + println!("vesad: {}x{} stride {} at 0x{:X}", width, height, stride, physbaseptr); if physbaseptr == 0 { return; } - redox_daemon::Daemon::new(|daemon| inner(daemon, width, height, physbaseptr, &spec)).expect("failed to create daemon"); + redox_daemon::Daemon::new(|daemon| inner(daemon, width, height, physbaseptr, stride, &spec)).expect("failed to create daemon"); } -fn inner(daemon: redox_daemon::Daemon, width: usize, height: usize, physbaseptr: usize, spec: &[bool]) -> ! { +fn inner(daemon: redox_daemon::Daemon, width: usize, height: usize, physbaseptr: usize, stride: usize, spec: &[bool]) -> ! { let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); - let size = width * height; - //TODO: Remap on resize - let largest_size = 8 * 1024 * 1024; - let onscreen = unsafe { physmap(physbaseptr, largest_size * 4, PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; - unsafe { ptr::write_bytes(onscreen as *mut u32, 0, size); } - - let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); + let mut scheme = DisplayScheme::new(width, height, physbaseptr, stride, &spec); syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index b16f7cf456..f08f2782fd 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,8 +1,8 @@ use std::collections::BTreeMap; -use std::{mem, slice, str}; +use std::{mem, ptr, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, OldMap, O_NONBLOCK, Result, SchemeMut}; +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}; @@ -24,6 +24,9 @@ pub struct Handle { pub struct DisplayScheme { width: usize, height: usize, + physbaseptr: usize, + onscreen: &'static mut [u32], + stride: usize, active: usize, pub screens: BTreeMap>, next_id: usize, @@ -31,24 +34,42 @@ pub struct DisplayScheme { } impl DisplayScheme { - pub fn new(width: usize, height: usize, onscreen: usize, spec: &[bool]) -> 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); + + slice::from_raw_parts_mut( + onscreen_ptr, + size + ) + }; + 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, onscreen)))); + 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, onscreen)))); + screens.insert(screen_i, Box::new(TextScreen::new(Display::new(width, height)))); } screen_i += 1; } DisplayScheme { - width: width, - height: height, + width, + height, + physbaseptr, + onscreen, + stride, active: 1, - screens: screens, + screens, next_id: 0, handles: BTreeMap::new(), } @@ -69,6 +90,44 @@ impl DisplayScheme { Some(0) } + + fn resize(&mut self, width: usize, height: usize, stride: usize) { + println!("Resizing to {}, {} stride {}", width, height, stride); + + // Unmap old onscreen + unsafe { + physunmap(self.onscreen.as_mut_ptr() as usize).expect("vesad: failed to unmap framebuffer"); + } + + // Map new onscreen + self.onscreen = unsafe { + let size = stride * height; + let onscreen_ptr = physmap( + self.physbaseptr, + size * 4, + PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE + ).expect("vesad: failed to map framebuffer") as *mut u32; + ptr::write_bytes(onscreen_ptr, 0, size); + + slice::from_raw_parts_mut( + onscreen_ptr, + size + ) + }; + + // Update size + self.width = width; + self.height = height; + self.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); + } + } + } } impl SchemeMut for DisplayScheme { @@ -195,7 +254,7 @@ impl SchemeMut for DisplayScheme { 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(); + screen.sync(self.onscreen, self.stride); } return Ok(0); } @@ -224,7 +283,7 @@ impl SchemeMut for DisplayScheme { let new_active = (buf[0] - 0xF4) as usize + 1; if let Some(screen) = self.screens.get_mut(&new_active) { self.active = new_active; - screen.redraw(); + screen.redraw(self.onscreen, self.stride); } Ok(1) } else { @@ -246,15 +305,10 @@ impl SchemeMut for DisplayScheme { _ => () }, EventOption::Resize(resize_event) => { - println!("Resizing to {}, {}", resize_event.width, resize_event.height); - self.width = resize_event.width as usize; - self.height = resize_event.height as usize; - for (screen_i, screen) in self.screens.iter_mut() { - screen.resize(resize_event.width as usize, resize_event.height as usize); - if *screen_i == self.active { - screen.redraw(); - } - } + let width = resize_event.width as usize; + let height = resize_event.height as usize; + let stride = width; //TODO: get stride somehow + self.resize(width, height, stride); }, _ => () }; @@ -262,7 +316,7 @@ impl SchemeMut for DisplayScheme { if let Some(new_active) = new_active_opt { if let Some(screen) = self.screens.get_mut(&new_active) { self.active = new_active; - screen.redraw(); + screen.redraw(self.onscreen, self.stride); } } else { if let Some(screen) = self.screens.get_mut(&self.active) { @@ -274,7 +328,11 @@ impl SchemeMut for DisplayScheme { Ok(events.len() * mem::size_of::()) }, HandleKind::Screen(screen_i) => if let Some(screen) = self.screens.get_mut(&screen_i) { - screen.write(buf, screen_i == self.active) + let count = screen.write(buf)?; + if screen_i == self.active { + screen.sync(self.onscreen, self.stride); + } + Ok(count) } else { Err(Error::new(EBADF)) } diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 1dd5df6533..3c4763e467 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -75,7 +75,7 @@ impl Screen for GraphicScreen { } } - fn write(&mut self, buf: &[u8], sync: bool) -> Result { + fn write(&mut self, buf: &[u8]) -> Result { let size = cmp::max(0, cmp::min(self.display.offscreen.len() as isize - self.seek as isize, (buf.len()/4) as isize)) as usize; if size > 0 { @@ -85,13 +85,6 @@ impl Screen for GraphicScreen { self.display.offscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, size * 4 ); - if sync { - ptr::copy( - buf.as_ptr(), - self.display.onscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, - size * 4 - ); - } } } @@ -111,13 +104,13 @@ impl Screen for GraphicScreen { Ok(self.seek * 4) } - fn sync(&mut self) { - self.redraw(); + fn sync(&mut self, onscreen: &mut [u32], stride: usize) { + self.redraw(onscreen, stride); } - fn redraw(&mut self) { + fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { let width = self.display.width; let height = self.display.height; - self.display.sync(0, 0, width, height); + self.display.sync(0, 0, width, height, onscreen, stride); } } diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs index a37778ee8f..e254e1c4fe 100644 --- a/vesad/src/screen/mod.rs +++ b/vesad/src/screen/mod.rs @@ -22,11 +22,11 @@ pub trait Screen { fn can_read(&self) -> Option; - fn write(&mut self, buf: &[u8], sync: bool) -> Result; + fn write(&mut self, buf: &[u8]) -> Result; fn seek(&mut self, pos: isize, whence: usize) -> Result; - fn sync(&mut self); + fn sync(&mut self, onscreen: &mut [u32], stride: usize); - fn redraw(&mut self); + fn redraw(&mut self, onscreen: &mut [u32], stride: usize); } diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 9035cb4fad..834aca6cf2 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -132,7 +132,7 @@ impl Screen for TextScreen { } } - fn write(&mut self, buf: &[u8], sync: bool) -> Result { + fn write(&mut self, buf: &[u8]) -> Result { if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { let x = self.console.state.x; let y = self.console.state.y; @@ -202,10 +202,6 @@ impl Screen for TextScreen { self.changed.insert(y); } - if sync { - self.sync(); - } - Ok(buf.len()) } @@ -213,18 +209,18 @@ impl Screen for TextScreen { Ok(0) } - fn sync(&mut self) { + fn sync(&mut self, onscreen: &mut [u32], stride: usize) { let width = self.display.width; for change in self.changed.iter() { - self.display.sync(0, change * 16, width, 16); + self.display.sync(0, change * 16, width, 16, onscreen, stride); } self.changed.clear(); } - fn redraw(&mut self) { + fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { let width = self.display.width; let height = self.display.height; - self.display.sync(0, 0, width, height); + self.display.sync(0, 0, width, height, onscreen, stride); self.changed.clear(); } }