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"
|
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 = []
|
||||||
|
@ -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,
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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 _)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
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;
|
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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user