From 123fe53c5d007b1497fb0693b96f652137d2df5c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Dec 2025 20:14:12 +0100 Subject: [PATCH 1/5] driver/graphics/graphics-ipc: Remove most helpers for the v1 api They aren't used within this repo and orbital has it's own copy of the rest. --- drivers/graphics/driver-graphics/src/lib.rs | 3 +- drivers/graphics/graphics-ipc/src/common.rs | 43 ------------ drivers/graphics/graphics-ipc/src/v1.rs | 76 --------------------- drivers/graphics/graphics-ipc/src/v2.rs | 2 +- 4 files changed, 3 insertions(+), 121 deletions(-) diff --git a/drivers/graphics/driver-graphics/src/lib.rs b/drivers/graphics/driver-graphics/src/lib.rs index 25d54b3593..29bece881b 100644 --- a/drivers/graphics/driver-graphics/src/lib.rs +++ b/drivers/graphics/driver-graphics/src/lib.rs @@ -8,7 +8,8 @@ use std::mem; use std::mem::transmute; use std::sync::Arc; -use graphics_ipc::v1::{CursorDamage, Damage}; +use graphics_ipc::v1::CursorDamage; +use graphics_ipc::v2::Damage; use inputd::{VtEvent, VtEventKind}; use libredox::Fd; use redox_scheme::scheme::SchemeSync; diff --git a/drivers/graphics/graphics-ipc/src/common.rs b/drivers/graphics/graphics-ipc/src/common.rs index 81e02640d5..27138151d5 100644 --- a/drivers/graphics/graphics-ipc/src/common.rs +++ b/drivers/graphics/graphics-ipc/src/common.rs @@ -30,46 +30,3 @@ impl Damage { self } } - -pub struct DisplayMap { - offscreen: *mut [u32], - width: usize, - height: usize, -} - -impl DisplayMap { - pub(crate) unsafe fn new(offscreen: *mut [u32], width: usize, height: usize) -> Self { - DisplayMap { - offscreen, - width, - height, - } - } - - pub fn ptr(&self) -> *const [u32] { - self.offscreen - } - - pub fn ptr_mut(&mut self) -> *mut [u32] { - self.offscreen - } - - pub fn width(&self) -> usize { - self.width - } - - pub fn height(&self) -> usize { - self.height - } -} - -unsafe impl Send for DisplayMap {} -unsafe impl Sync for DisplayMap {} - -impl Drop for DisplayMap { - fn drop(&mut self) { - unsafe { - let _ = libredox::call::munmap(self.offscreen as *mut (), self.offscreen.len()); - } - } -} diff --git a/drivers/graphics/graphics-ipc/src/v1.rs b/drivers/graphics/graphics-ipc/src/v1.rs index 640d117bab..df882024c2 100644 --- a/drivers/graphics/graphics-ipc/src/v1.rs +++ b/drivers/graphics/graphics-ipc/src/v1.rs @@ -1,80 +1,4 @@ -use std::fs::File; -use std::os::unix::io::AsRawFd; -use std::{io, mem, ptr, slice}; - -use libredox::flag; - pub use crate::common::Damage; -pub use crate::common::DisplayMap; - -/// A graphics handle using the v1 graphics API. -/// -/// The v1 graphics API only allows a single framebuffer for each VT, requires each display to be -/// handled separately and doesn't support page flipping. -/// -/// This API is stable. No breaking changes are allowed to be made without a version bump. -pub struct V1GraphicsHandle { - file: File, -} - -impl V1GraphicsHandle { - pub fn from_file(file: File) -> io::Result { - Ok(V1GraphicsHandle { file }) - } - - pub fn map_display(&self) -> io::Result { - let mut buf: [u8; 4096] = [0; 4096]; - let count = - libredox::call::fpath(self.file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { - panic!("Could not read display path with fpath(): {e}"); - }); - - let url = - String::from_utf8(Vec::from(&buf[..count])).expect("Could not create Utf8 Url String"); - let path = url.split(':').nth(1).expect("Could not get path from url"); - - let mut path_parts = path.split('/').skip(1); - let width = path_parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or(0); - let height = path_parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or(0); - - let display_ptr = unsafe { - libredox::call::mmap(libredox::call::MmapArgs { - fd: self.file.as_raw_fd() as usize, - offset: 0, - length: (width * height * 4), - prot: flag::PROT_READ | flag::PROT_WRITE, - flags: flag::MAP_SHARED, - addr: core::ptr::null_mut(), - })? - }; - let offscreen = ptr::slice_from_raw_parts_mut(display_ptr as *mut u32, width * height); - - Ok(unsafe { DisplayMap::new(offscreen, width, height) }) - } - - pub fn sync_full_screen(&self) -> io::Result<()> { - libredox::call::fsync(self.file.as_raw_fd() as usize)?; - Ok(()) - } - - pub fn sync_rect(&self, sync_rect: Damage) -> io::Result<()> { - libredox::call::write(self.file.as_raw_fd() as usize, unsafe { - slice::from_raw_parts( - ptr::addr_of!(sync_rect).cast::(), - mem::size_of::(), - ) - })?; - Ok(()) - } -} #[derive(Debug, Copy, Clone)] #[repr(C, packed)] diff --git a/drivers/graphics/graphics-ipc/src/v2.rs b/drivers/graphics/graphics-ipc/src/v2.rs index fb9c98b997..19d50f33d1 100644 --- a/drivers/graphics/graphics-ipc/src/v2.rs +++ b/drivers/graphics/graphics-ipc/src/v2.rs @@ -9,7 +9,7 @@ use drm::control::Device as _; use drm::{ClientCapability, Device as _, DriverCapability}; use drm_fourcc::DrmFourcc; -pub use crate::common::{Damage, DisplayMap}; +pub use crate::common::Damage; extern "C" { fn redox_sys_call_v0( From 03783e61e94611a9e5edfefe49d9af9eba7221a4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Dec 2025 20:17:21 +0100 Subject: [PATCH 2/5] drivers/graphics: Move DisplayMap to console-draw And inline a bunch of V2GraphicsHandle methods --- Cargo.lock | 2 +- drivers/graphics/console-draw/Cargo.toml | 1 + drivers/graphics/console-draw/src/lib.rs | 22 ++++++++ drivers/graphics/fbbootlogd/src/scheme.rs | 61 +++++++++-------------- drivers/graphics/fbcond/src/display.rs | 61 +++++++++-------------- drivers/graphics/graphics-ipc/Cargo.toml | 1 - drivers/graphics/graphics-ipc/src/v2.rs | 22 -------- 7 files changed, 70 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4722e016e7..e8c04fa45e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -469,6 +469,7 @@ dependencies = [ name = "console-draw" version = "0.1.0" dependencies = [ + "drm", "graphics-ipc", "orbclient", "ransid", @@ -956,7 +957,6 @@ version = "0.1.0" dependencies = [ "common", "drm", - "drm-fourcc", "libredox", "log", "redox-ioctl", diff --git a/drivers/graphics/console-draw/Cargo.toml b/drivers/graphics/console-draw/Cargo.toml index 6153d6143d..80496fb250 100644 --- a/drivers/graphics/console-draw/Cargo.toml +++ b/drivers/graphics/console-draw/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +drm = "0.14" orbclient = "0.3.27" ransid = "0.4" diff --git a/drivers/graphics/console-draw/src/lib.rs b/drivers/graphics/console-draw/src/lib.rs index 20bc77b6e6..1a5d3eee8d 100644 --- a/drivers/graphics/console-draw/src/lib.rs +++ b/drivers/graphics/console-draw/src/lib.rs @@ -4,9 +4,31 @@ use std::collections::VecDeque; use std::convert::{TryFrom, TryInto}; use std::{cmp, ptr}; +use drm::buffer::Buffer; +use drm::control::dumbbuffer::{DumbBuffer, DumbMapping}; use graphics_ipc::v1::Damage; +use graphics_ipc::v2::V2GraphicsHandle; use orbclient::FONT; +pub struct V2DisplayMap { + pub display_handle: V2GraphicsHandle, + pub fb: DumbBuffer, + pub mapping: DumbMapping<'static>, +} + +impl V2DisplayMap { + pub unsafe fn console_map(&mut self) -> DisplayMap { + DisplayMap { + offscreen: ptr::slice_from_raw_parts_mut( + self.mapping.as_mut_ptr() as *mut u32, + self.mapping.len() / 4, + ), + width: self.fb.size().0 as usize, + height: self.fb.size().1 as usize, + } + } +} + pub struct DisplayMap { pub offscreen: *mut [u32], pub width: usize, diff --git a/drivers/graphics/fbbootlogd/src/scheme.rs b/drivers/graphics/fbbootlogd/src/scheme.rs index 3ea92547a3..35fd11fe1a 100644 --- a/drivers/graphics/fbbootlogd/src/scheme.rs +++ b/drivers/graphics/fbbootlogd/src/scheme.rs @@ -1,9 +1,10 @@ use std::collections::VecDeque; use std::{cmp, mem, ptr}; -use console_draw::TextScreen; -use drm::buffer::Buffer; -use drm::control::dumbbuffer::{DumbBuffer, DumbMapping}; +use console_draw::{TextScreen, V2DisplayMap}; +use drm::buffer::{Buffer, DrmFourcc}; +use drm::control::dumbbuffer::DumbMapping; +use drm::control::Device; use graphics_ipc::v2::V2GraphicsHandle; use inputd::ConsumerHandle; use orbclient::{Event, EventOption}; @@ -12,28 +13,9 @@ use redox_scheme::{CallerCtx, OpenResult}; use syscall::schemev2::NewFdFlags; use syscall::{Error, Result, EINVAL, ENOENT}; -pub struct DisplayMap { - display_handle: V2GraphicsHandle, - fb: DumbBuffer, - mapping: DumbMapping<'static>, -} - -impl DisplayMap { - unsafe fn console_map(&mut self) -> console_draw::DisplayMap { - console_draw::DisplayMap { - offscreen: ptr::slice_from_raw_parts_mut( - self.mapping.as_mut_ptr() as *mut u32, - self.mapping.len() / 4, - ), - width: self.fb.size().0 as usize, - height: self.fb.size().1 as usize, - } - } -} - pub struct FbbootlogScheme { pub input_handle: ConsumerHandle, - display_map: Option, + display_map: Option, text_screen: console_draw::TextScreen, text_buffer: console_draw::TextBuffer, is_scrollback: bool, @@ -68,13 +50,15 @@ impl FbbootlogScheme { }; let (width, height) = new_display_handle - .display_size(new_display_handle.first_display().unwrap()) - .unwrap(); + .get_connector(new_display_handle.first_display().unwrap(), true) + .unwrap() + .modes()[0] + .size(); let mut fb = new_display_handle - .create_dumb_framebuffer(width, height) + .create_dumb_buffer((width.into(), height.into()), DrmFourcc::Argb8888, 32) .unwrap(); - let display_map = match new_display_handle.map_dumb_framebuffer(&mut fb) { + let display_map = match new_display_handle.map_dumb_buffer(&mut fb) { Ok(display_map) => unsafe { mem::transmute::, DumbMapping<'static>>(display_map) }, @@ -84,7 +68,7 @@ impl FbbootlogScheme { } }; - self.display_map = Some(DisplayMap { + self.display_map = Some(V2DisplayMap { display_handle: new_display_handle, mapping: display_map, fb, @@ -178,13 +162,11 @@ impl FbbootlogScheme { } } - fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) { - let (width, height) = match map - .display_handle - .first_display() - .and_then(|handle| map.display_handle.display_size(handle)) - { - Ok((width, height)) => (width, height), + fn handle_resize(map: &mut V2DisplayMap, text_screen: &mut TextScreen) { + let (width, height) = match map.display_handle.first_display().and_then(|handle| { + Ok(map.display_handle.get_connector(handle, true)?.modes()[0].size()) + }) { + Ok((width, height)) => (width.into(), height.into()), Err(err) => { eprintln!("fbbootlogd: failed to get display size: {}", err); map.fb.size() @@ -192,9 +174,12 @@ impl FbbootlogScheme { }; if (width, height) != map.fb.size() { - match map.display_handle.create_dumb_framebuffer(width, height) { + match map + .display_handle + .create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32) + { Ok(mut fb) => { - let mut new_map = match map.display_handle.map_dumb_framebuffer(&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) }, @@ -221,7 +206,7 @@ impl FbbootlogScheme { let old_fb = mem::replace(&mut map.fb, fb); map.mapping = new_map; - let _ = map.display_handle.destroy_dumb_framebuffer(old_fb); + let _ = map.display_handle.destroy_dumb_buffer(old_fb); eprintln!("fbbootlogd: mapped display"); } diff --git a/drivers/graphics/fbcond/src/display.rs b/drivers/graphics/fbcond/src/display.rs index 0a4d7fb833..253896ea83 100644 --- a/drivers/graphics/fbcond/src/display.rs +++ b/drivers/graphics/fbcond/src/display.rs @@ -1,32 +1,14 @@ -use console_draw::TextScreen; -use drm::buffer::Buffer; -use drm::control::dumbbuffer::{DumbBuffer, DumbMapping}; +use console_draw::{TextScreen, V2DisplayMap}; +use drm::buffer::{Buffer, DrmFourcc}; +use drm::control::dumbbuffer::DumbMapping; +use drm::control::Device; use graphics_ipc::v2::{Damage, V2GraphicsHandle}; use inputd::ConsumerHandle; use std::{io, mem, ptr}; pub struct Display { pub input_handle: ConsumerHandle, - pub map: Option, -} - -pub struct DisplayMap { - display_handle: V2GraphicsHandle, - fb: DumbBuffer, - mapping: DumbMapping<'static>, -} - -impl DisplayMap { - pub unsafe fn console_map(&mut self) -> console_draw::DisplayMap { - console_draw::DisplayMap { - offscreen: ptr::slice_from_raw_parts_mut( - self.mapping.as_mut_ptr() as *mut u32, - self.mapping.len() / 4, - ), - width: self.fb.size().0 as usize, - height: self.fb.size().1 as usize, - } - } + pub map: Option, } impl Display { @@ -49,13 +31,15 @@ impl Display { log::debug!("fbcond: Opened new display"); let (width, height) = new_display_handle - .display_size(new_display_handle.first_display().unwrap()) - .unwrap(); + .get_connector(new_display_handle.first_display().unwrap(), true) + .unwrap() + .modes()[0] + .size(); let mut fb = new_display_handle - .create_dumb_framebuffer(width, height) + .create_dumb_buffer((width.into(), height.into()), DrmFourcc::Argb8888, 32) .unwrap(); - let map = match new_display_handle.map_dumb_framebuffer(&mut fb) { + let map = match new_display_handle.map_dumb_buffer(&mut fb) { Ok(map) => unsafe { mem::transmute::, DumbMapping<'static>>(map) }, Err(err) => { log::error!("failed to map display: {}", err); @@ -69,20 +53,18 @@ impl Display { fb.size().1, ); - self.map = Some(DisplayMap { + self.map = Some(V2DisplayMap { display_handle: new_display_handle, fb, mapping: map, }); } - pub fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) { - let (width, height) = match map - .display_handle - .first_display() - .and_then(|handle| map.display_handle.display_size(handle)) - { - Ok((width, height)) => (width, height), + pub fn handle_resize(map: &mut V2DisplayMap, text_screen: &mut TextScreen) { + let (width, height) = match map.display_handle.first_display().and_then(|handle| { + Ok(map.display_handle.get_connector(handle, true)?.modes()[0].size()) + }) { + Ok((width, height)) => (width.into(), height.into()), Err(err) => { log::error!("fbcond: failed to get display size: {}", err); map.fb.size() @@ -90,9 +72,12 @@ impl Display { }; if (width, height) != map.fb.size() { - match map.display_handle.create_dumb_framebuffer(width, height) { + match map + .display_handle + .create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32) + { Ok(mut fb) => { - let mut new_map = match map.display_handle.map_dumb_framebuffer(&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) }, @@ -119,7 +104,7 @@ impl Display { let old_fb = mem::replace(&mut map.fb, fb); map.mapping = new_map; - let _ = map.display_handle.destroy_dumb_framebuffer(old_fb); + let _ = map.display_handle.destroy_dumb_buffer(old_fb); eprintln!("fbcond: mapped display"); } diff --git a/drivers/graphics/graphics-ipc/Cargo.toml b/drivers/graphics/graphics-ipc/Cargo.toml index 8e8d98503d..5ad5afd9a0 100644 --- a/drivers/graphics/graphics-ipc/Cargo.toml +++ b/drivers/graphics/graphics-ipc/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] drm = "0.14" -drm-fourcc = "2.2.0" log = "0.4" libredox = "0.1.3" redox-ioctl = { git = "https://gitlab.redox-os.org/redox-os/relibc.git" } diff --git a/drivers/graphics/graphics-ipc/src/v2.rs b/drivers/graphics/graphics-ipc/src/v2.rs index 19d50f33d1..fc368ccb89 100644 --- a/drivers/graphics/graphics-ipc/src/v2.rs +++ b/drivers/graphics/graphics-ipc/src/v2.rs @@ -4,10 +4,8 @@ use std::os::unix::io::AsRawFd; use std::{io, mem}; use drm::control::connector::{self, State}; -use drm::control::dumbbuffer::{DumbBuffer, DumbMapping}; use drm::control::Device as _; use drm::{ClientCapability, Device as _, DriverCapability}; -use drm_fourcc::DrmFourcc; pub use crate::common::Damage; @@ -75,26 +73,6 @@ impl V2GraphicsHandle { Err(io::Error::other("no connected display")) } - pub fn display_size(&self, handle: connector::Handle) -> io::Result<(u32, u32)> { - let (width, height) = self.get_connector(handle, true)?.modes()[0].size(); - Ok((u32::from(width), u32::from(height))) - } - - pub fn create_dumb_framebuffer(&self, width: u32, height: u32) -> io::Result { - self.create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32) - } - - pub fn map_dumb_framebuffer<'a>( - &self, - buffer: &'a mut DumbBuffer, - ) -> io::Result> { - self.map_dumb_buffer(buffer) - } - - pub fn destroy_dumb_framebuffer(&self, buffer: DumbBuffer) -> io::Result<()> { - self.destroy_dumb_buffer(buffer) - } - pub fn update_plane(&self, display_id: usize, fb_id: u32, damage: Damage) -> io::Result<()> { let mut cmd = ipc::UpdatePlane { display_id, From fe383e5ee01ad66f14550ded994cc96949bab062 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Dec 2025 20:39:31 +0100 Subject: [PATCH 3/5] drivers/graphics: Exclusively use V2DisplayMap in the public api of console-draw --- drivers/graphics/console-draw/src/lib.rs | 63 +++++++++++++++++------ drivers/graphics/fbbootlogd/src/scheme.rs | 58 +++++---------------- drivers/graphics/fbcond/src/display.rs | 31 ++--------- drivers/graphics/fbcond/src/text.rs | 4 +- 4 files changed, 67 insertions(+), 89 deletions(-) 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); } From aa0373af6155e5ec896fc37703d110192bb24e2d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Dec 2025 20:49:17 +0100 Subject: [PATCH 4/5] drivers/graphics: Move dumb buffer creation into console-draw --- drivers/graphics/console-draw/src/lib.rs | 41 +++++++++++++----- drivers/graphics/fbbootlogd/src/scheme.rs | 35 +++------------ drivers/graphics/fbcond/src/display.rs | 53 ++++++++--------------- 3 files changed, 53 insertions(+), 76 deletions(-) diff --git a/drivers/graphics/console-draw/src/lib.rs b/drivers/graphics/console-draw/src/lib.rs index 64f2ad2f9a..20be8bb8d2 100644 --- a/drivers/graphics/console-draw/src/lib.rs +++ b/drivers/graphics/console-draw/src/lib.rs @@ -4,7 +4,7 @@ use std::collections::VecDeque; use std::convert::{TryFrom, TryInto}; use std::{cmp, io, mem, ptr}; -use drm::buffer::Buffer; +use drm::buffer::{Buffer, DrmFourcc}; use drm::control::dumbbuffer::{DumbBuffer, DumbMapping}; use drm::control::Device; use graphics_ipc::v1::Damage; @@ -14,10 +14,23 @@ use orbclient::FONT; pub struct V2DisplayMap { pub display_handle: V2GraphicsHandle, pub fb: DumbBuffer, - pub mapping: DumbMapping<'static>, + mapping: DumbMapping<'static>, } impl V2DisplayMap { + pub fn new(display_handle: V2GraphicsHandle, width: u32, height: u32) -> io::Result { + let mut fb = display_handle.create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32)?; + + let map = display_handle.map_dumb_buffer(&mut fb)?; + let map = unsafe { mem::transmute::, DumbMapping<'static>>(map) }; + + Ok(Self { + display_handle, + fb, + mapping: map, + }) + } + unsafe fn console_map(&mut self) -> DisplayMap { DisplayMap { offscreen: ptr::slice_from_raw_parts_mut( @@ -30,10 +43,10 @@ impl V2DisplayMap { } } -pub struct DisplayMap { - pub offscreen: *mut [u32], - pub width: usize, - pub height: usize, +struct DisplayMap { + offscreen: *mut [u32], + width: usize, + height: usize, } pub struct TextScreen { @@ -257,7 +270,7 @@ impl TextScreen { damage } - pub fn resize(&mut self, old_map: &mut V2DisplayMap, mut new_fb: DumbBuffer) -> io::Result<()> { + pub fn resize(&mut self, map: &mut V2DisplayMap, width: u32, height: u32) -> io::Result<()> { // FIXME fold row when target is narrower and maybe unfold when it is wider fn copy_row( old_map: &mut DisplayMap, @@ -274,14 +287,18 @@ impl TextScreen { } } - let new_mapping = old_map.display_handle.map_dumb_buffer(&mut new_fb)?; + let mut new_fb = + map.display_handle + .create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32)?; + + let new_mapping = 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 old_map = unsafe { &mut map.console_map() }; let new_map = &mut DisplayMap { offscreen: ptr::slice_from_raw_parts_mut( new_mapping.as_mut_ptr() as *mut u32, @@ -307,10 +324,10 @@ impl TextScreen { } } - let old_fb = mem::replace(&mut old_map.fb, new_fb); - old_map.mapping = new_mapping; + let old_fb = mem::replace(&mut map.fb, new_fb); + map.mapping = new_mapping; - let _ = old_map.display_handle.destroy_dumb_buffer(old_fb); + let _ = 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 41e6f3f009..832c511d76 100644 --- a/drivers/graphics/fbbootlogd/src/scheme.rs +++ b/drivers/graphics/fbbootlogd/src/scheme.rs @@ -1,9 +1,8 @@ +use std::cmp; use std::collections::VecDeque; -use std::{cmp, mem}; use console_draw::{TextScreen, V2DisplayMap}; -use drm::buffer::{Buffer, DrmFourcc}; -use drm::control::dumbbuffer::DumbMapping; +use drm::buffer::Buffer; use drm::control::Device; use graphics_ipc::v2::V2GraphicsHandle; use inputd::ConsumerHandle; @@ -54,26 +53,15 @@ impl FbbootlogScheme { .unwrap() .modes()[0] .size(); - let mut fb = new_display_handle - .create_dumb_buffer((width.into(), height.into()), DrmFourcc::Argb8888, 32) - .unwrap(); - let display_map = match new_display_handle.map_dumb_buffer(&mut fb) { - Ok(display_map) => unsafe { - mem::transmute::, DumbMapping<'static>>(display_map) - }, + match V2DisplayMap::new(new_display_handle, width.into(), height.into()) { + Ok(display_map) => self.display_map = Some(display_map), Err(err) => { eprintln!("fbbootlogd: failed to open display: {}", err); return; } }; - self.display_map = Some(V2DisplayMap { - display_handle: new_display_handle, - mapping: display_map, - fb, - }); - eprintln!("fbbootlogd: mapped display"); } @@ -173,19 +161,10 @@ impl FbbootlogScheme { }; if (width, height) != map.fb.size() { - match map - .display_handle - .create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32) - { - Ok(fb) => match text_screen.resize(map, fb) { - Ok(()) => eprintln!("fbbootlogd: mapped display"), - Err(err) => { - eprintln!("fbbootlogd: failed to open display: {}", err); - return; - } - }, + match text_screen.resize(map, width, height) { + Ok(()) => eprintln!("fbbootlogd: mapped display"), Err(err) => { - eprintln!("fbbootlogd: failed to create framebuffer: {}", err); + eprintln!("fbbootlogd: failed to create or map framebuffer: {}", err); return; } } diff --git a/drivers/graphics/fbcond/src/display.rs b/drivers/graphics/fbcond/src/display.rs index 0d23e95ab9..639bc8f06a 100644 --- a/drivers/graphics/fbcond/src/display.rs +++ b/drivers/graphics/fbcond/src/display.rs @@ -1,10 +1,9 @@ use console_draw::{TextScreen, V2DisplayMap}; -use drm::buffer::{Buffer, DrmFourcc}; -use drm::control::dumbbuffer::DumbMapping; +use drm::buffer::Buffer; use drm::control::Device; use graphics_ipc::v2::{Damage, V2GraphicsHandle}; use inputd::ConsumerHandle; -use std::{io, mem}; +use std::io; pub struct Display { pub input_handle: ConsumerHandle, @@ -35,29 +34,21 @@ impl Display { .unwrap() .modes()[0] .size(); - let mut fb = new_display_handle - .create_dumb_buffer((width.into(), height.into()), DrmFourcc::Argb8888, 32) - .unwrap(); - let map = match new_display_handle.map_dumb_buffer(&mut fb) { - Ok(map) => unsafe { mem::transmute::, DumbMapping<'static>>(map) }, + match V2DisplayMap::new(new_display_handle, width.into(), height.into()) { + Ok(map) => { + log::debug!( + "fbcond: Mapped new display with size {}x{}", + map.fb.size().0, + map.fb.size().1, + ); + self.map = Some(map) + } Err(err) => { - log::error!("failed to map display: {}", err); + eprintln!("fbcond: failed to open display: {}", err); return; } - }; - - log::debug!( - "fbcond: Mapped new display with size {}x{}", - fb.size().0, - fb.size().1, - ); - - self.map = Some(V2DisplayMap { - display_handle: new_display_handle, - fb, - mapping: map, - }); + } } pub fn handle_resize(map: &mut V2DisplayMap, text_screen: &mut TextScreen) { @@ -72,21 +63,11 @@ impl Display { }; if (width, height) != map.fb.size() { - match map - .display_handle - .create_dumb_buffer((width, height), DrmFourcc::Argb8888, 32) - { - Ok(fb) => { - match text_screen.resize(map, fb) { - Ok(()) => eprintln!("fbcond: mapped display"), - Err(err) => { - eprintln!("fbcond: failed to open display: {}", err); - return; - } - }; - } + match text_screen.resize(map, width, height) { + Ok(()) => eprintln!("fbcond: mapped display"), Err(err) => { - log::error!("fbcond: failed to create framebuffer: {}", err); + eprintln!("fbcond: failed to create or map framebuffer: {}", err); + return; } } } From c46d5dea7ada8e02e1a28348ac2448b42d9d0e06 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Dec 2025 21:12:19 +0100 Subject: [PATCH 5/5] drivers/graphics/fbbootlogd: Reduce flickering while scrolling --- drivers/graphics/fbbootlogd/src/scheme.rs | 15 ++++++----- drivers/graphics/graphics-ipc/src/common.rs | 29 +++++++++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/drivers/graphics/fbbootlogd/src/scheme.rs b/drivers/graphics/fbbootlogd/src/scheme.rs index 832c511d76..ff0108e46c 100644 --- a/drivers/graphics/fbbootlogd/src/scheme.rs +++ b/drivers/graphics/fbbootlogd/src/scheme.rs @@ -4,7 +4,7 @@ use std::collections::VecDeque; use console_draw::{TextScreen, V2DisplayMap}; use drm::buffer::Buffer; use drm::control::Device; -use graphics_ipc::v2::V2GraphicsHandle; +use graphics_ipc::v2::{Damage, V2GraphicsHandle}; use inputd::ConsumerHandle; use orbclient::{Event, EventOption}; use redox_scheme::scheme::SchemeSync; @@ -127,6 +127,8 @@ impl FbbootlogScheme { let mut i = self.scrollback_offset; self.text_screen .write(map, b"\x1B[1;1H\x1B[2J", &mut VecDeque::new()); + + let mut total_damage = Damage::NONE; while i < buffer_len { let mut damage = self.text_screen @@ -136,17 +138,16 @@ impl FbbootlogScheme { if i == buffer_len || yd + spare_lines * 16 > map.fb.size().1 as usize { // render until end of screen damage.height = map.fb.size().1 - damage.y; - map.display_handle - .update_plane(0, u32::from(map.fb.handle()), damage) - .unwrap(); + total_damage = total_damage.merge(damage); self.is_scrollback = i < buffer_len; break; } else { - map.display_handle - .update_plane(0, u32::from(map.fb.handle()), damage) - .unwrap(); + total_damage = total_damage.merge(damage); } } + map.display_handle + .update_plane(0, u32::from(map.fb.handle()), total_damage) + .unwrap(); } fn handle_resize(map: &mut V2DisplayMap, text_screen: &mut TextScreen) { diff --git a/drivers/graphics/graphics-ipc/src/common.rs b/drivers/graphics/graphics-ipc/src/common.rs index 27138151d5..ca5dc48392 100644 --- a/drivers/graphics/graphics-ipc/src/common.rs +++ b/drivers/graphics/graphics-ipc/src/common.rs @@ -13,6 +13,35 @@ pub struct Damage { } impl Damage { + pub const NONE: Self = Damage { + x: 0, + y: 0, + width: 0, + height: 0, + }; + + pub fn merge(self, other: Self) -> Self { + if self.width == 0 || self.height == 0 { + return other; + } + + if other.width == 0 || other.height == 0 { + return self; + } + + let x = cmp::min(self.x, other.x); + let y = cmp::min(self.y, other.y); + let x2 = cmp::max(self.x + self.width, other.x + other.width); + let y2 = cmp::max(self.y + self.height, other.y + other.height); + + Damage { + x, + y, + width: x2 - x, + height: y2 - y, + } + } + #[must_use] pub fn clip(mut self, width: u32, height: u32) -> Self { // Clip damage