drivers/graphics: Unify buffer types between regular and cursor planes

Also correct the cursor size for virtio-gpu.
This commit is contained in:
bjorn3
2026-03-12 22:32:43 +01:00
parent 93249717e8
commit 4317189d7b
4 changed files with 105 additions and 165 deletions
+34 -35
View File
@@ -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<Self::Cursor>, 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<Self::Buffer>>, dirty_fb: bool);
}
pub trait Framebuffer {
pub trait Buffer {
fn width(&self) -> u32;
fn height(&self) -> u32;
}
pub struct CursorPlane<C: CursorFramebuffer> {
#[derive(Debug)]
pub struct CursorPlane<C: Buffer> {
pub x: i32,
pub y: i32,
pub hot_x: i32,
@@ -87,8 +87,6 @@ pub struct CursorPlane<C: CursorFramebuffer> {
pub framebuffer: C,
}
pub trait CursorFramebuffer {}
pub struct GraphicsScheme<T: GraphicsAdapter> {
inner: GraphicsSchemeInner<T>,
inputd_handle: DisplayHandle,
@@ -224,8 +222,10 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
);
}
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<T: GraphicsAdapter> {
}
struct VtState<T: GraphicsAdapter> {
display_fbs: Vec<Arc<T::Framebuffer>>,
cursor_plane: Option<CursorPlane<T::Cursor>>,
display_fbs: Vec<Arc<T::Buffer>>,
cursor_plane: Option<CursorPlane<T::Buffer>>,
}
enum Handle<T: GraphicsAdapter> {
@@ -304,7 +304,7 @@ enum Handle<T: GraphicsAdapter> {
V2 {
vt: usize,
next_id: u32,
fbs: HashMap<u32, Arc<T::Framebuffer>>,
fbs: HashMap<u32, Arc<T::Buffer>>,
},
SchemeRoot,
}
@@ -319,25 +319,17 @@ impl<T: GraphicsAdapter> GraphicsSchemeInner<T> {
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<T: GraphicsAdapter> GraphicsSchemeInner<T> {
) -> 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<T: GraphicsAdapter> GraphicsSchemeInner<T> {
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<T: GraphicsAdapter> GraphicsSchemeInner<T> {
return Ok(());
}
self.adapter.handle_cursor(cursor_plane, true);
self.adapter.handle_cursor(Some(cursor_plane), true);
}
return Ok(());
@@ -755,7 +754,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsSchemeInner<T> {
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<T: GraphicsAdapter> SchemeSync for GraphicsSchemeInner<T> {
),
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)
}
}
+9 -16
View File
@@ -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::<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) {
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<Self::Cursor>, _dirty_fb: bool) {
fn handle_cursor(&mut self, _cursor: Option<&CursorPlane<Self::Buffer>>, _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
}
+9 -15
View File
@@ -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::<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) {
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<VesadCursor>, _dirty_fb: bool) {
fn handle_cursor(&mut self, _cursor: Option<&CursorPlane<Self::Buffer>>, _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
}
+53 -99
View File
@@ -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<dyn Transport>,
has_edid: bool,
displays: Vec<Display>,
hidden_cursor: Option<Arc<VirtGpuFramebuffer<'a>>>,
}
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<u64> {
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<VirtGpuCursor>, 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<Self::Buffer>>, 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(