Merge branch 'virtio_gpud_refactor' into 'master'
Various virtio-gpud improvements See merge request redox-os/drivers!222
This commit is contained in:
+18
-9
@@ -15,6 +15,8 @@ use crate::dma::phys_contiguous_fd;
|
||||
pub struct Sgl {
|
||||
/// A raw pointer to the SGL in virtual memory
|
||||
virt: *mut u8,
|
||||
/// The length of the allocated memory, guaranteed to be a multiple of [PAGE_SIZE].
|
||||
aligned_length: usize,
|
||||
/// The length of the allocated memory. This value is NOT guaranteed to be a multiple of [PAGE_SIZE]
|
||||
unaligned_length: NonZeroUsize,
|
||||
/// The vector of chunks tracked by this [Sgl] object. This is the sparsely-populated vector in the SGL algorithm.
|
||||
@@ -39,15 +41,20 @@ impl Sgl {
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// 'unaligned_length: [usize]' - The length of the SGL, not aligned to the nearest page.
|
||||
/// 'unaligned_length: [usize]' - The length of the SGL, not necessarily aligned to the nearest
|
||||
/// page.
|
||||
pub fn new(unaligned_length: usize) -> Result<Self> {
|
||||
let unaligned_length = NonZeroUsize::new(unaligned_length).ok_or(Error::new(EINVAL))?;
|
||||
|
||||
// TODO: Both PAGE_SIZE and MAX_ALLOC_SIZE should be dynamic.
|
||||
let aligned_length = unaligned_length.get().next_multiple_of(PAGE_SIZE);
|
||||
const MAX_ALLOC_SIZE: usize = 1 << 22;
|
||||
|
||||
unsafe {
|
||||
let virt = libredox::call::mmap(MmapArgs {
|
||||
flags: MAP_PRIVATE,
|
||||
prot: PROT_READ | PROT_WRITE,
|
||||
length: unaligned_length.get(),
|
||||
length: aligned_length,
|
||||
|
||||
offset: 0,
|
||||
fd: !0,
|
||||
@@ -57,21 +64,23 @@ impl Sgl {
|
||||
|
||||
let mut this = Self {
|
||||
virt,
|
||||
aligned_length,
|
||||
unaligned_length,
|
||||
chunks: Vec::new(),
|
||||
};
|
||||
|
||||
let phys_contiguous_fd = phys_contiguous_fd()?;
|
||||
|
||||
// TODO: Both PAGE_SIZE and MAX_ALLOC_SIZE should be dynamic.
|
||||
let aligned_length = unaligned_length.get().next_multiple_of(PAGE_SIZE);
|
||||
const MAX_ALLOC_SIZE: usize = 1 << 22;
|
||||
|
||||
let mut offset = 0;
|
||||
while offset < unaligned_length.get() {
|
||||
let chunk_length = (aligned_length - offset)
|
||||
while offset < aligned_length {
|
||||
let preferred_chunk_length = (aligned_length - offset)
|
||||
.min(MAX_ALLOC_SIZE)
|
||||
.next_power_of_two();
|
||||
let chunk_length = if preferred_chunk_length > aligned_length - offset {
|
||||
preferred_chunk_length / 2
|
||||
} else {
|
||||
preferred_chunk_length
|
||||
};
|
||||
libredox::call::mmap(MmapArgs {
|
||||
addr: virt.add(offset).cast(),
|
||||
flags: MAP_PRIVATE | (MAP_FIXED.bits() as u32),
|
||||
@@ -112,7 +121,7 @@ impl Sgl {
|
||||
impl Drop for Sgl {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let _ = libredox::call::munmap(self.virt.cast(), self.unaligned_length.get());
|
||||
let _ = libredox::call::munmap(self.virt.cast(), self.aligned_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,9 +124,13 @@ impl TextScreen {
|
||||
buf: &[u8],
|
||||
input: &mut VecDeque<u8>,
|
||||
) -> Vec<Damage> {
|
||||
self.console.state.w = map.width / 8;
|
||||
self.console.state.h = map.height / 16;
|
||||
self.console.state.bottom_margin = (map.height / 16).saturating_sub(1);
|
||||
self.console.resize(map.width / 8, map.height / 16);
|
||||
if self.console.state.x > self.console.state.w {
|
||||
self.console.state.x = self.console.state.w;
|
||||
}
|
||||
if self.console.state.y > self.console.state.h {
|
||||
self.console.state.y = self.console.state.h;
|
||||
}
|
||||
|
||||
if self.console.state.cursor
|
||||
&& self.console.state.x < self.console.state.w
|
||||
@@ -138,68 +142,65 @@ impl TextScreen {
|
||||
self.changed.insert(y);
|
||||
}
|
||||
|
||||
{
|
||||
let changed = &mut self.changed;
|
||||
self.console.write(buf, |event| match event {
|
||||
ransid::Event::Char {
|
||||
x,
|
||||
y,
|
||||
c,
|
||||
color,
|
||||
bold,
|
||||
..
|
||||
} => {
|
||||
Self::char(map, x * 8, y * 16, c, color.as_rgb(), bold, false);
|
||||
changed.insert(y);
|
||||
self.console.write(buf, |event| match event {
|
||||
ransid::Event::Char {
|
||||
x,
|
||||
y,
|
||||
c,
|
||||
color,
|
||||
bold,
|
||||
..
|
||||
} => {
|
||||
Self::char(map, x * 8, y * 16, c, color.as_rgb(), bold, false);
|
||||
self.changed.insert(y);
|
||||
}
|
||||
ransid::Event::Input { data } => input.extend(data),
|
||||
ransid::Event::Rect { x, y, w, h, color } => {
|
||||
Self::rect(map, x * 8, y * 16, w * 8, h * 16, color.as_rgb());
|
||||
for y2 in y..y + h {
|
||||
self.changed.insert(y2);
|
||||
}
|
||||
ransid::Event::Input { data } => input.extend(data),
|
||||
ransid::Event::Rect { x, y, w, h, color } => {
|
||||
Self::rect(map, x * 8, y * 16, w * 8, h * 16, color.as_rgb());
|
||||
for y2 in y..y + h {
|
||||
changed.insert(y2);
|
||||
}
|
||||
}
|
||||
ransid::Event::ScreenBuffer { .. } => (),
|
||||
ransid::Event::Move {
|
||||
from_x,
|
||||
from_y,
|
||||
to_x,
|
||||
to_y,
|
||||
w,
|
||||
h,
|
||||
} => {
|
||||
let width = map.width;
|
||||
let pixels = unsafe { &mut *map.offscreen };
|
||||
}
|
||||
ransid::Event::ScreenBuffer { .. } => (),
|
||||
ransid::Event::Move {
|
||||
from_x,
|
||||
from_y,
|
||||
to_x,
|
||||
to_y,
|
||||
w,
|
||||
h,
|
||||
} => {
|
||||
let width = map.width;
|
||||
let pixels = unsafe { &mut *map.offscreen };
|
||||
|
||||
for raw_y in 0..h {
|
||||
let y = if from_y > to_y { raw_y } else { h - raw_y - 1 };
|
||||
for raw_y in 0..h {
|
||||
let y = if from_y > to_y { raw_y } else { h - raw_y - 1 };
|
||||
|
||||
for pixel_y in 0..16 {
|
||||
{
|
||||
let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8;
|
||||
let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8;
|
||||
let len = w * 8;
|
||||
for pixel_y in 0..16 {
|
||||
{
|
||||
let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8;
|
||||
let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8;
|
||||
let len = w * 8;
|
||||
|
||||
if off_from + len <= pixels.len() && off_to + len <= pixels.len() {
|
||||
unsafe {
|
||||
let data_ptr = pixels.as_mut_ptr() as *mut u32;
|
||||
ptr::copy(
|
||||
data_ptr.offset(off_from as isize),
|
||||
data_ptr.offset(off_to as isize),
|
||||
len,
|
||||
);
|
||||
}
|
||||
if off_from + len <= pixels.len() && off_to + len <= pixels.len() {
|
||||
unsafe {
|
||||
let data_ptr = pixels.as_mut_ptr() as *mut u32;
|
||||
ptr::copy(
|
||||
data_ptr.offset(off_from as isize),
|
||||
data_ptr.offset(off_to as isize),
|
||||
len,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
changed.insert(to_y + y);
|
||||
}
|
||||
|
||||
self.changed.insert(to_y + y);
|
||||
}
|
||||
ransid::Event::Resize { .. } => (),
|
||||
ransid::Event::Title { .. } => (),
|
||||
});
|
||||
}
|
||||
}
|
||||
ransid::Event::Resize { .. } => (),
|
||||
ransid::Event::Title { .. } => (),
|
||||
});
|
||||
|
||||
if self.console.state.cursor
|
||||
&& self.console.state.x < self.console.state.w
|
||||
|
||||
@@ -61,11 +61,17 @@ impl Display {
|
||||
|
||||
let (mut new_display_file, width, height) = Self::open_display(&self.input_handle).unwrap();
|
||||
|
||||
eprintln!("fbcond: Opened new display");
|
||||
eprintln!("fbcond: Opened new display with size {width}x{height}");
|
||||
|
||||
match display_fd_map(width, height, &mut new_display_file) {
|
||||
Ok(offscreen) => {
|
||||
unsafe {
|
||||
display_fd_unmap(self.offscreen);
|
||||
}
|
||||
|
||||
self.offscreen = offscreen;
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
self.display_file = new_display_file;
|
||||
|
||||
eprintln!("fbcond: Mapped new display");
|
||||
@@ -107,7 +113,13 @@ impl Display {
|
||||
pub fn resize(&mut self, width: usize, height: usize) {
|
||||
match display_fd_map(width, height, &mut self.display_file) {
|
||||
Ok(offscreen) => {
|
||||
unsafe {
|
||||
display_fd_unmap(self.offscreen);
|
||||
}
|
||||
|
||||
self.offscreen = offscreen;
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("failed to resize display to {}x{}: {}", width, height, err);
|
||||
|
||||
+114
-144
@@ -1,4 +1,3 @@
|
||||
use std::cell::RefCell;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
@@ -8,7 +7,7 @@ use common::{dma::Dma, sgl};
|
||||
use inputd::{Damage, VtEvent, VtEventKind};
|
||||
|
||||
use redox_scheme::Scheme;
|
||||
use syscall::{Error as SysError, MapFlags, EINVAL, PAGE_SIZE};
|
||||
use syscall::{Error as SysError, MapFlags, EBADF, EINVAL, PAGE_SIZE};
|
||||
|
||||
use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags};
|
||||
use virtio_core::transport::{Error, Queue, Transport};
|
||||
@@ -27,52 +26,18 @@ impl Into<GpuRect> for Damage {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Display<'a> {
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
|
||||
active_vt: RefCell<usize>,
|
||||
vts_map: RefCell<HashMap<usize, sgl::Sgl>>,
|
||||
vts_res: RefCell<HashMap<usize, ResourceId>>,
|
||||
|
||||
width: u32,
|
||||
height: u32,
|
||||
|
||||
id: usize,
|
||||
struct GpuResource {
|
||||
id: ResourceId,
|
||||
sgl: sgl::Sgl,
|
||||
}
|
||||
|
||||
impl<'a> Display<'a> {
|
||||
pub fn new(
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
id: usize,
|
||||
) -> Self {
|
||||
Self {
|
||||
control_queue,
|
||||
cursor_queue,
|
||||
|
||||
active_vt: RefCell::new(0),
|
||||
vts_map: RefCell::new(HashMap::new()),
|
||||
vts_res: RefCell::new(HashMap::new()),
|
||||
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
transport,
|
||||
|
||||
id,
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_fpath(&self, buffer: &mut [u8]) -> Result<usize, Error> {
|
||||
let path = format!("display.virtio-gpu:3.0/{}/{}", self.width, self.height);
|
||||
|
||||
// Copy the path into the target buffer.
|
||||
buffer[..path.len()].copy_from_slice(path.as_bytes());
|
||||
Ok(path.len())
|
||||
}
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Display {
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl GpuScheme<'_> {
|
||||
async fn send_request<T>(&self, request: Dma<T>) -> Result<Dma<ControlHeader>, Error> {
|
||||
let header = Dma::new(ControlHeader::default())?;
|
||||
let command = ChainBuilder::new()
|
||||
@@ -91,41 +56,31 @@ impl<'a> Display<'a> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn mmap_screen(&self, vt: usize, offset: usize) -> Result<*mut u8, Error> {
|
||||
if let Some(sgl) = self.vts_map.borrow().get(&vt) {
|
||||
return Ok(sgl.as_ptr().wrapping_add(offset));
|
||||
async fn res_for_screen(
|
||||
&mut self,
|
||||
vt: usize,
|
||||
screen: usize,
|
||||
) -> Result<(ResourceId, *mut u8), Error> {
|
||||
if let Some(res) = self.vts.entry(vt).or_default().get(&screen) {
|
||||
return Ok((res.id, res.sgl.as_ptr()));
|
||||
}
|
||||
|
||||
let bpp = 32;
|
||||
let fb_size = self.width as usize * self.height as usize * bpp / 8;
|
||||
let mapped = sgl::Sgl::new(fb_size)?;
|
||||
let fb_size =
|
||||
self.displays[screen].width as usize * self.displays[screen].height as usize * bpp / 8;
|
||||
let sgl = sgl::Sgl::new(fb_size)?;
|
||||
|
||||
unsafe {
|
||||
core::ptr::write_bytes(mapped.as_ptr() as *mut u8, 255, fb_size);
|
||||
core::ptr::write_bytes(sgl.as_ptr() as *mut u8, 255, fb_size);
|
||||
}
|
||||
|
||||
let mut mapped_vts = self.vts_map.borrow_mut();
|
||||
let sgl = mapped_vts.entry(vt).or_insert(mapped);
|
||||
Ok(sgl.as_ptr().wrapping_add(offset))
|
||||
}
|
||||
|
||||
async fn create_res_for_screen(&self, vt: usize) -> Result<ResourceId, Error> {
|
||||
if let Some(&res_id) = self.vts_res.borrow().get(&vt) {
|
||||
return Ok(res_id);
|
||||
}
|
||||
|
||||
self.mmap_screen(vt, 0).await?;
|
||||
|
||||
let vts_map = self.vts_map.borrow();
|
||||
let mapped = &vts_map.get(&vt).unwrap();
|
||||
|
||||
let res_id = ResourceId::alloc();
|
||||
|
||||
// Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`.
|
||||
let mut request = Dma::new(ResourceCreate2d::default())?;
|
||||
|
||||
request.set_width(self.width);
|
||||
request.set_height(self.height);
|
||||
request.set_width(self.displays[screen].width);
|
||||
request.set_height(self.displays[screen].height);
|
||||
request.set_format(ResourceFormat::Bgrx);
|
||||
request.set_resource_id(res_id);
|
||||
|
||||
@@ -135,8 +90,8 @@ impl<'a> Display<'a> {
|
||||
// Use the allocated framebuffer from tthe guest ram, and attach it as backing
|
||||
// storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`.
|
||||
|
||||
let mut mem_entries = unsafe { Dma::zeroed_slice(mapped.chunks().len())?.assume_init() };
|
||||
for (entry, chunk) in mem_entries.iter_mut().zip(mapped.chunks().iter()) {
|
||||
let mut mem_entries = unsafe { Dma::zeroed_slice(sgl.chunks().len())?.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,
|
||||
@@ -155,43 +110,52 @@ impl<'a> Display<'a> {
|
||||
self.control_queue.send(command).await;
|
||||
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
|
||||
|
||||
let mut mapped_vts = self.vts_res.borrow_mut();
|
||||
mapped_vts.insert(vt, res_id);
|
||||
Ok(res_id)
|
||||
let res = self
|
||||
.vts
|
||||
.entry(vt)
|
||||
.or_default()
|
||||
.entry(screen)
|
||||
.or_insert(GpuResource { id: res_id, sgl });
|
||||
Ok((res.id, res.sgl.as_ptr()))
|
||||
}
|
||||
|
||||
async fn set_scanout(&self, vt: usize) -> Result<(), Error> {
|
||||
let res_id = self.create_res_for_screen(vt).await?;
|
||||
async fn set_scanout(&mut self, vt: usize, screen: usize) -> Result<(), Error> {
|
||||
let (res_id, _) = self.res_for_screen(vt, screen).await?;
|
||||
|
||||
let scanout_request = Dma::new(SetScanout::new(
|
||||
self.id as u32,
|
||||
screen as u32,
|
||||
res_id,
|
||||
GpuRect::new(0, 0, self.width, self.height),
|
||||
GpuRect::new(
|
||||
0,
|
||||
0,
|
||||
self.displays[screen].width,
|
||||
self.displays[screen].height,
|
||||
),
|
||||
))?;
|
||||
let header = self.send_request(scanout_request).await?;
|
||||
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
|
||||
|
||||
self.flush(vt, None).await?;
|
||||
self.flush(vt, screen, None).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// If `damage` is `None`, the entire screen is flushed.
|
||||
async fn flush(&self, vt: usize, damage: Option<&[Damage]>) -> Result<(), Error> {
|
||||
let Some(&res_id) = self.vts_res.borrow().get(&vt) else {
|
||||
// The resource is not yet created. Ignore the damage. We will write the entire backing
|
||||
// storage to the resource once we create the resource, which is equivalent to damaging
|
||||
// the entire resource.
|
||||
return Ok(());
|
||||
};
|
||||
async fn flush(
|
||||
&mut self,
|
||||
vt: usize,
|
||||
screen: usize,
|
||||
damage: Option<&[Damage]>,
|
||||
) -> Result<(), Error> {
|
||||
let (res_id, _) = self.res_for_screen(vt, screen).await?;
|
||||
|
||||
let req = Dma::new(XferToHost2d::new(
|
||||
res_id,
|
||||
GpuRect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
width: self.displays[screen].width,
|
||||
height: self.displays[screen].height,
|
||||
},
|
||||
0,
|
||||
))?;
|
||||
@@ -202,7 +166,12 @@ impl<'a> Display<'a> {
|
||||
for damage in damage {
|
||||
self.flush_resource(ResourceFlush::new(
|
||||
res_id,
|
||||
damage.clip(self.width as i32, self.height as i32).into(),
|
||||
damage
|
||||
.clip(
|
||||
self.displays[screen].width as i32,
|
||||
self.displays[screen].height as i32,
|
||||
)
|
||||
.into(),
|
||||
))
|
||||
.await?;
|
||||
}
|
||||
@@ -212,8 +181,8 @@ impl<'a> Display<'a> {
|
||||
GpuRect {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: self.width,
|
||||
height: self.height,
|
||||
width: self.displays[screen].width,
|
||||
height: self.displays[screen].height,
|
||||
},
|
||||
))
|
||||
.await?;
|
||||
@@ -222,17 +191,24 @@ impl<'a> Display<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
struct Handle<'a> {
|
||||
display: Arc<Display<'a>>,
|
||||
struct Handle {
|
||||
screen: usize,
|
||||
vt: usize,
|
||||
}
|
||||
|
||||
pub struct GpuScheme<'a> {
|
||||
handles: BTreeMap<usize /* file descriptor */, Handle<'a>>,
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
pub inputd_handle: inputd::DisplayHandle,
|
||||
|
||||
handles: BTreeMap<usize /* file descriptor */, Handle>,
|
||||
/// Counter used for file descriptor allocation.
|
||||
next_id: AtomicUsize,
|
||||
displays: Vec<Arc<Display<'a>>>,
|
||||
pub inputd_handle: inputd::DisplayHandle,
|
||||
|
||||
active_vt: usize,
|
||||
vts: HashMap<usize, HashMap<usize, GpuResource>>,
|
||||
displays: Vec<Display>,
|
||||
}
|
||||
|
||||
impl<'a> GpuScheme<'a> {
|
||||
@@ -242,50 +218,45 @@ impl<'a> GpuScheme<'a> {
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
) -> Result<GpuScheme<'a>, Error> {
|
||||
let displays = Self::probe(
|
||||
control_queue.clone(),
|
||||
cursor_queue.clone(),
|
||||
transport.clone(),
|
||||
config,
|
||||
)
|
||||
.await?;
|
||||
let displays = Self::probe(control_queue.clone(), config).await?;
|
||||
|
||||
let inputd_handle = inputd::DisplayHandle::new("virtio-gpu").unwrap();
|
||||
|
||||
Ok(Self {
|
||||
control_queue,
|
||||
cursor_queue,
|
||||
transport,
|
||||
inputd_handle,
|
||||
|
||||
handles: BTreeMap::new(),
|
||||
next_id: AtomicUsize::new(0),
|
||||
|
||||
active_vt: 0,
|
||||
vts: HashMap::new(),
|
||||
displays,
|
||||
inputd_handle,
|
||||
})
|
||||
}
|
||||
|
||||
async fn probe(
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
config: &GpuConfig,
|
||||
) -> Result<Vec<Arc<Display<'a>>>, Error> {
|
||||
) -> Result<Vec<Display>, Error> {
|
||||
let mut display_info = Self::get_display_info(control_queue.clone()).await?;
|
||||
let displays = &mut display_info.display_info[..config.num_scanouts() as usize];
|
||||
|
||||
let mut result = vec![];
|
||||
|
||||
for (id, info) in displays.iter().enumerate() {
|
||||
for info in displays.iter() {
|
||||
log::info!(
|
||||
"virtio-gpu: opening display ({}x{}px)",
|
||||
info.rect().width,
|
||||
info.rect().height
|
||||
);
|
||||
|
||||
let display = Display::new(
|
||||
control_queue.clone(),
|
||||
cursor_queue.clone(),
|
||||
transport.clone(),
|
||||
id,
|
||||
);
|
||||
|
||||
result.push(Arc::new(display));
|
||||
result.push(Display {
|
||||
width: info.rect().width,
|
||||
height: info.rect().height,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
@@ -314,13 +285,13 @@ impl<'a> GpuScheme<'a> {
|
||||
VtEventKind::Activate => {
|
||||
log::info!("activate {}", vt_event.vt);
|
||||
|
||||
for display in &self.displays {
|
||||
for id in 0..self.displays.len() {
|
||||
log::warn!("virtio-gpu: activating");
|
||||
|
||||
futures::executor::block_on(display.set_scanout(vt_event.vt)).unwrap();
|
||||
|
||||
*display.active_vt.borrow_mut() = vt_event.vt;
|
||||
futures::executor::block_on(self.set_scanout(vt_event.vt, id)).unwrap();
|
||||
}
|
||||
|
||||
self.active_vt = vt_event.vt;
|
||||
}
|
||||
|
||||
VtEventKind::Deactivate => {
|
||||
@@ -349,46 +320,45 @@ impl<'a> Scheme for GpuScheme<'a> {
|
||||
|
||||
dbg!(vt, id);
|
||||
|
||||
let display = self.displays.get(id).ok_or(SysError::new(EINVAL))?;
|
||||
if id >= self.displays.len() {
|
||||
return Err(SysError::new(EINVAL));
|
||||
};
|
||||
|
||||
let fd = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.insert(
|
||||
fd,
|
||||
Handle {
|
||||
display: display.clone(),
|
||||
vt,
|
||||
},
|
||||
);
|
||||
self.handles.insert(fd, Handle { screen: id, vt });
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result<usize> {
|
||||
let handle = self.handles.get(&id).unwrap();
|
||||
let bytes_copied = futures::executor::block_on(handle.display.get_fpath(buf)).unwrap();
|
||||
Ok(bytes_copied)
|
||||
let path = format!(
|
||||
"display.virtio-gpu:3.0/{}/{}",
|
||||
self.displays[handle.screen].width, self.displays[handle.screen].height
|
||||
);
|
||||
buf[..path.len()].copy_from_slice(path.as_bytes());
|
||||
Ok(path.len())
|
||||
}
|
||||
|
||||
fn fsync(&mut self, id: usize) -> syscall::Result<usize> {
|
||||
let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?;
|
||||
if handle.vt != *handle.display.active_vt.borrow() {
|
||||
let handle = self.handles.get(&id).ok_or(SysError::new(EBADF))?;
|
||||
if handle.vt != self.active_vt {
|
||||
// This is a protection against background VT's spamming us with flush requests. We will
|
||||
// flush the resource on the next scanout anyway
|
||||
return Ok(0);
|
||||
}
|
||||
futures::executor::block_on(handle.display.flush(handle.vt, None)).unwrap();
|
||||
futures::executor::block_on(self.flush(handle.vt, handle.screen, None)).unwrap();
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn read(
|
||||
&mut self,
|
||||
_id: usize,
|
||||
id: usize,
|
||||
_buf: &mut [u8],
|
||||
_offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
) -> syscall::Result<usize> {
|
||||
// TODO: figure out how to get input lol
|
||||
log::warn!("virtio_gpu::read is a stub!");
|
||||
Ok(0)
|
||||
let _handle = self.handles.get(&id).ok_or(SysError::new(EBADF))?;
|
||||
Err(SysError::new(EINVAL))
|
||||
}
|
||||
|
||||
fn write(
|
||||
@@ -398,9 +368,9 @@ impl<'a> Scheme for GpuScheme<'a> {
|
||||
_offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
) -> syscall::Result<usize> {
|
||||
let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?;
|
||||
let handle = self.handles.get(&id).ok_or(SysError::new(EBADF))?;
|
||||
|
||||
if handle.vt != *handle.display.active_vt.borrow() {
|
||||
if handle.vt != self.active_vt {
|
||||
// This is a protection against background VT's spamming us with flush requests. We will
|
||||
// flush the resource on the next scanout anyway
|
||||
return Ok(buf.len());
|
||||
@@ -413,12 +383,13 @@ impl<'a> Scheme for GpuScheme<'a> {
|
||||
)
|
||||
};
|
||||
|
||||
futures::executor::block_on(handle.display.flush(handle.vt, Some(damage))).unwrap();
|
||||
futures::executor::block_on(self.flush(handle.vt, handle.screen, Some(damage))).unwrap();
|
||||
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn close(&mut self, _id: usize) -> syscall::Result<usize> {
|
||||
fn close(&mut self, id: usize) -> syscall::Result<usize> {
|
||||
self.handles.remove(&id).ok_or(SysError::new(EBADF))?;
|
||||
Ok(0)
|
||||
}
|
||||
fn mmap_prep(
|
||||
@@ -430,9 +401,8 @@ impl<'a> Scheme for GpuScheme<'a> {
|
||||
) -> syscall::Result<usize> {
|
||||
log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size);
|
||||
let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?;
|
||||
let ptr =
|
||||
futures::executor::block_on(handle.display.mmap_screen(handle.vt, offset as usize))
|
||||
.unwrap();
|
||||
Ok(ptr as usize)
|
||||
let (_, ptr) =
|
||||
futures::executor::block_on(self.res_for_screen(handle.vt, handle.screen)).unwrap();
|
||||
Ok(unsafe { ptr.offset(offset as isize) } as usize)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user