rewrote render.rs

rewrote the entire rendering system for the project, the terminal now supports scrollback and the vga blinking cursor actually moves around now (that was really getting on my nerves lmao)
This commit is contained in:
FantasyPvP
2023-10-01 02:40:52 +01:00
parent 9e7335e05f
commit ded4140f7c
5 changed files with 320 additions and 21 deletions
+3 -2
View File
@@ -3,8 +3,9 @@ pub mod fs;
pub mod gdt;
pub mod interrupts;
pub mod memory;
pub mod render;
//pub mod render;
pub mod serial;
pub mod tasks;
pub mod sysinit;
pub mod authenticator;
pub mod authenticator;
pub mod render2;
+298
View File
@@ -0,0 +1,298 @@
use core::fmt;
use lazy_static::lazy_static;
use spin::Mutex;
use volatile::Volatile;
use alloc::borrow::ToOwned;
use alloc::vec;
use alloc::vec::Vec;
use crate::std::io::Screen;
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Color {
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGray = 7,
DarkGray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
Pink = 13,
Yellow = 14,
White = 15,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(transparent)]
pub struct ColorCode(u8);
impl ColorCode {
pub fn new(foreground: Color, background: Color) -> ColorCode {
ColorCode((background as u8) << 5 | (foreground as u8))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
struct ScreenChar {
character: u8,
colour: ColorCode,
}
impl ScreenChar {
fn null() -> ScreenChar {
ScreenChar {
character: 0u8,
colour: ColorCode::new(Color::White, Color::Black),
}
}
fn white(character: u8) -> ScreenChar {
ScreenChar {
character,
colour: ColorCode::new(Color::White, Color::Black),
}
}
}
pub const BUFFER_HEIGHT: usize = 25;
pub const BUFFER_WIDTH: usize = 80;
#[repr(transparent)]
struct VGAOutput {
chars: [[Volatile<ScreenChar>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
pub struct Renderer {
col_pos: usize,
//col_code: ColorCode, // TODO: fully replace this with a colour code used in the fmt::Write function
screen_ref: &'static mut VGAOutput, // this should not be accessed unless the screen is rendering a new frame
term_buffer: Vec<[ScreenChar; BUFFER_WIDTH]>, // this is the standard terminal output view
app_buffer: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT], // this is where applications render their frames to
application_mode: bool, // if false: term mode; if true: app mode
}
lazy_static! {
pub static ref RENDERER: Mutex<Renderer> = Mutex::new(Renderer {
col_pos: 0,
screen_ref: unsafe { &mut *(0xb8000 as *mut VGAOutput) },
term_buffer: vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT],
app_buffer: [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT],
application_mode: false,
});
}
impl Renderer {
// EXTERNAL API : for use by standard library and other parts of the kernel
pub fn render_frame(&mut self, frame: [[char; BUFFER_WIDTH]; BUFFER_HEIGHT]) { // renders the given frame to the app buffer
let mut processed_frame: [[ScreenChar; BUFFER_WIDTH]; BUFFER_HEIGHT] = [[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
for (i, row) in frame.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
processed_frame[i][j] = match self.special_char(*col) {
Some(c) => ScreenChar::white(c as u8),
None => ScreenChar::white(*col as u8)
};
}
}
self.app_buffer = processed_frame;
}
// TODO: change standard library for alternative to these functions
pub fn application_mode(&mut self) -> Result<(), ()> {
if self.application_mode {
return Err(());
} else {
self.application_mode = true;
self.internal_render();
Ok(())
}
}
pub fn terminal_mode(&mut self) -> Result<(), ()> {
if !self.application_mode {
return Err(());
} else {
self.application_mode = false;
self.internal_render();
Ok(())
}
}
pub fn mode_is_app(&self) -> bool {
self.application_mode
}
pub fn write_char(&mut self, ch: u8, col: Option<ColorCode>) { // default colour if no colour is selected for character
self.write_byte(ch, col);
self.internal_render();
}
pub fn write_string(&mut self, string: &str, col: Option<ColorCode>) {
for ch in string.chars() {
match self.special_char(ch) {
Some(c) => self.write_byte(c, col),
None => match ch as u8 {
0x20..=0xff | b'\n' => self.write_byte(ch as u8, col),
_ => self.write_byte(0xfe, col),
}
}
}
self.internal_render();
}
pub fn backspace(&mut self) -> Result<(), ()> {
self.internal_backspace()?;
self.internal_render();
Ok(())
}
pub fn clear(&mut self) { // clears the screen and all scroll-back
if self.application_mode { return; };
self.term_buffer = vec![[ScreenChar::null(); BUFFER_WIDTH]; BUFFER_HEIGHT];
self.internal_render();
}
// INTERNAL API ONLY
fn set_cursor_position(&mut self, row: usize, col: usize) {
use x86_64::instructions::port::Port;
let cursor_position: u16 = (row as u16) * 80 + (col as u16);
unsafe {// Write the high byte of the cursor position to register 14
let mut control_port = Port::<u8>::new(0x3D4);
control_port.write(14);
// Write the high byte of the cursor position to register 15
let mut data_port = Port::<u8>::new(0x3D5);
data_port.write((cursor_position >> 8) as u8);
// Write the low byte of the cursor position to register 14
control_port.write(15);
// Write the low byte of the cursor position to register 15
data_port.write((cursor_position & 0xFF) as u8);
}
}
fn internal_backspace(&mut self) -> Result<(), ()> {
if self.col_pos == 0 {
self.internal_lastline();
}
self.col_pos -= 1;
let col = self.col_pos;
let buff_len = self.term_buffer.len();
self.term_buffer[buff_len - 1][col] = ScreenChar::null();
Ok(())
}
fn internal_newline(&mut self) { // moves all content one line up the screen and creates new line
if self.application_mode { return; }; // only in terminal mode
self.term_buffer.push([ScreenChar::null(); BUFFER_WIDTH]);
self.col_pos = 0;
}
fn internal_lastline(&mut self) { // goes back to previous line and shifts all lines down
if self.application_mode { return; };
self.term_buffer.pop();
self.col_pos = BUFFER_WIDTH;
}
fn write_screen_char(&mut self, ch: ScreenChar) { // TODO: optimise so that screen is not fully re-rendered for every string written.
match ch.character as u8 {
b'\n' => self.internal_newline(),
_ => {
if self.col_pos >= BUFFER_WIDTH {
self.internal_newline();
}
let row = BUFFER_HEIGHT - 1;
let col = self.col_pos;
let buff_len = self.term_buffer.len();
self.term_buffer[buff_len - 1][col] = ch;
self.col_pos += 1;
}
}
}
fn write_byte(&mut self, byte: u8, col: Option<ColorCode>) { // default colour if no colour is selected for character
self.write_screen_char(ScreenChar {
character: byte,
colour: match col {
Some(c) => c,
None => ColorCode::new(Color::White, Color::Black),
},
});
}
fn internal_render(&mut self) { // private function that can only be used from within this struct.
if self.application_mode {
for (i, row) in self.app_buffer.iter().enumerate() {
for (j, col) in row.iter().enumerate() {
self.screen_ref.chars[i][j].write(*col);
}
}
} else {
let buff_len = self.term_buffer.len();
for (i, row) in self.term_buffer[buff_len - BUFFER_HEIGHT..buff_len].iter().enumerate() {
for (j, col) in row.iter().enumerate() {
self.screen_ref.chars[i][j].write(*col);
}
}
}
self.set_cursor_position(BUFFER_HEIGHT - 1, self.col_pos);
}
fn special_char(&self, ch: char) -> Option<u8> {
let res: u8 = match ch {
'│' => 179,
'─' => 196,
'┴' => 193,
'┤' => 180,
'═' => 205,
'║' => 186,
'╗' => 187,
'╝' => 188,
'╚' => 200,
'╔' => 201,
'»' => 175,
'┐' => 191,
'└' => 192,
'┘' => 217,
'┌' => 218,
'┼' => 197,
'░' => 176,
'▓' => 178,
'«' => 174,
_ => {
return None;
}
};
Some(res)
}
}
impl fmt::Write for Renderer {
fn write_str(&mut self, string: &str) -> fmt::Result {
self.write_string(string, None);
Ok(())
}
}
pub fn write(args: fmt::Arguments, cols: (Color, Color)) {
use core::fmt::Write;
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock();
writer.write_fmt(args).unwrap()
})
}
+1 -1
View File
@@ -13,7 +13,7 @@ use futures_util::task::AtomicWaker;
use futures_util::stream::StreamExt;
use pc_keyboard::{layouts, DecodedKey, HandleControl, Keyboard, ScancodeSet1};
use crate::print;
use crate::kernel::render::RENDERER;
use crate::kernel::render2::RENDERER;
use alloc::{string::String};
static WAKER: AtomicWaker = AtomicWaker::new();
+17 -17
View File
@@ -1,9 +1,8 @@
use crate::{
kernel::render::{RENDERER, BUFFER_WIDTH, BUFFER_HEIGHT, ColorCode},
kernel::render2::{RENDERER, BUFFER_WIDTH, BUFFER_HEIGHT, ColorCode},
kernel::tasks::keyboard::KEYBOARD,
};
use alloc::{boxed::Box, string::{String, ToString}, vec::Vec};
pub use crate::{print, println, serial_print, serial_println};
@@ -27,16 +26,16 @@ impl Stdin {
pub struct Screen {}
impl Screen {
pub fn terminal_mode() {
RENDERER.lock().text_mode().unwrap();
RENDERER.lock().terminal_mode().unwrap();
}
pub fn application_mode() {
RENDERER.lock().sandbox_mode().unwrap();
RENDERER.lock().application_mode().unwrap();
}
pub fn switch() {
if RENDERER.lock().sandbox == true {
RENDERER.lock().text_mode().unwrap();
if RENDERER.lock().mode_is_app() == true {
RENDERER.lock().terminal_mode().unwrap();
} else {
RENDERER.lock().sandbox_mode().unwrap();
RENDERER.lock().application_mode().unwrap();
}
}
pub fn clear() {
@@ -173,7 +172,7 @@ macro_rules! print {
($($arg:tt)*) => ($crate::std::io::_print(format_args!($($arg)*)));
}
pub use crate::kernel::render::Color;
#[doc(hidden)]
pub fn _print(args: core::fmt::Arguments) {
@@ -181,12 +180,12 @@ pub fn _print(args: core::fmt::Arguments) {
use x86_64::instructions::interrupts;
interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock();
writer.col_code = ColorCode::new(Color::White, Color::Black);
writer.write_fmt(args).unwrap();
let mut writer = RENDERER.lock();
writer.write_fmt(args).unwrap();
//WRITER.lock().write_fmt(args).unwrap();
});
//writer.col_code = crate::kernel::render2::ColorCode::new(Color::White, Color::Black);
});
}
#[doc(hidden)]
@@ -196,15 +195,16 @@ pub fn _log(args: core::fmt::Arguments) {
interrupts::without_interrupts(|| {
let mut writer = RENDERER.lock();
writer.col_code = ColorCode::new(Color::Yellow, Color::Black);
writer.write_fmt(args).unwrap();
//WRITER.lock().write_fmt(args).unwrap();
//writer.col_code = crate::kernel::render2::ColorCode::new(Color::Yellow, Color::Black);
//WRITER.lock().write_fmt(args).unwrap();
});
}
pub use crate::kernel::render2::Color;
pub fn write(args: core::fmt::Arguments, cols: (Color, Color)) {
crate::kernel::render::write(args, cols);
crate::kernel::render2::write(args, cols);
}
pub fn mkfs() {
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::kernel::render::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER};
use crate::kernel::render2::{BUFFER_HEIGHT, BUFFER_WIDTH, RENDERER};
use crate::std::io::Frame;
use crate::{print, println};
use alloc::{