1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! VESA Bios Extensions Framebuffer

use spin::Mutex;
use crate::syscalls;
use crate::libuser::error::Error;
use core::slice;

/// A rgb color
#[derive(Copy, Clone, Debug)]
#[repr(C)]
#[allow(clippy::missing_docs_in_private_items)]
pub struct VBEColor {
    pub b: u8,
    pub g: u8,
    pub r: u8,
    pub a: u8, // Unused
}

/// Some colors for the vbe
impl VBEColor {
    /// Creates a VBEColor from the given red/green/blue component. Alpha is set
    /// to 0.
    pub const fn rgb(r: u8, g: u8, b: u8) -> VBEColor {
        VBEColor {r, g, b, a: 0 }
    }
}

/// A wrapper around a linear framebuffer. The framebuffer is usually acquired
/// through the [map_framebuffer](syscalls::map_framebuffer) syscall.
#[allow(clippy::missing_docs_in_private_items)]
pub struct Framebuffer<'a> {
    buf: &'a mut [VBEColor],
    width: usize,
    height: usize,
    /// Bits-per-pixel. Usually 8.
    bpp: usize
}


impl<'a> Framebuffer<'a> {
    /// Creates an instance of the linear framebuffer.
    ///
    /// # Safety
    ///
    /// This function should only be called once, to ensure there is only a
    /// single mutable reference to the underlying framebuffer.
    pub fn new() -> Result<Framebuffer<'static>, Error> {
        let (buf, width, height, bpp) = syscalls::map_framebuffer()?;

        let mut fb = Framebuffer {
            buf: unsafe { slice::from_raw_parts_mut(buf as *mut _ as *mut _ as *mut VBEColor, buf.len() / 4) },
            width,
            height,
            bpp
        };
        fb.clear();
        Ok(fb)
    }

    /// Creates a backbuffer backed by an in-memory array.
    ///
    /// This is useful to avoid flickering and other display artifact.
    /// Compositing should happen in such a backbuffer, and the final result
    /// should then be copied into the actual framebuffer.
    pub fn new_buffer(buf: &'a mut [VBEColor], width: usize, height: usize, bpp: usize) -> Framebuffer<'a> {
        Framebuffer { buf, width, height, bpp }
    }

    /// framebuffer width in pixels. Does not account for bpp
    #[inline]
    pub fn width(&self) -> usize {
        self.width
    }

    /// framebuffer height in pixels. Does not account for bpp
    #[inline]
    pub fn height(&self) -> usize {
        self.height
    }

    /// The number of bits that forms a pixel.
    /// Used to compute offsets in framebuffer memory to corresponding pixel
    /// px_offset = px_nbr * bpp
    #[inline]
    #[allow(dead_code)]
    pub fn bpp(&self) -> usize {
        self.bpp
    }

    /// Gets the offset in memory of a pixel based on an x and y.
    ///
    /// # Panics
    ///
    /// Panics if `y >= self.height()` or `x >= self.width()`
    #[inline]
    pub fn get_px_offset(&self, x: usize, y: usize) -> usize {
        assert!(y < self.height());
        assert!(x < self.width());
        y * self.width() + x
    }

    /// Writes a pixel in the framebuffer respecting the bgr pattern
    ///
    /// # Panics
    ///
    /// Panics if offset is invalid
    #[inline]
    pub fn write_px(&mut self, offset: usize, color: VBEColor) {
        self.buf[offset] = color;
    }

    /// Writes a pixel in the framebuffer respecting the bgr pattern
    /// Computes the offset in the framebuffer from x and y
    ///
    /// # Panics
    ///
    /// Panics if coords are invalid
    #[inline]
    pub fn write_px_at(&mut self, x: usize, y: usize, color: VBEColor) {
        let offset = self.get_px_offset(x, y);
        self.write_px(offset, color);
    }

    /// Gets the underlying framebuffer
    pub fn get_fb(&mut self) -> &mut [VBEColor] {
        self.buf
    }

    /// Clears the whole screen
    pub fn clear(&mut self) {
        let fb = self.get_fb();
        for i in fb.iter_mut() { *i = VBEColor::rgb(0, 0, 0); }
    }

    /// Clears a segment of the screen.
    ///
    /// # Panics
    ///
    /// Panics if x + width or y + height falls outside the framebuffer.
    pub fn clear_at(&mut self, x: usize, y: usize, width: usize, height: usize) {
        for y in y..y + height {
            for x in x..x + width {
                self.write_px_at(x, y, VBEColor::rgb(0, 0, 0));
            }
        }
    }
}

lazy_static! {
    pub static ref FRAMEBUFFER: Mutex<Framebuffer<'static>> = Mutex::new(Framebuffer::new().unwrap());
}