Merge branch 'master' into 'master'
adding support for gpu cursor See merge request redox-os/drivers!260
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::io;
|
||||
|
||||
use graphics_ipc::v1::Damage;
|
||||
use graphics_ipc::v1::{CursorDamage, Damage};
|
||||
use inputd::{VtEvent, VtEventKind};
|
||||
use libredox::Fd;
|
||||
use redox_scheme::{RequestKind, Scheme, SignalBehavior, Socket};
|
||||
@@ -9,6 +9,7 @@ use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL};
|
||||
|
||||
pub trait GraphicsAdapter {
|
||||
type Framebuffer: Framebuffer;
|
||||
type Cursor: Cursor;
|
||||
|
||||
fn displays(&self) -> Vec<usize>;
|
||||
fn display_size(&self, display_id: usize) -> (u32, u32);
|
||||
@@ -17,6 +18,10 @@ pub trait GraphicsAdapter {
|
||||
fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8;
|
||||
|
||||
fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
pub trait Framebuffer {
|
||||
@@ -24,6 +29,8 @@ pub trait Framebuffer {
|
||||
fn height(&self) -> u32;
|
||||
}
|
||||
|
||||
pub trait Cursor {}
|
||||
|
||||
pub struct GraphicsScheme<T: GraphicsAdapter> {
|
||||
adapter: T,
|
||||
|
||||
@@ -34,6 +41,7 @@ pub struct GraphicsScheme<T: GraphicsAdapter> {
|
||||
|
||||
active_vt: usize,
|
||||
vts_fb: HashMap<usize, HashMap<usize, T::Framebuffer>>,
|
||||
cursor_resources: HashMap<usize, T::Cursor>,
|
||||
}
|
||||
|
||||
enum Handle {
|
||||
@@ -53,6 +61,7 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
handles: BTreeMap::new(),
|
||||
active_vt: 0,
|
||||
vts_fb: HashMap::new(),
|
||||
cursor_resources: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +176,11 @@ 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 });
|
||||
@@ -201,12 +215,21 @@ impl<T: GraphicsAdapter> Scheme for GraphicsScheme<T> {
|
||||
fn read(
|
||||
&mut self,
|
||||
id: usize,
|
||||
_buf: &mut [u8],
|
||||
buf: &mut [u8],
|
||||
_offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
) -> Result<usize> {
|
||||
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
Err(Error::new(EINVAL))
|
||||
|
||||
//Currently read is only used for Orbital to check GPU cursor support
|
||||
//and only expects a buf to pass a 0 or 1 flag
|
||||
if self.adapter.supports_hw_cursor() {
|
||||
buf[0] = 1;
|
||||
} else {
|
||||
buf[0] = 0;
|
||||
}
|
||||
|
||||
Ok(1)
|
||||
}
|
||||
|
||||
fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result<usize> {
|
||||
@@ -218,6 +241,19 @@ impl<T: GraphicsAdapter> Scheme for GraphicsScheme<T> {
|
||||
return Ok(buf.len());
|
||||
}
|
||||
|
||||
if size_of_val(buf) == std::mem::size_of::<CursorDamage>()
|
||||
&& self.adapter.supports_hw_cursor()
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
return Ok(buf.len());
|
||||
}
|
||||
|
||||
let framebuffer = &self.vts_fb[vt][screen];
|
||||
|
||||
assert_eq!(buf.len(), std::mem::size_of::<Damage>());
|
||||
|
||||
@@ -110,6 +110,19 @@ impl Drop for DisplayMap {
|
||||
}
|
||||
}
|
||||
|
||||
#[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],
|
||||
}
|
||||
|
||||
// Keep synced with orbital's SyncRect
|
||||
// Technically orbital uses i32 rather than u32, but values larger than i32::MAX
|
||||
// would be a bug anyway.
|
||||
|
||||
@@ -2,8 +2,8 @@ use std::alloc::{self, Layout};
|
||||
use std::convert::TryInto;
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
use driver_graphics::{Framebuffer, GraphicsAdapter};
|
||||
use graphics_ipc::v1::Damage;
|
||||
use driver_graphics::{Cursor, Framebuffer, GraphicsAdapter};
|
||||
use graphics_ipc::v1::{CursorDamage, Damage};
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
use crate::framebuffer::FrameBuffer;
|
||||
@@ -12,8 +12,13 @@ pub struct FbAdapter {
|
||||
pub framebuffers: Vec<FrameBuffer>,
|
||||
}
|
||||
|
||||
pub enum VesadCursor {}
|
||||
|
||||
impl Cursor for VesadCursor {}
|
||||
|
||||
impl GraphicsAdapter for FbAdapter {
|
||||
type Framebuffer = GraphicScreen;
|
||||
type Cursor = VesadCursor;
|
||||
|
||||
fn displays(&self) -> Vec<usize> {
|
||||
(0..self.framebuffers.len()).collect()
|
||||
@@ -37,6 +42,18 @@ impl GraphicsAdapter for FbAdapter {
|
||||
fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage) {
|
||||
framebuffer.sync(&mut self.framebuffers[display_id], damage)
|
||||
}
|
||||
|
||||
fn supports_hw_cursor(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn create_cursor_framebuffer(&mut self) -> VesadCursor {
|
||||
unimplemented!("Vesad does not support this function");
|
||||
}
|
||||
|
||||
fn handle_cursor(&mut self, _cursor_damage: CursorDamage, _cursor_resource: &mut VesadCursor) {
|
||||
unimplemented!("Vesad does not support this function");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GraphicScreen {
|
||||
|
||||
@@ -361,6 +361,73 @@ impl XferToHost2d {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct CursorPos {
|
||||
pub scanout_id: u32,
|
||||
pub x: i32,
|
||||
pub y: i32,
|
||||
_padding: u32,
|
||||
}
|
||||
|
||||
impl CursorPos {
|
||||
pub fn new(scanout_id: u32, x: i32, y: i32) -> Self {
|
||||
Self {
|
||||
scanout_id,
|
||||
x,
|
||||
y,
|
||||
_padding: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct UpdateCursor {
|
||||
pub header: ControlHeader,
|
||||
pub pos: CursorPos,
|
||||
pub resource_id: ResourceId,
|
||||
pub hot_x: i32,
|
||||
pub hot_y: i32,
|
||||
_padding: u32,
|
||||
}
|
||||
|
||||
impl UpdateCursor {
|
||||
pub fn update_cursor(x: i32, y: i32, hot_x: i32, hot_y: i32, resource_id: ResourceId) -> Self {
|
||||
Self {
|
||||
header: ControlHeader::with_ty(CommandTy::UpdateCursor),
|
||||
pos: CursorPos::new(0, x, y),
|
||||
resource_id,
|
||||
hot_x,
|
||||
hot_y,
|
||||
_padding: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MoveCursor {
|
||||
pub header: ControlHeader,
|
||||
pub pos: CursorPos,
|
||||
pub resource_id: ResourceId,
|
||||
pub hot_x: i32,
|
||||
pub hot_y: i32,
|
||||
_padding: u32,
|
||||
}
|
||||
|
||||
impl MoveCursor {
|
||||
pub fn move_cursor(x: i32, y: i32, hot_x: i32, hot_y: i32, resource_id: ResourceId) -> Self {
|
||||
Self {
|
||||
header: ControlHeader::with_ty(CommandTy::MoveCursor),
|
||||
pos: CursorPos::new(0, x, y),
|
||||
resource_id,
|
||||
hot_x,
|
||||
hot_y,
|
||||
_padding: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DEVICE: spin::Once<virtio_core::Device> = spin::Once::new();
|
||||
|
||||
fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use common::{dma::Dma, sgl};
|
||||
use driver_graphics::{Framebuffer, GraphicsAdapter, GraphicsScheme};
|
||||
use graphics_ipc::v1::Damage;
|
||||
use driver_graphics::{Cursor, Framebuffer, GraphicsAdapter, GraphicsScheme};
|
||||
use graphics_ipc::v1::{CursorDamage, Damage};
|
||||
use inputd::DisplayHandle;
|
||||
|
||||
use syscall::PAGE_SIZE;
|
||||
@@ -40,6 +40,14 @@ impl Framebuffer for VirtGpuFramebuffer {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VirtGpuCursor {
|
||||
resource_id: ResourceId,
|
||||
sgl: sgl::Sgl,
|
||||
set: bool,
|
||||
}
|
||||
|
||||
impl Cursor for VirtGpuCursor {}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Display {
|
||||
width: u32,
|
||||
@@ -92,10 +100,93 @@ 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
//Transfering cursor resource to host
|
||||
futures::executor::block_on(async {
|
||||
let transfer_request = Dma::new(XferToHost2d::new(
|
||||
cursor.resource_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);
|
||||
});
|
||||
|
||||
//Update the cursor position
|
||||
let request = Dma::new(UpdateCursor::update_cursor(
|
||||
x,
|
||||
y,
|
||||
hot_x,
|
||||
hot_y,
|
||||
cursor.resource_id,
|
||||
))
|
||||
.unwrap();
|
||||
futures::executor::block_on(async {
|
||||
let command = ChainBuilder::new().chain(Buffer::new(&request)).build();
|
||||
self.cursor_queue.send(command).await;
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
futures::executor::block_on(async {
|
||||
let command = ChainBuilder::new().chain(Buffer::new(&request)).build();
|
||||
self.cursor_queue.send(command).await;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphicsAdapter for VirtGpuAdapter<'_> {
|
||||
type Framebuffer = VirtGpuFramebuffer;
|
||||
type Cursor = VirtGpuCursor;
|
||||
|
||||
fn displays(&self) -> Vec<usize> {
|
||||
self.displays.iter().enumerate().map(|(i, _)| i).collect()
|
||||
@@ -207,6 +298,87 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> {
|
||||
assert_eq!(header.ty, CommandTy::RespOkNodata);
|
||||
});
|
||||
}
|
||||
|
||||
fn supports_hw_cursor(&self) -> bool {
|
||||
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: sgl,
|
||||
set: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_cursor(&mut self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) {
|
||||
if !cursor.set {
|
||||
cursor.set = true;
|
||||
self.update_cursor(cursor_damage, cursor);
|
||||
}
|
||||
|
||||
if cursor_damage.header == 0 {
|
||||
self.move_cursor(cursor_damage, cursor);
|
||||
} else {
|
||||
self.update_cursor(cursor_damage, cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GpuScheme {}
|
||||
|
||||
Reference in New Issue
Block a user