use limine::request::FramebufferRequest; #[used] #[unsafe(link_section = ".requests")] static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new(); use super::colour::Colour; use core::panic; use limine::framebuffer::Framebuffer; use spin::{Lazy, Mutex}; pub static FRAMEBUFFER_WRITER: Lazy>> = Lazy::new(|| { Mutex::new(FRAMEBUFFER_REQUEST.get_response().map_or_else( || { panic!("Framebuffer request failed"); }, |framebuffer_response| { let framebuffer = framebuffer_response.framebuffers().next().unwrap(); Some(FramebufferWriter::new(framebuffer)) }, )) }); /// The updated writer stores necessary fields from the [Framebuffer]. /// This ensures that the contained types are Send, as Framebuffer was /// not marked as Send. /// /// It also avoids the requirement for lifetimes. /// /// Note this does not implement Writer as these functions only handle drawing pixels. pub struct FramebufferWriter { pitch: u64, bpp: u16, addr: *mut u8, width: u64, height: u64, } unsafe impl Send for FramebufferWriter {} unsafe impl Sync for FramebufferWriter {} impl FramebufferWriter { pub fn new(framebuffer: Framebuffer) -> Self { Self { pitch: framebuffer.pitch(), bpp: framebuffer.bpp(), addr: framebuffer.addr(), width: framebuffer.width(), height: framebuffer.height(), } } pub fn write_pixel(&self, x: usize, y: usize, color: Colour) { let pitch = self.pitch as usize; let bpp = (self.bpp / 8) as usize; let pixel_offset = y * pitch + x * bpp; unsafe { *(self.addr.add(pixel_offset) as *mut u32) = color.into(); } } pub fn render_frame(&self, buffer: &[Colour; 1280 * 800]) { for (y, row) in buffer.chunks(1280).enumerate() { for (x, pixel) in row.iter().enumerate() { self.write_pixel(x, y, *pixel); } } } pub const fn width(&self) -> u32 { self.width as u32 } pub const fn height(&self) -> u32 { self.height as u32 } pub fn clear(&self) { let width = self.width as usize; let height = self.height as usize; for y in 0..height { for x in 0..width { self.write_pixel(x, y, Colour::Black); } } } } pub fn screensize_px() -> (u32, u32) { FRAMEBUFFER_WRITER .lock() .as_mut() .map_or_else(|| (0, 0), |writer| (writer.width(), writer.height())) }