Merge branch 'misc_graphics_cleanups' into 'master'
Various cleanups for the graphics subsystem See merge request redox-os/drivers!225
This commit is contained in:
Generated
-7
@@ -941,12 +941,6 @@ dependencies = [
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "paste"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||
|
||||
[[package]]
|
||||
name = "paw"
|
||||
version = "1.0.0"
|
||||
@@ -1778,7 +1772,6 @@ dependencies = [
|
||||
"libredox",
|
||||
"log",
|
||||
"orbclient",
|
||||
"paste",
|
||||
"pcid",
|
||||
"redox-daemon",
|
||||
"redox_event",
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
use std::alloc::{self, Layout};
|
||||
use std::ptr;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub struct OffscreenBuffer {
|
||||
ptr: NonNull<[u32]>,
|
||||
}
|
||||
|
||||
impl OffscreenBuffer {
|
||||
#[inline]
|
||||
fn layout(len: usize) -> Layout {
|
||||
// optimizes to an integer mul
|
||||
Layout::array::<u32>(len).unwrap().align_to(4096).unwrap()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn new(len: usize) -> Self {
|
||||
let layout = Self::layout(len);
|
||||
let ptr = unsafe { alloc::alloc_zeroed(layout) };
|
||||
let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len);
|
||||
let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
|
||||
OffscreenBuffer { ptr }
|
||||
}
|
||||
|
||||
pub fn ptr(&self) -> *mut u8 {
|
||||
self.ptr.as_mut_ptr().cast::<u8>()
|
||||
}
|
||||
}
|
||||
impl Drop for OffscreenBuffer {
|
||||
fn drop(&mut self) {
|
||||
let layout = Self::layout(self.ptr.len());
|
||||
unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) };
|
||||
}
|
||||
}
|
||||
impl std::ops::Deref for OffscreenBuffer {
|
||||
type Target = [u32];
|
||||
fn deref(&self) -> &[u32] {
|
||||
unsafe { self.ptr.as_ref() }
|
||||
}
|
||||
}
|
||||
impl std::ops::DerefMut for OffscreenBuffer {
|
||||
fn deref_mut(&mut self) -> &mut [u32] {
|
||||
unsafe { self.ptr.as_mut() }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
use std::ptr;
|
||||
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
pub struct FrameBuffer {
|
||||
pub onscreen: *mut [u32],
|
||||
pub phys: usize,
|
||||
@@ -58,36 +56,4 @@ impl FrameBuffer {
|
||||
let stride = parse_number(parts.next()?)?;
|
||||
Some(Self::new(phys, width, height, stride))
|
||||
}
|
||||
|
||||
pub unsafe fn resize(&mut self, width: usize, height: usize, stride: usize) {
|
||||
// Unmap old onscreen
|
||||
unsafe {
|
||||
let slice = self.onscreen;
|
||||
libredox::call::munmap(slice.cast(), (slice.len() * 4).next_multiple_of(PAGE_SIZE))
|
||||
.expect("vesad: failed to unmap framebuffer");
|
||||
}
|
||||
|
||||
// Map new onscreen
|
||||
self.onscreen = unsafe {
|
||||
let size = stride * height;
|
||||
let onscreen_ptr = common::physmap(
|
||||
self.phys,
|
||||
size * 4,
|
||||
common::Prot {
|
||||
read: true,
|
||||
write: true,
|
||||
},
|
||||
common::MemoryType::WriteCombining,
|
||||
)
|
||||
.expect("vesad: failed to map framebuffer") as *mut u32;
|
||||
ptr::write_bytes(onscreen_ptr, 0, size);
|
||||
|
||||
ptr::slice_from_raw_parts_mut(onscreen_ptr, size)
|
||||
};
|
||||
|
||||
// Update size
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
self.stride = stride;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#![feature(int_roundings, slice_ptr_get)]
|
||||
extern crate orbclient;
|
||||
extern crate syscall;
|
||||
|
||||
@@ -12,7 +11,6 @@ use std::os::fd::AsRawFd;
|
||||
use crate::framebuffer::FrameBuffer;
|
||||
use crate::scheme::FbAdapter;
|
||||
|
||||
mod display;
|
||||
mod framebuffer;
|
||||
mod scheme;
|
||||
mod screen;
|
||||
|
||||
@@ -25,7 +25,7 @@ impl GraphicsAdapter for FbAdapter {
|
||||
}
|
||||
|
||||
fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8 {
|
||||
resource.offscreen.ptr()
|
||||
resource.ptr()
|
||||
}
|
||||
|
||||
fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource) {
|
||||
|
||||
@@ -1,25 +1,44 @@
|
||||
use std::alloc::{self, Layout};
|
||||
use std::convert::TryInto;
|
||||
use std::{cmp, ptr};
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
use driver_graphics::Resource;
|
||||
use inputd::Damage;
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
use crate::display::OffscreenBuffer;
|
||||
use crate::framebuffer::FrameBuffer;
|
||||
|
||||
pub struct GraphicScreen {
|
||||
pub width: usize,
|
||||
pub height: usize,
|
||||
pub offscreen: OffscreenBuffer,
|
||||
ptr: NonNull<[u32]>,
|
||||
}
|
||||
|
||||
impl GraphicScreen {
|
||||
pub fn new(width: usize, height: usize) -> GraphicScreen {
|
||||
GraphicScreen {
|
||||
width,
|
||||
height,
|
||||
offscreen: OffscreenBuffer::new(width * height),
|
||||
}
|
||||
let len = width * height;
|
||||
let layout = Self::layout(len);
|
||||
let ptr = unsafe { alloc::alloc_zeroed(layout) };
|
||||
let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len);
|
||||
let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout));
|
||||
|
||||
GraphicScreen { width, height, ptr }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn layout(len: usize) -> Layout {
|
||||
// optimizes to an integer mul
|
||||
Layout::array::<u32>(len)
|
||||
.unwrap()
|
||||
.align_to(PAGE_SIZE)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GraphicScreen {
|
||||
fn drop(&mut self) {
|
||||
let layout = Self::layout(self.ptr.len());
|
||||
unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,49 +53,8 @@ impl Resource for GraphicScreen {
|
||||
}
|
||||
|
||||
impl GraphicScreen {
|
||||
pub fn resize(&mut self, width: usize, height: usize) {
|
||||
//TODO: Fix issue with mapped screens
|
||||
|
||||
if width != self.width || height != self.height {
|
||||
println!("Resize display to {}, {}", width, height);
|
||||
|
||||
let size = width * height;
|
||||
let mut offscreen = OffscreenBuffer::new(size);
|
||||
|
||||
let mut old_ptr = self.offscreen.as_ptr();
|
||||
let mut new_ptr = offscreen.as_mut_ptr();
|
||||
|
||||
for _y in 0..cmp::min(height, self.height) {
|
||||
unsafe {
|
||||
ptr::copy(old_ptr, new_ptr, cmp::min(width, self.width));
|
||||
if width > self.width {
|
||||
ptr::write_bytes(
|
||||
new_ptr.offset(self.width as isize),
|
||||
0,
|
||||
width - self.width,
|
||||
);
|
||||
}
|
||||
old_ptr = old_ptr.offset(self.width as isize);
|
||||
new_ptr = new_ptr.offset(width as isize);
|
||||
}
|
||||
}
|
||||
|
||||
if height > self.height {
|
||||
for _y in self.height..height {
|
||||
unsafe {
|
||||
ptr::write_bytes(new_ptr, 0, width);
|
||||
new_ptr = new_ptr.offset(width as isize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.width = width;
|
||||
self.height = height;
|
||||
|
||||
self.offscreen = offscreen;
|
||||
} else {
|
||||
println!("Display is already {}, {}", width, height);
|
||||
};
|
||||
pub fn ptr(&self) -> *mut u8 {
|
||||
self.ptr.as_ptr().cast::<u8>()
|
||||
}
|
||||
|
||||
pub fn sync(&self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) {
|
||||
@@ -95,7 +73,7 @@ impl GraphicScreen {
|
||||
|
||||
let row_pixel_count = w;
|
||||
|
||||
let mut offscreen_ptr = self.offscreen.as_ptr();
|
||||
let mut offscreen_ptr = self.ptr.as_ptr() as *mut u32;
|
||||
let mut onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable
|
||||
|
||||
unsafe {
|
||||
|
||||
@@ -9,7 +9,6 @@ log = "0.4"
|
||||
static_assertions = "1.1.0"
|
||||
futures = { version = "0.3.28", features = ["executor"] }
|
||||
anyhow = "1.0.71"
|
||||
paste = "1.0.13"
|
||||
|
||||
common = { path = "../../common" }
|
||||
driver-graphics = { path = "../driver-graphics" }
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
|
||||
#![feature(int_roundings)]
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
@@ -37,28 +36,6 @@ mod scheme;
|
||||
// const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0;
|
||||
const VIRTIO_GPU_MAX_SCANOUTS: usize = 16;
|
||||
|
||||
macro_rules! make_getter_setter {
|
||||
($($field:ident: $return_ty:ty),*) => {
|
||||
$(
|
||||
pub fn $field(&self) -> $return_ty {
|
||||
self.$field.get()
|
||||
}
|
||||
|
||||
paste::item! {
|
||||
pub fn [<set_ $field>](&mut self, value: $return_ty) {
|
||||
self.$field.set(value)
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
|
||||
(@$field:ident: $return_ty:ty) => {
|
||||
pub fn $field(&mut self, value: $return_ty) {
|
||||
self.$field.set(value)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct GpuConfig {
|
||||
/// Signals pending events to the driver.
|
||||
@@ -137,18 +114,18 @@ static_assertions::const_assert_eq!(core::mem::size_of::<CommandTy>(), 4);
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct ControlHeader {
|
||||
pub ty: VolatileCell<CommandTy>,
|
||||
pub flags: VolatileCell<u32>,
|
||||
pub fence_id: VolatileCell<u64>,
|
||||
pub ctx_id: VolatileCell<u32>,
|
||||
pub ring_index: VolatileCell<u8>,
|
||||
pub ty: CommandTy,
|
||||
pub flags: u32,
|
||||
pub fence_id: u64,
|
||||
pub ctx_id: u32,
|
||||
pub ring_index: u8,
|
||||
padding: [u8; 3],
|
||||
}
|
||||
|
||||
impl ControlHeader {
|
||||
pub fn with_ty(ty: CommandTy) -> Self {
|
||||
Self {
|
||||
ty: VolatileCell::new(ty),
|
||||
ty,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -157,11 +134,11 @@ impl ControlHeader {
|
||||
impl Default for ControlHeader {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
ty: VolatileCell::new(CommandTy::Undefined),
|
||||
flags: VolatileCell::new(0),
|
||||
fence_id: VolatileCell::new(0),
|
||||
ctx_id: VolatileCell::new(0),
|
||||
ring_index: VolatileCell::new(0),
|
||||
ty: CommandTy::Undefined,
|
||||
flags: 0,
|
||||
fence_id: 0,
|
||||
ctx_id: 0,
|
||||
ring_index: 0,
|
||||
padding: [0; 3],
|
||||
}
|
||||
}
|
||||
@@ -190,16 +167,9 @@ impl GpuRect {
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct DisplayInfo {
|
||||
rect: UnsafeCell<GpuRect>,
|
||||
pub enabled: VolatileCell<u32>,
|
||||
pub flags: VolatileCell<u32>,
|
||||
}
|
||||
|
||||
impl DisplayInfo {
|
||||
pub fn rect(&self) -> &GpuRect {
|
||||
// SAFETY: We never give out mutable references to `self.rect`.
|
||||
unsafe { &*self.rect.get() }
|
||||
}
|
||||
rect: GpuRect,
|
||||
pub enabled: u32,
|
||||
pub flags: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -213,7 +183,7 @@ impl Default for GetDisplayInfo {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
header: ControlHeader {
|
||||
ty: VolatileCell::new(CommandTy::GetDisplayInfo),
|
||||
ty: CommandTy::GetDisplayInfo,
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
@@ -247,31 +217,20 @@ pub enum ResourceFormat {
|
||||
#[repr(C)]
|
||||
pub struct ResourceCreate2d {
|
||||
pub header: ControlHeader,
|
||||
|
||||
// FIXME we can likely use regular loads and stores as the ring buffer should provide the
|
||||
// necessary synchronization.
|
||||
resource_id: VolatileCell<ResourceId>,
|
||||
format: VolatileCell<ResourceFormat>,
|
||||
width: VolatileCell<u32>,
|
||||
height: VolatileCell<u32>,
|
||||
resource_id: ResourceId,
|
||||
format: ResourceFormat,
|
||||
width: u32,
|
||||
height: u32,
|
||||
}
|
||||
|
||||
impl ResourceCreate2d {
|
||||
make_getter_setter!(resource_id: ResourceId, format: ResourceFormat, width: u32, height: u32);
|
||||
}
|
||||
|
||||
impl Default for ResourceCreate2d {
|
||||
fn default() -> Self {
|
||||
fn new(resource_id: ResourceId, format: ResourceFormat, width: u32, height: u32) -> Self {
|
||||
Self {
|
||||
header: ControlHeader {
|
||||
ty: VolatileCell::new(CommandTy::ResourceCreate2d),
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
resource_id: VolatileCell::new(ResourceId(0)),
|
||||
format: VolatileCell::new(ResourceFormat::Unknown),
|
||||
width: VolatileCell::new(0),
|
||||
height: VolatileCell::new(0),
|
||||
header: ControlHeader::with_ty(CommandTy::ResourceCreate2d),
|
||||
resource_id,
|
||||
format,
|
||||
width,
|
||||
height,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -392,11 +351,7 @@ pub struct XferToHost2d {
|
||||
impl XferToHost2d {
|
||||
pub fn new(resource_id: ResourceId, rect: GpuRect, offset: u64) -> Self {
|
||||
Self {
|
||||
header: ControlHeader {
|
||||
ty: VolatileCell::new(CommandTy::TransferToHost2d),
|
||||
..Default::default()
|
||||
},
|
||||
|
||||
header: ControlHeader::with_ty(CommandTy::TransferToHost2d),
|
||||
rect,
|
||||
offset,
|
||||
resource_id,
|
||||
@@ -437,7 +392,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
device.transport.run_device();
|
||||
deamon.ready().unwrap();
|
||||
|
||||
let mut scheme = futures::executor::block_on(scheme::GpuScheme::new(
|
||||
let (mut scheme, mut inputd_handle) = futures::executor::block_on(scheme::GpuScheme::new(
|
||||
config,
|
||||
control_queue.clone(),
|
||||
cursor_queue.clone(),
|
||||
@@ -455,14 +410,14 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
EventQueue::new().expect("virtio-gpud: failed to create event queue");
|
||||
event_queue
|
||||
.subscribe(
|
||||
scheme.inputd_handle.inner().as_raw_fd() as usize,
|
||||
inputd_handle.inner().as_raw_fd() as usize,
|
||||
Source::Input,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.unwrap();
|
||||
event_queue
|
||||
.subscribe(
|
||||
scheme.inner.event_handle().raw(),
|
||||
scheme.event_handle().raw(),
|
||||
Source::Scheme,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
@@ -475,17 +430,15 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
{
|
||||
match event {
|
||||
Source::Input => {
|
||||
while let Some(vt_event) = scheme
|
||||
.inputd_handle
|
||||
while let Some(vt_event) = inputd_handle
|
||||
.read_vt_event()
|
||||
.expect("virtio-gpud: failed to read display handle")
|
||||
{
|
||||
scheme.inner.handle_vt_event(vt_event);
|
||||
scheme.handle_vt_event(vt_event);
|
||||
}
|
||||
}
|
||||
Source::Scheme => {
|
||||
scheme
|
||||
.inner
|
||||
.tick()
|
||||
.expect("virtio-gpud: failed to process scheme events");
|
||||
}
|
||||
|
||||
@@ -2,13 +2,12 @@ use std::sync::Arc;
|
||||
|
||||
use common::{dma::Dma, sgl};
|
||||
use driver_graphics::{GraphicsAdapter, GraphicsScheme, Resource};
|
||||
use inputd::Damage;
|
||||
use inputd::{Damage, DisplayHandle};
|
||||
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags};
|
||||
use virtio_core::transport::{Error, Queue, Transport};
|
||||
use virtio_core::utils::VolatileCell;
|
||||
|
||||
use crate::*;
|
||||
|
||||
@@ -67,10 +66,25 @@ impl VirtGpuAdapter<'_> {
|
||||
|
||||
async fn flush_resource_inner(&self, flush: ResourceFlush) -> Result<(), Error> {
|
||||
let header = self.send_request(Dma::new(flush)?).await?;
|
||||
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
|
||||
assert_eq!(header.ty, CommandTy::RespOkNodata);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_display_info(&self) -> Result<Dma<GetDisplayInfo>, Error> {
|
||||
let header = Dma::new(ControlHeader::with_ty(CommandTy::GetDisplayInfo))?;
|
||||
|
||||
let response = Dma::new(GetDisplayInfo::default())?;
|
||||
let command = ChainBuilder::new()
|
||||
.chain(Buffer::new(&header))
|
||||
.chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY))
|
||||
.build();
|
||||
|
||||
self.control_queue.send(command).await;
|
||||
assert!(response.header.ty == CommandTy::RespOkDisplayInfo);
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphicsAdapter for VirtGpuAdapter<'_> {
|
||||
@@ -100,17 +114,18 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> {
|
||||
let res_id = ResourceId::alloc();
|
||||
|
||||
// Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`.
|
||||
let mut request = Dma::new(ResourceCreate2d::default()).unwrap();
|
||||
|
||||
request.set_width(width);
|
||||
request.set_height(height);
|
||||
request.set_format(ResourceFormat::Bgrx);
|
||||
request.set_resource_id(res_id);
|
||||
let request = Dma::new(ResourceCreate2d::new(
|
||||
res_id,
|
||||
ResourceFormat::Bgrx,
|
||||
width,
|
||||
height,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
let header = self.send_request(request).await.unwrap();
|
||||
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
|
||||
assert_eq!(header.ty, CommandTy::RespOkNodata);
|
||||
|
||||
// Use the allocated framebuffer from tthe guest ram, and attach it as backing
|
||||
// Use the allocated framebuffer from the guest ram, and attach it as backing
|
||||
// storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`.
|
||||
|
||||
let mut mem_entries =
|
||||
@@ -133,7 +148,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> {
|
||||
.build();
|
||||
|
||||
self.control_queue.send(command).await;
|
||||
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
|
||||
assert_eq!(header.ty, CommandTy::RespOkNodata);
|
||||
|
||||
VirtGpuResource {
|
||||
id: res_id,
|
||||
@@ -153,16 +168,11 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> {
|
||||
let scanout_request = Dma::new(SetScanout::new(
|
||||
display_id as u32,
|
||||
resource.id,
|
||||
GpuRect::new(
|
||||
0,
|
||||
0,
|
||||
self.displays[display_id].width,
|
||||
self.displays[display_id].height,
|
||||
),
|
||||
GpuRect::new(0, 0, resource.width, resource.height),
|
||||
))
|
||||
.unwrap();
|
||||
let header = self.send_request(scanout_request).await.unwrap();
|
||||
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
|
||||
assert_eq!(header.ty, CommandTy::RespOkNodata);
|
||||
});
|
||||
|
||||
self.flush_resource(display_id, resource, None);
|
||||
@@ -187,7 +197,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> {
|
||||
))
|
||||
.unwrap();
|
||||
let header = self.send_request(req).await.unwrap();
|
||||
assert_eq!(header.ty.get(), CommandTy::RespOkNodata);
|
||||
assert_eq!(header.ty, CommandTy::RespOkNodata);
|
||||
|
||||
if let Some(damage) = damage {
|
||||
for damage in damage {
|
||||
@@ -217,86 +227,53 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GpuScheme<'a> {
|
||||
pub inner: GraphicsScheme<VirtGpuAdapter<'a>>,
|
||||
pub inputd_handle: inputd::DisplayHandle,
|
||||
}
|
||||
pub struct GpuScheme {}
|
||||
|
||||
impl<'a> GpuScheme<'a> {
|
||||
impl<'a> GpuScheme {
|
||||
pub async fn new(
|
||||
config: &'a mut GpuConfig,
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
) -> Result<GpuScheme<'a>, Error> {
|
||||
let displays = Self::probe(control_queue.clone(), config).await?;
|
||||
) -> Result<(GraphicsScheme<VirtGpuAdapter<'a>>, DisplayHandle), Error> {
|
||||
let mut adapter = VirtGpuAdapter {
|
||||
control_queue,
|
||||
cursor_queue,
|
||||
transport,
|
||||
displays: vec![],
|
||||
};
|
||||
|
||||
let inputd_handle = inputd::DisplayHandle::new("virtio-gpu").unwrap();
|
||||
let mut display_info = adapter.get_display_info().await?;
|
||||
let raw_displays = &mut display_info.display_info[..config.num_scanouts() as usize];
|
||||
|
||||
Ok(Self {
|
||||
inner: GraphicsScheme::new(
|
||||
VirtGpuAdapter {
|
||||
control_queue,
|
||||
cursor_queue,
|
||||
transport,
|
||||
displays,
|
||||
},
|
||||
"display.virtio-gpu".to_owned(),
|
||||
),
|
||||
inputd_handle,
|
||||
})
|
||||
}
|
||||
|
||||
async fn probe(
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
config: &GpuConfig,
|
||||
) -> 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 info in displays.iter() {
|
||||
for info in raw_displays.iter() {
|
||||
log::info!(
|
||||
"virtio-gpu: opening display ({}x{}px)",
|
||||
info.rect().width,
|
||||
info.rect().height
|
||||
info.rect.width,
|
||||
info.rect.height
|
||||
);
|
||||
|
||||
if info.rect().width == 0 || info.rect().height == 0 {
|
||||
if info.rect.width == 0 || info.rect.height == 0 {
|
||||
// QEMU gives all displays other than the first a zero width and height, but trying
|
||||
// to attach a zero sized framebuffer to the display will result an error, so
|
||||
// default to 640x480px.
|
||||
result.push(Display {
|
||||
adapter.displays.push(Display {
|
||||
width: 640,
|
||||
height: 480,
|
||||
});
|
||||
} else {
|
||||
result.push(Display {
|
||||
width: info.rect().width,
|
||||
height: info.rect().height,
|
||||
adapter.displays.push(Display {
|
||||
width: info.rect.width,
|
||||
height: info.rect.height,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
let inputd_handle = DisplayHandle::new("virtio-gpu").unwrap();
|
||||
|
||||
async fn get_display_info(control_queue: Arc<Queue<'a>>) -> Result<Dma<GetDisplayInfo>, Error> {
|
||||
let header = Dma::new(ControlHeader {
|
||||
ty: VolatileCell::new(CommandTy::GetDisplayInfo),
|
||||
..Default::default()
|
||||
})?;
|
||||
|
||||
let response = Dma::new(GetDisplayInfo::default())?;
|
||||
let command = ChainBuilder::new()
|
||||
.chain(Buffer::new(&header))
|
||||
.chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY))
|
||||
.build();
|
||||
|
||||
control_queue.send(command).await;
|
||||
assert!(response.header.ty.get() == CommandTy::RespOkDisplayInfo);
|
||||
|
||||
Ok(response)
|
||||
Ok((
|
||||
GraphicsScheme::new(adapter, "display.virtio-gpu".to_owned()),
|
||||
inputd_handle,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user