1#![no_std]
2
3extern crate alloc;
4use alloc::vec::Vec;
5use embedded_graphics::pixelcolor::RgbColor;
6use embedded_graphics::{
7 draw_target::DrawTarget,
8 geometry::{OriginDimensions, Size},
9 pixelcolor::{IntoStorage, Rgb888},
10 prelude::Point,
11 primitives::Rectangle,
12 Pixel,
13};
14use uefi::proto::console::gop::{FrameBuffer, ModeInfo};
15
16pub use crate::error::UefiDisplayError;
17pub mod error;
18
19#[derive(Debug)]
21pub struct UefiDisplay {
22 fb_ptr: *mut u8,
24 buffer: Vec<u8>,
26 stride: u32,
27 size: (u32, u32),
28}
29
30impl UefiDisplay {
31 pub fn new(
33 mut frame_buffer: FrameBuffer,
34 mode_info: ModeInfo,
35 ) -> Result<Self, UefiDisplayError> {
36 let (width, height) = (
37 mode_info.resolution().0 as u32,
38 mode_info.resolution().1 as u32,
39 );
40 let stride = mode_info.stride() as u32;
41 let buf_len = width
42 .checked_mul(height)
43 .and_then(|p| p.checked_mul(4))
44 .ok_or(UefiDisplayError::InvalidResolution)?;
45
46 let mut buffer = Vec::new();
48 buffer.resize(buf_len as usize, 0);
49
50 let mut display = UefiDisplay {
51 fb_ptr: frame_buffer.as_mut_ptr(),
52 buffer,
53 stride,
54 size: (width, height),
55 };
56
57 display.fill_solid(
59 &Rectangle::new(Point::zero(), Size::new(width, height)),
60 Rgb888::BLACK,
61 )?;
62 display.flush();
63
64 Ok(display)
65 }
66
67 pub fn flush(&self) {
69 unsafe {
71 core::ptr::copy_nonoverlapping(self.buffer.as_ptr(), self.fb_ptr, self.buffer.len());
72 }
73 }
74}
75
76impl OriginDimensions for UefiDisplay {
77 fn size(&self) -> Size {
78 Size::new(self.size.0, self.size.1)
79 }
80}
81
82impl DrawTarget for UefiDisplay {
83 type Color = Rgb888;
84 type Error = UefiDisplayError;
85
86 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
87 where
88 I: IntoIterator<Item = Pixel<Self::Color>>,
89 {
90 let (width, _height) = self.size;
91 let stride = self.stride as usize;
92 let buf = &mut self.buffer;
93
94 for Pixel(Point { x, y }, color) in pixels.into_iter() {
95 if x < 0 || y < 0 {
97 continue;
98 }
99 let (x, y): (usize, usize) = (x as usize, y as usize);
100 if x >= width as usize {
101 continue;
102 }
103
104 let idx = y
106 .checked_mul(stride)
107 .and_then(|row| row.checked_add(x))
108 .and_then(|pix| pix.checked_mul(4))
109 .ok_or(UefiDisplayError::OutOfBounds)?;
110
111 let pixel_val: u32 = color.into_storage();
112 let pixel_bytes = pixel_val.to_le_bytes();
113 buf[idx..idx + 4].copy_from_slice(&pixel_bytes);
114 }
115 Ok(())
116 }
117}