From 1ae1030e4590b9bb53512ab9e4892e39c4e2ada6 Mon Sep 17 00:00:00 2001 From: ajh123 Date: Wed, 1 Nov 2023 18:49:26 +0000 Subject: [PATCH] Nearly working graphics api --- kernel/src/drivers/framebuffer.rs | 45 +++-------------- kernel/src/graphics.rs | 81 +++++++++++++++++++++++++++++++ kernel/src/lib.rs | 1 + kernel/src/main.rs | 62 +++++++++++++++++++---- 4 files changed, 142 insertions(+), 47 deletions(-) create mode 100644 kernel/src/graphics.rs diff --git a/kernel/src/drivers/framebuffer.rs b/kernel/src/drivers/framebuffer.rs index b31b6af..0af7e81 100644 --- a/kernel/src/drivers/framebuffer.rs +++ b/kernel/src/drivers/framebuffer.rs @@ -1,3 +1,5 @@ +use core::cell::RefCell; + use spin::{Mutex, MutexGuard}; #[derive(Debug, Clone, Copy)] @@ -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 { - 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; - -/// initializes the framebuffer -pub(crate) fn init_framebuffer(boot_info: &'static mut bootloader_api::BootInfo) -> Option> { - 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; @@ -90,8 +59,8 @@ impl Framebuffer { } #[inline] - pub fn get_pixel(fb: &FramebufferMemory, index: FramebufferIndex) -> Option { - if let Some(offset) = Framebuffer::index_to_offset(fb, index) { + pub fn get_pixel(fb: FramebufferMemory, index: FramebufferIndex) -> Option { + if let Some(offset) = Framebuffer::index_to_offset(&fb, index) { return Some(Pixel { b: fb.buffer[offset], g: fb.buffer[offset + 1], diff --git a/kernel/src/graphics.rs b/kernel/src/graphics.rs new file mode 100644 index 0000000..9c2aa3d --- /dev/null +++ b/kernel/src/graphics.rs @@ -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>, +} + +impl<'a> GraphicsAPI<'a> { + pub fn new(framebuffer: RefCell>) -> 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 + } +} diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index b62c396..3dbd446 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -13,6 +13,7 @@ #![reexport_test_harness_main = "test_main"] pub mod drivers; +pub mod graphics; use core::panic::PanicInfo; diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 8620c13..3f7a869 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -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{}", "!");