diff --git a/Cargo.lock b/Cargo.lock index 5a965b2..644bdc6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,6 +109,16 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" +[[package]] +name = "fontdue" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe23d02309319171d00d794c9ff48d4f903c0e481375b1b04b017470838af04" +dependencies = [ + "hashbrown", + "ttf-parser", +] + [[package]] name = "gimli" version = "0.28.1" @@ -154,6 +164,7 @@ dependencies = [ "crossbeam-queue", "derive-try-from-primitive", "elf", + "fontdue", "hashbrown", "humansize", "intrusive-collections", @@ -365,6 +376,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ttf-parser" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c591d83f69777866b9126b24c6dd9a18351f177e49d625920d19f989fd31cf8" + [[package]] name = "uart_16550" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index c07c795..453e4cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,3 +28,10 @@ saturating_cast = "0.1.0" humansize = "2.1.3" cast = "0.3.0" az = "1.2.1" +fontdue = { version = "0.9.2", default-features = false, features = ["hashbrown"] } + +[profile.release] +strip = true +lto = true +# opt-level = "z" +codegen-units=1 diff --git a/FiraCode-Regular.ttf b/FiraCode-Regular.ttf new file mode 100644 index 0000000..bd73685 Binary files /dev/null and b/FiraCode-Regular.ttf differ diff --git a/src/fbuffer.rs b/src/fbuffer.rs new file mode 100644 index 0000000..d87715b --- /dev/null +++ b/src/fbuffer.rs @@ -0,0 +1,129 @@ +use bootloader_api::info::FrameBufferInfo; +use fontdue::{layout::{CoordinateSystem, Layout, LayoutSettings, TextStyle}, Font, FontSettings}; +use spin::{Lazy, Mutex}; +use crate::{bootinfo::BOOTINFO, dbg}; +use alloc::{string::String, vec::Vec, vec}; +use core::slice; + + +struct Framebuffer<'a> { + info: FrameBufferInfo, + buffer: &'a mut [u8], + draw_buffer: Vec, +} + +impl<'a> Framebuffer<'a> { + pub fn new(info: FrameBufferInfo, buffer: &'a mut [u8]) -> Self { + dbg!(&info); + let draw_buffer = vec![0; buffer.len()]; + Self { info, buffer, draw_buffer } + } + + fn get_row_buf(&mut self, row: usize) -> &mut [u8] { + &mut self.draw_buffer[(self.info.stride * self.info.bytes_per_pixel * row)..] + [..(self.info.bytes_per_pixel * self.info.width)] + } + + fn get_pixel_buf(&mut self, row: usize, col: usize) -> &mut [u8] { + let pbuf_start = col * self.info.bytes_per_pixel; + let pbuf_len = self.info.bytes_per_pixel; + &mut self.get_row_buf(row)[pbuf_start..][..pbuf_len] + } + + pub fn set_pixel(&mut self, row: usize, col: usize, value: u8) { + if row >= self.info.height || col >= self.info.width { + return; + } + self.get_pixel_buf(row, col).fill(value); + } + + pub fn clear(&mut self) { + for row in 0..self.info.height { + self.get_row_buf(row).fill(0); + } + } + + pub fn update_screen(&mut self) { + self.buffer.copy_from_slice(&self.draw_buffer); + } +} + +static FBUFFER: Lazy>> = Lazy::new(|| { + // Testing the framebuffer + let fbuf = BOOTINFO.framebuffer.as_ref().unwrap(); + + // No good way to get mutable buffer, so do this. No, its probably not safe. Too lazy to do it + // right. + let buf_start = fbuf.buffer().as_ptr(); + let fbuf_buf = unsafe { slice::from_raw_parts_mut(buf_start as *mut u8, fbuf.buffer().len()) }; + let fbuf_info = fbuf.info(); + + let mut fbuf = Framebuffer::new(fbuf_info, fbuf_buf); + fbuf.clear(); + fbuf.update_screen(); + Mutex::new(fbuf) +}); + +pub static OUT_STRING: Lazy> = Lazy::new(|| { + Mutex::new(String::new()) +}); + +pub static FIRA_CODE: Lazy = Lazy::new(|| { + Font::from_bytes(include_bytes!("../FiraCode-Regular.ttf").as_slice(), FontSettings::default()).unwrap() +}); + +pub fn write_str(s: &str) { + OUT_STRING.lock().push_str(s); +} + +pub fn write_char(c: char) { + OUT_STRING.lock().push(c); +} + +pub fn update_screen() { + let out_string = OUT_STRING.lock(); + let mut fbuf = FBUFFER.lock(); + fbuf.clear(); + let mut layout = Layout::new(CoordinateSystem::PositiveYDown); + + layout.reset(&LayoutSettings { + max_width: Some(fbuf.info.width as f32), + max_height: Some(fbuf.info.height as f32), + ..Default::default() + }); + + layout.append(&[&*FIRA_CODE], &TextStyle::new(&out_string, 12.0, 0)); + + let height = layout.height(); + let top_row = if height as usize > fbuf.info.height { + height as usize - fbuf.info.height + } else { + 0 + }; + + let glyphs = layout.glyphs(); + + let mut first_line_top_offset = None; + + for line in layout.lines().unwrap() { + if ((line.baseline_y - line.max_ascent) as usize) < top_row { + continue; + } + if first_line_top_offset.is_none() { + first_line_top_offset = Some(((line.baseline_y - line.max_ascent) as usize) - top_row); + } + let first_line_top_offset = first_line_top_offset.unwrap(); + for glyph_pos in &glyphs[line.glyph_start..=line.glyph_end] { + if glyph_pos.width == 0 || glyph_pos.height == 0 { + continue; + } + let (_, bitmap) = FIRA_CODE.rasterize_config(glyph_pos.key); + for (i, &pixel) in bitmap.iter().enumerate() { + let row = i / glyph_pos.width; + let col = i % glyph_pos.width; + fbuf.set_pixel(row + glyph_pos.y as usize - top_row - first_line_top_offset, col + glyph_pos.x as usize, pixel); + } + } + } + fbuf.update_screen(); +} diff --git a/src/interrupts.rs b/src/interrupts.rs index c85030e..fd72887 100644 --- a/src/interrupts.rs +++ b/src/interrupts.rs @@ -6,7 +6,7 @@ use crate::{ virtual_memory::{ASpaceMutex, AddressSpace, ACTIVE_SPACE, KERNEL_SPACE}, TASKING, }; -use alloc::{boxed::Box, vec::Vec}; +use alloc::{boxed::Box, string::ToString, vec::Vec}; use az::WrappingCast; use cast::{u64, usize}; use core::{arch::asm, ffi::CStr, ptr, slice}; @@ -251,7 +251,9 @@ extern "C" fn syscall_handler() { match regs.rax { 0 => { let rval = if let Some(chr) = char::from_u32(regs.rcx.wrapping_cast()) { + crate::fbuffer::write_char(chr); if chr == '\n' { + crate::fbuffer::update_screen(); print!("\r\n"); } else { print!("{}", chr); diff --git a/src/main.rs b/src/main.rs index 78d5725..68e9c54 100644 --- a/src/main.rs +++ b/src/main.rs @@ -84,6 +84,7 @@ mod serial; mod start; mod tasking; mod virtual_memory; +mod fbuffer; use core::{ptr, slice};