hal_x86_64/
framebuffer.rs

1use core::{
2    fmt,
3    ops::{Deref, DerefMut},
4};
5use hal_core::framebuffer::{Draw, RgbColor};
6use volatile::Volatile;
7
8pub struct Framebuffer<'buf, B: Deref<Target = [u8]>> {
9    /// A reference to the framebuffer itself.
10    ///
11    /// This is wrapped in a [`Volatile`] cell because we will typically never
12    /// read from the framebuffer, so we need to use volatile writes every time
13    /// it's written to.
14    buf: Volatile<B>,
15
16    /// Length of the actual framebuffer array.
17    ///
18    /// This is stored in the struct because when we construct a new
19    /// `Framebuffer`, we wrap `buf` in a `Volatile` cell, and calling random
20    /// methods like `[u8]::len()` on it becomes kind of a pain.
21    len: usize,
22
23    /// Framebuffer configuration values.
24    cfg: &'buf Config,
25}
26
27#[derive(Debug, Clone)]
28pub struct Config {
29    /// The framebuffer height in pixels
30    pub height: usize,
31    /// The framebuffer width in pixels.
32    pub width: usize,
33    pub px_bytes: usize,
34    pub line_len: usize,
35    pub px_kind: PixelKind,
36}
37
38#[derive(Copy, Clone, Debug, Eq, PartialEq)]
39pub enum PixelKind {
40    Bgr,
41    Rgb,
42    Gray,
43}
44
45impl<'buf, B> Framebuffer<'buf, B>
46where
47    B: Deref<Target = [u8]> + DerefMut,
48{
49    pub fn new(cfg: &'buf Config, buf: B) -> Self {
50        let len = buf[..].len();
51        Self {
52            cfg,
53            buf: Volatile::new(buf),
54            len,
55        }
56    }
57
58    pub fn clear(&mut self) -> &mut Self {
59        self.buf.fill(0);
60        self
61    }
62
63    pub fn set_pixel_rgb(&mut self, x: usize, y: usize, color: RgbColor) -> &mut Self {
64        let px_bytes = self.cfg.px_bytes;
65        let start = (y * self.cfg.line_len + x) * px_bytes;
66        let end = start + px_bytes;
67
68        let px_vals = &self.cfg.px_kind.convert_rgb(color)[..px_bytes];
69        self.buf.index_mut(start..end).copy_from_slice(px_vals);
70        self
71    }
72}
73
74impl<B> Draw for Framebuffer<'_, B>
75where
76    B: Deref<Target = [u8]> + DerefMut,
77{
78    fn height(&self) -> usize {
79        self.cfg.height
80    }
81
82    fn width(&self) -> usize {
83        self.cfg.width
84    }
85
86    fn set_pixel(&mut self, x: usize, y: usize, color: RgbColor) -> &mut Self {
87        self.set_pixel_rgb(x, y, color)
88    }
89
90    fn scroll_vert(&mut self, amount: isize) -> &mut Self {
91        if amount < 0 {
92            todo!("eliza: handle negatives!")
93        }
94        let amount_px = (amount as usize * self.cfg.line_len) * self.cfg.px_bytes;
95        self.buf.copy_within(amount_px.., 0);
96        let revealed_start = self.len - amount_px;
97        self.buf.index_mut(revealed_start..).fill(0);
98        self
99    }
100}
101
102// `Volatile<B>` is only `Debug` if `<B as Deref>::Target: Copy`,
103// so we must implement this manually.
104impl<B> fmt::Debug for Framebuffer<'_, B>
105where
106    B: Deref<Target = [u8]>,
107{
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        let Self { cfg, len, buf: _ } = self;
110        f.debug_struct("Framebuffer")
111            .field("len", len)
112            .field("cfg", cfg)
113            // don't print every pixel value in the entire framebuffer...
114            .field("buf", &format_args!("[..]"))
115            .finish()
116    }
117}
118
119impl PixelKind {
120    fn convert_rgb(self, RgbColor { red, green, blue }: RgbColor) -> [u8; 4] {
121        match self {
122            PixelKind::Bgr => [blue, green, red, 0],
123            PixelKind::Rgb => [red, green, blue, 0],
124            PixelKind::Gray => [Self::rgb_to_luminance(red, green, blue), 0, 0, 0],
125        }
126    }
127
128    fn rgb_to_luminance(r: u8, g: u8, b: u8) -> u8 {
129        // Thanks to @mystor for magic numbers!
130        ((21 * (r as u32) + 72 * (g as u32) + 7 * (b as u32)) / 100) as u8
131    }
132}