From c54357668577d1e16a378758a0851a3393cdafa3 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Wed, 6 Sep 2023 18:48:00 +0300 Subject: [PATCH] dev: optimize display output a bit --- Cargo.toml | 7 +- lib/kernel-util/src/lib.rs | 6 ++ lib/kernel-util/src/util.rs | 2 +- src/device/display/console.rs | 11 +-- src/device/display/fb_console.rs | 136 ++++++++++++------------------- src/device/display/font.psfu | Bin 0 -> 4969 bytes src/device/display/font.rs | 65 +++++++++++++++ src/device/display/mod.rs | 1 + 8 files changed, 135 insertions(+), 93 deletions(-) create mode 100644 src/device/display/font.psfu create mode 100644 src/device/display/font.rs 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 0000000000000000000000000000000000000000..e789b77189b9c3e585075eeed5a5eba693f3c435 GIT binary patch literal 4969 zcmZu!TWlO>6&`}L;$h{6w-K?N0^xq?(t@+JgAJkF3KS@m`(;VWHo(xD0*;}>W}P~& zLoL*ccN5dnI7yQ<7bp!)5NV<;Gt!6$Yx9OyT4P1?V80+_sZ!#HXg|L5UuI`qj{VQf z`Oo*C|J?pFvyYs=XWAj%%JBwy;AJy!GTtQo>!>z)d~)*g{N!X!i)!cs(JEkg$MJil zpe!mBZ7v5{*7dyA)m7K^jM(*RT-@h5O^Bd}QQ9 z18=!~Vv#hVHF#B$=W+whkKQp_B8{zG)BN6Ddv}o@TwQ7D3D@m#b{R>%H~0 zYpuExZz>E7jr2x_1`3-D+@or@W({^^I}-0&zPH=$KDtFn@j+ZE`*G}-i*cX<>M9}A zEW@GonRsfRQ^tOIBK0?9xQe}^kt!XfO0QDND0f<|meHa`7h)B;MLkn;i;CR7hgA=riMGNpI(9Fsg@$AnIBBh>a_bK#HWkD^lW!-8 z<1T4UbKP$rrprp*JM{8{=iFA~Nw<7)Sgq(z{fl?6MhxS@%U)t@`U)-mC81J+Zs8vufgH_)29h zvwk^_t9NQ%c2e7!{iOI5d0IZCs-b`0SGd*01UFsL^0kVhbU*1N-AKsjU%B2}Zuk9B zu@=_&tNarc#y%te*K$xC5DiK$KAQa~uat|0bUnKBIeSI5BBNiK5=CrL+8)JsyRiL3 ziCnL0?WLSplJOtWv?T8zk?xI-r;kgiWaJJz*jRZm?N^>YKE3MaoRVor~7C{OLVitgn-ynDL2{-3kKtaqyVC7~1fr`qJi7(~j0$&V@s)bX( zKQ8)Bd|8@h6;R_}q2LVgIFQ)pxtMre00ytY{df_w0`}x?mrt6OM7@nSr*w+@{%CoS zmVmX-9_gj=YQH|zdRBn-Z*!@1Q&KWKXm)cPVx(*}>xlDJe{lPx{i6d$yDkEwmeZi%EK!<%=Fopq#~vb5DQ29e^;d>+5mP4ULQ?baW4 z-(DI`can$EQeJ+;N%bonoEsa~r+6bz@d|gNk5~4gug~a7@pk=2|8n~c52yAj9Q{-4 z>?Px`nHt@&9+ubksN-t4l>5efrSVfgf-)DQKb=|IK(}ll1GJXv`}k6)(^=Br=Z^fg z>MXJav9SyB+l+@%NH`(+{1?(30qkl0_Y-GpRM%16MM2cdmmRic7K|@xR}EWZ3s=A3 z3~$;q+k_%vW7+P%njhll?1-q;{YfTkeA(Bul-D;F$iG&z+YOc~(%vhjL4&aUHMT2w zSoFV{Fh4JBO_ziR^`9N7mVR!_9&D2Q*QENPdG6or%RHTN z?b9vl^X@;s?`eNJ5*nKdg2pPX;Q<%dU9|I$#jDYFCn~u@FZo#OuxwS6vs0h zPjftpWae-(OO4ZWgq-8Jgj>Ufq+U9|WFt($NkK#_;1rHy?2uAU7 zd;&Z0N!*Q3;nVmGK8w%c9(*2Oz!z~ZzJxF1E4U9|#n*5@zK(C;oA?&Kjql*Q_#VEG zAE1ICVkdUt0sIJ6Jc!-+F@A!d!pG0>5FW-DevU`*3;Ytl!Z`L|0>8#@@F)WO7BwWZ z`w%^j=n|q+h>jw90nq}Y(2!XgILk2pjqD7{%D_#bt?PtX7W literal 0 HcmV?d00001 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;