Skip to content

Commit

Permalink
gfxconsole: keep track of console contents and support scrolling
Browse files Browse the repository at this point in the history
  • Loading branch information
IsaacWoods committed Dec 19, 2024
1 parent 92fc601 commit 281644e
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 55 deletions.
2 changes: 2 additions & 0 deletions lib/gfxconsole/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

107 changes: 57 additions & 50 deletions lib/gfxconsole/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,38 +1,61 @@
#![no_std]

pub mod fb;
extern crate alloc;

pub mod fb;
pub use fb::{Framebuffer, Rgb32};

use alloc::vec::Vec;
use core::fmt;

type Cell = usize;

const GLYPH_SIZE: usize = 8;

pub struct GfxConsole {
pub framebuffer: Framebuffer,
bg_color: Rgb32,
text_color: Rgb32,
cursor_x: Cell,
cursor_y: Cell,
width: Cell,
height: Cell,
cursor_x: usize,
cursor_y: usize,
width: usize,
height: usize,
cells: Vec<Cell>,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub struct Cell {
c: char,
fg: Rgb32,
bg: Rgb32,
}

impl GfxConsole {
pub fn new(mut framebuffer: Framebuffer, bg_color: Rgb32, text_color: Rgb32) -> GfxConsole {
let width = framebuffer.width / GLYPH_SIZE;
let height = framebuffer.height / GLYPH_SIZE;
let mut cells = Vec::with_capacity(width * height);

for _ in 0..(width * height) {
cells.push(Cell { c: ' ', fg: text_color, bg: bg_color });
}

framebuffer.clear(bg_color);
GfxConsole { framebuffer, bg_color, text_color, cursor_x: 0, cursor_y: 0, width, height }
GfxConsole { framebuffer, bg_color, text_color, cursor_x: 0, cursor_y: 0, width, height, cells }
}

pub fn clear(&mut self) {
self.framebuffer.clear(self.bg_color);
self.cursor_x = 0;
self.cursor_y = 0;

for i in 0..(self.width * self.height) {
self.cells[i] = Cell { c: ' ', fg: self.text_color, bg: self.bg_color };
}
}

#[inline(always)]
pub fn put_cell(&mut self, x: usize, y: usize, c: Cell) {
self.cells[y * self.width + x] = c;
self.framebuffer.draw_glyph(c.c, x * GLYPH_SIZE, y * GLYPH_SIZE, c.fg);
}
}

Expand Down Expand Up @@ -60,29 +83,25 @@ impl fmt::Write for GfxConsole {
* produced when backspace on a keyboard is pressed.
*/
self.cursor_x -= 1;
self.framebuffer.draw_rect(
self.cursor_x * GLYPH_SIZE,
self.cursor_y * GLYPH_SIZE,
GLYPH_SIZE,
GLYPH_SIZE,
self.bg_color,
self.put_cell(
self.cursor_x,
self.cursor_y,
Cell { c: ' ', fg: self.text_color, bg: self.bg_color },
);
}

_ => {
self.framebuffer.draw_glyph(
c,
self.cursor_x * GLYPH_SIZE,
self.cursor_y * GLYPH_SIZE,
self.text_color,
self.put_cell(
self.cursor_x,
self.cursor_y,
Cell { c, fg: self.text_color, bg: self.bg_color },
);

self.cursor_x += 1;
}
}

/*
* If we've reached the end of the line, or if the character is '\n', advance to the next line.
* If we've reached the end of the line, advance to the next line.
*/
if self.cursor_x == self.width {
self.cursor_x = 0;
Expand All @@ -93,35 +112,23 @@ impl fmt::Write for GfxConsole {
* If we've reached the end of the screen, scroll the console up.
*/
if self.cursor_y == self.height {
// TODO: scrolling is somehow too hard for us rn so just clear the screen and start again
self.clear();

// // TODO: uhh how do we do this non-badly - the naive way would be need to read from video memory
// // which is meant to be really terrible to do.
// // TODO: this also falls over badly if stride!=width; we should probably do it line by line
// let dest_pixels: &mut [Pixel<F>] = unsafe {
// // TODO: lmao this is actually UB because we end up aliasing the framebuffer data. Def do line
// // by line
// slice::from_raw_parts_mut(
// self.framebuffer.ptr,
// self.framebuffer.stride * self.framebuffer.height,
// )
// };
// let source_pixels: &[Pixel<F>] = {
// let start = self.framebuffer.stride;
// let num_pixels = (self.framebuffer.stride * self.framebuffer.height) - start;
// unsafe { slice::from_raw_parts(self.framebuffer.ptr.offset(start as isize), num_pixels) }
// };
// dest_pixels.copy_from_slice(source_pixels);

// // Clear the last line
// self.framebuffer.draw_rect(
// 0,
// self.framebuffer.width,
// self.framebuffer.height - GLYPH_SIZE,
// GLYPH_SIZE,
// self.bg_color,
// );
self.framebuffer.clear(self.bg_color);

// Copy each line up one, minus the last line
for y in 0..(self.height - 1) {
for x in 0..self.width {
let cell_below = self.cells[(y + 1) * self.width + x];
self.put_cell(x, y, cell_below);
}
}

// Clear the last line
for x in 0..self.width {
self.cells[(self.height - 1) * self.width + x] =
Cell { c: ' ', fg: self.text_color, bg: self.bg_color };
}
self.cursor_x = 0;
self.cursor_y -= 1;
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ unsafe extern "C" fn rust_entry() -> ! {
* probably free massive heaps if tasks have a high tidemark but low normal usage or whatever.
*/
const HEAP_START: usize = 0x600000000;
const HEAP_SIZE: usize = 0x8000;
const HEAP_SIZE: usize = 0x800000;
let heap = MemoryObject::create(HEAP_SIZE, MemoryObjectFlags::WRITABLE).unwrap();
let _mapped_heap = heap.map_at(HEAP_START).unwrap();
ALLOCATOR.lock().init(HEAP_START as *mut u8, HEAP_SIZE);
Expand Down
2 changes: 1 addition & 1 deletion seed/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions seed/seed_uefi/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use uefi::{
/*
* These are the custom UEFI memory types we use. They're all collected here so we can easily see which numbers
* we're using.
* TODO: I think some UEFI impls don't like this so get rid of it at some point.
*/
pub const KERNEL_MEMORY_TYPE: MemoryType = MemoryType::custom(0x80000000);
pub const IMAGE_MEMORY_TYPE: MemoryType = MemoryType::custom(0x80000001);
Expand All @@ -44,13 +45,13 @@ fn efi_main(image_handle: Handle, system_table: SystemTable<Boot>) -> Status {
Logger::init();
info!("Hello, World!");

let video_mode = create_framebuffer(system_table.boot_services(), 800, 600);
Logger::switch_to_graphical(&video_mode);

unsafe {
uefi::allocator::init(system_table.boot_services());
}

let video_mode = create_framebuffer(system_table.boot_services(), 800, 600);
Logger::switch_to_graphical(&video_mode);

/*
* We create a set of page tables for the kernel. Because memory is identity-mapped in UEFI, we can act as
* if we've placed the physical mapping at 0x0.
Expand Down

0 comments on commit 281644e

Please sign in to comment.