graphics/virtio-gpud: Handle VIRTIO_GPU_EVENT_DISPLAY
This doesn't yet provide a way for individual consumers to resize their own framebuffer in response to the display changing size.
This commit is contained in:
@@ -31,7 +31,7 @@ use virtio_core::MSIX_PRIMARY_VECTOR;
|
||||
|
||||
mod scheme;
|
||||
|
||||
// const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0;
|
||||
const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0;
|
||||
const VIRTIO_GPU_MAX_SCANOUTS: usize = 16;
|
||||
|
||||
#[repr(C)]
|
||||
@@ -457,6 +457,8 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
.transport
|
||||
.setup_queue(MSIX_PRIMARY_VECTOR, &device.irq_handle)?;
|
||||
|
||||
device.transport.setup_config_notify(MSIX_PRIMARY_VECTOR);
|
||||
|
||||
device.transport.run_device();
|
||||
deamon.ready().unwrap();
|
||||
|
||||
@@ -471,6 +473,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
enum Source {
|
||||
Input,
|
||||
Scheme,
|
||||
Interrupt,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -490,8 +493,15 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.unwrap();
|
||||
event_queue
|
||||
.subscribe(
|
||||
device.irq_handle.as_raw_fd() as usize,
|
||||
Source::Interrupt,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let all = [Source::Input, Source::Scheme];
|
||||
let all = [Source::Input, Source::Scheme, Source::Interrupt];
|
||||
for event in all
|
||||
.into_iter()
|
||||
.chain(event_queue.map(|e| e.expect("virtio-gpud: failed to get next event").user_data))
|
||||
@@ -510,6 +520,22 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
.tick()
|
||||
.expect("virtio-gpud: failed to process scheme events");
|
||||
}
|
||||
Source::Interrupt => loop {
|
||||
let before_gen = device.transport.config_generation();
|
||||
|
||||
let events = config.events_read.get();
|
||||
|
||||
if events & VIRTIO_GPU_EVENT_DISPLAY != 0 {
|
||||
futures::executor::block_on(scheme.adapter_mut().update_displays(config))
|
||||
.unwrap();
|
||||
config.events_clear.set(VIRTIO_GPU_EVENT_DISPLAY);
|
||||
}
|
||||
|
||||
let after_gen = device.transport.config_generation();
|
||||
if before_gen == after_gen {
|
||||
break;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,40 @@ pub struct VirtGpuAdapter<'a> {
|
||||
}
|
||||
|
||||
impl VirtGpuAdapter<'_> {
|
||||
pub async fn update_displays(&mut self, config: &mut GpuConfig) -> Result<(), Error> {
|
||||
let mut display_info = self.get_display_info().await?;
|
||||
let raw_displays = &mut display_info.display_info[..config.num_scanouts() as usize];
|
||||
|
||||
self.displays.resize(
|
||||
raw_displays.len(),
|
||||
Display {
|
||||
width: 0,
|
||||
height: 0,
|
||||
active_resource: None,
|
||||
},
|
||||
);
|
||||
for (i, info) in raw_displays.iter().enumerate() {
|
||||
log::info!(
|
||||
"virtio-gpu: display {i} ({}x{}px)",
|
||||
info.rect.width,
|
||||
info.rect.height
|
||||
);
|
||||
|
||||
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.
|
||||
self.displays[i].width = 640;
|
||||
self.displays[i].height = 480;
|
||||
} else {
|
||||
self.displays[i].width = info.rect.width;
|
||||
self.displays[i].height = info.rect.height;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn send_request<T>(&self, request: Dma<T>) -> Result<Dma<ControlHeader>, Error> {
|
||||
let header = Dma::new(ControlHeader::default())?;
|
||||
let command = ChainBuilder::new()
|
||||
@@ -350,7 +384,7 @@ pub struct GpuScheme {}
|
||||
|
||||
impl<'a> GpuScheme {
|
||||
pub async fn new(
|
||||
config: &'a mut GpuConfig,
|
||||
config: &mut GpuConfig,
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
@@ -362,33 +396,7 @@ impl<'a> GpuScheme {
|
||||
displays: vec![],
|
||||
};
|
||||
|
||||
let mut display_info = adapter.get_display_info().await?;
|
||||
let raw_displays = &mut display_info.display_info[..config.num_scanouts() as usize];
|
||||
|
||||
for info in raw_displays.iter() {
|
||||
log::info!(
|
||||
"virtio-gpu: opening display ({}x{}px)",
|
||||
info.rect.width,
|
||||
info.rect.height
|
||||
);
|
||||
|
||||
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.
|
||||
adapter.displays.push(Display {
|
||||
width: 640,
|
||||
height: 480,
|
||||
active_resource: None,
|
||||
});
|
||||
} else {
|
||||
adapter.displays.push(Display {
|
||||
width: info.rect.width,
|
||||
height: info.rect.height,
|
||||
active_resource: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
adapter.update_displays(config).await?;
|
||||
|
||||
let scheme = GraphicsScheme::new(adapter, "display.virtio-gpu".to_owned());
|
||||
let handle = DisplayHandle::new("virtio-gpu").unwrap();
|
||||
|
||||
@@ -492,6 +492,12 @@ pub trait Transport: Sync + Send {
|
||||
self.insert_status(DeviceStatusFlags::DRIVER_OK);
|
||||
}
|
||||
|
||||
/// Request to be notified on configuration changes on the given MSI-X vector.
|
||||
fn setup_config_notify(&self, vector: u16);
|
||||
|
||||
/// Each time the device configuration changes this number will be updated.
|
||||
fn config_generation(&self) -> u32;
|
||||
|
||||
/// Creates a new queue.
|
||||
///
|
||||
/// ## Panics
|
||||
@@ -601,6 +607,14 @@ impl Transport for StandardTransport<'_> {
|
||||
assert!((confirm & DeviceStatusFlags::FEATURES_OK) == DeviceStatusFlags::FEATURES_OK);
|
||||
}
|
||||
|
||||
fn setup_config_notify(&self, vector: u16) {
|
||||
self.common.lock().unwrap().config_msix_vector.set(vector);
|
||||
}
|
||||
|
||||
fn config_generation(&self) -> u32 {
|
||||
u32::from(self.common.lock().unwrap().config_generation.get())
|
||||
}
|
||||
|
||||
fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result<Arc<Queue>, Error> {
|
||||
let mut common = self.common.lock().unwrap();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user