Merge branch 'virtio_gpu_cursor_changes' into 'master'

Handle vt switching for cursors without requiring a cursor update

See merge request redox-os/drivers!261
This commit is contained in:
Jeremy Soller
2025-04-04 19:25:36 +00:00
4 changed files with 113 additions and 78 deletions
+79 -13
View File
@@ -9,7 +9,7 @@ use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL};
pub trait GraphicsAdapter {
type Framebuffer: Framebuffer;
type Cursor: Cursor;
type Cursor: CursorFramebuffer;
fn displays(&self) -> Vec<usize>;
fn display_size(&self, display_id: usize) -> (u32, u32);
@@ -21,7 +21,8 @@ pub trait GraphicsAdapter {
fn supports_hw_cursor(&self) -> bool;
fn create_cursor_framebuffer(&mut self) -> Self::Cursor;
fn handle_cursor(&mut self, cursor_damage: CursorDamage, cursor_resource: &mut Self::Cursor);
fn map_cursor_framebuffer(&mut self, cursor: &Self::Cursor) -> *mut u8;
fn handle_cursor(&mut self, cursor: &mut CursorPlane<Self::Cursor>, dirty_fb: bool);
}
pub trait Framebuffer {
@@ -29,7 +30,15 @@ pub trait Framebuffer {
fn height(&self) -> u32;
}
pub trait Cursor {}
pub struct CursorPlane<C: CursorFramebuffer> {
pub x: i32,
pub y: i32,
pub hot_x: i32,
pub hot_y: i32,
pub framebuffer: C,
}
pub trait CursorFramebuffer {}
pub struct GraphicsScheme<T: GraphicsAdapter> {
adapter: T,
@@ -41,7 +50,7 @@ pub struct GraphicsScheme<T: GraphicsAdapter> {
active_vt: usize,
vts_fb: HashMap<usize, HashMap<usize, T::Framebuffer>>,
cursor_resources: HashMap<usize, T::Cursor>,
cursor_planes: HashMap<usize, CursorPlane<T::Cursor>>,
}
enum Handle {
@@ -61,7 +70,7 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
handles: BTreeMap::new(),
active_vt: 0,
vts_fb: HashMap::new(),
cursor_resources: HashMap::new(),
cursor_planes: HashMap::new(),
}
}
@@ -95,6 +104,15 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
Self::update_whole_screen(&mut self.adapter, display_id, framebuffer);
self.active_vt = vt_event.vt;
if self.adapter.supports_hw_cursor() {
let cursor_plane = Self::cursor_plane_for_vt(
&mut self.adapter,
&mut self.cursor_planes,
self.active_vt,
);
self.adapter.handle_cursor(cursor_plane, true);
}
}
}
@@ -149,6 +167,20 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
},
);
}
fn cursor_plane_for_vt<'a>(
adapter: &mut T,
cursor_planes: &'a mut HashMap<usize, CursorPlane<T::Cursor>>,
vt: usize,
) -> &'a mut CursorPlane<T::Cursor> {
cursor_planes.entry(vt).or_insert_with(|| CursorPlane {
x: 0,
y: 0,
hot_x: 0,
hot_y: 0,
framebuffer: adapter.create_cursor_framebuffer(),
})
}
}
impl<T: GraphicsAdapter> Scheme for GraphicsScheme<T> {
@@ -176,11 +208,6 @@ impl<T: GraphicsAdapter> Scheme for GraphicsScheme<T> {
self.adapter.create_dumb_framebuffer(width, height)
});
if self.adapter.supports_hw_cursor() {
self.cursor_resources
.insert(vt, self.adapter.create_cursor_framebuffer());
}
self.next_id += 1;
self.handles
.insert(self.next_id, Handle::Screen { vt, screen: id });
@@ -246,9 +273,48 @@ impl<T: GraphicsAdapter> Scheme for GraphicsScheme<T> {
{
let cursor_damage = unsafe { *buf.as_ptr().cast::<CursorDamage>() };
//There is always expected to be cursor_resource if supports_hw_cursor returns true
if let Some(cursor_resource) = self.cursor_resources.get_mut(vt) {
self.adapter.handle_cursor(cursor_damage, cursor_resource);
let cursor_plane = Self::cursor_plane_for_vt(
&mut self.adapter,
&mut self.cursor_planes,
self.active_vt,
);
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::<u32>().offset(64 * row as isize),
w as usize,
);
}
}
self.adapter.handle_cursor(cursor_plane, true);
}
return Ok(buf.len());
+8 -4
View File
@@ -2,8 +2,8 @@ use std::alloc::{self, Layout};
use std::convert::TryInto;
use std::ptr::{self, NonNull};
use driver_graphics::{Cursor, Framebuffer, GraphicsAdapter};
use graphics_ipc::v1::{CursorDamage, Damage};
use driver_graphics::{CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter};
use graphics_ipc::v1::Damage;
use syscall::PAGE_SIZE;
use crate::framebuffer::FrameBuffer;
@@ -14,7 +14,7 @@ pub struct FbAdapter {
pub enum VesadCursor {}
impl Cursor for VesadCursor {}
impl CursorFramebuffer for VesadCursor {}
impl GraphicsAdapter for FbAdapter {
type Framebuffer = GraphicScreen;
@@ -51,7 +51,11 @@ impl GraphicsAdapter for FbAdapter {
unimplemented!("Vesad does not support this function");
}
fn handle_cursor(&mut self, _cursor_damage: CursorDamage, _cursor_resource: &mut VesadCursor) {
fn map_cursor_framebuffer(&mut self, _cursor: &Self::Cursor) -> *mut u8 {
unimplemented!("Vesad does not support this function");
}
fn handle_cursor(&mut self, _cursor: &mut CursorPlane<VesadCursor>, _dirty_fb: bool) {
unimplemented!("Vesad does not support this function");
}
}
+4 -4
View File
@@ -416,13 +416,13 @@ pub struct MoveCursor {
}
impl MoveCursor {
pub fn move_cursor(x: i32, y: i32, hot_x: i32, hot_y: i32, resource_id: ResourceId) -> Self {
pub fn move_cursor(x: i32, y: i32) -> Self {
Self {
header: ControlHeader::with_ty(CommandTy::MoveCursor),
pos: CursorPos::new(0, x, y),
resource_id,
hot_x,
hot_y,
resource_id: ResourceId(0),
hot_x: 0,
hot_y: 0,
_padding: 0,
}
}
+22 -57
View File
@@ -1,8 +1,10 @@
use std::sync::Arc;
use common::{dma::Dma, sgl};
use driver_graphics::{Cursor, Framebuffer, GraphicsAdapter, GraphicsScheme};
use graphics_ipc::v1::{CursorDamage, Damage};
use driver_graphics::{
CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, GraphicsScheme,
};
use graphics_ipc::v1::Damage;
use inputd::DisplayHandle;
use syscall::PAGE_SIZE;
@@ -43,10 +45,9 @@ impl Framebuffer for VirtGpuFramebuffer {
pub struct VirtGpuCursor {
resource_id: ResourceId,
sgl: sgl::Sgl,
set: bool,
}
impl Cursor for VirtGpuCursor {}
impl CursorFramebuffer for VirtGpuCursor {}
#[derive(Debug, Copy, Clone)]
pub struct Display {
@@ -101,35 +102,7 @@ impl VirtGpuAdapter<'_> {
Ok(response)
}
fn update_cursor(&mut self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) {
let x = cursor_damage.x;
let y = cursor_damage.y;
let hot_x = cursor_damage.hot_x;
let 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;
//Clear previous image from backing storage
unsafe {
core::ptr::write_bytes(cursor.sgl.as_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.sgl.as_ptr() as *mut u32).offset(64 * row as isize),
w as usize,
);
}
}
fn update_cursor(&mut self, cursor: &VirtGpuCursor, 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(
@@ -162,20 +135,8 @@ impl VirtGpuAdapter<'_> {
});
}
fn move_cursor(&self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) {
let x = cursor_damage.x;
let y = cursor_damage.y;
let hot_x = cursor_damage.hot_x;
let hot_y = cursor_damage.hot_y;
let request = Dma::new(MoveCursor::move_cursor(
x,
y,
hot_x,
hot_y,
cursor.resource_id,
))
.unwrap();
fn move_cursor(&mut self, x: i32, y: i32) {
let request = Dma::new(MoveCursor::move_cursor(x, y)).unwrap();
futures::executor::block_on(async {
let command = ChainBuilder::new().chain(Buffer::new(&request)).build();
@@ -362,21 +323,25 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> {
VirtGpuCursor {
resource_id: res_id,
sgl: sgl,
set: false,
sgl,
}
}
fn handle_cursor(&mut self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) {
if !cursor.set {
cursor.set = true;
self.update_cursor(cursor_damage, cursor);
}
fn map_cursor_framebuffer(&mut self, cursor: &Self::Cursor) -> *mut u8 {
cursor.sgl.as_ptr()
}
if cursor_damage.header == 0 {
self.move_cursor(cursor_damage, cursor);
fn handle_cursor(&mut self, cursor: &mut CursorPlane<VirtGpuCursor>, dirty_fb: bool) {
if dirty_fb {
self.update_cursor(
&cursor.framebuffer,
cursor.x,
cursor.y,
cursor.hot_x,
cursor.hot_y,
);
} else {
self.update_cursor(cursor_damage, cursor);
self.move_cursor(cursor.x, cursor.y);
}
}
}