From b36deffa6109801a6dc746199b84d8ee1e95cc5e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Sep 2025 17:15:02 +0200 Subject: [PATCH] Replace scrolling with wraparound in graphical debug Inspired by how Haiku does printing for its kernel debugger, this commit gets rid of the scrolling when the bootlog reaches the end of the screen and instead wraps around to the start of the screen. Between the last written line and the first visible written line there is always a blank line to provide visual separation. Getting rid of the scrolling significantly simplifies the implementation of graphical debug and removes the need for double buffering for performance as we no longer need to read back the framebuffer when scrolling which is very expensive on write-combining memory like the framebuffer. --- src/arch/aarch64/start.rs | 3 -- src/arch/x86_shared/start.rs | 3 -- src/devices/graphical_debug/debug.rs | 58 +++++++++--------------- src/devices/graphical_debug/display.rs | 63 +------------------------- src/devices/graphical_debug/mod.rs | 7 --- 5 files changed, 23 insertions(+), 111 deletions(-) diff --git a/src/arch/aarch64/start.rs b/src/arch/aarch64/start.rs index 8667688b1a..19edc2ac67 100644 --- a/src/arch/aarch64/start.rs +++ b/src/arch/aarch64/start.rs @@ -179,9 +179,6 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! { // Setup kernel heap allocator::init(); - // Set up double buffer for graphical debug now that heap is available - graphical_debug::init_heap(); - // Activate memory logging crate::log::init(); diff --git a/src/arch/x86_shared/start.rs b/src/arch/x86_shared/start.rs index 415b8aa1e9..c643c02c88 100644 --- a/src/arch/x86_shared/start.rs +++ b/src/arch/x86_shared/start.rs @@ -170,9 +170,6 @@ pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! { #[cfg(all(target_arch = "x86_64", feature = "profiling"))] crate::profiling::init(); - // Set up double buffer for graphical debug now that heap is available - graphical_debug::init_heap(); - // Activate memory logging crate::log::init(); diff --git a/src/devices/graphical_debug/debug.rs b/src/devices/graphical_debug/debug.rs index 80b3eca91c..4378e1d8b3 100644 --- a/src/devices/graphical_debug/debug.rs +++ b/src/devices/graphical_debug/debug.rs @@ -1,5 +1,3 @@ -use core::{cmp, ptr}; - use super::Display; static FONT: &[u8] = include_bytes!("../../../res/unifont.font"); @@ -29,30 +27,32 @@ impl DebugDisplay { for &b in buf { if self.x >= self.w || b == b'\n' { self.x = 0; - self.y += 1; + self.y = (self.y + 1) % self.h; } - if self.y >= self.h { - let new_y = self.h - 1; - let d_y = self.y - new_y; - - self.scroll(d_y * 16); - - unsafe { - self.display.sync_screen(); - } - - self.y = new_y; + if b == b'\n' { + continue; } - if b != b'\n' { - self.char(self.x * 8, self.y * 16, b as char, 0xFFFFFF); + if self.x == 0 { + self.clear_row(self.y); + self.clear_row((self.y + 1) % self.h); + } - unsafe { - self.display.sync(self.x * 8, self.y * 16, 8, 16); - } + self.char(self.x * 8, self.y * 16, b as char, 0xFFFFFF); - self.x += 1; + self.x += 1; + } + } + + fn clear_row(&mut self, y: usize) { + for row in y * 16..(y + 1) * 16 { + unsafe { + core::ptr::write_bytes( + self.display.data_mut().add(row * self.display.stride), + 0, + self.display.width, + ); } } } @@ -60,7 +60,7 @@ impl DebugDisplay { /// Draw a character fn char(&mut self, x: usize, y: usize, character: char, color: u32) { if x + 8 <= self.display.width && y + 16 <= self.display.height { - let phys_y = (self.display.offset_y + y) % self.display.height; + let phys_y = y % self.display.height; let mut dst = unsafe { self.display .data_mut() @@ -89,20 +89,4 @@ impl DebugDisplay { } } } - - /// Scroll the screen - fn scroll(&mut self, lines: usize) { - let lines = cmp::min(self.h * 16, lines); // clamp - self.display.offset_y = (self.display.offset_y + lines) % self.display.height; - - // clear the new lines - let start_y = (self.display.offset_y + self.h * 16 - lines) % self.display.height; - for row in 0..lines { - let y = (start_y + row) % self.display.height; - unsafe { - let ptr = self.display.data_mut().add(y * self.display.stride); - ptr::write_bytes(ptr, 0, self.display.stride); - } - } - } } diff --git a/src/devices/graphical_debug/display.rs b/src/devices/graphical_debug/display.rs index 34c3842692..f0f1d0e915 100644 --- a/src/devices/graphical_debug/display.rs +++ b/src/devices/graphical_debug/display.rs @@ -1,5 +1,4 @@ -use alloc::boxed::Box; -use core::{ptr, slice}; +use core::ptr; /// A display pub(super) struct Display { @@ -7,8 +6,6 @@ pub(super) struct Display { pub(super) height: usize, pub(super) stride: usize, onscreen_ptr: *mut u32, - offscreen: Option>, - pub(super) offset_y: usize, } unsafe impl Send for Display {} @@ -28,66 +25,10 @@ impl Display { height, stride, onscreen_ptr, - offscreen: None, - offset_y: 0, } } - pub(super) fn heap_init(&mut self) { - let onscreen = - unsafe { slice::from_raw_parts(self.onscreen_ptr, self.stride * self.height) }; - self.offscreen = Some(onscreen.to_vec().into_boxed_slice()); - } - pub(super) fn data_mut(&mut self) -> *mut u32 { - match &mut self.offscreen { - Some(offscreen) => offscreen.as_mut_ptr(), - None => self.onscreen_ptr, - } - } - - /// Sync from offscreen to onscreen, unsafe because it trusts provided x, y, w, h - pub(super) unsafe fn sync(&mut self, x: usize, y: usize, w: usize, mut h: usize) { - unsafe { - if let Some(offscreen) = &self.offscreen { - let mut y = y; - while h > 0 { - let src_y = (self.offset_y + y) % self.height; - let src_offset = src_y * self.stride + x; - let dst_offset = y * self.stride + x; - - ptr::copy( - offscreen.as_ptr().add(src_offset), - self.onscreen_ptr.add(dst_offset), - w, - ); - - y += 1; - h -= 1; - } - } - } - } - - // sync the whole screen (faster) - pub(super) unsafe fn sync_screen(&mut self) { - unsafe { - if let Some(offscreen) = &self.offscreen { - let stride_bytes = self.stride; - let first_part_len = (self.height - self.offset_y) * stride_bytes; - let second_part_len = self.offset_y * stride_bytes; - - ptr::copy( - offscreen.as_ptr().add(self.offset_y * stride_bytes), - self.onscreen_ptr, - first_part_len, - ); - ptr::copy( - offscreen.as_ptr(), - self.onscreen_ptr.add(first_part_len), - second_part_len, - ); - } - } + self.onscreen_ptr } } diff --git a/src/devices/graphical_debug/mod.rs b/src/devices/graphical_debug/mod.rs index 9591aba2a0..3f00c5ebdd 100644 --- a/src/devices/graphical_debug/mod.rs +++ b/src/devices/graphical_debug/mod.rs @@ -67,13 +67,6 @@ pub fn init(env: &[u8]) { } } -#[allow(unused)] -pub fn init_heap() { - if let Some(debug_display) = &mut *DEBUG_DISPLAY.lock() { - debug_display.display.heap_init(); - } -} - #[allow(unused)] pub fn fini() { DEBUG_DISPLAY.lock().take();