1
0
Fork 0
forked from wry/wry

metal: allow changing the connector mode

This commit is contained in:
Julian Orth 2024-03-04 17:18:44 +01:00
parent 558bea47b7
commit 98b6eba81c
9 changed files with 124 additions and 4 deletions

View file

@ -83,6 +83,7 @@ pub trait Connector {
fn drm_feedback(&self) -> Option<Rc<DrmFeedback>> {
None
}
fn set_mode(&self, mode: Mode);
}
#[derive(Debug)]

View file

@ -2,7 +2,7 @@ use {
crate::{
async_engine::SpawnedFuture,
backend::{
Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, DrmDeviceId,
Backend, Connector, ConnectorEvent, ConnectorId, ConnectorKernelId, DrmDeviceId, Mode,
},
video::drm::ConnectorType,
},
@ -56,4 +56,8 @@ impl Connector for DummyOutput {
fn set_enabled(&self, _enabled: bool) {
// nothing
}
fn set_mode(&self, _mode: Mode) {
// nothing
}
}

View file

@ -3,7 +3,7 @@ use {
async_engine::{Phase, SpawnedFuture},
backend::{
BackendDrmDevice, BackendEvent, Connector, ConnectorEvent, ConnectorId,
ConnectorKernelId, DrmDeviceId, HardwareCursor, MonitorInfo,
ConnectorKernelId, DrmDeviceId, HardwareCursor, Mode, MonitorInfo,
},
backends::metal::{MetalBackend, MetalError},
drm_feedback::DrmFeedback,
@ -155,7 +155,7 @@ pub struct ConnectorDisplayData {
pub crtc_id: MutableProperty<DrmCrtc>,
pub crtcs: AHashMap<DrmCrtc, Rc<MetalCrtc>>,
pub modes: Vec<DrmModeInfo>,
pub mode: Option<Rc<DrmModeInfo>>,
pub mode: Option<DrmModeInfo>,
pub refresh: u32,
pub monitor_manufacturer: String,
@ -862,6 +862,44 @@ impl Connector for MetalConnector {
fn drm_feedback(&self) -> Option<Rc<DrmFeedback>> {
self.drm_feedback.get()
}
fn set_mode(&self, be_mode: Mode) {
let mut dd = self.display.borrow_mut();
let Some(mode) = dd.modes.iter().find(|m| m.to_backend() == be_mode) else {
log::warn!("Connector does not support mode {:?}", be_mode);
return;
};
let prev = dd.mode.clone();
if prev.as_ref() == Some(mode) {
return;
}
if dd.connection != ConnectorStatus::Connected {
log::warn!("Cannot change mode of connector that is not connected");
return;
}
let Some(dev) = self.backend.device_holder.drm_devices.get(&self.dev.devnum) else {
log::warn!("Cannot change mode because underlying device does not exist?");
return;
};
log::info!("Trying to change mode from {:?} to {:?}", prev, mode);
dd.mode = Some(mode.clone());
drop(dd);
let Err(e) = self.backend.handle_drm_change_(&dev, true) else {
self.on_change
.send_event(ConnectorEvent::ModeChanged(be_mode));
return;
};
log::warn!("Could not change mode: {}", ErrorFmt(&e));
self.display.borrow_mut().mode = prev;
if let MetalError::Modeset(DrmError::Atomic(OsError(c::EACCES))) = e {
log::warn!("Failed due to access denied. Resetting in memory only.");
return;
}
log::warn!("Trying to re-initialize the drm device");
if let Err(e) = self.backend.handle_drm_change_(&dev, true) {
log::warn!("Could not restore the previous mode: {}", ErrorFmt(e));
};
}
}
#[derive(Debug)]
@ -1021,7 +1059,7 @@ fn create_connector_display_data(
let mut name = String::new();
let mut manufacturer = String::new();
let mut serial_number = String::new();
let mode = info.modes.first().cloned().map(Rc::new);
let mode = info.modes.first().cloned();
let refresh = mode
.as_ref()
.map(|m| 1_000_000_000_000u64 / (m.refresh_rate_millihz() as u64))
@ -1402,6 +1440,13 @@ impl MetalBackend {
}
};
let mut old = c.display.borrow_mut();
if old.is_same_monitor(&dd) {
if let Some(mode) = &old.mode {
if dd.modes.contains(mode) {
dd.mode = Some(mode.clone());
}
}
}
mem::swap(old.deref_mut(), &mut dd);
if c.connect_sent.get() {
if !c.enabled.get()

View file

@ -1058,6 +1058,10 @@ impl Connector for XOutput {
fn set_enabled(&self, _enabled: bool) {
// nothing
}
fn set_mode(&self, _mode: Mode) {
log::warn!("X backend doesn't support changing the connector mode");
}
}
struct XSeat {

View file

@ -695,6 +695,20 @@ impl ConfigProxyHandler {
Ok(())
}
fn handle_connector_set_mode(
&self,
connector: Connector,
mode: WireMode,
) -> Result<(), CphError> {
let connector = self.get_output(connector)?;
connector.connector.connector.set_mode(backend::Mode {
width: mode.width,
height: mode.height,
refresh_rate_millihz: mode.refresh_millihz,
});
Ok(())
}
fn handle_connector_modes(&self, connector: Connector) -> Result<(), CphError> {
let connector = self.get_output(connector)?;
self.respond(Response::ConnectorModes {
@ -1391,6 +1405,9 @@ impl ConfigProxyHandler {
ClientMessage::ConnectorModes { connector } => self
.handle_connector_modes(connector)
.wrn("connector_modes")?,
ClientMessage::ConnectorSetMode { connector, mode } => self
.handle_connector_set_mode(connector, mode)
.wrn("connector_set_mode")?,
}
Ok(())
}

View file

@ -246,6 +246,10 @@ impl Connector for TestConnector {
fn set_enabled(&self, _enabled: bool) {
// todo
}
fn set_mode(&self, _mode: Mode) {
// todo
}
}
pub struct TestMouseClick {