diff --git a/drivers/graphics/console-draw/src/lib.rs b/drivers/graphics/console-draw/src/lib.rs index 1a5d3eee8d..64f2ad2f9a 100644 --- a/drivers/graphics/console-draw/src/lib.rs +++ b/drivers/graphics/console-draw/src/lib.rs @@ -2,10 +2,11 @@ extern crate ransid; use std::collections::VecDeque; use std::convert::{TryFrom, TryInto}; -use std::{cmp, ptr}; +use std::{cmp, io, mem, ptr}; use drm::buffer::Buffer; use drm::control::dumbbuffer::{DumbBuffer, DumbMapping}; +use drm::control::Device; use graphics_ipc::v1::Damage; use graphics_ipc::v2::V2GraphicsHandle; use orbclient::FONT; @@ -17,7 +18,7 @@ pub struct V2DisplayMap { } impl V2DisplayMap { - pub unsafe fn console_map(&mut self) -> DisplayMap { + unsafe fn console_map(&mut self) -> DisplayMap { DisplayMap { offscreen: ptr::slice_from_raw_parts_mut( self.mapping.as_mut_ptr() as *mut u32, @@ -138,7 +139,14 @@ impl TextScreen { } impl TextScreen { - pub fn write(&mut self, map: &mut DisplayMap, buf: &[u8], input: &mut VecDeque) -> Damage { + pub fn write( + &mut self, + map: &mut V2DisplayMap, + buf: &[u8], + input: &mut VecDeque, + ) -> Damage { + let map = unsafe { &mut map.console_map() }; + let mut min_changed = map.height; let mut max_changed = 0; let mut line_changed = |line| { @@ -249,7 +257,7 @@ impl TextScreen { damage } - pub fn resize(&mut self, old_map: &mut DisplayMap, new_map: &mut DisplayMap) { + pub fn resize(&mut self, old_map: &mut V2DisplayMap, mut new_fb: DumbBuffer) -> io::Result<()> { // FIXME fold row when target is narrower and maybe unfold when it is wider fn copy_row( old_map: &mut DisplayMap, @@ -266,20 +274,45 @@ impl TextScreen { } } - if new_map.height >= old_map.height { - for row in 0..old_map.height { - copy_row(old_map, new_map, row, row); - } - } else { - let deleted_rows = (old_map.height - new_map.height).div_ceil(16); - for row in 0..new_map.height { - if row + (deleted_rows + 1) * 16 >= old_map.height { - break; + let new_mapping = old_map.display_handle.map_dumb_buffer(&mut new_fb)?; + let mut new_mapping = + unsafe { mem::transmute::, DumbMapping<'static>>(new_mapping) }; + + new_mapping.fill(0); + + { + let old_map = unsafe { &mut old_map.console_map() }; + let new_map = &mut DisplayMap { + offscreen: ptr::slice_from_raw_parts_mut( + new_mapping.as_mut_ptr() as *mut u32, + new_mapping.len() / 4, + ), + width: new_fb.size().0 as usize, + height: new_fb.size().1 as usize, + }; + + if new_map.height >= old_map.height { + for row in 0..old_map.height { + copy_row(old_map, new_map, row, row); } - copy_row(old_map, new_map, row + deleted_rows * 16, row); + } else { + let deleted_rows = (old_map.height - new_map.height).div_ceil(16); + for row in 0..new_map.height { + if row + (deleted_rows + 1) * 16 >= old_map.height { + break; + } + copy_row(old_map, new_map, row + deleted_rows * 16, row); + } + self.console.state.y = self.console.state.y.saturating_sub(deleted_rows); } - self.console.state.y = self.console.state.y.saturating_sub(deleted_rows); } + + let old_fb = mem::replace(&mut old_map.fb, new_fb); + old_map.mapping = new_mapping; + + let _ = old_map.display_handle.destroy_dumb_buffer(old_fb); + + Ok(()) } } diff --git a/drivers/graphics/fbbootlogd/src/scheme.rs b/drivers/graphics/fbbootlogd/src/scheme.rs index 35fd11fe1a..41e6f3f009 100644 --- a/drivers/graphics/fbbootlogd/src/scheme.rs +++ b/drivers/graphics/fbbootlogd/src/scheme.rs @@ -1,5 +1,5 @@ use std::collections::VecDeque; -use std::{cmp, mem, ptr}; +use std::{cmp, mem}; use console_draw::{TextScreen, V2DisplayMap}; use drm::buffer::{Buffer, DrmFourcc}; @@ -129,26 +129,25 @@ impl FbbootlogScheme { return; }; let buffer_len = self.text_buffer.lines.len(); - let dmap = unsafe { &mut map.console_map() }; // for both extra space on wrapping text and a scrollback indicator let spare_lines = 3; self.is_scrollback = true; self.scrollback_offset = cmp::min( self.scrollback_offset, - buffer_len - dmap.height / 16 + spare_lines, + buffer_len - map.fb.size().1 as usize / 16 + spare_lines, ); let mut i = self.scrollback_offset; self.text_screen - .write(dmap, b"\x1B[1;1H\x1B[2J", &mut VecDeque::new()); + .write(map, b"\x1B[1;1H\x1B[2J", &mut VecDeque::new()); while i < buffer_len { let mut damage = self.text_screen - .write(dmap, &self.text_buffer.lines[i][..], &mut VecDeque::new()); + .write(map, &self.text_buffer.lines[i][..], &mut VecDeque::new()); i += 1; let yd = (damage.y + damage.height) as usize; - if i == buffer_len || yd + spare_lines * 16 > dmap.height { + if i == buffer_len || yd + spare_lines * 16 > map.fb.size().1 as usize { // render until end of screen - damage.height = (dmap.height as u32) - damage.y; + damage.height = map.fb.size().1 - damage.y; map.display_handle .update_plane(0, u32::from(map.fb.handle()), damage) .unwrap(); @@ -178,38 +177,13 @@ impl FbbootlogScheme { .display_handle .create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32) { - Ok(mut fb) => { - let mut new_map = match map.display_handle.map_dumb_buffer(&mut fb) { - Ok(new_map) => unsafe { - mem::transmute::, DumbMapping<'static>>(new_map) - }, - Err(err) => { - eprintln!("fbbootlogd: failed to open display: {}", err); - return; - } - }; - - new_map.fill(0); - - text_screen.resize( - unsafe { &mut map.console_map() }, - &mut console_draw::DisplayMap { - offscreen: ptr::slice_from_raw_parts_mut( - new_map.as_mut_ptr() as *mut u32, - new_map.len() / 4, - ), - width: fb.size().0 as usize, - height: fb.size().1 as usize, - }, - ); - - let old_fb = mem::replace(&mut map.fb, fb); - map.mapping = new_map; - - let _ = map.display_handle.destroy_dumb_buffer(old_fb); - - eprintln!("fbbootlogd: mapped display"); - } + Ok(fb) => match text_screen.resize(map, fb) { + Ok(()) => eprintln!("fbbootlogd: mapped display"), + Err(err) => { + eprintln!("fbbootlogd: failed to open display: {}", err); + return; + } + }, Err(err) => { eprintln!("fbbootlogd: failed to create framebuffer: {}", err); return; @@ -271,11 +245,7 @@ impl SchemeSync for FbbootlogScheme { self.text_buffer.write(buf); if !self.is_scrollback { - let damage = self.text_screen.write( - unsafe { &mut map.console_map() }, - buf, - &mut VecDeque::new(), - ); + let damage = self.text_screen.write(map, buf, &mut VecDeque::new()); if let Some(map) = &self.display_map { map.display_handle diff --git a/drivers/graphics/fbcond/src/display.rs b/drivers/graphics/fbcond/src/display.rs index 253896ea83..0d23e95ab9 100644 --- a/drivers/graphics/fbcond/src/display.rs +++ b/drivers/graphics/fbcond/src/display.rs @@ -4,7 +4,7 @@ use drm::control::dumbbuffer::DumbMapping; use drm::control::Device; use graphics_ipc::v2::{Damage, V2GraphicsHandle}; use inputd::ConsumerHandle; -use std::{io, mem, ptr}; +use std::{io, mem}; pub struct Display { pub input_handle: ConsumerHandle, @@ -76,37 +76,14 @@ impl Display { .display_handle .create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32) { - Ok(mut fb) => { - let mut new_map = match map.display_handle.map_dumb_buffer(&mut fb) { - Ok(new_map) => unsafe { - mem::transmute::, DumbMapping<'static>>(new_map) - }, + Ok(fb) => { + match text_screen.resize(map, fb) { + Ok(()) => eprintln!("fbcond: mapped display"), Err(err) => { eprintln!("fbcond: failed to open display: {}", err); return; } }; - - new_map.fill(0); - - text_screen.resize( - unsafe { &mut map.console_map() }, - &mut console_draw::DisplayMap { - offscreen: ptr::slice_from_raw_parts_mut( - new_map.as_mut_ptr() as *mut u32, - new_map.len() / 4, - ), - width: fb.size().0 as usize, - height: fb.size().1 as usize, - }, - ); - - let old_fb = mem::replace(&mut map.fb, fb); - map.mapping = new_map; - - let _ = map.display_handle.destroy_dumb_buffer(old_fb); - - eprintln!("fbcond: mapped display"); } Err(err) => { log::error!("fbcond: failed to create framebuffer: {}", err); diff --git a/drivers/graphics/fbcond/src/text.rs b/drivers/graphics/fbcond/src/text.rs index 438af68912..8a24bbebe6 100644 --- a/drivers/graphics/fbcond/src/text.rs +++ b/drivers/graphics/fbcond/src/text.rs @@ -124,9 +124,7 @@ impl TextScreen { if let Some(map) = &mut self.display.map { Display::handle_resize(map, &mut self.inner); - let damage = self - .inner - .write(unsafe { &mut map.console_map() }, buf, &mut self.input); + let damage = self.inner.write(map, buf, &mut self.input); self.display.sync_rect(damage); }