Skip to content

Commit

Permalink
Nearly working graphics api
Browse files Browse the repository at this point in the history
  • Loading branch information
ajh123 committed Nov 1, 2023
1 parent e9e5976 commit 1ae1030
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 47 deletions.
45 changes: 7 additions & 38 deletions kernel/src/drivers/framebuffer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::cell::RefCell;

use spin::{Mutex, MutexGuard};

#[derive(Debug, Clone, Copy)]
Expand All @@ -14,53 +16,20 @@ pub struct Pixel {

/// Represents a framebuffer memory region and other metadata used to control
/// different functions of framebuffer.
pub struct FramebufferMemory {
pub struct FramebufferMemory<'a> {
/// contains a reference to framebuffer slice
pub buffer: &'static mut [u8],
pub buffer: &'a mut[u8],
pub width: usize,
pub height: usize,
pub bytes_per_pixel: usize,
}


pub struct FramebufferIndex {
pub x: usize,
pub y: usize,
}

impl FramebufferMemory {
/// creates a new frame buffer memory region over the framebuffer area
/// provided by the bootloader.
pub fn new(boot_info: &'static mut bootloader_api::BootInfo) -> Option<Self> {
if let Some(framebuffer_info) = boot_info.framebuffer.as_mut() {
Some(FramebufferMemory {
width: framebuffer_info.info().width,
height: framebuffer_info.info().height,
bytes_per_pixel: framebuffer_info.info().bytes_per_pixel,
buffer: framebuffer_info.buffer_mut(),
})
} else {
// log::error!(
// "Could not initialize framebuffer,
// because the bootloader did not provide framebuffer info."
// );
return None;
}
}
}

/// LockedFramebuffer represents a framebuffer memory region with mutex.
pub type LockedFramebuffer = Mutex<FramebufferMemory>;

/// initializes the framebuffer
pub(crate) fn init_framebuffer(boot_info: &'static mut bootloader_api::BootInfo) -> Option<Mutex<FramebufferMemory>> {
let fb_opt = FramebufferMemory::new(boot_info);
if fb_opt.is_none() {
return None;
}

Some(Mutex::new(fb_opt.unwrap()))
}

/// Set of control functions used for writing pixels to frame buffer
pub struct Framebuffer;

Expand Down Expand Up @@ -90,8 +59,8 @@ impl Framebuffer {
}

#[inline]
pub fn get_pixel(fb: &FramebufferMemory, index: FramebufferIndex) -> Option<Pixel> {
if let Some(offset) = Framebuffer::index_to_offset(fb, index) {
pub fn get_pixel(fb: FramebufferMemory, index: FramebufferIndex) -> Option<Pixel> {
if let Some(offset) = Framebuffer::index_to_offset(&fb, index) {
return Some(Pixel {
b: fb.buffer[offset],
g: fb.buffer[offset + 1],
Expand Down
81 changes: 81 additions & 0 deletions kernel/src/graphics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// graphics.rs

use core::cell::RefCell;

use crate::drivers::framebuffer::{Framebuffer, FramebufferIndex, Pixel, FramebufferMemory};

/// A simple graphics API for plotting pixels and drawing rectangles on the framebuffer.

pub struct GraphicsAPI<'a> {
framebuffer: RefCell<FramebufferMemory<'a>>,
}

impl<'a> GraphicsAPI<'a> {
pub fn new(framebuffer: RefCell<FramebufferMemory<'a>>) -> Self {
GraphicsAPI { framebuffer }
}

/// Plot a pixel at the specified location (x, y) with the given colour.
pub fn plot_pixel(&mut self, x: usize, y: usize, pixel: Pixel) {
// let fb = *self.framebuffer.get_mut();

// // let fb_ptr = self.framebuffer.as_ptr();
// // let fb = unsafe {&mut *fb_ptr };

// let index = FramebufferIndex { x, y };
// Framebuffer::set_pixel(fb, pixel, index); // fb needs to be `&mut FramebufferMemory<'_>`
let mut fb = self.framebuffer.borrow_mut();
let index = FramebufferIndex { x, y };
Framebuffer::set_pixel(&mut fb, pixel, index);
}

/// Draw a filled rectangle at the specified location with the given colour.
pub fn draw_filled_rectangle(&mut self, x: usize, y: usize, width: usize, height: usize, pixel: Pixel) {
for i in y..(y + height) {
for j in x..(x + width) {
self.plot_pixel(j, i, pixel);
}
}
}

/// Draw a line from (x1, y1) to (x2, y2) with the given colour.
pub fn draw_line(&mut self, x1: usize, y1: usize, x2: usize, y2: usize, pixel: Pixel) {
let dx = (x2 as isize - x1 as isize).abs();
let dy = (y2 as isize - y1 as isize).abs();
let sx = if x1 < x2 { 1 } else { -1 };
let sy = if y1 < y2 { 1 } else { -1 };
let mut err = dx - dy;

let mut x = x1 as isize;
let mut y = y1 as isize;

while x != x2 as isize || y != y2 as isize {
self.plot_pixel(x as usize, y as usize, pixel);

let e2 = 2 * err;
if e2 > -dy {
err -= dy;
x += sx;
}
if e2 < dx {
err += dx;
y += sy;
}
}
}

/// Fill the entire framebuffer with the given pixel colour.
pub fn fill_framebuffer(&mut self, pixel: Pixel) {
let width = self.framebuffer.borrow().width;
let height = self.framebuffer.borrow().height;
self.draw_filled_rectangle(0, 0, width, height, pixel);
}

pub fn get_width(&self) -> usize {
return self.framebuffer.borrow().width;
}

pub fn get_height(&self) -> usize {
return self.framebuffer.borrow().height
}
}
1 change: 1 addition & 0 deletions kernel/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#![reexport_test_harness_main = "test_main"]

pub mod drivers;
pub mod graphics;

use core::panic::PanicInfo;

Expand Down
62 changes: 53 additions & 9 deletions kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,67 @@
#![reexport_test_harness_main = "test_main"]

mod drivers;
mod graphics;

use core::panic::PanicInfo;
use core::{panic::PanicInfo, cell::RefCell};

use drivers::framebuffer::Pixel;

bootloader_api::entry_point!(kernel_main);


fn kernel_main(boot_info: &'static mut bootloader_api::BootInfo) -> ! {
let framebuffer = drivers::framebuffer::init_framebuffer(boot_info);
let fb_ref = framebuffer.as_ref();

drivers::framebuffer::Framebuffer::fill(&mut fb_ref.unwrap().lock(), drivers::framebuffer::Pixel {
b: 0xFF,
g: 0xFF,
r: 0xFF,
channel: 0
});
if let Some(framebuffer) = boot_info.framebuffer.as_mut() {
let fb_mem = RefCell::new(drivers::framebuffer::FramebufferMemory {
width: framebuffer.info().width,
height: framebuffer.info().height,
bytes_per_pixel: framebuffer.info().bytes_per_pixel,
buffer: framebuffer.buffer_mut(),
});
let graphics_api: &mut graphics::GraphicsAPI = &mut graphics::GraphicsAPI::new(fb_mem);

// drivers::framebuffer::Framebuffer::fill(fb, drivers::framebuffer::Pixel {
// b: 0xFF,
// g: 0xFF,
// r: 0xFF,
// channel: 0
// });

// Fill the entire framebuffer with a white colour.
// graphics_api.draw_filled_rectangle(0, 0, graphics_api.get_width(), graphics_api.get_height(), Pixel {
// b: 0xFF,
// g: 0xFF,
// r: 0xFF,
// channel: 0xFF,
// });

// Fill the entire framebuffer with a white colour.
// graphics_api.fill_framebuffer(Pixel {
// b: 0xFF,
// g: 0xFF,
// r: 0xFF,
// channel: 0xFF,
// });

// Draw a line from (10, 10) to (100, 100) with a red colour.
let red_pixel = Pixel {
b: 0x00,
g: 0x00,
r: 0xFF,
channel: 0x00,
};
graphics_api.draw_line(10, 10, 100, 100, red_pixel);

// Draw a filled rectangle at (50, 50) with a blue colour.
let blue_pixel = Pixel {
b: 0xFF,
g: 0x00,
r: 0x00,
channel: 0x00,
};
graphics_api.draw_filled_rectangle(5, 5, 30, 30, blue_pixel);
}

// println!("Welcome to GT-MOS!\nGT-MOS is (c) 2023 Samuel Hulme, All rights reserved.");
// println!("Hello World{}", "!");
Expand Down

0 comments on commit 1ae1030

Please sign in to comment.