diff --git a/Kernel/Modules/virtio/devices/video.rs b/Kernel/Modules/virtio/devices/video.rs index 0ad3579a8f0b2a35c764c731abf95b35bad23c62..28f7ce564c7f82f044b5f650be6a03f63ac39417 100644 --- a/Kernel/Modules/virtio/devices/video.rs +++ b/Kernel/Modules/virtio/devices/video.rs @@ -6,7 +6,9 @@ use interface::Interface; use queue::{Queue,Buffer}; use kernel::lib::mem::aref::{Aref,ArefBorrow}; use kernel::sync::Mutex; +use core::marker::PhantomData; +/// Device instance (as stored by the device manager) pub struct VideoDevice<I> where I: Interface + Send + Sync @@ -19,6 +21,7 @@ where { } +/// Common device structure ("owned" by the device manager, shared by scanouts) struct DeviceCore<I> where I: Interface + Send + Sync @@ -28,8 +31,10 @@ where cursorq: Queue, scanouts: Mutex<Vec<Option<video::FramebufferRegistration>>>, + next_resource_id: ::core::sync::atomic::AtomicU32, } +/// Video metadevice framebuffer wrapping a scanout struct Framebuffer<I> where I: Interface + Send + Sync @@ -37,6 +42,16 @@ where dev: ArefBorrow<DeviceCore<I>>, scanout_idx: usize, dims: (u32, u32,), + + backing_alloc: ::kernel::memory::virt::AllocHandle, + backing_res: Resource2D<I>, +} + +/// 2D Resource +struct Resource2D<I> +{ + _pd: PhantomData<ArefBorrow<I>>, + idx: u32, } impl<I> VideoDevice<I> @@ -53,6 +68,7 @@ where cursorq: int.get_queue(1, 0).expect("Queue #1 'cursorq' missing on virtio gpu device"), scanouts: Mutex::new(Vec::from_fn(num_scanouts, |_| None)), interface: int, + next_resource_id: Default::default(), }); let di = core.get_display_info(); @@ -104,6 +120,64 @@ where Err( () ) => panic!("TODO: Handle error waiting for VIRTIO_GPU_CMD_GET_DISPLAY_INFO response"), } } + + fn allocate_resource_id(&self) -> u32 + { + self.next_resource_id.fetch_add(1, ::core::sync::atomic::Ordering::SeqCst) + } + fn allocate_resource(&self, format: hw::virtio_gpu_formats, width: u32, height: u32) -> Resource2D<I> + { + let hdr = hw::CtrlHeader { + type_: hw::VIRTIO_GPU_CMD_RESOURCE_CREATE_2D as u32, + flags: 0, + fence_id: 0, + ctx_id: 0, + _padding: 0, + }; + let res_id = self.allocate_resource_id(); + let cmd = hw::ResourceCreate2d { + resource_id: res_id, + format: format as u32, + width: width, + height: height, + }; + let _rv = { + let h = self.controlq.send_buffers(&self.interface, &mut [ + Buffer::Read(::kernel::lib::as_byte_slice(&hdr)), + Buffer::Read(::kernel::lib::as_byte_slice(&cmd)), + ]); + h.wait_for_completion().expect("") + }; + + Resource2D { + _pd: PhantomData, + idx: res_id, + } + } + + fn set_scanout_backing(&self, scanout_idx: usize, rect: hw::Rect, resource_handle: &Resource2D<I>) + { + let hdr = hw::CtrlHeader { + type_: hw::VIRTIO_GPU_CMD_SET_SCANOUT as u32, + flags: 0, + fence_id: 0, + ctx_id: 0, + _padding: 0, + }; + let cmd = hw::SetScanout { + r: rect, + scanout_id: scanout_idx as u32, + resource_id: resource_handle.idx, + }; + + let _rv = { + let h = self.controlq.send_buffers(&self.interface, &mut [ + Buffer::Read(::kernel::lib::as_byte_slice(&hdr)), + Buffer::Read(::kernel::lib::as_byte_slice(&cmd)), + ]); + h.wait_for_completion().expect("") + }; + } } impl<I> Framebuffer<I> @@ -112,10 +186,22 @@ where { fn new(dev: ArefBorrow<DeviceCore<I>>, scanout_idx: usize, info: &hw::DisplayOne) -> Self { + let fb = ::kernel::memory::virt::alloc_dma(64, ::kernel::lib::num::div_up(info.r.width as usize * info.r.width as usize * 4, ::kernel::PAGE_SIZE), "virtio-video").expect(""); + // - Create resource (TODO: Should the resource handle its backing buffer?) + let mut res = dev.allocate_resource(hw::VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM, info.r.width, info.r.height); + // SAFE: We'e ensuring that both the backing memory and the resource are kept as long as they're in use + unsafe { + // - Bind framebuffer to it + res.attach_backing(&dev, fb.as_slice(0,1)); + // - Set scanout's backing to that resource + dev.set_scanout_backing(scanout_idx, info.r, &res); + } Framebuffer { dev: dev, scanout_idx: scanout_idx, dims: (info.r.width, info.r.height,), + backing_alloc: fb, + backing_res: res, } } } @@ -158,6 +244,18 @@ where } } +impl<I> Resource2D<I> +where + I: 'static + Interface + Send + Sync +{ + pub fn drop(self, dev: &DeviceCore<I>) + { + } + pub unsafe fn attach_backing(&mut self, dev: &DeviceCore<I>, buffer: &[u32]) + { + } +} + mod hw { @@ -205,6 +303,7 @@ mod hw } #[repr(C)] + #[derive(Copy,Clone)] pub struct Rect { pub x: u32, @@ -225,5 +324,39 @@ mod hw pub enabled: u32, pub flags: u32, } + + #[repr(C)] + #[derive(Debug)] + pub struct ResourceCreate2d + { + pub resource_id: u32, + pub format: u32, + pub width: u32, + pub height: u32, + } + #[allow(non_camel_case_types,dead_code)] + pub enum virtio_gpu_formats + { + VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1, + VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2, + VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3, + VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4, + + VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67, + VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68, + + VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121, + VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134, + } + pub use self::virtio_gpu_formats::*; + + #[repr(C)] + #[derive(Debug)] + pub struct SetScanout + { + pub r: Rect, + pub scanout_id: u32, + pub resource_id: u32, + } } diff --git a/Kernel/Modules/virtio/lib.rs b/Kernel/Modules/virtio/lib.rs index 70cad334eb6931e15179dc2fce7287220be368b6..57cc54e15d940035cf0b0514ec4e4b782d34d3b8 100644 --- a/Kernel/Modules/virtio/lib.rs +++ b/Kernel/Modules/virtio/lib.rs @@ -5,6 +5,7 @@ //! Virtual IO devices #![no_std] #![feature(linkage)] +#![feature(integer_atomics)] #[macro_use] extern crate kernel;