dev: optimize display output a bit

This commit is contained in:
Mark Poliakov 2023-09-06 18:48:00 +03:00
parent 1719b84534
commit c543576685
8 changed files with 135 additions and 93 deletions

View File

@ -22,12 +22,13 @@ tock-registers = "0.8.1"
cfg-if = "1.0.0" cfg-if = "1.0.0"
git-version = "0.3.5" git-version = "0.3.5"
bitmap-font = { version = "0.3.0", optional = true } # bitmap-font = { version = "0.3.0", optional = true }
embedded-graphics = { version = "0.8.0", optional = true } # embedded-graphics = { version = "0.8.0", optional = true }
log = "0.4.20" log = "0.4.20"
futures-util = { version = "0.3.28", default-features = false, features = ["alloc", "async-await"] } futures-util = { version = "0.3.28", default-features = false, features = ["alloc", "async-await"] }
crossbeam-queue = { version = "0.3.8", default-features = false, features = ["alloc"] } crossbeam-queue = { version = "0.3.8", default-features = false, features = ["alloc"] }
bytemuck = { version = "1.14.0", features = ["derive"] }
[dependencies.elf] [dependencies.elf]
version = "0.7.2" version = "0.7.2"
@ -49,7 +50,7 @@ xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" }
[features] [features]
default = [] default = []
fb_console = ["bitmap-font", "embedded-graphics"] fb_console = []
aarch64_qemu = [] aarch64_qemu = []
aarch64_orange_pi3 = [] aarch64_orange_pi3 = []
aarch64_rpi3b = [] aarch64_rpi3b = []

View File

@ -3,3 +3,9 @@
pub mod sync; pub mod sync;
pub mod util; pub mod util;
#[repr(C)]
pub struct AlignedTo<Align, Bytes: ?Sized> {
pub align: [Align; 0],
pub bytes: Bytes,
}

View File

@ -4,7 +4,7 @@ use core::{
mem::MaybeUninit, mem::MaybeUninit,
ops::{Deref, DerefMut}, ops::{Deref, DerefMut},
panic, panic,
sync::atomic::{AtomicBool, AtomicUsize, Ordering}, sync::atomic::{AtomicUsize, Ordering},
}; };
/// Statically-allocated "dynamic" vector /// Statically-allocated "dynamic" vector

View File

