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"
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 = []

View File

@ -3,3 +3,9 @@
pub mod sync;
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,
ops::{Deref, DerefMut},
panic,
sync::atomic::{AtomicBool, AtomicUsize, Ordering},
sync::atomic::{AtomicUsize, Ordering},
};
/// Statically-allocated "dynamic" vector

View File

@ -133,8 +133,6 @@ pub struct RowIter<'a> {
pub trait DisplayConsole {
/// Returns the state lock
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
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;

View File

@ -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<PcScreenFont<'static>>,
) -> 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_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<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;
pub mod console;
pub mod font;
#[cfg(feature = "fb_console")]
pub mod fb_console;