From f01d0fe8a18312c6ef8234d7fd5f20fa732cc397 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 11 Mar 2026 23:17:38 +0100 Subject: [PATCH] drivers/graphics: Introduce UPDATE_CURSOR ioctl Orbital needs this as we don't implement cursor planes yet. --- drivers/graphics/driver-graphics/src/lib.rs | 132 ++++++++++++-------- drivers/graphics/graphics-ipc/src/v1.rs | 14 +-- drivers/graphics/graphics-ipc/src/v2.rs | 16 ++- 3 files changed, 99 insertions(+), 63 deletions(-) diff --git a/drivers/graphics/driver-graphics/src/lib.rs b/drivers/graphics/driver-graphics/src/lib.rs index e43c4cbc95..bcd150d510 100644 --- a/drivers/graphics/driver-graphics/src/lib.rs +++ b/drivers/graphics/driver-graphics/src/lib.rs @@ -349,6 +349,67 @@ impl GraphicsSchemeInner { }, ); } + + fn handle_cursor_update( + &mut self, + vt: usize, + cursor_damage: &graphics_ipc::v2::ipc::UpdateCursor, + ) -> Result<()> { + let vt_state = self.vts.get_mut(&vt).unwrap(); + + let Some(cursor_plane) = &mut vt_state.cursor_plane else { + // Hardware cursor not supported + return Err(Error::new(EINVAL)); + }; + + cursor_plane.x = cursor_damage.x; + cursor_plane.y = cursor_damage.y; + + if cursor_damage.header == 0 { + if vt != self.active_vt { + return Ok(()); + } + + self.adapter.handle_cursor(cursor_plane, false); + } else { + cursor_plane.hot_x = cursor_damage.hot_x; + cursor_plane.hot_y = cursor_damage.hot_y; + + let w: i32 = cursor_damage.width; + let h: i32 = cursor_damage.height; + let cursor_image = cursor_damage.cursor_img_bytes; + let cursor_ptr = self + .adapter + .map_cursor_framebuffer(&cursor_plane.framebuffer); + + //Clear previous image from backing storage + unsafe { + core::ptr::write_bytes(cursor_ptr as *mut u8, 0, 64 * 64 * 4); + } + + //Write image to backing storage + for row in 0..h { + let start: usize = (w * row) as usize; + let end: usize = (w * row + w) as usize; + + unsafe { + core::ptr::copy_nonoverlapping( + cursor_image[start..end].as_ptr(), + cursor_ptr.cast::().offset(64 * row as isize), + w as usize, + ); + } + } + + if vt != self.active_vt { + return Ok(()); + } + + self.adapter.handle_cursor(cursor_plane, true); + } + + return Ok(()); + } } const MAP_FAKE_OFFSET_MULTIPLIER: usize = 0x10_000_000; @@ -495,6 +556,14 @@ impl SchemeSync for GraphicsSchemeInner { ) -> Result { match self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::V1Screen { vt, screen } => { + if size_of_val(buf) == std::mem::size_of::() { + let cursor_damage = unsafe { &*buf.as_ptr().cast::() }; + + self.handle_cursor_update(*vt, cursor_damage)?; + + return Ok(buf.len()); + } + if *vt != self.active_vt { // This is a protection against background VT's spamming us with flush requests. We will // flush the framebuffer on the next VT switch anyway @@ -503,55 +572,6 @@ impl SchemeSync for GraphicsSchemeInner { let vt_state = self.vts.get_mut(vt).unwrap(); - if size_of_val(buf) == std::mem::size_of::() { - let Some(cursor_plane) = &mut vt_state.cursor_plane else { - // Hardware cursor not supported - return Err(Error::new(EINVAL)); - }; - - let cursor_damage = unsafe { *buf.as_ptr().cast::() }; - - cursor_plane.x = cursor_damage.x; - cursor_plane.y = cursor_damage.y; - - if cursor_damage.header == 0 { - self.adapter.handle_cursor(cursor_plane, false); - } else { - cursor_plane.hot_x = cursor_damage.hot_x; - cursor_plane.hot_y = cursor_damage.hot_y; - - let w: i32 = cursor_damage.width; - let h: i32 = cursor_damage.height; - let cursor_image = cursor_damage.cursor_img_bytes; - let cursor_ptr = self - .adapter - .map_cursor_framebuffer(&cursor_plane.framebuffer); - - //Clear previous image from backing storage - unsafe { - core::ptr::write_bytes(cursor_ptr as *mut u8, 0, 64 * 64 * 4); - } - - //Write image to backing storage - for row in 0..h { - let start: usize = (w * row) as usize; - let end: usize = (w * row + w) as usize; - - unsafe { - core::ptr::copy_nonoverlapping( - cursor_image[start..end].as_ptr(), - cursor_ptr.cast::().offset(64 * row as isize), - w as usize, - ); - } - } - - self.adapter.handle_cursor(cursor_plane, true); - } - - return Ok(buf.len()); - } - assert_eq!(buf.len(), std::mem::size_of::()); let damage = unsafe { *buf.as_ptr().cast::() }; @@ -935,6 +955,20 @@ impl SchemeSync for GraphicsSchemeInner { Ok(size_of::()) } + ipc::UPDATE_CURSOR => { + if payload.len() < size_of::() { + return Err(Error::new(EINVAL)); + } + let payload = unsafe { + transmute::<&mut [u8; size_of::()], &mut ipc::UpdateCursor>( + payload.as_mut_array().unwrap(), + ) + }; + let vt = *vt; + self.handle_cursor_update(vt, payload)?; + + Ok(size_of::()) + } _ => return Err(Error::new(EINVAL)), }, } diff --git a/drivers/graphics/graphics-ipc/src/v1.rs b/drivers/graphics/graphics-ipc/src/v1.rs index df882024c2..fbf2227268 100644 --- a/drivers/graphics/graphics-ipc/src/v1.rs +++ b/drivers/graphics/graphics-ipc/src/v1.rs @@ -1,14 +1,2 @@ pub use crate::common::Damage; - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct CursorDamage { - pub header: u32, - pub x: i32, - pub y: i32, - pub hot_x: i32, - pub hot_y: i32, - pub width: i32, - pub height: i32, - pub cursor_img_bytes: [u32; 4096], -} +pub use crate::v2::ipc::UpdateCursor as CursorDamage; diff --git a/drivers/graphics/graphics-ipc/src/v2.rs b/drivers/graphics/graphics-ipc/src/v2.rs index 7e132351b3..31b098f0bf 100644 --- a/drivers/graphics/graphics-ipc/src/v2.rs +++ b/drivers/graphics/graphics-ipc/src/v2.rs @@ -69,11 +69,25 @@ pub mod ipc { pub use redox_ioctl::drm::*; // FIXME replace these with proper drm interfaces - pub const UPDATE_PLANE: u64 = 6; + pub const UPDATE_PLANE: u64 = 0x12345670; #[repr(C, packed)] pub struct UpdatePlane { pub display_id: usize, pub fb_id: u32, pub damage: Damage, } + + pub const UPDATE_CURSOR: u64 = 0x12345671; + #[derive(Debug, Copy, Clone)] + #[repr(C, packed)] + pub struct UpdateCursor { + pub header: u32, + pub x: i32, + pub y: i32, + pub hot_x: i32, + pub hot_y: i32, + pub width: i32, + pub height: i32, + pub cursor_img_bytes: [u32; 4096], + } }