From 4317189d7bc3f9f602e9e4a65f96dd23051cd457 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 12 Mar 2026 22:32:43 +0100 Subject: [PATCH] drivers/graphics: Unify buffer types between regular and cursor planes Also correct the cursor size for virtio-gpu. --- drivers/graphics/driver-graphics/src/lib.rs | 69 +++++---- drivers/graphics/ihdgd/src/device/scheme.rs | 25 ++-- drivers/graphics/vesad/src/scheme.rs | 24 ++-- drivers/graphics/virtio-gpud/src/scheme.rs | 152 +++++++------------- 4 files changed, 105 insertions(+), 165 deletions(-) diff --git a/drivers/graphics/driver-graphics/src/lib.rs b/drivers/graphics/driver-graphics/src/lib.rs index 8dfb34612c..5c4a04f763 100644 --- a/drivers/graphics/driver-graphics/src/lib.rs +++ b/drivers/graphics/driver-graphics/src/lib.rs @@ -39,8 +39,7 @@ pub struct StandardProperties { pub trait GraphicsAdapter: Sized + Debug { type Connector: Debug + 'static; - type Framebuffer: Framebuffer; - type Cursor: CursorFramebuffer; + type Buffer: Buffer; fn name(&self) -> &'static [u8]; fn desc(&self) -> &'static [u8]; @@ -63,23 +62,24 @@ pub trait GraphicsAdapter: Sized + Debug { fn display_count(&self) -> usize; fn display_size(&self, display_id: usize) -> (u32, u32); - fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer; - fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8; + fn create_dumb_buffer(&mut self, width: u32, height: u32) -> Self::Buffer; + fn map_dumb_buffer(&mut self, framebuffer: &Self::Buffer) -> *mut u8; - fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage); + fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Buffer, damage: Damage); fn supports_hw_cursor(&self) -> bool; - fn create_cursor_framebuffer(&mut self) -> Self::Cursor; - fn map_cursor_framebuffer(&mut self, cursor: &Self::Cursor) -> *mut u8; - fn handle_cursor(&mut self, cursor: &CursorPlane, dirty_fb: bool); + fn create_cursor_framebuffer(&mut self) -> Self::Buffer; + fn map_cursor_framebuffer(&mut self, cursor: &Self::Buffer) -> *mut u8; + fn handle_cursor(&mut self, cursor: Option<&CursorPlane>, dirty_fb: bool); } -pub trait Framebuffer { +pub trait Buffer { fn width(&self) -> u32; fn height(&self) -> u32; } -pub struct CursorPlane { +#[derive(Debug)] +pub struct CursorPlane { pub x: i32, pub y: i32, pub hot_x: i32, @@ -87,8 +87,6 @@ pub struct CursorPlane { pub framebuffer: C, } -pub trait CursorFramebuffer {} - pub struct GraphicsScheme { inner: GraphicsSchemeInner, inputd_handle: DisplayHandle, @@ -224,8 +222,10 @@ impl GraphicsScheme { ); } - if let Some(cursor_plane) = &vt_state.cursor_plane { - self.inner.adapter.handle_cursor(cursor_plane, true); + if self.inner.adapter.supports_hw_cursor() { + self.inner + .adapter + .handle_cursor(vt_state.cursor_plane.as_ref(), true); } } @@ -291,8 +291,8 @@ struct GraphicsSchemeInner { } struct VtState { - display_fbs: Vec>, - cursor_plane: Option>, + display_fbs: Vec>, + cursor_plane: Option>, } enum Handle { @@ -304,7 +304,7 @@ enum Handle { V2 { vt: usize, next_id: u32, - fbs: HashMap>, + fbs: HashMap>, }, SchemeRoot, } @@ -319,25 +319,17 @@ impl GraphicsSchemeInner { let mut display_fbs = vec![]; for display_id in 0..adapter.display_count() { let (width, height) = adapter.display_size(display_id); - display_fbs.push(Arc::new(adapter.create_dumb_framebuffer(width, height))); + display_fbs.push(Arc::new(adapter.create_dumb_buffer(width, height))); } - let cursor_plane = adapter.supports_hw_cursor().then(|| CursorPlane { - x: 0, - y: 0, - hot_x: 0, - hot_y: 0, - framebuffer: adapter.create_cursor_framebuffer(), - }); - VtState { display_fbs, - cursor_plane, + cursor_plane: None, } }) } - fn update_whole_screen(adapter: &mut T, screen: usize, framebuffer: &T::Framebuffer) { + fn update_whole_screen(adapter: &mut T, screen: usize, framebuffer: &T::Buffer) { adapter.update_plane( screen, framebuffer, @@ -357,10 +349,17 @@ impl GraphicsSchemeInner { ) -> Result<()> { let vt_state = self.vts.get_mut(&vt).unwrap(); - let Some(cursor_plane) = &mut vt_state.cursor_plane else { - // Hardware cursor not supported + if !self.adapter.supports_hw_cursor() { return Err(Error::new(EINVAL)); - }; + } + + let cursor_plane = vt_state.cursor_plane.get_or_insert_with(|| CursorPlane { + x: 0, + y: 0, + hot_x: 0, + hot_y: 0, + framebuffer: self.adapter.create_cursor_framebuffer(), + }); cursor_plane.x = cursor_damage.x; cursor_plane.y = cursor_damage.y; @@ -370,7 +369,7 @@ impl GraphicsSchemeInner { return Ok(()); } - self.adapter.handle_cursor(cursor_plane, false); + self.adapter.handle_cursor(Some(cursor_plane), false); } else { cursor_plane.hot_x = cursor_damage.hot_x; cursor_plane.hot_y = cursor_damage.hot_y; @@ -405,7 +404,7 @@ impl GraphicsSchemeInner { return Ok(()); } - self.adapter.handle_cursor(cursor_plane, true); + self.adapter.handle_cursor(Some(cursor_plane), true); } return Ok(()); @@ -755,7 +754,7 @@ impl SchemeSync for GraphicsSchemeInner { let fb = self .adapter - .create_dumb_framebuffer(data.width(), data.height()); + .create_dumb_buffer(data.width(), data.height()); *next_id += 1; fbs.insert(*next_id, Arc::new(fb)); @@ -910,7 +909,7 @@ impl SchemeSync for GraphicsSchemeInner { ), Handle::V1Screen { .. } | Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)), }; - let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer); + let ptr = T::map_dumb_buffer(&mut self.adapter, framebuffer); Ok(unsafe { ptr.add(offset as usize) } as usize) } } diff --git a/drivers/graphics/ihdgd/src/device/scheme.rs b/drivers/graphics/ihdgd/src/device/scheme.rs index 742d61a1db..d04208d682 100644 --- a/drivers/graphics/ihdgd/src/device/scheme.rs +++ b/drivers/graphics/ihdgd/src/device/scheme.rs @@ -6,8 +6,7 @@ use std::ptr::{self, NonNull}; use driver_graphics::objects::{DrmConnectorStatus, DrmObjectId, DrmObjects}; use driver_graphics::{ - modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, - StandardProperties, + modeinfo_for_size, Buffer, CursorPlane, GraphicsAdapter, StandardProperties, }; use drm_sys::DRM_MODE_DPMS_ON; use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT}; @@ -21,16 +20,10 @@ pub struct Connector { framebuffer_id: usize, } -//TODO: use hardware cursor -pub enum Cursor {} - -impl CursorFramebuffer for Cursor {} - impl GraphicsAdapter for Device { type Connector = Connector; - type Framebuffer = DumbFb; - type Cursor = Cursor; + type Buffer = DumbFb; fn name(&self) -> &'static [u8] { b"ihdgd" @@ -94,15 +87,15 @@ impl GraphicsAdapter for Device { ) } - fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer { + fn create_dumb_buffer(&mut self, width: u32, height: u32) -> Self::Buffer { DumbFb::new(width as usize, height as usize) } - fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8 { + fn map_dumb_buffer(&mut self, framebuffer: &Self::Buffer) -> *mut u8 { framebuffer.ptr.as_ptr().cast::() } - fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage) { + fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Buffer, damage: Damage) { framebuffer.sync(&mut self.framebuffers[display_id], damage) } @@ -110,15 +103,15 @@ impl GraphicsAdapter for Device { false } - fn create_cursor_framebuffer(&mut self) -> Self::Cursor { + fn create_cursor_framebuffer(&mut self) -> Self::Buffer { unimplemented!("ihdgd does not support this function"); } - fn map_cursor_framebuffer(&mut self, _cursor: &Self::Cursor) -> *mut u8 { + fn map_cursor_framebuffer(&mut self, _cursor: &Self::Buffer) -> *mut u8 { unimplemented!("ihdgd does not support this function"); } - fn handle_cursor(&mut self, _cursor: &CursorPlane, _dirty_fb: bool) { + fn handle_cursor(&mut self, _cursor: Option<&CursorPlane>, _dirty_fb: bool) { unimplemented!("ihdgd does not support this function"); } } @@ -185,7 +178,7 @@ impl Drop for DumbFb { } } -impl Framebuffer for DumbFb { +impl Buffer for DumbFb { fn width(&self) -> u32 { self.width as u32 } diff --git a/drivers/graphics/vesad/src/scheme.rs b/drivers/graphics/vesad/src/scheme.rs index ab58b4b14a..3a5232f4f5 100644 --- a/drivers/graphics/vesad/src/scheme.rs +++ b/drivers/graphics/vesad/src/scheme.rs @@ -4,8 +4,7 @@ use std::ptr::{self, NonNull}; use driver_graphics::objects::{DrmConnectorStatus, DrmObjectId, DrmObjects}; use driver_graphics::{ - modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, - StandardProperties, + modeinfo_for_size, Buffer, CursorPlane, GraphicsAdapter, StandardProperties, }; use drm_sys::DRM_MODE_DPMS_ON; use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT}; @@ -23,15 +22,10 @@ pub struct Connector { height: u32, } -pub enum VesadCursor {} - -impl CursorFramebuffer for VesadCursor {} - impl GraphicsAdapter for FbAdapter { type Connector = Connector; - type Framebuffer = GraphicScreen; - type Cursor = VesadCursor; + type Buffer = GraphicScreen; fn name(&self) -> &'static [u8] { b"vesad" @@ -94,15 +88,15 @@ impl GraphicsAdapter for FbAdapter { ) } - fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer { + fn create_dumb_buffer(&mut self, width: u32, height: u32) -> Self::Buffer { GraphicScreen::new(width as usize, height as usize) } - fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8 { + fn map_dumb_buffer(&mut self, framebuffer: &Self::Buffer) -> *mut u8 { framebuffer.ptr.as_ptr().cast::() } - fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage) { + fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Buffer, damage: Damage) { framebuffer.sync(&mut self.framebuffers[display_id], damage) } @@ -110,15 +104,15 @@ impl GraphicsAdapter for FbAdapter { false } - fn create_cursor_framebuffer(&mut self) -> VesadCursor { + fn create_cursor_framebuffer(&mut self) -> Self::Buffer { unimplemented!("Vesad does not support this function"); } - fn map_cursor_framebuffer(&mut self, _cursor: &Self::Cursor) -> *mut u8 { + fn map_cursor_framebuffer(&mut self, _cursor: &Self::Buffer) -> *mut u8 { unimplemented!("Vesad does not support this function"); } - fn handle_cursor(&mut self, _cursor: &CursorPlane, _dirty_fb: bool) { + fn handle_cursor(&mut self, _cursor: Option<&CursorPlane>, _dirty_fb: bool) { unimplemented!("Vesad does not support this function"); } } @@ -216,7 +210,7 @@ impl Drop for GraphicScreen { } } -impl Framebuffer for GraphicScreen { +impl Buffer for GraphicScreen { fn width(&self) -> u32 { self.width as u32 } diff --git a/drivers/graphics/virtio-gpud/src/scheme.rs b/drivers/graphics/virtio-gpud/src/scheme.rs index 9aaae63770..24700f1782 100644 --- a/drivers/graphics/virtio-gpud/src/scheme.rs +++ b/drivers/graphics/virtio-gpud/src/scheme.rs @@ -4,8 +4,8 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; use driver_graphics::objects::{DrmConnectorStatus, DrmObjectId, DrmObjects}; use driver_graphics::{ - modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, - GraphicsScheme, StandardProperties, + modeinfo_for_size, Buffer as DrmBuffer, CursorPlane, GraphicsAdapter, GraphicsScheme, + StandardProperties, }; use drm_sys::{ DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH, DRM_MODE_DPMS_ON, DRM_MODE_TYPE_PREFERRED, @@ -44,7 +44,7 @@ pub struct VirtGpuFramebuffer<'a> { height: u32, } -impl Framebuffer for VirtGpuFramebuffer<'_> { +impl DrmBuffer for VirtGpuFramebuffer<'_> { fn width(&self) -> u32 { self.width } @@ -70,13 +70,6 @@ impl Drop for VirtGpuFramebuffer<'_> { } } -pub struct VirtGpuCursor { - resource_id: ResourceId, - sgl: sgl::Sgl, -} - -impl CursorFramebuffer for VirtGpuCursor {} - #[derive(Debug, Clone)] pub struct Display { enabled: bool, @@ -93,6 +86,7 @@ pub struct VirtGpuAdapter<'a> { transport: Arc, has_edid: bool, displays: Vec, + hidden_cursor: Option>>, } impl<'a> fmt::Debug for VirtGpuAdapter<'a> { @@ -200,11 +194,18 @@ impl VirtGpuAdapter<'_> { Ok(response) } - fn update_cursor(&mut self, cursor: &VirtGpuCursor, x: i32, y: i32, hot_x: i32, hot_y: i32) { + fn update_cursor( + &mut self, + cursor: &VirtGpuFramebuffer, + x: i32, + y: i32, + hot_x: i32, + hot_y: i32, + ) { //Transfering cursor resource to host futures::executor::block_on(async { let transfer_request = Dma::new(XferToHost2d::new( - cursor.resource_id, + cursor.id, GpuRect { x: 0, y: 0, @@ -219,14 +220,7 @@ impl VirtGpuAdapter<'_> { }); //Update the cursor position - let request = Dma::new(UpdateCursor::update_cursor( - x, - y, - hot_x, - hot_y, - cursor.resource_id, - )) - .unwrap(); + let request = Dma::new(UpdateCursor::update_cursor(x, y, hot_x, hot_y, cursor.id)).unwrap(); futures::executor::block_on(async { let command = ChainBuilder::new().chain(Buffer::new(&request)).build(); self.cursor_queue.send(command).await; @@ -241,13 +235,25 @@ impl VirtGpuAdapter<'_> { self.cursor_queue.send(command).await; }); } + + fn disable_cursor(&mut self) { + if self.hidden_cursor.is_none() { + let cursor = self.create_dumb_buffer(64, 64); + unsafe { + core::ptr::write_bytes(cursor.sgl.as_ptr() as *mut u8, 0, 64 * 64 * 4); + } + self.hidden_cursor = Some(Arc::new(cursor)); + } + let hidden_cursor = self.hidden_cursor.as_ref().unwrap().clone(); + + self.update_cursor(&hidden_cursor, 0, 0, 0, 0); + } } impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> { type Connector = VirtGpuConnector; - type Framebuffer = VirtGpuFramebuffer<'a>; - type Cursor = VirtGpuCursor; + type Buffer = VirtGpuFramebuffer<'a>; fn name(&self) -> &'static [u8] { b"virtio-gpud" @@ -278,8 +284,8 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> { fn get_cap(&self, cap: u32) -> syscall::Result { match cap { DRM_CAP_DUMB_BUFFER => Ok(1), - DRM_CAP_CURSOR_WIDTH => Ok(32), - DRM_CAP_CURSOR_HEIGHT => Ok(32), + DRM_CAP_CURSOR_WIDTH => Ok(64), + DRM_CAP_CURSOR_HEIGHT => Ok(64), _ => Err(syscall::Error::new(EINVAL)), } } @@ -367,7 +373,7 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> { ) } - fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer { + fn create_dumb_buffer(&mut self, width: u32, height: u32) -> Self::Buffer { futures::executor::block_on(async { let bpp = 32; let fb_size = width as usize * height as usize * bpp / 8; @@ -426,11 +432,11 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> { }) } - fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8 { + fn map_dumb_buffer(&mut self, framebuffer: &Self::Buffer) -> *mut u8 { framebuffer.sgl.as_ptr() } - fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage) { + fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Buffer, damage: Damage) { futures::executor::block_on(async { let req = Dma::new(XferToHost2d::new( framebuffer.id, @@ -472,84 +478,31 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> { true } - fn create_cursor_framebuffer(&mut self) -> VirtGpuCursor { - //Creating a new resource for the cursor - let fb_size = 64 * 64 * 4; - let sgl = sgl::Sgl::new(fb_size).unwrap(); - let res_id = ResourceId::alloc(); - - futures::executor::block_on(async { - unsafe { - core::ptr::write_bytes(sgl.as_ptr() as *mut u8, 0, fb_size); - } - - let resource_request = - Dma::new(ResourceCreate2d::new(res_id, ResourceFormat::Bgrx, 64, 64)).unwrap(); - - let header = self.send_request_fenced(resource_request).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - - //Attaching cursor resource as backing storage - let mut mem_entries = - unsafe { Dma::zeroed_slice(sgl.chunks().len()).unwrap().assume_init() }; - for (entry, chunk) in mem_entries.iter_mut().zip(sgl.chunks().iter()) { - *entry = MemEntry { - address: chunk.phys as u64, - length: chunk.length.next_multiple_of(PAGE_SIZE) as u32, - padding: 0, - }; - } - - let attach_request = - Dma::new(AttachBacking::new(res_id, mem_entries.len() as u32)).unwrap(); - let mut header = Dma::new(ControlHeader::default()).unwrap(); - header.flags |= VIRTIO_GPU_FLAG_FENCE; - let command = ChainBuilder::new() - .chain(Buffer::new(&attach_request)) - .chain(Buffer::new_unsized(&mem_entries)) - .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - self.control_queue.send(command).await; - assert_eq!(header.ty, CommandTy::RespOkNodata); - - //Transfering cursor resource to host - let transfer_request = Dma::new(XferToHost2d::new( - res_id, - GpuRect { - x: 0, - y: 0, - width: 64, - height: 64, - }, - 0, - )) - .unwrap(); - let header = self.send_request_fenced(transfer_request).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - }); - - VirtGpuCursor { - resource_id: res_id, - sgl, - } + fn create_cursor_framebuffer(&mut self) -> Self::Buffer { + self.create_dumb_buffer(64, 64) } - fn map_cursor_framebuffer(&mut self, cursor: &Self::Cursor) -> *mut u8 { + fn map_cursor_framebuffer(&mut self, cursor: &Self::Buffer) -> *mut u8 { cursor.sgl.as_ptr() } - fn handle_cursor(&mut self, cursor: &CursorPlane, dirty_fb: bool) { - if dirty_fb { - self.update_cursor( - &cursor.framebuffer, - cursor.x, - cursor.y, - cursor.hot_x, - cursor.hot_y, - ); + fn handle_cursor(&mut self, cursor: Option<&CursorPlane>, dirty_fb: bool) { + if let Some(cursor) = cursor { + if dirty_fb { + self.update_cursor( + &cursor.framebuffer, + cursor.x, + cursor.y, + cursor.hot_x, + cursor.hot_y, + ); + } else { + self.move_cursor(cursor.x, cursor.y); + } } else { - self.move_cursor(cursor.x, cursor.y); + if dirty_fb { + self.disable_cursor(); + } } } } @@ -571,6 +524,7 @@ impl<'a> GpuScheme { transport, has_edid, displays: vec![], + hidden_cursor: None, }; Ok(GraphicsScheme::new(