Merge branch 'gpu_drm10' into 'main'
Begin supporting DRM object properties See merge request redox-os/base!77
This commit is contained in:
Generated
+6
-3
@@ -903,7 +903,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "generic-rt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#16decee904d8d6d92f27794beab8d3f5b1915358"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#99e8cd93e0d125010130d8e3aee7d343735d8b5c"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
@@ -1085,6 +1085,7 @@ dependencies = [
|
||||
"common",
|
||||
"daemon",
|
||||
"driver-graphics",
|
||||
"drm-sys",
|
||||
"edid",
|
||||
"embedded-hal",
|
||||
"graphics-ipc",
|
||||
@@ -1777,7 +1778,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "redox-ioctl"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#16decee904d8d6d92f27794beab8d3f5b1915358"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#99e8cd93e0d125010130d8e3aee7d343735d8b5c"
|
||||
dependencies = [
|
||||
"drm-sys",
|
||||
"redox_syscall 0.6.0",
|
||||
@@ -1804,7 +1805,7 @@ checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
|
||||
[[package]]
|
||||
name = "redox-rt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#16decee904d8d6d92f27794beab8d3f5b1915358"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#99e8cd93e0d125010130d8e3aee7d343735d8b5c"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"generic-rt",
|
||||
@@ -2512,6 +2513,7 @@ dependencies = [
|
||||
"common",
|
||||
"daemon",
|
||||
"driver-graphics",
|
||||
"drm-sys",
|
||||
"graphics-ipc",
|
||||
"inputd",
|
||||
"libredox",
|
||||
@@ -2566,6 +2568,7 @@ dependencies = [
|
||||
"common",
|
||||
"daemon",
|
||||
"driver-graphics",
|
||||
"drm-sys",
|
||||
"futures",
|
||||
"graphics-ipc",
|
||||
"inputd",
|
||||
|
||||
@@ -9,7 +9,12 @@ use std::mem;
|
||||
use std::mem::transmute;
|
||||
use std::sync::Arc;
|
||||
|
||||
use drm_sys::drm_mode_modeinfo;
|
||||
use drm_sys::{
|
||||
drm_mode_modeinfo, drm_mode_property_enum, DRM_MODE_DPMS_OFF, DRM_MODE_DPMS_ON,
|
||||
DRM_MODE_DPMS_STANDBY, DRM_MODE_DPMS_SUSPEND, DRM_MODE_PROP_ATOMIC, DRM_MODE_PROP_BITMASK,
|
||||
DRM_MODE_PROP_BLOB, DRM_MODE_PROP_ENUM, DRM_MODE_PROP_IMMUTABLE, DRM_MODE_PROP_OBJECT,
|
||||
DRM_MODE_PROP_RANGE, DRM_MODE_PROP_SIGNED_RANGE, DRM_PROP_NAME_LEN,
|
||||
};
|
||||
use graphics_ipc::v1::CursorDamage;
|
||||
use graphics_ipc::v2::Damage;
|
||||
use inputd::{VtEvent, VtEventKind};
|
||||
@@ -19,10 +24,16 @@ 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::{DrmConnector, DrmObjectId, DrmObjects};
|
||||
use crate::objects::{DrmObjectId, DrmObjects, DrmPropertyKind};
|
||||
|
||||
pub mod objects;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct StandardProperties {
|
||||
pub edid: DrmObjectId,
|
||||
pub dpms: DrmObjectId,
|
||||
}
|
||||
|
||||
pub trait GraphicsAdapter: Sized + Debug {
|
||||
type Connector: Debug;
|
||||
|
||||
@@ -32,12 +43,17 @@ pub trait GraphicsAdapter: Sized + Debug {
|
||||
fn name(&self) -> &'static [u8];
|
||||
fn desc(&self) -> &'static [u8];
|
||||
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>);
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>, standard_properties: &StandardProperties);
|
||||
|
||||
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>);
|
||||
fn probe_connector(
|
||||
&mut self,
|
||||
objects: &mut DrmObjects<Self>,
|
||||
standard_properties: &StandardProperties,
|
||||
id: DrmObjectId,
|
||||
);
|
||||
|
||||
/// The maximum amount of displays that could be attached.
|
||||
///
|
||||
@@ -78,6 +94,7 @@ pub struct GraphicsScheme<T: GraphicsAdapter> {
|
||||
disable_graphical_debug: Option<File>,
|
||||
socket: Socket,
|
||||
objects: DrmObjects<T>,
|
||||
standard_properties: StandardProperties,
|
||||
next_id: usize,
|
||||
handles: BTreeMap<usize, Handle<T>>,
|
||||
|
||||
@@ -113,8 +130,25 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
);
|
||||
|
||||
let mut objects = DrmObjects::new();
|
||||
adapter.init(&mut objects);
|
||||
objects.for_each_connector_mut(|connector| adapter.probe_connector(connector));
|
||||
|
||||
let edid = objects.add_property("EDID", true, false, DrmPropertyKind::Blob);
|
||||
let dpms = objects.add_property(
|
||||
"DPMS",
|
||||
false,
|
||||
false,
|
||||
DrmPropertyKind::Enum(vec![
|
||||
("On", DRM_MODE_DPMS_ON.into()),
|
||||
("Standby", DRM_MODE_DPMS_STANDBY.into()),
|
||||
("Suspend", DRM_MODE_DPMS_SUSPEND.into()),
|
||||
("Off", DRM_MODE_DPMS_OFF.into()),
|
||||
]),
|
||||
);
|
||||
let standard_properties = StandardProperties { edid, dpms };
|
||||
|
||||
adapter.init(&mut objects, &standard_properties);
|
||||
for connector_id in objects.connector_ids().to_vec() {
|
||||
adapter.probe_connector(&mut objects, &standard_properties, connector_id)
|
||||
}
|
||||
|
||||
GraphicsScheme {
|
||||
adapter,
|
||||
@@ -122,6 +156,7 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
disable_graphical_debug,
|
||||
socket,
|
||||
objects,
|
||||
standard_properties,
|
||||
next_id: 0,
|
||||
handles: BTreeMap::new(),
|
||||
active_vt: 0,
|
||||
@@ -153,6 +188,10 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
(&mut self.adapter, &mut self.objects)
|
||||
}
|
||||
|
||||
pub fn standard_properties(&self) -> StandardProperties {
|
||||
self.standard_properties
|
||||
}
|
||||
|
||||
pub fn handle_vt_event(&mut self, vt_event: VtEvent) {
|
||||
match vt_event.kind {
|
||||
VtEventKind::Activate => {
|
||||
@@ -471,7 +510,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
}
|
||||
|
||||
fn crtc_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 9)
|
||||
id_index(i) | (1 << 10)
|
||||
}
|
||||
|
||||
fn fb_id(i: u32) -> u32 {
|
||||
@@ -575,20 +614,117 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
Ok(0)
|
||||
}),
|
||||
ipc::MODE_GET_CONNECTOR => ipc::DrmModeGetConnector::with(payload, |mut data| {
|
||||
if data.count_modes() == 0 {
|
||||
self.adapter.probe_connector(
|
||||
&mut self.objects,
|
||||
&self.standard_properties,
|
||||
DrmObjectId(data.connector_id()),
|
||||
);
|
||||
}
|
||||
let connector = self
|
||||
.objects
|
||||
.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);
|
||||
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(&[connector.encoder_id.0]);
|
||||
let props = self
|
||||
.objects
|
||||
.get_object_properties(DrmObjectId(data.connector_id()))?;
|
||||
data.set_props_ptr(&props.iter().map(|&(id, _)| id.0).collect::<Vec<_>>());
|
||||
data.set_prop_values_ptr(
|
||||
&props.iter().map(|&(_, value)| value).collect::<Vec<_>>(),
|
||||
);
|
||||
Ok(0)
|
||||
}),
|
||||
ipc::MODE_GET_PROPERTY => ipc::DrmModeGetProperty::with(payload, |mut data| {
|
||||
let property = self.objects.get_property(DrmObjectId(data.prop_id()))?;
|
||||
data.set_name(property.name);
|
||||
let mut flags = 0;
|
||||
if property.immutable {
|
||||
flags |= DRM_MODE_PROP_IMMUTABLE;
|
||||
}
|
||||
if property.atomic {
|
||||
flags |= DRM_MODE_PROP_ATOMIC;
|
||||
}
|
||||
match &property.kind {
|
||||
&DrmPropertyKind::Range(start, end) => {
|
||||
data.set_flags(flags | DRM_MODE_PROP_RANGE);
|
||||
data.set_values_ptr(&[start, end]);
|
||||
data.set_enum_blob_ptr(&[]);
|
||||
}
|
||||
DrmPropertyKind::Enum(variants) => {
|
||||
data.set_flags(flags | DRM_MODE_PROP_ENUM);
|
||||
data.set_values_ptr(
|
||||
&variants.iter().map(|&(_, value)| value).collect::<Vec<_>>(),
|
||||
);
|
||||
data.set_enum_blob_ptr(
|
||||
&variants
|
||||
.iter()
|
||||
.map(|&(name, value)| {
|
||||
let mut name_bytes = [0; DRM_PROP_NAME_LEN as usize];
|
||||
for (to, &from) in
|
||||
name_bytes.iter_mut().zip(name.as_bytes())
|
||||
{
|
||||
*to = from as c_char;
|
||||
}
|
||||
drm_mode_property_enum {
|
||||
name: name_bytes,
|
||||
value,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
DrmPropertyKind::Blob => {
|
||||
data.set_flags(flags | DRM_MODE_PROP_BLOB);
|
||||
data.set_values_ptr(&[]);
|
||||
data.set_enum_blob_ptr(&[]);
|
||||
}
|
||||
DrmPropertyKind::Bitmask(bitmask_flags) => {
|
||||
data.set_flags(flags | DRM_MODE_PROP_BITMASK);
|
||||
data.set_values_ptr(
|
||||
&bitmask_flags
|
||||
.iter()
|
||||
.map(|&(_, value)| value)
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
data.set_enum_blob_ptr(
|
||||
&bitmask_flags
|
||||
.iter()
|
||||
.map(|&(name, value)| {
|
||||
let mut name_bytes = [0; DRM_PROP_NAME_LEN as usize];
|
||||
for (to, &from) in
|
||||
name_bytes.iter_mut().zip(name.as_bytes())
|
||||
{
|
||||
*to = from as c_char;
|
||||
}
|
||||
drm_mode_property_enum {
|
||||
name: name_bytes,
|
||||
value,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
}
|
||||
DrmPropertyKind::Object => {
|
||||
data.set_flags(flags | DRM_MODE_PROP_OBJECT);
|
||||
data.set_values_ptr(&[]);
|
||||
data.set_enum_blob_ptr(&[]);
|
||||
}
|
||||
&DrmPropertyKind::SignedRange(start, end) => {
|
||||
data.set_flags(flags | DRM_MODE_PROP_SIGNED_RANGE);
|
||||
data.set_values_ptr(&[start as u64, end as u64]);
|
||||
data.set_enum_blob_ptr(&[]);
|
||||
}
|
||||
}
|
||||
Ok(0)
|
||||
}),
|
||||
ipc::MODE_GET_PROP_BLOB => ipc::DrmModeGetBlob::with(payload, |mut data| {
|
||||
let blob = self.objects.get_blob(DrmObjectId(data.blob_id()))?;
|
||||
data.set_data(&blob);
|
||||
Ok(0)
|
||||
}),
|
||||
ipc::MODE_GET_FB => ipc::DrmModeFbCmd::with(payload, |mut data| {
|
||||
@@ -665,9 +801,21 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
}),
|
||||
ipc::MODE_OBJ_GET_PROPERTIES => {
|
||||
ipc::DrmModeObjGetProperties::with(payload, |mut data| {
|
||||
// TODO
|
||||
data.set_props_ptr(&[]);
|
||||
data.set_prop_values_ptr(&[]);
|
||||
// FIXME remove once all drm objects are materialized in self.objects
|
||||
if data.obj_id() >= 1 << 10 {
|
||||
data.set_props_ptr(&[]);
|
||||
data.set_prop_values_ptr(&[]);
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let props = self
|
||||
.objects
|
||||
.get_object_properties(DrmObjectId(data.obj_id()))?;
|
||||
data.set_props_ptr(&props.iter().map(|&(id, _)| id.0).collect::<Vec<_>>());
|
||||
data.set_prop_values_ptr(
|
||||
&props.iter().map(|&(_, value)| value).collect::<Vec<_>>(),
|
||||
);
|
||||
data.set_obj_type(self.objects.object_type(DrmObjectId(data.obj_id()))?);
|
||||
Ok(0)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::c_char;
|
||||
|
||||
use drm_sys::drm_mode_modeinfo;
|
||||
use drm_sys::{
|
||||
drm_mode_modeinfo, DRM_MODE_OBJECT_BLOB, DRM_MODE_OBJECT_CONNECTOR, DRM_MODE_OBJECT_ENCODER,
|
||||
DRM_MODE_OBJECT_PROPERTY, DRM_PROP_NAME_LEN,
|
||||
};
|
||||
use syscall::{Error, Result, EINVAL};
|
||||
|
||||
use crate::GraphicsAdapter;
|
||||
@@ -23,6 +27,124 @@ impl<T: GraphicsAdapter> DrmObjects<T> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn object_type(&self, id: DrmObjectId) -> Result<u32> {
|
||||
let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?;
|
||||
Ok(match object.kind {
|
||||
DrmObjectKind::Property(_) => DRM_MODE_OBJECT_PROPERTY,
|
||||
DrmObjectKind::Blob(_) => DRM_MODE_OBJECT_BLOB,
|
||||
DrmObjectKind::Connector(_) => DRM_MODE_OBJECT_CONNECTOR,
|
||||
DrmObjectKind::Encoder(_) => DRM_MODE_OBJECT_ENCODER,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn add_property(
|
||||
&mut self,
|
||||
name: &str,
|
||||
immutable: bool,
|
||||
atomic: bool,
|
||||
kind: DrmPropertyKind,
|
||||
) -> DrmObjectId {
|
||||
if name.len() > DRM_PROP_NAME_LEN as usize {
|
||||
panic!("Property name {name} is too long");
|
||||
}
|
||||
|
||||
match &kind {
|
||||
DrmPropertyKind::Range(start, end) => assert!(start < end),
|
||||
DrmPropertyKind::Enum(variants) => {
|
||||
// FIXME check duplicate variant numbers
|
||||
for (variant_name, _) in variants {
|
||||
if variant_name.len() > DRM_PROP_NAME_LEN as usize {
|
||||
panic!("Property variant name {variant_name} is too long");
|
||||
}
|
||||
}
|
||||
}
|
||||
DrmPropertyKind::Blob => {}
|
||||
DrmPropertyKind::Bitmask(bitmask_flags) => {
|
||||
// FIXME check overlapping flag numbers
|
||||
for (flag_name, _) in bitmask_flags {
|
||||
if flag_name.len() > DRM_PROP_NAME_LEN as usize {
|
||||
panic!("Property bitflag name {flag_name} is too long");
|
||||
}
|
||||
}
|
||||
}
|
||||
DrmPropertyKind::Object => {}
|
||||
DrmPropertyKind::SignedRange(start, end) => assert!(start < end),
|
||||
}
|
||||
|
||||
let mut name_bytes = [0; DRM_PROP_NAME_LEN as usize];
|
||||
for (to, &from) in name_bytes.iter_mut().zip(name.as_bytes()) {
|
||||
*to = from as c_char;
|
||||
}
|
||||
|
||||
let id = self.next_id;
|
||||
self.objects.insert(
|
||||
id,
|
||||
DrmObject {
|
||||
kind: DrmObjectKind::Property(DrmProperty {
|
||||
name: name_bytes,
|
||||
immutable,
|
||||
atomic,
|
||||
kind,
|
||||
}),
|
||||
properties: vec![],
|
||||
},
|
||||
);
|
||||
self.next_id.0 += 1;
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
pub fn get_property(&self, id: DrmObjectId) -> Result<&DrmProperty> {
|
||||
let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?;
|
||||
match &object.kind {
|
||||
DrmObjectKind::Property(drm_property) => Ok(drm_property),
|
||||
_ => Err(Error::new(EINVAL)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_object_property(&mut self, object: DrmObjectId, property: DrmObjectId, value: u64) {
|
||||
let object = self.objects.get_mut(&object).unwrap();
|
||||
// FIXME validate property uniqueness and value
|
||||
object.properties.push((property, value));
|
||||
}
|
||||
|
||||
pub fn set_object_property(&mut self, object: DrmObjectId, property: DrmObjectId, value: u64) {
|
||||
let object = self.objects.get_mut(&object).unwrap();
|
||||
// FIXME validate property existence and value
|
||||
for (prop, val) in object.properties.iter_mut() {
|
||||
if *prop == property {
|
||||
*val = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_object_properties(&self, id: DrmObjectId) -> Result<&[(DrmObjectId, u64)]> {
|
||||
let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?;
|
||||
Ok(&object.properties)
|
||||
}
|
||||
|
||||
pub fn add_blob(&mut self, data: Vec<u8>) -> DrmObjectId {
|
||||
let id = self.next_id;
|
||||
self.objects.insert(
|
||||
id,
|
||||
DrmObject {
|
||||
kind: DrmObjectKind::Blob(data),
|
||||
properties: vec![],
|
||||
},
|
||||
);
|
||||
self.next_id.0 += 1;
|
||||
|
||||
id
|
||||
}
|
||||
|
||||
pub fn get_blob(&self, id: DrmObjectId) -> Result<&[u8]> {
|
||||
let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?;
|
||||
match &object.kind {
|
||||
DrmObjectKind::Blob(data) => Ok(data),
|
||||
_ => Err(Error::new(EINVAL)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_connector(&mut self, driver_data: T::Connector) -> DrmObjectId {
|
||||
let connector_id = self.next_id;
|
||||
let encoder_id = DrmObjectId(self.next_id.0 + 1);
|
||||
@@ -40,6 +162,7 @@ impl<T: GraphicsAdapter> DrmObjects<T> {
|
||||
subpixel: DrmSubpixelOrder::Unknown,
|
||||
driver_data,
|
||||
}),
|
||||
properties: vec![],
|
||||
},
|
||||
);
|
||||
self.connectors.push(connector_id);
|
||||
@@ -52,6 +175,7 @@ impl<T: GraphicsAdapter> DrmObjects<T> {
|
||||
possible_crtcs: 0,
|
||||
possible_clones: 0,
|
||||
}),
|
||||
properties: vec![],
|
||||
},
|
||||
);
|
||||
self.encoders.push(encoder_id);
|
||||
@@ -73,15 +197,6 @@ impl<T: GraphicsAdapter> DrmObjects<T> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn for_each_connector_mut<'a>(&mut self, mut f: impl FnMut(&mut DrmConnector<T>)) {
|
||||
for id in &self.connectors {
|
||||
match &mut self.objects.get_mut(&id).unwrap().kind {
|
||||
DrmObjectKind::Connector(connector) => f(connector),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_connector(&self, id: DrmObjectId) -> Result<&DrmConnector<T>> {
|
||||
let object = self.objects.get(&id).ok_or(Error::new(EINVAL))?;
|
||||
match &object.kind {
|
||||
@@ -126,17 +241,44 @@ impl DrmObjectId {
|
||||
pub const INVALID: DrmObjectId = DrmObjectId(0);
|
||||
}
|
||||
|
||||
impl From<DrmObjectId> for u64 {
|
||||
fn from(value: DrmObjectId) -> Self {
|
||||
value.0.into()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DrmObject<T: GraphicsAdapter> {
|
||||
kind: DrmObjectKind<T>,
|
||||
properties: Vec<(DrmObjectId, u64)>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum DrmObjectKind<T: GraphicsAdapter> {
|
||||
Property(DrmProperty),
|
||||
Blob(Vec<u8>),
|
||||
Connector(DrmConnector<T>),
|
||||
Encoder(DrmEncoder),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DrmProperty {
|
||||
pub name: [c_char; DRM_PROP_NAME_LEN as usize],
|
||||
pub immutable: bool,
|
||||
pub atomic: bool,
|
||||
pub kind: DrmPropertyKind,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DrmPropertyKind {
|
||||
Range(u64, u64),
|
||||
Enum(Vec<(&'static str, u64)>),
|
||||
Blob,
|
||||
Bitmask(Vec<(&'static str, u64)>),
|
||||
Object,
|
||||
SignedRange(i64, i64),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DrmConnector<T: GraphicsAdapter> {
|
||||
pub modes: Vec<drm_mode_modeinfo>,
|
||||
|
||||
@@ -5,6 +5,7 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bitbang-hal = "0.3"
|
||||
drm-sys = "0.8.0"
|
||||
#TODO: edid is abandoned, fork it an maintain?
|
||||
edid = "0.3.0"
|
||||
#TODO: waiting for bitbang-hal to update to embedded-hal 1.0
|
||||
@@ -25,4 +26,4 @@ pcid = { path = "../../pcid" }
|
||||
libredox = "0.1.3"
|
||||
redox-scheme = "0.8"
|
||||
redox_event = "0.4.1"
|
||||
redox_syscall = "0.6"
|
||||
redox_syscall = "0.6"
|
||||
|
||||
@@ -4,10 +4,12 @@ use std::alloc::{self, Layout};
|
||||
use std::convert::TryInto;
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
use driver_graphics::objects::{DrmConnector, DrmConnectorStatus, DrmObjects};
|
||||
use driver_graphics::objects::{DrmConnectorStatus, DrmObjectId, DrmObjects};
|
||||
use driver_graphics::{
|
||||
modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter,
|
||||
StandardProperties,
|
||||
};
|
||||
use drm_sys::DRM_MODE_DPMS_ON;
|
||||
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};
|
||||
@@ -38,10 +40,15 @@ impl GraphicsAdapter for Device {
|
||||
b"Intel HD Graphics"
|
||||
}
|
||||
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>) {
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>, standard_properties: &StandardProperties) {
|
||||
// FIXME enumerate actual connectors
|
||||
for (framebuffer_id, _) in self.framebuffers.iter().enumerate() {
|
||||
objects.add_connector(Connector { framebuffer_id });
|
||||
let connector = objects.add_connector(Connector { framebuffer_id });
|
||||
objects.add_object_property(
|
||||
connector,
|
||||
standard_properties.dpms,
|
||||
DRM_MODE_DPMS_ON.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,13 +67,20 @@ impl GraphicsAdapter for Device {
|
||||
}
|
||||
}
|
||||
|
||||
fn probe_connector(&mut self, connector: &mut DrmConnector<Self>) {
|
||||
fn probe_connector(
|
||||
&mut self,
|
||||
objects: &mut DrmObjects<Self>,
|
||||
_standard_properties: &StandardProperties,
|
||||
id: DrmObjectId,
|
||||
) {
|
||||
let connector = objects.get_connector_mut(id).unwrap();
|
||||
let framebuffer = &self.framebuffers[connector.driver_data.framebuffer_id];
|
||||
connector.connection = DrmConnectorStatus::Connected;
|
||||
connector.modes = vec![modeinfo_for_size(
|
||||
framebuffer.width as u32,
|
||||
framebuffer.height as u32,
|
||||
)];
|
||||
// FIXME fetch EDID
|
||||
}
|
||||
|
||||
fn display_count(&self) -> usize {
|
||||
|
||||
@@ -4,6 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
drm-sys = "0.8.0"
|
||||
orbclient = "0.3.27"
|
||||
ransid = "0.4"
|
||||
redox_syscall = "0.6"
|
||||
|
||||
@@ -2,10 +2,12 @@ use std::alloc::{self, Layout};
|
||||
use std::convert::TryInto;
|
||||
use std::ptr::{self, NonNull};
|
||||
|
||||
use driver_graphics::objects::{DrmConnector, DrmConnectorStatus, DrmObjects};
|
||||
use driver_graphics::objects::{DrmConnectorStatus, DrmObjectId, DrmObjects};
|
||||
use driver_graphics::{
|
||||
modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter,
|
||||
StandardProperties,
|
||||
};
|
||||
use drm_sys::DRM_MODE_DPMS_ON;
|
||||
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};
|
||||
@@ -39,12 +41,17 @@ impl GraphicsAdapter for FbAdapter {
|
||||
b"VESA"
|
||||
}
|
||||
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>) {
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>, standard_properties: &StandardProperties) {
|
||||
for framebuffer in &self.framebuffers {
|
||||
objects.add_connector(Connector {
|
||||
let connector = objects.add_connector(Connector {
|
||||
width: framebuffer.width as u32,
|
||||
height: framebuffer.height as u32,
|
||||
});
|
||||
objects.add_object_property(
|
||||
connector,
|
||||
standard_properties.dpms,
|
||||
DRM_MODE_DPMS_ON.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +69,13 @@ impl GraphicsAdapter for FbAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
fn probe_connector(&mut self, connector: &mut DrmConnector<Self>) {
|
||||
fn probe_connector(
|
||||
&mut self,
|
||||
objects: &mut DrmObjects<Self>,
|
||||
_standard_properties: &StandardProperties,
|
||||
id: DrmObjectId,
|
||||
) {
|
||||
let connector = objects.get_connector_mut(id).unwrap();
|
||||
connector.modes = vec![modeinfo_for_size(
|
||||
connector.driver_data.width,
|
||||
connector.driver_data.height,
|
||||
|
||||
@@ -5,6 +5,7 @@ edition = "2021"
|
||||
authors = ["Anhad Singh <andypython@protonmail.com>"]
|
||||
|
||||
[dependencies]
|
||||
drm-sys = "0.8.0"
|
||||
log = "0.4"
|
||||
static_assertions = "1.1.0"
|
||||
futures = { version = "0.3.28", features = ["executor"] }
|
||||
|
||||
@@ -32,6 +32,12 @@ use virtio_core::MSIX_PRIMARY_VECTOR;
|
||||
|
||||
mod scheme;
|
||||
|
||||
//const VIRTIO_GPU_F_VIRGL: u32 = 0;
|
||||
const VIRTIO_GPU_F_EDID: u32 = 1;
|
||||
//const VIRTIO_GPU_F_RESOURCE_UUID: u32 = 2;
|
||||
//const VIRTIO_GPU_F_RESOURCE_BLOB: u32 = 3;
|
||||
//const VIRTIO_GPU_F_CONTEXT_INIT: u32 = 4;
|
||||
|
||||
const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0;
|
||||
const VIRTIO_GPU_MAX_SCANOUTS: usize = 16;
|
||||
|
||||
@@ -362,6 +368,44 @@ impl XferToHost2d {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct GetEdid {
|
||||
pub header: ControlHeader,
|
||||
pub scanout: u32,
|
||||
pub padding: u32,
|
||||
}
|
||||
|
||||
impl GetEdid {
|
||||
pub fn new(scanout_id: u32) -> Self {
|
||||
Self {
|
||||
header: ControlHeader::with_ty(CommandTy::GetEdid),
|
||||
scanout: scanout_id,
|
||||
padding: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct GetEdidResp {
|
||||
pub header: ControlHeader,
|
||||
pub size: u32,
|
||||
pub padding: u32,
|
||||
pub edid: [u8; 1024],
|
||||
}
|
||||
|
||||
impl GetEdidResp {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
header: ControlHeader::with_ty(CommandTy::GetEdid),
|
||||
size: 0,
|
||||
padding: 0,
|
||||
edid: [0; 1024],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
pub struct CursorPos {
|
||||
@@ -461,6 +505,10 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow:
|
||||
let config = unsafe { &mut *(device.device_space as *mut GpuConfig) };
|
||||
|
||||
// Negotiate features.
|
||||
let has_edid = device.transport.check_device_feature(VIRTIO_GPU_F_EDID);
|
||||
if has_edid {
|
||||
device.transport.ack_driver_feature(VIRTIO_GPU_F_EDID);
|
||||
}
|
||||
device.transport.finalize_features();
|
||||
|
||||
// Queue for sending control commands.
|
||||
@@ -483,6 +531,7 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow:
|
||||
control_queue.clone(),
|
||||
cursor_queue.clone(),
|
||||
device.transport.clone(),
|
||||
has_edid,
|
||||
)?;
|
||||
|
||||
user_data! {
|
||||
@@ -542,9 +591,12 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow:
|
||||
let events = scheme.adapter().config.events_read.get();
|
||||
|
||||
if events & VIRTIO_GPU_EVENT_DISPLAY != 0 {
|
||||
let standard_properties = scheme.standard_properties();
|
||||
let (adapter, objects) = scheme.adapter_and_objects_mut();
|
||||
futures::executor::block_on(async { adapter.update_displays().await.unwrap() });
|
||||
objects.for_each_connector_mut(|connector| adapter.probe_connector(connector));
|
||||
for connector_id in objects.connector_ids().to_vec() {
|
||||
adapter.probe_connector(objects, &standard_properties, connector_id);
|
||||
}
|
||||
scheme.notify_displays_changed();
|
||||
scheme
|
||||
.adapter_mut()
|
||||
|
||||
@@ -2,10 +2,12 @@ use std::fmt;
|
||||
use std::sync::Arc;
|
||||
|
||||
use common::{dma::Dma, sgl};
|
||||
use driver_graphics::objects::{DrmConnector, DrmConnectorStatus, DrmObjects};
|
||||
use driver_graphics::objects::{DrmConnectorStatus, DrmObjectId, DrmObjects};
|
||||
use driver_graphics::{
|
||||
modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, GraphicsScheme,
|
||||
modeinfo_for_size, CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter,
|
||||
GraphicsScheme, StandardProperties,
|
||||
};
|
||||
use drm_sys::DRM_MODE_DPMS_ON;
|
||||
use graphics_ipc::v1::Damage;
|
||||
use graphics_ipc::v2::ipc::{DRM_CAP_DUMB_BUFFER, DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT};
|
||||
use inputd::DisplayHandle;
|
||||
@@ -74,11 +76,12 @@ pub struct VirtGpuCursor {
|
||||
|
||||
impl CursorFramebuffer for VirtGpuCursor {}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Display {
|
||||
enabled: bool,
|
||||
width: u32,
|
||||
height: u32,
|
||||
edid: Vec<u8>,
|
||||
active_resource: Option<ResourceId>,
|
||||
}
|
||||
|
||||
@@ -87,6 +90,7 @@ pub struct VirtGpuAdapter<'a> {
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
has_edid: bool,
|
||||
displays: Vec<Display>,
|
||||
}
|
||||
|
||||
@@ -109,6 +113,7 @@ impl VirtGpuAdapter<'_> {
|
||||
enabled: false,
|
||||
width: 0,
|
||||
height: 0,
|
||||
edid: vec![],
|
||||
active_resource: None,
|
||||
},
|
||||
);
|
||||
@@ -131,6 +136,11 @@ impl VirtGpuAdapter<'_> {
|
||||
self.displays[i].width = info.rect.width;
|
||||
self.displays[i].height = info.rect.height;
|
||||
}
|
||||
|
||||
if self.has_edid {
|
||||
let edid = self.get_edid(i as u32).await?;
|
||||
self.displays[i].edid = edid.edid[..edid.size as usize].to_vec();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -174,6 +184,21 @@ impl VirtGpuAdapter<'_> {
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
async fn get_edid(&self, scanout_id: u32) -> Result<Dma<GetEdidResp>, Error> {
|
||||
let header = Dma::new(GetEdid::new(scanout_id))?;
|
||||
|
||||
let response = Dma::new(GetEdidResp::new())?;
|
||||
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::RespOkEdid);
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
||||
fn update_cursor(&mut self, cursor: &VirtGpuCursor, x: i32, y: i32, hot_x: i32, hot_y: i32) {
|
||||
//Transfering cursor resource to host
|
||||
futures::executor::block_on(async {
|
||||
@@ -231,13 +256,21 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
|
||||
b"VirtIO GPU"
|
||||
}
|
||||
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>) {
|
||||
fn init(&mut self, objects: &mut DrmObjects<Self>, standard_properties: &StandardProperties) {
|
||||
futures::executor::block_on(async {
|
||||
self.update_displays().await.unwrap();
|
||||
});
|
||||
|
||||
for display_id in 0..self.config.num_scanouts.get() {
|
||||
objects.add_connector(VirtGpuConnector { display_id });
|
||||
let connector = objects.add_connector(VirtGpuConnector { display_id });
|
||||
if self.has_edid {
|
||||
objects.add_object_property(connector, standard_properties.edid, 0);
|
||||
}
|
||||
objects.add_object_property(
|
||||
connector,
|
||||
standard_properties.dpms,
|
||||
DRM_MODE_DPMS_ON.into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -256,8 +289,14 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn probe_connector(&mut self, connector: &mut DrmConnector<Self>) {
|
||||
fn probe_connector(
|
||||
&mut self,
|
||||
objects: &mut DrmObjects<Self>,
|
||||
standard_properties: &StandardProperties,
|
||||
id: DrmObjectId,
|
||||
) {
|
||||
futures::executor::block_on(async {
|
||||
let connector = objects.get_connector_mut(id).unwrap();
|
||||
let display = &self.displays[connector.driver_data.display_id as usize];
|
||||
|
||||
connector.modes = vec![modeinfo_for_size(display.width, display.height)];
|
||||
@@ -266,6 +305,11 @@ impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> {
|
||||
} else {
|
||||
DrmConnectorStatus::Disconnected
|
||||
};
|
||||
|
||||
if self.has_edid {
|
||||
let blob = objects.add_blob(display.edid.clone());
|
||||
objects.set_object_property(id, standard_properties.edid, blob.into());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -475,12 +519,14 @@ impl<'a> GpuScheme {
|
||||
control_queue: Arc<Queue<'a>>,
|
||||
cursor_queue: Arc<Queue<'a>>,
|
||||
transport: Arc<dyn Transport>,
|
||||
has_edid: bool,
|
||||
) -> Result<(GraphicsScheme<VirtGpuAdapter<'a>>, DisplayHandle), Error> {
|
||||
let adapter = VirtGpuAdapter {
|
||||
config,
|
||||
control_queue,
|
||||
cursor_queue,
|
||||
transport,
|
||||
has_edid,
|
||||
displays: vec![],
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user