feat: select primary drm connector
This commit is contained in:
1 parent
c101b2cf8b
commit
9fdbb8e625
1 file changed
+108
-9
@@ -10,8 +10,14 @@ use smithay::{
|
|||||||
session::{Event as SessionEvent, Session, libseat::LibSeatSession},
|
session::{Event as SessionEvent, Session, libseat::LibSeatSession},
|
||||||
udev::{UdevBackend, UdevEvent, primary_gpu},
|
udev::{UdevBackend, UdevEvent, primary_gpu},
|
||||||
},
|
},
|
||||||
reexports::{calloop::EventLoop, input::Libinput, rustix::fs::OFlags},
|
output::{Mode as OutputMode, Output, PhysicalProperties, Scale, Subpixel},
|
||||||
utils::DeviceFd,
|
reexports::{
|
||||||
|
calloop::EventLoop,
|
||||||
|
drm::control::{Device as ControlDevice, Mode as DrmMode, ModeTypeFlags, connector, crtc},
|
||||||
|
input::Libinput,
|
||||||
|
rustix::fs::OFlags,
|
||||||
|
},
|
||||||
|
utils::{DeviceFd, Transform},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::Ferese;
|
use crate::Ferese;
|
||||||
@@ -35,6 +41,14 @@ struct DirectDevice {
|
|||||||
gbm: GbmDevice<DrmDeviceFd>,
|
gbm: GbmDevice<DrmDeviceFd>,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
renderer: GlesRenderer,
|
renderer: GlesRenderer,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
connector: connector::Handle,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
crtc: crtc::Handle,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
mode: DrmMode,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
output: Output,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<(), Box<dyn Error>> {
|
pub fn init(event_loop: &mut EventLoop<Ferese>, state: &mut Ferese) -> Result<(), Box<dyn Error>> {
|
||||||
@@ -121,12 +135,14 @@ fn open_primary_device(
|
|||||||
state: &mut Ferese,
|
state: &mut Ferese,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
) -> Result<(), Box<dyn Error>> {
|
) -> Result<(), Box<dyn Error>> {
|
||||||
let backend = state
|
let mut session = state
|
||||||
.direct_backend
|
.direct_backend
|
||||||
.as_mut()
|
.as_ref()
|
||||||
.expect("direct backend state is initialized before the DRM device");
|
.expect("direct backend state is initialized before the DRM device")
|
||||||
|
.session
|
||||||
|
.clone();
|
||||||
let node = DrmNode::from_path(path)?;
|
let node = DrmNode::from_path(path)?;
|
||||||
let fd = backend.session.open(
|
let fd = session.open(
|
||||||
path,
|
path,
|
||||||
OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK,
|
OFlags::RDWR | OFlags::CLOEXEC | OFlags::NOCTTY | OFlags::NONBLOCK,
|
||||||
)?;
|
)?;
|
||||||
@@ -138,6 +154,8 @@ fn open_primary_device(
|
|||||||
let egl_context = EGLContext::new(&egl_display)?;
|
let egl_context = EGLContext::new(&egl_display)?;
|
||||||
// SAFETY: the new context is not current on another thread and remains renderer-owned.
|
// SAFETY: the new context is not current on another thread and remains renderer-owned.
|
||||||
let renderer = unsafe { GlesRenderer::new(egl_context)? };
|
let renderer = unsafe { GlesRenderer::new(egl_context)? };
|
||||||
|
let (connector, crtc, mode) = select_output(&drm)?;
|
||||||
|
let output = create_output(state, &connector, mode);
|
||||||
|
|
||||||
event_loop
|
event_loop
|
||||||
.handle()
|
.handle()
|
||||||
@@ -153,13 +171,94 @@ fn open_primary_device(
|
|||||||
}
|
}
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
backend
|
state
|
||||||
|
.direct_backend
|
||||||
|
.as_mut()
|
||||||
|
.expect("direct backend state remains initialized")
|
||||||
.devices
|
.devices
|
||||||
.insert(node, DirectDevice { drm, gbm, renderer });
|
.insert(
|
||||||
tracing::info!(?node, ?path, "initialized primary DRM/GBM device");
|
node,
|
||||||
|
DirectDevice {
|
||||||
|
drm,
|
||||||
|
gbm,
|
||||||
|
renderer,
|
||||||
|
connector: connector.handle(),
|
||||||
|
crtc,
|
||||||
|
mode,
|
||||||
|
output,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
state.relayout();
|
||||||
|
tracing::info!(?node, ?path, ?crtc, connector = %connector, "initialized primary DRM/GBM device");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn select_output(drm: &DrmDevice) -> io::Result<(connector::Info, crtc::Handle, DrmMode)> {
|
||||||
|
let resources = drm.resource_handles()?;
|
||||||
|
|
||||||
|
for handle in resources.connectors() {
|
||||||
|
let connector = drm.get_connector(*handle, true)?;
|
||||||
|
if connector.state() != connector::State::Connected {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let Some(mode) = connector
|
||||||
|
.modes()
|
||||||
|
.iter()
|
||||||
|
.find(|mode| mode.mode_type().contains(ModeTypeFlags::PREFERRED))
|
||||||
|
.or_else(|| connector.modes().first())
|
||||||
|
.copied()
|
||||||
|
else {
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
let current_crtc = connector
|
||||||
|
.current_encoder()
|
||||||
|
.and_then(|handle| drm.get_encoder(handle).ok())
|
||||||
|
.and_then(|encoder| encoder.crtc());
|
||||||
|
let compatible_crtc = connector.encoders().iter().find_map(|handle| {
|
||||||
|
let encoder = drm.get_encoder(*handle).ok()?;
|
||||||
|
resources
|
||||||
|
.filter_crtcs(encoder.possible_crtcs())
|
||||||
|
.into_iter()
|
||||||
|
.next()
|
||||||
|
});
|
||||||
|
if let Some(crtc) = current_crtc.or(compatible_crtc) {
|
||||||
|
return Ok((connector, crtc, mode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::NotFound,
|
||||||
|
"no connected desktop DRM connector with a usable CRTC",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_output(state: &mut Ferese, connector: &connector::Info, mode: DrmMode) -> Output {
|
||||||
|
let name = connector.to_string();
|
||||||
|
let physical_size = connector.size().unwrap_or((0, 0));
|
||||||
|
let output = Output::new(
|
||||||
|
name,
|
||||||
|
PhysicalProperties {
|
||||||
|
size: (physical_size.0 as i32, physical_size.1 as i32).into(),
|
||||||
|
subpixel: Subpixel::from(connector.subpixel()),
|
||||||
|
make: "Unknown".into(),
|
||||||
|
model: "Unknown".into(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
let output_mode = OutputMode::from(mode);
|
||||||
|
|
||||||
|
output.create_global::<Ferese>(&state.display_handle);
|
||||||
|
output.set_preferred(output_mode);
|
||||||
|
output.change_current_state(
|
||||||
|
Some(output_mode),
|
||||||
|
Some(Transform::Normal),
|
||||||
|
Some(Scale::Integer(1)),
|
||||||
|
Some((0, 0).into()),
|
||||||
|
);
|
||||||
|
state.space.map_output(&output, (0, 0));
|
||||||
|
output
|
||||||
|
}
|
||||||
|
|
||||||
impl DirectBackendState {
|
impl DirectBackendState {
|
||||||
pub fn record_presentation(&mut self, time: DrmEventTime, sequence: u32) -> Option<Duration> {
|
pub fn record_presentation(&mut self, time: DrmEventTime, sequence: u32) -> Option<Duration> {
|
||||||
self.presentation.record(time, sequence)
|
self.presentation.record(time, sequence)
|
||||||
|
|||||||
Reference in new issue
Block a user