dev: optimize display output a bit
This commit is contained in:
parent
1719b84534
commit
c543576685
@ -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 = []
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 _)
|
||||
}
|
||||
}
|
||||
|
BIN
src/device/display/font.psfu
Normal file
BIN
src/device/display/font.psfu
Normal file
Binary file not shown.
65
src/device/display/font.rs
Normal file
65
src/device/display/font.rs
Normal 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..]
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
use super::Device;
|
||||
|
||||
pub mod console;
|
||||
pub mod font;
|
||||
|
||||
#[cfg(feature = "fb_console")]
|
||||
pub mod fb_console;
|
||||
|
Loading…
x
Reference in New Issue
Block a user