drivers/graphics: Implement force probing of connectors in virtio-gpud

This commit is contained in:
bjorn3
2025-12-20 19:07:28 +01:00
parent 0e98a36495
commit 816d661c9d
6 changed files with 85 additions and 32 deletions
+20 -4
View File
@@ -18,7 +18,7 @@ use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket};
use syscall::schemev2::NewFdFlags;
use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL, ENOENT, EOPNOTSUPP};
use crate::objects::{DrmObjectId, DrmObjects};
use crate::objects::{DrmConnector, DrmObjectId, DrmObjects};
pub mod objects;
@@ -36,6 +36,8 @@ pub trait GraphicsAdapter: Sized {
fn get_cap(&self, cap: u32) -> Result<u64>;
fn set_client_cap(&self, cap: u32, value: u64) -> Result<()>;
fn probe_connector(&mut self, connector: &mut DrmConnector<Self>);
/// The maximum amount of displays that could be attached.
///
/// This must be constant for the lifetime of the graphics adapter.
@@ -111,6 +113,9 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
let mut objects = DrmObjects::new();
adapter.init(&mut objects);
for connector in objects.connectors_mut() {
adapter.probe_connector(connector);
}
GraphicsScheme {
adapter,
@@ -523,9 +528,17 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
}),
ipc::MODE_CARD_RES => ipc::DrmModeCardRes::with(payload, |mut data| {
let count = self.adapter.display_count();
let conn_ids = self.objects.connectors().map(|id| id.0).collect::<Vec<_>>();
let conn_ids = self
.objects
.connector_ids()
.map(|id| id.0)
.collect::<Vec<_>>();
let mut crtc_ids = Vec::with_capacity(count);
let enc_ids = self.objects.encoders().map(|id| id.0).collect::<Vec<_>>();
let enc_ids = self
.objects
.encoder_ids()
.map(|id| id.0)
.collect::<Vec<_>>();
let mut fb_ids = Vec::with_capacity(count);
for i in 0..(count as u32) {
crtc_ids.push(crtc_id(i));
@@ -563,7 +576,10 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
ipc::MODE_GET_CONNECTOR => ipc::DrmModeGetConnector::with(payload, |mut data| {
let connector = self
.objects
.get_connector(DrmObjectId(data.connector_id()))?;
.get_connector_mut(DrmObjectId(data.connector_id()))?;
if data.count_modes() == 0 {
self.adapter.probe_connector(connector);
}
data.set_connection(connector.connection as u32);
data.set_modes_ptr(&connector.modes);
data.set_mm_width(connector.mm_width);
@@ -47,7 +47,7 @@ impl<T: GraphicsAdapter> DrmObjects<T> {
connector_id
}
pub fn connectors(&self) -> impl Iterator<Item = DrmObjectId> + use<'_, T> {
pub fn connector_ids(&self) -> impl Iterator<Item = DrmObjectId> + use<'_, T> {
self.objects
.iter()
.filter_map(|(&id, object)| match object.kind {
@@ -56,6 +56,24 @@ impl<T: GraphicsAdapter> DrmObjects<T> {
})
}
pub fn connectors(&self) -> impl Iterator<Item = &DrmConnector<T>> + use<'_, T> {
self.objects
.values()
.filter_map(|object| match &object.kind {
DrmObjectKind::Connector(connector) => Some(connector),
_ => None,
})
}
pub fn connectors_mut(&mut self) -> impl Iterator<Item = &mut DrmConnector<T>> + use<'_, T> {
self.objects
.values_mut()
.filter_map(|object| match &mut object.kind {
DrmObjectKind::Connector(connector) => Some(connector),
_ => None,
})
}
pub fn get_connector(&self, id: DrmObjectId) -> Result<&DrmConnector<T>> {
let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?;
match &object.kind {
@@ -72,7 +90,7 @@ impl<T: GraphicsAdapter> DrmObjects<T> {
}
}
pub fn encoders(&self) -> impl Iterator<Item = DrmObjectId> + use<'_, T> {
pub fn encoder_ids(&self) -> impl Iterator<Item = DrmObjectId> + use<'_, T> {
self.objects
.iter()
.filter_map(|(&id, object)| match object.kind {
+16 -7
View File
@@ -16,13 +16,17 @@ use syscall::{error::EINVAL, PAGE_SIZE};
use super::Device;
pub struct Connector {
framebuffer_id: usize,
}
//TODO: use hardware cursor
pub enum Cursor {}
impl CursorFramebuffer for Cursor {}
impl GraphicsAdapter for Device {
type Connector = ();
type Connector = Connector;
type Framebuffer = DumbFb;
type Cursor = Cursor;
@@ -37,12 +41,9 @@ impl GraphicsAdapter for Device {
fn init(&mut self, objects: &mut DrmObjects<Self>) {
// FIXME enumerate actual connectors
for framebuffer in &self.framebuffers {
for (framebuffer_id, _) in self.framebuffers.iter().enumerate() {
objects.add_connector(DrmConnector {
modes: vec![modeinfo_for_size(
framebuffer.width as u32,
framebuffer.height as u32,
)],
modes: vec![],
encoder_id: DrmObjectId::INVALID,
connector_type: 0,
connector_type_id: 0,
@@ -50,7 +51,7 @@ impl GraphicsAdapter for Device {
mm_width: 0,
mm_height: 0,
subpixel: DrmSubpixelOrder::Unknown,
driver_data: (),
driver_data: Connector { framebuffer_id },
});
}
}
@@ -70,6 +71,14 @@ impl GraphicsAdapter for Device {
}
}
fn probe_connector(&mut self, connector: &mut DrmConnector<Self>) {
let framebuffer = &self.framebuffers[connector.driver_data.framebuffer_id];
connector.modes = vec![modeinfo_for_size(
framebuffer.width as u32,
framebuffer.height as u32,
)];
}
fn display_count(&self) -> usize {
self.framebuffers.len()
}
+2
View File
@@ -67,6 +67,8 @@ impl GraphicsAdapter for FbAdapter {
}
}
fn probe_connector(&mut self, _connector: &mut DrmConnector<Self>) {}
fn display_count(&self) -> usize {
self.framebuffers.len()
}
+5 -1
View File
@@ -23,6 +23,7 @@
use std::os::fd::AsRawFd;
use std::sync::atomic::{AtomicU32, Ordering};
use driver_graphics::GraphicsAdapter;
use event::{user_data, EventQueue};
use pcid_interface::PciFunctionHandle;
@@ -542,7 +543,10 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow:
if events & VIRTIO_GPU_EVENT_DISPLAY != 0 {
let (adapter, objects) = scheme.adapter_and_objects_mut();
futures::executor::block_on(adapter.update_displays(objects)).unwrap();
futures::executor::block_on(async { adapter.update_displays().await.unwrap() });
for connector in objects.connectors_mut() {
adapter.probe_connector(connector);
}
scheme.notify_displays_changed();
scheme
.adapter_mut()
+22 -18
View File
@@ -76,6 +76,7 @@ impl CursorFramebuffer for VirtGpuCursor {}
#[derive(Debug, Copy, Clone)]
pub struct Display {
enabled: bool,
width: u32,
height: u32,
active_resource: Option<ResourceId>,
@@ -90,13 +91,14 @@ pub struct VirtGpuAdapter<'a> {
}
impl VirtGpuAdapter<'_> {
pub async fn update_displays(&mut self, objects: &mut DrmObjects<Self>) -> Result<(), Error> {
pub async fn update_displays(&mut self) -> Result<(), Error> {
let display_info = self.get_display_info().await?;
let raw_displays = &display_info.display_info[..self.config.num_scanouts() as usize];
self.displays.resize(
raw_displays.len(),
Display {
enabled: false,
width: 0,
height: 0,
active_resource: None,
@@ -109,6 +111,8 @@ impl VirtGpuAdapter<'_> {
info.rect.height
);
self.displays[i].enabled = info.enabled != 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
@@ -121,19 +125,6 @@ impl VirtGpuAdapter<'_> {
}
}
for connector in objects.connectors().collect::<Vec<_>>() {
let connector = objects.get_connector_mut(connector).unwrap();
let display = &self.displays[connector.driver_data.display_id as usize];
connector.modes = vec![modeinfo_for_size(display.width, display.height)];
connector.connection =
if raw_displays[connector.driver_data.display_id as usize].enabled != 0 {
DrmConnectorStatus::Connected
} else {
DrmConnectorStatus::Disconnected
};
}
Ok(())
}
@@ -233,6 +224,10 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
}
fn init(&mut self, objects: &mut DrmObjects<Self>) {
futures::executor::block_on(async {
self.update_displays().await.unwrap();
});
for display_id in 0..self.config.num_scanouts.get() {
objects.add_connector(DrmConnector {
modes: vec![],
@@ -246,10 +241,6 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
driver_data: VirtGpuConnector { display_id },
});
}
futures::executor::block_on(async {
self.update_displays(objects).await.unwrap();
});
}
fn get_cap(&self, cap: u32) -> syscall::Result<u64> {
@@ -267,6 +258,19 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
}
}
fn probe_connector(&mut self, connector: &mut DrmConnector<Self>) {
futures::executor::block_on(async {
let display = &self.displays[connector.driver_data.display_id as usize];
connector.modes = vec![modeinfo_for_size(display.width, display.height)];
connector.connection = if display.enabled {
DrmConnectorStatus::Connected
} else {
DrmConnectorStatus::Disconnected
};
});
}
fn display_count(&self) -> usize {
self.displays.len()
}