diff --git a/Cargo.toml b/Cargo.toml index 3221e470..94605465 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,12 +22,13 @@ tock-registers = "0.8.1" cfg-if = "1.0.0" git-version = "0.3.5" -bitmap-font = { version = "0.3.0", optional = true } -embedded-graphics = { version = "0.8.0", optional = true } +# bitmap-font = { version = "0.3.0", optional = true } +# embedded-graphics = { version = "0.8.0", optional = true } log = "0.4.20" futures-util = { version = "0.3.28", default-features = false, features = ["alloc", "async-await"] } crossbeam-queue = { version = "0.3.8", default-features = false, features = ["alloc"] } +bytemuck = { version = "1.14.0", features = ["derive"] } [dependencies.elf] version = "0.7.2" @@ -49,7 +50,7 @@ xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" } [features] default = [] -fb_console = ["bitmap-font", "embedded-graphics"] +fb_console = [] aarch64_qemu = [] aarch64_orange_pi3 = [] aarch64_rpi3b = [] diff --git a/lib/kernel-util/src/lib.rs b/lib/kernel-util/src/lib.rs index 06f7b372..9597c0aa 100644 --- a/lib/kernel-util/src/lib.rs +++ b/lib/kernel-util/src/lib.rs @@ -3,3 +3,9 @@ pub mod sync; pub mod util; + +#[repr(C)] +pub struct AlignedTo { + pub align: [Align; 0], + pub bytes: Bytes, +} diff --git a/lib/kernel-util/src/util.rs b/lib/kernel-util/src/util.rs index 5e11e00a..8f505750 100644 --- a/lib/kernel-util/src/util.rs +++ b/lib/kernel-util/src/util.rs @@ -4,7 +4,7 @@ use core::{ mem::MaybeUninit, ops::{Deref, DerefMut}, panic, - sync::atomic::{AtomicBool, AtomicUsize, Ordering}, + sync::atomic::{AtomicUsize, Ordering}, }; /// Statically-allocated "dynamic" vector diff --git a/src/device/display/console.rs b/src/device/display/console.rs index 01da5ad4..1b8927ad 100644 --- a/src/device/display/console.rs +++ b/src/device/display/console.rs @@ -133,8 +133,6 @@ pub struct RowIter<'a> { pub trait DisplayConsole { /// Returns the state lock fn state(&self) -> &IrqSafeSpinlock; - /// Allocates a new buffer for the console according to the display's size - fn reallocate_buffer(&self) -> Result<(), Error>; /// Flushes the data from console buffer to the display fn flush(&self, state: &mut ConsoleState); @@ -157,7 +155,7 @@ impl ConsoleChar { }; /// Constructs a console character from a char and its attributes - #[inline] + #[inline(always)] pub fn from_parts( char: u8, fg: ColorAttribute, @@ -175,7 +173,7 @@ impl ConsoleChar { } /// Returns the attributes of the character - #[inline] + #[inline(always)] pub fn attributes(self) -> (ColorAttribute, ColorAttribute, Attributes) { let fg = ColorAttribute::try_from((self.attributes & 0xF) as u8).unwrap_or(DEFAULT_FG_COLOR); @@ -188,7 +186,7 @@ impl ConsoleChar { } /// Returns the character data of this [ConsoleChar] - #[inline] + #[inline(always)] pub const fn character(self) -> u8 { self.char } @@ -369,6 +367,9 @@ impl ConsoleState { self.esc_state = EscapeState::Escape; return false; } + b'\r' => { + self.cursor_col = 0; + } b'\n' => { self.cursor_row += 1; self.cursor_col = 0; diff --git a/src/device/display/fb_console.rs b/src/device/display/fb_console.rs index 952e547e..6890b168 100644 --- a/src/device/display/fb_console.rs +++ b/src/device/display/fb_console.rs @@ -1,33 +1,23 @@ //! Framebuffer console driver use abi::error::Error; -use bitmap_font::{BitmapFont, TextStyle}; -use embedded_graphics::{ - pixelcolor::BinaryColor, - prelude::{DrawTarget, OriginDimensions, Point, Size}, - text::Text, - Drawable, Pixel, -}; use crate::{debug::DebugSink, sync::IrqSafeSpinlock}; use super::{ console::{Attributes, ConsoleBuffer, ConsoleState, DisplayConsole}, + font::PcScreenFont, linear_fb::LinearFramebuffer, - DisplayDevice, DisplayDimensions, + DisplayDevice, }; struct Inner { framebuffer: &'static LinearFramebuffer, - font: &'static BitmapFont<'static>, + font: PcScreenFont<'static>, char_width: u32, char_height: u32, width: u32, height: u32, - - fg_color: u32, - #[allow(dead_code)] - bg_color: u32, } /// Framebuffer console device wrapper @@ -52,20 +42,14 @@ impl DisplayConsole for FramebufferConsole { &self.state } - fn reallocate_buffer(&self) -> Result<(), Error> { - let mut state = self.state.lock(); - let inner = self.inner.lock(); - - let new_height = inner.height; - state.buffer.reallocate(new_height) - } - fn flush(&self, state: &mut ConsoleState) { let mut inner = self.inner.lock(); let font = inner.font; let cw = inner.char_width; let ch = inner.char_height; + let bytes_per_line = (font.width() as usize + 7) / 8; + let mut iter = state.buffer.flush_rows(); while let Some((row_idx, row)) = iter.next_dirty() { @@ -77,20 +61,18 @@ impl DisplayConsole for FramebufferConsole { let glyph = chr.character(); let (fg, bg, attr) = chr.attributes(); - if glyph == 0 { - continue; - } + let fg = fg.as_rgba(attr.contains(Attributes::BOLD)); + let bg = bg.as_rgba(false); - inner.fg_color = fg.as_rgba(attr.contains(Attributes::BOLD)); - - inner.fill_rect( + inner.draw_glyph( + font, (col_idx as u32) * cw, row_idx * ch, - cw, - ch, - bg.as_rgba(false), + glyph, + fg, + bg, + bytes_per_line, ); - inner.draw_glyph(font, (col_idx as u32) * cw, row_idx * ch, glyph); } } @@ -112,9 +94,9 @@ impl FramebufferConsole { /// Constructs an instance of console from its framebuffer reference pub fn from_framebuffer( framebuffer: &'static LinearFramebuffer, - font: Option<&'static BitmapFont<'static>>, + font: Option>, ) -> Result { - let font = font.unwrap_or(&bitmap_font::tamzen::FONT_7x14); + let font = font.unwrap_or(PcScreenFont::default()); let char_width = font.width(); let char_height = font.height(); let dim = framebuffer.dimensions(); @@ -127,9 +109,6 @@ impl FramebufferConsole { height: dim.height / char_height, char_width, char_height, - - fg_color: 0, - bg_color: 0, }; Ok(Self { @@ -140,62 +119,51 @@ impl FramebufferConsole { } impl Inner { - fn draw_glyph(&mut self, font: &BitmapFont, x: u32, y: u32, c: u8) { - let text_data = [c]; - let text_str = unsafe { core::str::from_utf8_unchecked(&text_data) }; - let text = Text::new( - text_str, - Point::new(x as _, y as _), - TextStyle::new(font, BinaryColor::On), - ); + #[optimize(speed)] + fn draw_glyph( + &mut self, + font: PcScreenFont<'static>, + sx: u32, + sy: u32, + c: u8, + fg: u32, + bg: u32, + bytes_per_line: usize, + ) { + let mut fb = unsafe { self.framebuffer.lock() }; - text.draw(self).ok(); + let mut c = c as u32; + if c >= font.len() { + c = b'?' as u32; + } + + let mut glyph = font.raw_glyph_data(c); + + let mut y = 0; + + while y < font.height() { + let mut mask = 1 << (font.width() - 1); + let mut x = 0; + + while x < font.width() { + let v = if glyph[0] & mask != 0 { fg } else { bg }; + fb[sy + y][(sx + x) as usize] = v; + mask >>= 1; + x += 1; + } + + glyph = &glyph[bytes_per_line..]; + y += 1; + } } + #[optimize(speed)] fn fill_rect(&mut self, x: u32, y: u32, w: u32, h: u32, val: u32) { let mut fb = unsafe { self.framebuffer.lock() }; for i in 0..h { let row = &mut fb[i + y]; - for j in 0..w { - row[(j + x) as usize] = val; - } + row[x as usize..(x + w) as usize].fill(val); } } } - -impl OriginDimensions for Inner { - fn size(&self) -> Size { - self.framebuffer.dimensions().into() - } -} - -impl DrawTarget for Inner { - type Color = BinaryColor; - type Error = (); - - fn draw_iter(&mut self, pixels: I) -> Result<(), Self::Error> - where - I: IntoIterator>, - { - let mut fb = unsafe { self.framebuffer.lock() }; - for Pixel(coord, color) in pixels { - let row = &mut fb[coord.y as u32]; - let color = if color.is_on() { - self.fg_color - } else { - 0xFF000000 - }; - - row[coord.x as usize] = color; - } - - Ok(()) - } -} - -impl From for Size { - fn from(value: DisplayDimensions) -> Self { - Self::new(value.width as _, value.height as _) - } -} diff --git a/src/device/display/font.psfu b/src/device/display/font.psfu new file mode 100644 index 00000000..e789b771 Binary files /dev/null and b/src/device/display/font.psfu differ diff --git a/src/device/display/font.rs b/src/device/display/font.rs new file mode 100644 index 00000000..cbebdcfc --- /dev/null +++ b/src/device/display/font.rs @@ -0,0 +1,65 @@ +use core::mem::size_of; + +use abi::error::Error; +use bytemuck::{Pod, Zeroable}; +use kernel_util::AlignedTo; + +// static CONSOLE_FONT: &[u8] = include_bytes!("font.psfu"); +static CONSOLE_FONT: &'static AlignedTo = &AlignedTo { + align: [], + bytes: *include_bytes!("font.psfu"), +}; + +#[repr(C)] +#[derive(Pod, Zeroable, Clone, Copy)] +struct PsfHeader { + magic: u32, + version: u32, + header_size: u32, + flags: u32, + num_glyph: u32, + bytes_per_glyph: u32, + height: u32, + width: u32, +} + +#[derive(Clone, Copy)] +pub struct PcScreenFont<'a> { + header: &'a PsfHeader, + glyph_data: &'a [u8], +} + +impl Default for PcScreenFont<'static> { + fn default() -> Self { + Self::from_bytes(&CONSOLE_FONT.bytes).unwrap() + } +} + +impl<'a> PcScreenFont<'a> { + pub fn from_bytes(bytes: &'a [u8]) -> Result { + let header: &PsfHeader = bytemuck::from_bytes(&bytes[..size_of::()]); + let glyph_data = &bytes[header.header_size as usize..]; + + Ok(Self { header, glyph_data }) + } + + #[inline] + pub const fn width(&self) -> u32 { + self.header.width + } + + #[inline] + pub const fn height(&self) -> u32 { + self.header.height + } + + #[inline] + pub const fn len(&self) -> u32 { + self.header.num_glyph + } + + #[inline] + pub fn raw_glyph_data(&self, index: u32) -> &[u8] { + &self.glyph_data[(index * self.header.bytes_per_glyph) as usize..] + } +} diff --git a/src/device/display/mod.rs b/src/device/display/mod.rs index e503e3ae..02df0cca 100644 --- a/src/device/display/mod.rs +++ b/src/device/display/mod.rs @@ -3,6 +3,7 @@ use super::Device; pub mod console; +pub mod font; #[cfg(feature = "fb_console")] pub mod fb_console;