Add graphical_debug module

This commit is contained in:
Jeremy Soller
2022-07-29 15:57:02 -06:00
parent 0c80643077
commit 897cd4c9f4
3 changed files with 213 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
use super::Display;
pub struct DebugDisplay {
pub (crate) display: Display,
x: usize,
y: usize,
w: usize,
h: usize,
}
impl DebugDisplay {
pub fn new(display: Display) -> DebugDisplay {
let w = display.width/8;
let h = display.height/16;
DebugDisplay {
display,
x: 0,
y: 0,
w: w,
h: h,
}
}
pub fn write_char(&mut self, c: char) {
if self.x >= self.w || c == '\n' {
self.x = 0;
self.y += 1;
}
if self.y >= self.h {
let new_y = self.h - 1;
let d_y = self.y - new_y;
self.display.scroll(d_y * 16);
unsafe {
self.display.sync(0, 0, self.display.width, self.display.height);
}
self.y = new_y;
}
if c != '\n' {
self.display.char(
self.x * 8, self.y * 16,
c,
0xFFFFFF
);
unsafe {
self.display.sync(self.x * 8, self.y * 16, 8, 16);
}
self.x += 1;
}
}
pub fn write(&mut self, buf: &[u8]) {
for &b in buf {
self.write_char(b as char);
}
}
}

View File

@@ -0,0 +1,80 @@
use alloc::boxed::Box;
use core::{cmp, ptr, slice};
use super::FONT;
/// A display
pub struct Display {
pub width: usize,
pub height: usize,
pub onscreen: &'static mut [u32],
pub offscreen: Option<Box<[u32]>>
}
impl Display {
pub fn new(width: usize, height: usize, onscreen_ptr: *mut u32) -> Display {
let size = width * height;
let onscreen = unsafe {
ptr::write_bytes(onscreen_ptr, 0, size);
slice::from_raw_parts_mut(onscreen_ptr, size)
};
Display {
width,
height,
onscreen,
offscreen: None,
}
}
pub fn data_mut(&mut self) -> &mut [u32] {
match &mut self.offscreen {
Some(offscreen) => offscreen,
None => self.onscreen,
}
}
/// Draw a character
pub fn char(&mut self, x: usize, y: usize, character: char, color: u32) {
if x + 8 <= self.width && y + 16 <= self.height {
let mut dst = self.data_mut().as_mut_ptr() as usize + (y * self.width + x) * 4;
let font_i = 16 * (character as usize);
if font_i + 16 <= FONT.len() {
for row in 0..16 {
let row_data = FONT[font_i + row];
for col in 0..8 {
if (row_data >> (7 - col)) & 1 == 1 {
unsafe { *((dst + col * 4) as *mut u32) = color; }
}
}
dst += self.width * 4;
}
}
}
}
/// Scroll the screen
pub fn scroll(&mut self, lines: usize) {
let offset = cmp::min(self.height, lines) * self.width;
let size = (self.width * self.height) - offset;
unsafe {
let ptr = self.data_mut().as_mut_ptr();
ptr::copy(ptr.add(offset), ptr, size);
ptr::write_bytes(ptr.add(size), 0, offset);
}
}
/// Sync from offscreen to onscreen, unsafe because it trusts provided x, y, w, h
pub unsafe fn sync(&mut self, x: usize, y: usize, w: usize, mut h: usize) {
if let Some(offscreen) = &self.offscreen {
let mut offset = y * self.width + x;
while h > 0 {
self.onscreen[offset..offset+w].copy_from_slice(
&offscreen[offset..offset+w]
);
offset += self.width;
h -= 1;
}
}
}
}

View File

@@ -0,0 +1,70 @@
use core::str;
use spin::Mutex;
pub use self::debug::DebugDisplay;
use self::display::Display;
pub mod debug;
pub mod display;
pub static FONT: &'static [u8] = include_bytes!("../../../res/unifont.font");
pub static DEBUG_DISPLAY: Mutex<Option<DebugDisplay>> = Mutex::new(None);
pub fn init(env: &[u8]) {
println!("Starting graphical debug");
let mut width = 0;
let mut height = 0;
let mut physbaseptr = 0;
//TODO: should errors be reported?
for line in str::from_utf8(env).unwrap_or("").lines() {
let mut parts = line.splitn(2, '=');
let name = parts.next().unwrap_or("");
let value = parts.next().unwrap_or("");
if name == "FRAMEBUFFER_ADDR" {
physbaseptr = usize::from_str_radix(value, 16).unwrap_or(0);
}
if name == "FRAMEBUFFER_WIDTH" {
width = usize::from_str_radix(value, 16).unwrap_or(0);
}
if name == "FRAMEBUFFER_HEIGHT" {
height = usize::from_str_radix(value, 16).unwrap_or(0);
}
}
if physbaseptr == 0 || width == 0 || height == 0 {
println!("Framebuffer not found");
return;
}
println!("Framebuffer {}x{} at {:X}", width, height, physbaseptr);
{
let size = width * height * 4;
let virtbaseptr = physbaseptr + crate::PHYS_OFFSET;
let display = Display::new(width, height, virtbaseptr as *mut u32);
let debug_display = DebugDisplay::new(display);
*DEBUG_DISPLAY.lock() = Some(debug_display);
}
}
pub fn init_heap() {
if let Some(debug_display) = &mut *DEBUG_DISPLAY.lock() {
debug_display.display.offscreen = Some(
debug_display.display.onscreen.to_vec().into_boxed_slice()
);
}
}
pub fn fini() {
DEBUG_DISPLAY.lock().take();
println!("Finished graphical debug");
}