drivers/graphics: Introduce DrmObjects and track connectors and encoders using it
This commit is contained in:
@@ -8,6 +8,7 @@ use std::mem;
|
||||
use std::mem::transmute;
|
||||
use std::sync::Arc;
|
||||
|
||||
use drm_sys::drm_mode_modeinfo;
|
||||
use graphics_ipc::v1::CursorDamage;
|
||||
use graphics_ipc::v2::Damage;
|
||||
use inputd::{VtEvent, VtEventKind};
|
||||
@@ -17,13 +18,21 @@ use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL, ENOENT, EOPNOTSUPP};
|
||||
|
||||
pub trait GraphicsAdapter {
|
||||
use crate::objects::{DrmObjectId, DrmObjects};
|
||||
|
||||
pub mod objects;
|
||||
|
||||
pub trait GraphicsAdapter: Sized {
|
||||
type Connector;
|
||||
|
||||
type Framebuffer: Framebuffer;
|
||||
type Cursor: CursorFramebuffer;
|
||||
|
||||
fn name(&self) -> &'static [u8];
|
||||
fn desc(&self) -> &'static [u8];
|
||||
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>);
|
||||
|
||||
fn get_cap(&self, cap: u32) -> Result<u64>;
|
||||
fn set_client_cap(&self, cap: u32, value: u64) -> Result<()>;
|
||||
|
||||
@@ -65,6 +74,7 @@ pub struct GraphicsScheme<T: GraphicsAdapter> {
|
||||
scheme_name: String,
|
||||
disable_graphical_debug: Option<File>,
|
||||
socket: Socket,
|
||||
objects: DrmObjects<T>,
|
||||
next_id: usize,
|
||||
handles: BTreeMap<usize, Handle<T>>,
|
||||
|
||||
@@ -90,7 +100,7 @@ enum Handle<T: GraphicsAdapter> {
|
||||
}
|
||||
|
||||
impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
pub fn new(adapter: T, scheme_name: String) -> Self {
|
||||
pub fn new(mut adapter: T, scheme_name: String) -> Self {
|
||||
assert!(scheme_name.starts_with("display"));
|
||||
let socket = Socket::nonblock(&scheme_name).expect("failed to create graphics scheme");
|
||||
|
||||
@@ -99,11 +109,15 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
.expect("vesad: Failed to open /scheme/debug/disable-graphical-debug"),
|
||||
);
|
||||
|
||||
let mut objects = DrmObjects::new();
|
||||
adapter.init(&mut objects);
|
||||
|
||||
GraphicsScheme {
|
||||
adapter,
|
||||
scheme_name,
|
||||
disable_graphical_debug,
|
||||
socket,
|
||||
objects,
|
||||
next_id: 0,
|
||||
handles: BTreeMap::new(),
|
||||
active_vt: 0,
|
||||
@@ -123,6 +137,18 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
&mut self.adapter
|
||||
}
|
||||
|
||||
pub fn objects(&self) -> &DrmObjects<T> {
|
||||
&self.objects
|
||||
}
|
||||
|
||||
pub fn objects_mut(&mut self) -> &mut DrmObjects<T> {
|
||||
&mut self.objects
|
||||
}
|
||||
|
||||
pub fn adapter_and_objects_mut(&mut self) -> (&mut T, &mut DrmObjects<T>) {
|
||||
(&mut self.adapter, &mut self.objects)
|
||||
}
|
||||
|
||||
pub fn handle_vt_event(&mut self, vt_event: VtEvent) {
|
||||
match vt_event.kind {
|
||||
VtEventKind::Activate => {
|
||||
@@ -440,18 +466,10 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
id & 0xFF
|
||||
}
|
||||
|
||||
fn conn_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 8)
|
||||
}
|
||||
|
||||
fn crtc_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 9)
|
||||
}
|
||||
|
||||
fn enc_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 10)
|
||||
}
|
||||
|
||||
fn fb_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 11)
|
||||
}
|
||||
@@ -468,40 +486,6 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
id_index(i) | (1 << 14)
|
||||
}
|
||||
|
||||
fn modeinfo_for_size(width: u32, height: u32) -> drm_sys::drm_mode_modeinfo {
|
||||
let mut modeinfo = drm_sys::drm_mode_modeinfo {
|
||||
// The actual visible display size
|
||||
hdisplay: width as u16,
|
||||
vdisplay: height as u16,
|
||||
|
||||
// These are used to calculate the refresh rate
|
||||
clock: 60 * width * height / 1000,
|
||||
htotal: width as u16,
|
||||
vtotal: height as u16,
|
||||
vscan: 0,
|
||||
vrefresh: 60,
|
||||
|
||||
type_: drm_sys::DRM_MODE_TYPE_PREFERRED | drm_sys::DRM_MODE_TYPE_DRIVER,
|
||||
name: [0; 32],
|
||||
|
||||
// These only matter when modesetting physical display adapters. For
|
||||
// those we should be able to parse the EDID blob.
|
||||
hsync_start: width as u16,
|
||||
hsync_end: width as u16,
|
||||
hskew: 0,
|
||||
vsync_start: height as u16,
|
||||
vsync_end: height as u16,
|
||||
flags: 0,
|
||||
};
|
||||
|
||||
let name = format!("{width}x{height}").into_bytes();
|
||||
for (to, from) in modeinfo.name.iter_mut().zip(name) {
|
||||
*to = from as c_char;
|
||||
}
|
||||
|
||||
modeinfo
|
||||
}
|
||||
|
||||
match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::V1Screen { .. } => {
|
||||
return Err(Error::new(EOPNOTSUPP));
|
||||
@@ -539,14 +523,12 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
}),
|
||||
ipc::MODE_CARD_RES => ipc::DrmModeCardRes::with(payload, |mut data| {
|
||||
let count = self.adapter.display_count();
|
||||
let mut conn_ids = Vec::with_capacity(count);
|
||||
let conn_ids = self.objects.connectors().map(|id| id.0).collect::<Vec<_>>();
|
||||
let mut crtc_ids = Vec::with_capacity(count);
|
||||
let mut enc_ids = Vec::with_capacity(count);
|
||||
let enc_ids = self.objects.encoders().map(|id| id.0).collect::<Vec<_>>();
|
||||
let mut fb_ids = Vec::with_capacity(count);
|
||||
for i in 0..(count as u32) {
|
||||
conn_ids.push(conn_id(i));
|
||||
crtc_ids.push(crtc_id(i));
|
||||
enc_ids.push(enc_id(i));
|
||||
fb_ids.push(fb_id(i));
|
||||
}
|
||||
data.set_fb_id_ptr(&fb_ids);
|
||||
@@ -561,7 +543,6 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
}),
|
||||
ipc::MODE_GET_CRTC => ipc::DrmModeCrtc::with(payload, |mut data| {
|
||||
let i = id_index(data.crtc_id());
|
||||
let (width, height) = self.adapter.display_size(i as usize);
|
||||
//TOOD: connectors
|
||||
data.set_fb_id(fb_id(i));
|
||||
data.set_x(0);
|
||||
@@ -573,21 +554,24 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
Ok(0)
|
||||
}),
|
||||
ipc::MODE_GET_ENCODER => ipc::DrmModeGetEncoder::with(payload, |mut data| {
|
||||
let i = id_index(data.encoder_id());
|
||||
let (width, height) = self.adapter.display_size(i as usize);
|
||||
data.set_crtc_id(crtc_id(i));
|
||||
data.set_possible_crtcs(1 << i);
|
||||
data.set_possible_clones(1 << i);
|
||||
let encoder = self.objects.get_encoder(DrmObjectId(data.encoder_id()))?;
|
||||
data.set_crtc_id(encoder.crtc_id.0);
|
||||
data.set_possible_crtcs(encoder.possible_crtcs);
|
||||
data.set_possible_clones(encoder.possible_clones);
|
||||
Ok(0)
|
||||
}),
|
||||
ipc::MODE_GET_CONNECTOR => ipc::DrmModeGetConnector::with(payload, |mut data| {
|
||||
let i = id_index(data.connector_id());
|
||||
let (width, height) = self.adapter.display_size(i as usize);
|
||||
data.set_connection(1 /* connected */);
|
||||
data.set_modes_ptr(&[modeinfo_for_size(width, height)]);
|
||||
let connector = self
|
||||
.objects
|
||||
.get_connector(DrmObjectId(data.connector_id()))?;
|
||||
data.set_connection(connector.connection as u32);
|
||||
data.set_modes_ptr(&connector.modes);
|
||||
data.set_mm_width(connector.mm_width);
|
||||
data.set_mm_height(connector.mm_width);
|
||||
data.set_subpixel(connector.subpixel as u32);
|
||||
data.set_props_ptr(&[]);
|
||||
data.set_prop_values_ptr(&[]);
|
||||
data.set_encoders_ptr(&[enc_id(i)]);
|
||||
data.set_encoders_ptr(&[connector.encoder_id.0]);
|
||||
Ok(0)
|
||||
}),
|
||||
ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |mut data| {
|
||||
@@ -656,7 +640,6 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
}),
|
||||
ipc::MODE_GET_PLANE => ipc::DrmModeGetPlane::with(payload, |mut data| {
|
||||
let i = id_index(data.plane_id());
|
||||
let (width, height) = self.adapter.display_size(i as usize);
|
||||
data.set_crtc_id(crtc_id(i));
|
||||
data.set_fb_id(fb_id(i));
|
||||
data.set_possible_crtcs(1 << i);
|
||||
@@ -748,3 +731,37 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
self.handles.remove(&id);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn modeinfo_for_size(width: u32, height: u32) -> drm_mode_modeinfo {
|
||||
let mut modeinfo = drm_mode_modeinfo {
|
||||
// The actual visible display size
|
||||
hdisplay: width as u16,
|
||||
vdisplay: height as u16,
|
||||
|
||||
// These are used to calculate the refresh rate
|
||||
clock: 60 * width * height / 1000,
|
||||
htotal: width as u16,
|
||||
vtotal: height as u16,
|
||||
vscan: 0,
|
||||
vrefresh: 60,
|
||||
|
||||
type_: drm_sys::DRM_MODE_TYPE_PREFERRED | drm_sys::DRM_MODE_TYPE_DRIVER,
|
||||
name: [0; 32],
|
||||
|
||||
// These only matter when modesetting physical display adapters. For
|
||||
// those we should be able to parse the EDID blob.
|
||||
hsync_start: width as u16,
|
||||
hsync_end: width as u16,
|
||||
hskew: 0,
|
||||
vsync_start: height as u16,
|
||||
vsync_end: height as u16,
|
||||
flags: 0,
|
||||
};
|
||||
|
||||
let name = format!("{width}x{height}").into_bytes();
|
||||
for (to, from) in modeinfo.name.iter_mut().zip(name) {
|
||||
*to = from as c_char;
|
||||
}
|
||||
|
||||
modeinfo
|
||||
}
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use drm_sys::drm_mode_modeinfo;
|
||||
use syscall::{Error, Result, EINVAL};
|
||||
|
||||
use crate::GraphicsAdapter;
|
||||
|
||||
pub struct DrmObjects<T: GraphicsAdapter> {
|
||||
next_id: DrmObjectId,
|
||||
objects: HashMap<DrmObjectId, DrmObject<T>>,
|
||||
}
|
||||
|
||||
impl<T: GraphicsAdapter> DrmObjects<T> {
|
||||
pub(crate) fn new() -> Self {
|
||||
DrmObjects {
|
||||
next_id: DrmObjectId(1),
|
||||
objects: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_connector(&mut self, connector: DrmConnector<T>) -> DrmObjectId {
|
||||
let connector_id = self.next_id;
|
||||
self.objects.insert(
|
||||
connector_id,
|
||||
DrmObject {
|
||||
kind: DrmObjectKind::Connector(connector),
|
||||
},
|
||||
);
|
||||
self.next_id.0 += 1;
|
||||
|
||||
let encoder_id = self.next_id;
|
||||
self.objects.insert(
|
||||
encoder_id,
|
||||
DrmObject {
|
||||
kind: DrmObjectKind::Encoder(DrmEncoder {
|
||||
crtc_id: DrmObjectId::INVALID,
|
||||
possible_crtcs: 0,
|
||||
possible_clones: 0,
|
||||
}),
|
||||
},
|
||||
);
|
||||
self.next_id.0 += 1;
|
||||
|
||||
// Attach encoder to connector
|
||||
self.get_connector_mut(connector_id).unwrap().encoder_id = encoder_id;
|
||||
|
||||
connector_id
|
||||
}
|
||||
|
||||
pub fn connectors(&self) -> impl Iterator<Item = DrmObjectId> + use<'_, T> {
|
||||
self.objects
|
||||
.iter()
|
||||
.filter_map(|(&id, object)| match object.kind {
|
||||
DrmObjectKind::Connector(_) => Some(id),
|
||||
_ => 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 {
|
||||
DrmObjectKind::Connector(drm_connector) => Ok(drm_connector),
|
||||
_ => Err(Error::new(EINVAL)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_connector_mut(&mut self, id: DrmObjectId) -> Result<&mut DrmConnector<T>> {
|
||||
let object = self.objects.get_mut(&id).ok_or(Error::new(EINVAL))?;
|
||||
match &mut object.kind {
|
||||
DrmObjectKind::Connector(drm_connector) => Ok(drm_connector),
|
||||
_ => Err(Error::new(EINVAL)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn encoders(&self) -> impl Iterator<Item = DrmObjectId> + use<'_, T> {
|
||||
self.objects
|
||||
.iter()
|
||||
.filter_map(|(&id, object)| match object.kind {
|
||||
DrmObjectKind::Encoder(_) => Some(id),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_encoder(&self, id: DrmObjectId) -> Result<&DrmEncoder> {
|
||||
let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?;
|
||||
match &object.kind {
|
||||
DrmObjectKind::Encoder(drm_encoder) => Ok(drm_encoder),
|
||||
_ => Err(Error::new(EINVAL)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_encoder_mut(&mut self, id: DrmObjectId) -> Result<&mut DrmEncoder> {
|
||||
let object = self.objects.get_mut(&id).ok_or(Error::new(EINVAL))?;
|
||||
match &mut object.kind {
|
||||
DrmObjectKind::Encoder(drm_encoder) => Ok(drm_encoder),
|
||||
_ => Err(Error::new(EINVAL)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct DrmObjectId(pub(crate) u32);
|
||||
|
||||
impl DrmObjectId {
|
||||
pub const INVALID: DrmObjectId = DrmObjectId(0);
|
||||
}
|
||||
|
||||
struct DrmObject<T: GraphicsAdapter> {
|
||||
kind: DrmObjectKind<T>,
|
||||
}
|
||||
|
||||
enum DrmObjectKind<T: GraphicsAdapter> {
|
||||
Connector(DrmConnector<T>),
|
||||
Encoder(DrmEncoder),
|
||||
}
|
||||
|
||||
pub struct DrmConnector<T: GraphicsAdapter> {
|
||||
pub modes: Vec<drm_mode_modeinfo>,
|
||||
pub encoder_id: DrmObjectId,
|
||||
pub connector_type: u32,
|
||||
pub connector_type_id: u32,
|
||||
pub connection: DrmConnectorStatus,
|
||||
pub mm_width: u32,
|
||||
pub mm_height: u32,
|
||||
pub subpixel: DrmSubpixelOrder,
|
||||
pub driver_data: T::Connector,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(u32)]
|
||||
pub enum DrmConnectorStatus {
|
||||
Disconnected = 0,
|
||||
Connected = 1,
|
||||
Unknown = 2,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(u32)]
|
||||
pub enum DrmSubpixelOrder {
|
||||
Unknown = 0,
|
||||
HorizontalRGB,
|
||||
HorizontalBGR,
|
||||
VerticalRGB,
|
||||
VerticalBGR,
|
||||
None,
|
||||
}
|
||||
|
||||
// FIXME can we represent connector and encoder using a single struct?
|
||||
pub struct DrmEncoder {
|
||||
pub crtc_id: DrmObjectId,
|
||||
pub possible_crtcs: u32,
|
||||
pub possible_clones: u32,
|
||||
}
|
||||
@@ -4,7 +4,12 @@ use std::alloc::{self, Layout};
|
||||
use std::convert::TryInto;
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
use driver_graphics::{CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter};
|
||||
use driver_graphics::objects::{
|
||||
DrmConnector, DrmConnectorStatus, DrmObjectId, DrmObjects, DrmSubpixelOrder,
|
||||
};
|
||||
use driver_graphics::{
|
||||
modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter,
|
||||
};
|
||||
use graphics_ipc::v1::Damage;
|
||||
use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT};
|
||||
use syscall::{error::EINVAL, PAGE_SIZE};
|
||||
@@ -17,6 +22,8 @@ pub enum Cursor {}
|
||||
impl CursorFramebuffer for Cursor {}
|
||||
|
||||
impl GraphicsAdapter for Device {
|
||||
type Connector = ();
|
||||
|
||||
type Framebuffer = DumbFb;
|
||||
type Cursor = Cursor;
|
||||
|
||||
@@ -28,6 +35,26 @@ impl GraphicsAdapter for Device {
|
||||
b"Intel HD Graphics"
|
||||
}
|
||||
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>) {
|
||||
// FIXME enumerate actual connectors
|
||||
for framebuffer in &self.framebuffers {
|
||||
objects.add_connector(DrmConnector {
|
||||
modes: vec![modeinfo_for_size(
|
||||
framebuffer.width as u32,
|
||||
framebuffer.height as u32,
|
||||
)],
|
||||
encoder_id: DrmObjectId::INVALID,
|
||||
connector_type: 0,
|
||||
connector_type_id: 0,
|
||||
connection: DrmConnectorStatus::Connected,
|
||||
mm_width: 0,
|
||||
mm_height: 0,
|
||||
subpixel: DrmSubpixelOrder::Unknown,
|
||||
driver_data: (),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cap(&self, cap: u32) -> syscall::Result<u64> {
|
||||
match cap {
|
||||
DRM_CAP_DUMB_BUFFER => Ok(1),
|
||||
|
||||
@@ -2,7 +2,12 @@ use std::alloc::{self, Layout};
|
||||
use std::convert::TryInto;
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
use driver_graphics::{CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter};
|
||||
use driver_graphics::objects::{
|
||||
DrmConnector, DrmConnectorStatus, DrmObjectId, DrmObjects, DrmSubpixelOrder,
|
||||
};
|
||||
use driver_graphics::{
|
||||
modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter,
|
||||
};
|
||||
use graphics_ipc::v1::Damage;
|
||||
use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT};
|
||||
use syscall::{EINVAL, PAGE_SIZE};
|
||||
@@ -16,6 +21,8 @@ pub enum VesadCursor {}
|
||||
impl CursorFramebuffer for VesadCursor {}
|
||||
|
||||
impl GraphicsAdapter for FbAdapter {
|
||||
type Connector = ();
|
||||
|
||||
type Framebuffer = GraphicScreen;
|
||||
type Cursor = VesadCursor;
|
||||
|
||||
@@ -27,6 +34,25 @@ impl GraphicsAdapter for FbAdapter {
|
||||
b"VESA"
|
||||
}
|
||||
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>) {
|
||||
for framebuffer in &self.framebuffers {
|
||||
objects.add_connector(DrmConnector {
|
||||
modes: vec![modeinfo_for_size(
|
||||
framebuffer.width as u32,
|
||||
framebuffer.height as u32,
|
||||
)],
|
||||
encoder_id: DrmObjectId::INVALID,
|
||||
connector_type: 0,
|
||||
connector_type_id: 0,
|
||||
connection: DrmConnectorStatus::Connected,
|
||||
mm_width: 0,
|
||||
mm_height: 0,
|
||||
subpixel: DrmSubpixelOrder::Unknown,
|
||||
driver_data: (),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cap(&self, cap: u32) -> syscall::Result<u64> {
|
||||
match cap {
|
||||
DRM_CAP_DUMB_BUFFER => Ok(1),
|
||||
|
||||
@@ -477,12 +477,12 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow:
|
||||
device.transport.run_device();
|
||||
deamon.ready();
|
||||
|
||||
let (mut scheme, mut inputd_handle) = futures::executor::block_on(scheme::GpuScheme::new(
|
||||
let (mut scheme, mut inputd_handle) = scheme::GpuScheme::new(
|
||||
config,
|
||||
control_queue.clone(),
|
||||
cursor_queue.clone(),
|
||||
device.transport.clone(),
|
||||
))?;
|
||||
)?;
|
||||
|
||||
user_data! {
|
||||
enum Source {
|
||||
@@ -538,13 +538,17 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow:
|
||||
Source::Interrupt => loop {
|
||||
let before_gen = device.transport.config_generation();
|
||||
|
||||
let events = config.events_read.get();
|
||||
let events = scheme.adapter().config.events_read.get();
|
||||
|
||||
if events & VIRTIO_GPU_EVENT_DISPLAY != 0 {
|
||||
futures::executor::block_on(scheme.adapter_mut().update_displays(config))
|
||||
.unwrap();
|
||||
let (adapter, objects) = scheme.adapter_and_objects_mut();
|
||||
futures::executor::block_on(adapter.update_displays(objects)).unwrap();
|
||||
scheme.notify_displays_changed();
|
||||
config.events_clear.set(VIRTIO_GPU_EVENT_DISPLAY);
|
||||
scheme
|
||||
.adapter_mut()
|
||||
.config
|
||||
.events_clear
|
||||
.set(VIRTIO_GPU_EVENT_DISPLAY);
|
||||
}
|
||||
|
||||
let after_gen = device.transport.config_generation();
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use common::{dma::Dma, sgl};
|
||||
use driver_graphics::objects::{
|
||||
DrmConnector, DrmConnectorStatus, DrmObjectId, DrmObjects, DrmSubpixelOrder,
|
||||
};
|
||||
use driver_graphics::{
|
||||
CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, GraphicsScheme,
|
||||
modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, GraphicsScheme,
|
||||
};
|
||||
use graphics_ipc::v1::Damage;
|
||||
use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT};
|
||||
@@ -26,6 +29,10 @@ impl Into<GpuRect> for Damage {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct VirtGpuConnector {
|
||||
display_id: u32,
|
||||
}
|
||||
|
||||
pub struct VirtGpuFramebuffer<'a> {
|
||||
queue: Arc<Queue<'a>>,
|
||||
id: ResourceId,
|
||||
@@ -75,6 +82,7 @@ pub struct Display {
|
||||
}
|
||||
|
||||
pub struct VirtGpuAdapter<'a> {
|
||||
pub config: &'a mut GpuConfig,
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
@@ -82,9 +90,9 @@ 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];
|
||||
pub async fn update_displays(&mut self, objects: &mut DrmObjects<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(),
|
||||
@@ -113,6 +121,19 @@ 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(())
|
||||
}
|
||||
|
||||
@@ -198,6 +219,8 @@ impl VirtGpuAdapter<'_> {
|
||||
}
|
||||
|
||||
impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
|
||||
type Connector = VirtGpuConnector;
|
||||
|
||||
type Framebuffer = VirtGpuFramebuffer<'a>;
|
||||
type Cursor = VirtGpuCursor;
|
||||
|
||||
@@ -209,6 +232,26 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
|
||||
b"VirtIO GPU"
|
||||
}
|
||||
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>) {
|
||||
for display_id in 0..self.config.num_scanouts.get() {
|
||||
objects.add_connector(DrmConnector {
|
||||
modes: vec![],
|
||||
encoder_id: DrmObjectId::INVALID,
|
||||
connector_type: 0,
|
||||
connector_type_id: 0,
|
||||
connection: DrmConnectorStatus::Disconnected,
|
||||
mm_width: 0,
|
||||
mm_height: 0,
|
||||
subpixel: DrmSubpixelOrder::Unknown,
|
||||
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> {
|
||||
match cap {
|
||||
DRM_CAP_DUMB_BUFFER => Ok(1),
|
||||
@@ -425,21 +468,20 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
|
||||
pub struct GpuScheme {}
|
||||
|
||||
impl<'a> GpuScheme {
|
||||
pub async fn new(
|
||||
config: &mut GpuConfig,
|
||||
pub fn new(
|
||||
config: &'a mut GpuConfig,
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
) -> Result<(GraphicsScheme<VirtGpuAdapter<'a>>, DisplayHandle), Error> {
|
||||
let mut adapter = VirtGpuAdapter {
|
||||
let adapter = VirtGpuAdapter {
|
||||
config,
|
||||
control_queue,
|
||||
cursor_queue,
|
||||
transport,
|
||||
displays: vec![],
|
||||
};
|
||||
|
||||
adapter.update_displays(config).await?;
|
||||
|
||||
let scheme = GraphicsScheme::new(adapter, "display.virtio-gpu".to_owned());
|
||||
let handle = DisplayHandle::new("virtio-gpu").unwrap();
|
||||
Ok((scheme, handle))
|
||||
|
||||
Reference in New Issue
Block a user