virtio-drivers
virtio-drivers copied to clipboard
Virtio GPU: Redrawing with timer interrupt on RISCV
Hi, first of all, thanks for the great bindings.
I am having problems redrawing the frame buffer periodically using a timer. The first succeeds, but all further draw calls fail with an IO Error. Maybe I do not understand the procedure correctly...
pub struct VirtGPU {
gpu: VirtIOGpu<HalImpl, MmioTransport>,
}
pub static VGPU: OnceLock<Spin<VirtGPU>> = OnceLock::new();
impl VirtGPU {
pub fn new(transport: MmioTransport) -> Self {
Self {
gpu: VirtIOGpu::new(transport).expect("initialize gpu driver"),
}
}
pub fn draw(&mut self) -> virtio_drivers::Result<()> {
let (width, height) = self.gpu.resolution()?;
let width = width as usize;
let height = height as usize;
serial!("GPU resolution is {width}x{height}");
let fb = self.gpu.setup_framebuffer()?; // <- IO Error happens here
let fb = unsafe {
core::slice::from_raw_parts_mut(fb.as_ptr() as *mut u32, fb.len() / size_of::<u32>())
};
serial!("Framebuffer size is {} ({})", fb.len(), width * height);
/// Update the framebuffer...
self.gpu.flush()?;
Ok(())
}
}
The MmioTransport is initialized as in the RISCV example.
A timer interrupt calls draw
periodically. The first draw
call succeeds; all subsequent ones fail in setup_framebuffer
.
QEMU command line:
qemu-system-riscv32 -m 2G -machine virt -device virtio-gpu-device -serial mon:stdio -gdb tcp::1234 -no-shutdown -no-reboot target/debug/kernel
Ok, it seems to work if the frame buffer is only set up once during initialization and then only flushed repeatedly. The downside is that this cannot respond to resolution changes...