uefi_graphics/
lib.rs

1//! An embedded-graphics display driver for UEFI environments
2#![no_std]
3use core::{convert::TryInto, marker::PhantomData};
4use embedded_graphics_core::{
5    draw_target::DrawTarget,
6    geometry::{OriginDimensions, Size},
7    pixelcolor::{IntoStorage, Rgb888},
8    Pixel,
9};
10
11#[derive(Debug)]
12pub struct Unsupported(());
13
14impl Unsupported {
15    fn new<T>(_: T) -> Self {
16        Unsupported(())
17    }
18}
19
20/// UEFI Display driver. This assumes Rgb888 pixel formatting.
21pub struct UefiDisplay<'a> {
22    /// UEFI Framebuffer
23    fb: *mut u8,
24    stride: u32,
25    size: (u32, u32),
26    spooky: PhantomData<&'a mut [u8]>,
27}
28
29impl<'a> UefiDisplay<'a> {
30    /// Create a new [`UefiDisplay`].
31    ///
32    /// `fb` must be the UEFI framebuffer base, and `stride` the pixel stride,
33    /// and `size` the horizontal and vertical resolution, respectively.
34    ///
35    /// In the UEFI spec this information is found
36    /// in the `EFI_GRAPHICS_OUTPUT_MODE_INFORMATION` structure.
37    ///
38    /// `T` is something providing a lifetime for `fb`.
39    /// If your UEFI API does not provide a lifetime, `&()` should work.
40    pub fn new<T>(fb: *mut u8, stride: u32, size: (u32, u32), _lifetime: &'a T) -> Self {
41        Self {
42            fb,
43            stride,
44            size,
45            spooky: PhantomData,
46        }
47    }
48}
49
50impl<'a> OriginDimensions for UefiDisplay<'a> {
51    /// Return the size of the display
52    fn size(&self) -> Size {
53        Size::from(self.size)
54    }
55}
56
57impl<'a> DrawTarget for UefiDisplay<'a> {
58    type Color = Rgb888;
59
60    type Error = Unsupported;
61
62    fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
63    where
64        I: IntoIterator<Item = Pixel<Self::Color>>,
65    {
66        let pixels = pixels.into_iter();
67        for Pixel(point, color) in pixels {
68            let bytes = color.into_storage();
69            let stride = self.stride as u64;
70            let (x, y) = (point.x as u64, point.y as u64);
71            // Get the linear index
72            let index: usize = (((y * stride) + x) * 4)
73                .try_into()
74                .map_err(Unsupported::new)?;
75            unsafe { (self.fb.add(index) as *mut u32).write_volatile(bytes) };
76        }
77        Ok(())
78    }
79}