Skip to main content

tg_rcore_tutorial_driver/
gpu.rs

1extern crate alloc;
2
3use alloc::vec::Vec;
4use core::any::Any;
5use embedded_graphics::pixelcolor::Rgb888;
6use spin::Mutex;
7use tinybmp::Bmp;
8use virtio_drivers::{Hal, MmioTransport, VirtIOGpu};
9
10use crate::devices::Device;
11
12pub trait GpuDevice: Device + Send + Sync + Any {
13    fn get_framebuffer(&self) -> Result<&mut [u8], virtio_drivers::Error>;
14    fn resolution(&self) -> Result<(u32, u32), virtio_drivers::Error>;
15    fn flush(&self) -> Result<(), virtio_drivers::Error>;
16}
17
18pub struct VirtIOGpuWrapper<H: Hal> {
19    gpu: Mutex<VirtIOGpu<'static, H, MmioTransport>>,
20    fb: &'static [u8],
21}
22
23unsafe impl<H: Hal> Send for VirtIOGpuWrapper<H> {}
24unsafe impl<H: Hal> Sync for VirtIOGpuWrapper<H> {}
25
26static BMP_DATA: &[u8] = include_bytes!("mouse.bmp");
27
28impl<H: Hal> VirtIOGpuWrapper<H> {
29    pub fn new(transport: MmioTransport) -> Result<Self, virtio_drivers::Error> {
30        let mut virtio = VirtIOGpu::new(transport)?;
31
32        let fbuffer = virtio.setup_framebuffer()?;
33        let len = fbuffer.len();
34        let ptr = fbuffer.as_mut_ptr();
35        // SAFETY: We own the VirtIOGpu device, and the framebuffer backing memory will live 
36        // as long as the device lives, which is 'static.
37        let fb = unsafe { core::slice::from_raw_parts_mut(ptr, len) };
38
39        let bmp = Bmp::<Rgb888>::from_slice(BMP_DATA).expect("Failed to parse mouse.bmp");
40        let raw = bmp.as_raw();
41        let mut b = Vec::new();
42        for i in raw.image_data().chunks(3) {
43            let mut v = i.to_vec();
44            b.append(&mut v);
45            if i == [255, 255, 255] {
46                b.push(0x0)
47            } else {
48                b.push(0xff)
49            }
50        }
51        virtio.setup_cursor(b.as_slice(), 50, 50, 50, 50)?;
52
53        Ok(Self {
54            gpu: Mutex::new(virtio),
55            fb,
56        })
57    }
58}
59
60impl<H: Hal + 'static> GpuDevice for VirtIOGpuWrapper<H> {
61    fn flush(&self) -> Result<(), virtio_drivers::Error> {
62        self.gpu.lock().flush()
63    }
64
65    fn resolution(&self) -> Result<(u32, u32), virtio_drivers::Error> {
66        self.gpu.lock().resolution()
67    }
68    
69    fn get_framebuffer(&self) -> Result<&mut [u8], virtio_drivers::Error> {
70        // SAFETY: Mutating the framebuffer is safe because the framebuffer slice is not aliased
71        // by the GPU device in a way that would cause data races on the CPU.
72        unsafe {
73            let ptr = self.fb.as_ptr() as *mut u8;
74            Ok(core::slice::from_raw_parts_mut(ptr, self.fb.len()))
75        }
76    }
77}
78
79impl<H: Hal + 'static> Device for VirtIOGpuWrapper<H> {
80    fn handle_irq(&self) {}
81}