@ -133,8 +133,6 @@ pub struct RowIter<'a> {
pub trait DisplayConsole { pub trait DisplayConsole {
/// Returns the state lock /// Returns the state lock
fn state(&self) -> &IrqSafeSpinlock<ConsoleState>; fn state(&self) -> &IrqSafeSpinlock<ConsoleState>;
/// 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 /// Flushes the data from console buffer to the display
fn flush(&self, state: &mut ConsoleState); fn flush(&self, state: &mut ConsoleState);
@ -157,7 +155,7 @@ impl ConsoleChar {
}; };
/// Constructs a console character from a char and its attributes /// Constructs a console character from a char and its attributes
#[inline] #[inline(always)]
pub fn from_parts( pub fn from_parts(
char: u8, char: u8,
fg: ColorAttribute, fg: ColorAttribute,
@ -175,7 +173,7 @@ impl ConsoleChar {
} }
/// Returns the attributes of the character /// Returns the attributes of the character
#[inline] #[inline(always)]
pub fn attributes(self) -> (ColorAttribute, ColorAttribute, Attributes) { pub fn attributes(self) -> (ColorAttribute, ColorAttribute, Attributes) {
let fg = let fg =
ColorAttribute::try_from((self.attributes & 0xF) as u8).unwrap_or(DEFAULT_FG_COLOR); 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] /// Returns the character data of this [ConsoleChar]
#[inline] #[inline(always)]
pub const fn character(self) -> u8 { pub const fn character(self) -> u8 {
self.char self.char
} }
@ -369,6 +367,9 @@ impl ConsoleState {
self.esc_state = EscapeState::Escape; self.esc_state = EscapeState::Escape;
return false; return false;
} }
b'\r' => {
self.cursor_col = 0;
}
b'\n' => { b'\n' => {
self.cursor_row += 1; self.cursor_row += 1;
self.cursor_col = 0; self.cursor_col = 0;

View File

@ -1,33 +1,23 @@
//! Framebuffer console driver //! Framebuffer console driver
use abi::error::Error; 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 crate::{debug::DebugSink, sync::IrqSafeSpinlock};
use super::{ use super::{
console::{Attributes, ConsoleBuffer, ConsoleState, DisplayConsole}, console::{Attributes, ConsoleBuffer, ConsoleState, DisplayConsole},
font::PcScreenFont,
linear_fb::LinearFramebuffer, linear_fb::LinearFramebuffer,
DisplayDevice, DisplayDimensions, DisplayDevice,
}; };
struct Inner { struct Inner {
framebuffer: &'static LinearFramebuffer, framebuffer: &'static LinearFramebuffer,
font: &'static BitmapFont<'static>, font: PcScreenFont<'static>,
char_width: u32, char_width: u32,
char_height: u32, char_height: u32,
width: u32, width: u32,
height: u32, height: u32,
fg_color: u32,
#[allow(dead_code)]
bg_color: u32,
} }
/// Framebuffer console device wrapper /// Framebuffer console device wrapper
@ -52,20 +42,14 @@ impl DisplayConsole for FramebufferConsole {
&self.state &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) { fn flush(&self, state: &mut ConsoleState) {
let mut inner = self.inner.lock(); let mut inner = self.inner.lock();
let font = inner.font; let font = inner.font;
let cw = inner.char_width; let cw = inner.char_width;
let ch = inner.char_height; let ch = inner.char_height;
let bytes_per_line = (font.width() as usize + 7) / 8;
let mut iter = state.buffer.flush_rows(); let mut iter = state.buffer.flush_rows();
while let Some((row_idx, row)) = iter.next_dirty() { while let Some((row_idx, row)) = iter.next_dirty() {
@ -77,20 +61,18 @@ impl DisplayConsole for FramebufferConsole {
let glyph = chr.character(); let glyph = chr.character();
let (fg, bg, attr) = chr.attributes(); let (fg, bg, attr) = chr.attributes();
if glyph == 0 { let fg = fg.as_rgba(attr.contains(Attributes::BOLD));
continue; let bg = bg.as_rgba(false);
}
inner.fg_color = fg.as_rgba(attr.contains(Attributes::BOLD)); inner.draw_glyph(
font,
inner.fill_rect(
(col_idx as u32) * cw, (col_idx as u32) * cw,
row_idx * ch, row_idx * ch,
cw, glyph,
ch, fg,
bg.as_rgba(false), 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 /// Constructs an instance of console from its framebuffer reference
pub fn from_framebuffer( pub fn from_framebuffer(
framebuffer: &'static LinearFramebuffer, framebuffer: &'static LinearFramebuffer,
font: Option<&'static BitmapFont<'static>>, font: Option<PcScreenFont<'static>>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let font = font.unwrap_or(&bitmap_font::tamzen::FONT_7x14); let font = font.unwrap_or(PcScreenFont::default());
let char_width = font.width(); let char_width = font.width();
let char_height = font.height(); let char_height = font.height();
let dim = framebuffer.dimensions(); let dim = framebuffer.dimensions();
@ -127,9 +109,6 @@ impl FramebufferConsole {
height: dim.height / char_height, height: dim.height / char_height,
char_width, char_width,
char_height, char_height,
fg_color: 0,
bg_color: 0,
}; };
Ok(Self { Ok(Self {
@ -140,62 +119,51 @@ impl FramebufferConsole {
} }
impl Inner { impl Inner {
fn draw_glyph(&mut self, font: &BitmapFont, x: u32, y: u32, c: u8) { #[optimize(speed)]
let text_data = [c]; fn draw_glyph(
let text_str = unsafe { core::str::from_utf8_unchecked(&text_data) }; &mut self,
let text = Text::new( font: PcScreenFont<'static>,
text_str, sx: u32,
Point::new(x as _, y as _), sy: u32,
TextStyle::new(font, BinaryColor::On), 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) { fn fill_rect(&mut self, x: u32, y: u32, w: u32, h: u32, val: u32) {
let mut fb = unsafe { self.framebuffer.lock() }; let mut fb = unsafe { self.framebuffer.lock() };
for i in 0..h { for i in 0..h {
let row = &mut fb[i + y]; let row = &mut fb[i + y];
for j in 0..w { row[x as usize..(x + w) as usize].fill(val);
row[(j + x) as usize] = 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<I>(&mut self, pixels: I) -> Result<(), Self::Error>
where
I: IntoIterator<Item = Pixel<Self::Color>>,
{
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<DisplayDimensions> for Size {
fn from(value: DisplayDimensions) -> Self {
Self::new(value.width as _, value.height as _)
}
}

Binary file not shown.

View File

@ -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<u32, [u8]> = &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<Self, Error> {
let header: &PsfHeader = bytemuck::from_bytes(&bytes[..size_of::<PsfHeader>()]);
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..]
}
}

View File

@ -3,6 +3,7 @@
use super::Device; use super::Device;
pub mod console; pub mod console;
pub mod font;
#[cfg(feature = "fb_console")] #[cfg(feature = "fb_console")]
pub mod fb_console; pub mod fb_console;