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.
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Box<[u32]>>,
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user