diff --git a/kernel/src/arch/aarch64/board/raspi3/fb.rs b/kernel/src/arch/aarch64/board/raspi3/fb.rs index 5f9ba64..869b7eb 100644 --- a/kernel/src/arch/aarch64/board/raspi3/fb.rs +++ b/kernel/src/arch/aarch64/board/raspi3/fb.rs @@ -176,15 +176,44 @@ impl Framebuffer { } } - /// Clean screen - pub fn clear(&mut self) { - let mut start = self.base_addr(); - let end = start + self.fb_info.screen_size as usize; + /// Copy buffer `[src_off .. src_off + size]` to `[dst_off .. dst_off + size]`. + /// `dst_off`, `src_off` and `size` must be aligned with `usize`. + pub fn copy(&mut self, dst_off: usize, src_off: usize, size: usize) { + const USIZE: usize = core::mem::size_of::(); + let mut dst = self.base_addr() + dst_off; + let mut src = self.base_addr() + src_off; + let src_end = src + size; + while src < src_end { + unsafe { *(dst as *mut usize) = *(src as *mut usize) } + dst += USIZE; + src += USIZE; + } + } + + /// Fill buffer `[offset .. offset + size]` with `pixel`. + /// `offset` and `size` must be aligned with `usize`. + pub fn fill(&mut self, offset: usize, size: usize, pixel: u32) { + const USIZE: usize = core::mem::size_of::(); + let mut value: usize = 0; + let repeat = USIZE * 8 / self.fb_info.depth as usize; + let mask = ((1u64 << self.fb_info.depth) - 1) as usize; + for i in 0..repeat { + value <<= self.fb_info.depth; + value += pixel as usize & mask; + } + + let mut start = self.base_addr() + offset; + let end = start + size; while start < end { - unsafe { *(start as *mut usize) = 0 } - start += core::mem::size_of::(); + unsafe { *(start as *mut usize) = value } + start += USIZE; } } + + /// Fill the entire buffer with `0`. + pub fn clear(&mut self) { + self.fill(0, self.fb_info.screen_size as usize, 0); + } } lazy_static! { diff --git a/kernel/src/arch/aarch64/driver/console.rs b/kernel/src/arch/aarch64/driver/console.rs index 209b45e..4822e41 100644 --- a/kernel/src/arch/aarch64/driver/console.rs +++ b/kernel/src/arch/aarch64/driver/console.rs @@ -9,10 +9,10 @@ use lazy_static::lazy_static; use log::*; use spin::Mutex; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] struct Color(u8); -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] #[repr(C)] pub struct ConsoleChar { ascii_char: u8, @@ -68,16 +68,23 @@ impl ConsoleBuffer { self.write(row, col, ConsoleChar::default()); } - /// Insert one blank line at the bottom and remove the top line. - /// TODO: improve performance - fn new_line(&mut self) { + /// Insert one blank line at the bottom, and scroll up one line. + /// XXX: read framebuffer is toooo slow, do not use `fb.copy()`. + pub fn new_line(&mut self) { for i in 1..self.num_row { for j in 0..self.num_col { - self.write(i - 1, j, self.buf[i][j]); + if self.buf[i - 1][j] != self.buf[i][j] { + self.write(i - 1, j, self.buf[i][j]); + } } } for j in 0..self.num_col { - self.write(self.num_row - 1, j, ConsoleChar::default()); + self.buf[self.num_row - 1][j] = ConsoleChar::default(); + } + + if let Some(fb) = FRAME_BUFFER.lock().as_mut() { + let rowbytes = F::HEIGHT * fb.fb_info.pitch as usize; + fb.fill(rowbytes * (self.num_row - 1), rowbytes, 0); } }