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
#[repr(u64)]
#[derive(Debug, Clone, Copy)]
#[non_exhaustive]
pub enum GraphicsCommand {
    /// Take ownership of the graphics device
    /// No arguments
    TakeOwnership,
    /// Release ownership of the graphics device
    /// No arguments
    ReleaseOwnership,
    /// Get information about the framebuffer
    /// &mut FrameBufferInfo
    GetFrameBufferInfo,
    /// Blit a region from userspace memory into the graphics framebuffer
    /// (must have ownership of the graphics device)
    /// &BlitCommand
    Blit,
}

impl GraphicsCommand {
    pub fn from_u64(value: u64) -> Option<Self> {
        match value {
            0 => Some(Self::TakeOwnership),
            1 => Some(Self::ReleaseOwnership),
            2 => Some(Self::GetFrameBufferInfo),
            3 => Some(Self::Blit),
            _ => None,
        }
    }

    pub fn to_u64(self) -> u64 {
        self as u64
    }
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct FrameBufferInfo {
    pub pitch: usize,
    pub height: usize,
    pub width: usize,
    pub field_pos: (u8, u8, u8),
    pub mask: (u8, u8, u8),
    pub byte_per_pixel: u8,
}

impl FrameBufferInfo {
    /// The size of the memory buffer required to hold the framebuffer
    pub fn memory_size(&self) -> usize {
        self.pitch * self.height
    }

    /// Get the position in the memory buffer for a given pixel
    /// Returns None if the position is out of bounds
    pub fn get_arr_pos(&self, pos: (usize, usize)) -> Option<usize> {
        if pos.0 >= self.width || pos.1 >= self.height {
            return None;
        }
        Some(pos.0 * self.byte_per_pixel as usize + pos.1 * self.pitch)
    }

    /// Get the pixel slice at a given position (read-only)
    pub fn pixel_mem<'a>(&self, memory: &'a [u8], pos: (usize, usize)) -> Option<&'a [u8]> {
        let i = self.get_arr_pos(pos)?;
        Some(&memory[i..i + self.byte_per_pixel as usize])
    }

    /// Get the pixel slice at a given position
    pub fn pixel_mem_mut<'a>(
        &self,
        memory: &'a mut [u8],
        pos: (usize, usize),
    ) -> Option<&'a mut [u8]> {
        let i = self.get_arr_pos(pos)?;
        Some(&mut memory[i..i + self.byte_per_pixel as usize])
    }
}

#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct BlitCommand {
    /// The memory buffer to blit from, this represent the whole framebuffer
    /// even if we are only blitting a part of it
    pub memory: *const u8,
    /// The framebuffer info of the source memory
    /// i.e. metadata about `memory`
    pub src_framebuffer_info: FrameBufferInfo,
    /// The position in the source framebuffer to start blitting from
    pub src: (usize, usize),
    /// The position in the destination framebuffer to start blitting to
    /// this destination is the kernel's framebuffer
    pub dst: (usize, usize),
    /// The size of the region to blit (width, height)
    pub size: (usize, usize),
}