diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index d8ee6aa..19cd778 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -38,7 +38,6 @@ use smithay::{ connector::{Info as ConnectorInfo, State as ConnectorState}, crtc, encoder::Info as EncoderInfo, - ResourceInfo, }, image::{ImageBuffer, Rgba}, input::Libinput, @@ -283,11 +282,9 @@ impl UdevHandlerImpl { for encoder_info in encoder_infos { for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { if !backends.contains_key(&crtc) { - let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.) - // create a backend let renderer = GliumDrawer::init( device - .create_surface(crtc, mode, vec![connector_info.handle()].into_iter()) + .create_surface(crtc) .unwrap(), egl_display.clone(), logger.clone(), @@ -332,11 +329,9 @@ impl UdevHandlerImpl { for encoder_info in encoder_infos { for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { if !backends.contains_key(&crtc) { - let mode = connector_info.modes()[0]; // Use first mode (usually highest resoltion, but in reality you should filter and sort and check and match with other connectors, if you use more then one.) - // create a backend let renderer = GliumDrawer::init( device - .create_surface(crtc, mode, vec![connector_info.handle()].into_iter()) + .create_surface(crtc) .unwrap(), logger.clone(), ); diff --git a/src/backend/drm/egl/mod.rs b/src/backend/drm/egl/mod.rs index b97cfac..759b65d 100644 --- a/src/backend/drm/egl/mod.rs +++ b/src/backend/drm/egl/mod.rs @@ -1,6 +1,5 @@ -use drm::control::{connector, crtc, Mode, ResourceHandles, ResourceInfo}; +use drm::control::{crtc, ResourceHandles, ResourceInfo}; use nix::libc::dev_t; -use std::iter::FromIterator; use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::Rc; use wayland_server::Display; @@ -25,19 +24,19 @@ pub mod session; /// Representation of an open gbm device to create rendering backends pub struct EglDevice< B: Backend::Surface> + 'static, - D: Device + NativeDisplay + 'static, + D: Device + NativeDisplay + 'static, > where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { dev: Rc>, logger: ::slog::Logger, } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> AsRawFd - for EglDevice +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > AsRawFd for EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn as_raw_fd(&self) -> RawFd { @@ -45,10 +44,11 @@ where } } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> - EglDevice +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { /// Create a new `EglGbmDrmDevice` from an open drm node @@ -96,18 +96,18 @@ where struct InternalDeviceHandler< B: Backend::Surface> + 'static, - D: Device + NativeDisplay + 'static, + D: Device + NativeDisplay + 'static, > where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { handler: Box> + 'static>, } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> - DeviceHandler for InternalDeviceHandler +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > DeviceHandler for InternalDeviceHandler where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { type Device = D; @@ -121,10 +121,11 @@ where } } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> Device - for EglDevice +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > Device for EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { type Surface = EglSurface; @@ -143,17 +144,10 @@ where self.dev.borrow_mut().clear_handler() } - fn create_surface( - &mut self, - crtc: crtc::Handle, - mode: Mode, - connectors: impl IntoIterator, - ) -> Result> { + fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { info!(self.logger, "Initializing EglSurface"); - let surface = self - .dev - .create_surface((crtc, mode, Vec::from_iter(connectors)).into())?; + let surface = self.dev.create_surface(crtc)?; Ok(EglSurface { dev: self.dev.clone(), @@ -181,10 +175,11 @@ where } #[cfg(feature = "native_lib")] -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> - EGLGraphicsBackend for EglDevice +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > EGLGraphicsBackend for EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn bind_wl_display(&self, display: &Display) -> EGLResult { @@ -192,13 +187,14 @@ where } } -impl::Surface> + 'static, D: Device + NativeDisplay + 'static> - Drop for EglDevice +impl< + B: Backend::Surface> + 'static, + D: Device + NativeDisplay + 'static, + > Drop for EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn drop(&mut self) { self.clear_handler(); } -} \ No newline at end of file +} diff --git a/src/backend/drm/egl/session.rs b/src/backend/drm/egl/session.rs index 4b7fc44..7247d2d 100644 --- a/src/backend/drm/egl/session.rs +++ b/src/backend/drm/egl/session.rs @@ -1,5 +1,5 @@ +use drm::control::{connector, crtc, Mode}; use std::os::unix::io::RawFd; -use drm::control::{crtc, connector, Mode}; use super::EglDevice; use backend::drm::Device; @@ -14,10 +14,9 @@ pub struct EglDeviceObserver { impl< S: SessionObserver + 'static, B: Backend::Surface> + 'static, - D: Device + NativeDisplay + AsSessionObserver + 'static, + D: Device + NativeDisplay + AsSessionObserver + 'static, > AsSessionObserver> for EglDevice where - >::Arguments: From<(crtc::Handle, Mode, Vec)>, ::Surface: NativeSurface, { fn observer(&mut self) -> EglDeviceObserver { diff --git a/src/backend/drm/egl/surface.rs b/src/backend/drm/egl/surface.rs index 5573abb..b8be770 100644 --- a/src/backend/drm/egl/surface.rs +++ b/src/backend/drm/egl/surface.rs @@ -54,15 +54,15 @@ where .chain_err(|| ErrorKind::UnderlyingBackendError) } - fn current_mode(&self) -> Mode { + fn current_mode(&self) -> Option { self.surface.current_mode() } - fn pending_mode(&self) -> Mode { + fn pending_mode(&self) -> Option { self.surface.pending_mode() } - fn use_mode(&self, mode: Mode) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<()> { self.surface .use_mode(mode) .chain_err(|| ErrorKind::UnderlyingBackendError) @@ -108,7 +108,7 @@ where } fn get_framebuffer_dimensions(&self) -> (u32, u32) { - let (w, h) = self.pending_mode().size(); + let (w, h) = self.pending_mode().map(|mode| mode.size()).unwrap_or((1, 1)); (w as u32, h as u32) } diff --git a/src/backend/drm/gbm/egl.rs b/src/backend/drm/gbm/egl.rs index 45b36bb..696b400 100644 --- a/src/backend/drm/gbm/egl.rs +++ b/src/backend/drm/gbm/egl.rs @@ -45,28 +45,8 @@ impl Backend for Gbm { } } -/// Arguments necessary to construct a `GbmSurface` -pub struct SurfaceArguments { - /// Crtc - pub crtc: crtc::Handle, - /// Mode - pub mode: Mode, - /// Connectors - pub connectors: Vec, -} - -impl From<(crtc::Handle, Mode, Vec)> for SurfaceArguments { - fn from((crtc, mode, connectors): (crtc::Handle, Mode, Vec)) -> Self { - SurfaceArguments { - crtc, - mode, - connectors: Vec::from_iter(connectors), - } - } -} - unsafe impl NativeDisplay> for GbmDevice { - type Arguments = SurfaceArguments; + type Arguments = crtc::Handle; type Error = Error; fn is_backend(&self) -> bool { @@ -77,8 +57,8 @@ unsafe impl NativeDisplay> for Gb Ok(self.dev.borrow().as_raw() as *const _) } - fn create_surface(&mut self, args: SurfaceArguments) -> Result> { - Device::create_surface(self, args.crtc, args.mode, args.connectors) + fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { + Device::create_surface(self, crtc) } } diff --git a/src/backend/drm/gbm/error.rs b/src/backend/drm/gbm/error.rs index 484e79c..e654c2d 100644 --- a/src/backend/drm/gbm/error.rs +++ b/src/backend/drm/gbm/error.rs @@ -16,6 +16,12 @@ error_chain! { display("Creation of gbm surface failed"), } + #[doc = "No mode is set, blocking the current operation"] + NoModeSet { + description("No mode is currently set"), + display("No mode is currently set"), + } + #[doc = "Creation of gbm buffer object failed"] BufferCreationFailed { description("Creation of gbm buffer object failed"), diff --git a/src/backend/drm/gbm/mod.rs b/src/backend/drm/gbm/mod.rs index 5bdba8c..7b4f4bd 100644 --- a/src/backend/drm/gbm/mod.rs +++ b/src/backend/drm/gbm/mod.rs @@ -119,18 +119,16 @@ impl Device for GbmDevice { self.dev.borrow_mut().clear_handler(); } - fn create_surface( - &mut self, - crtc: crtc::Handle, - mode: Mode, - connectors: impl IntoIterator, - ) -> Result> { + fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { info!(self.logger, "Initializing GbmSurface"); - let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors) + let drm_surface = Device::create_surface(&mut **self.dev.borrow_mut(), crtc) .chain_err(|| ErrorKind::UnderlyingBackendError)?; - let (w, h) = mode.size(); + let (w, h) = drm_surface + .pending_mode() + .map(|mode| mode.size()) + .unwrap_or((1, 1)); let surface = self .dev .borrow() @@ -197,4 +195,4 @@ impl Drop for GbmDevice { fn drop(&mut self) { self.clear_handler(); } -} \ No newline at end of file +} diff --git a/src/backend/drm/gbm/surface.rs b/src/backend/drm/gbm/surface.rs index 70167e7..704ee64 100644 --- a/src/backend/drm/gbm/surface.rs +++ b/src/backend/drm/gbm/surface.rs @@ -90,7 +90,7 @@ impl GbmSurfaceInternal { } pub fn recreate(&self) -> Result<()> { - let (w, h) = self.pending_mode().size(); + let (w, h) = self.pending_mode().chain_err(|| ErrorKind::NoModeSet)?.size(); // Recreate the surface and the related resources to match the new // resolution. @@ -161,15 +161,15 @@ impl Surface for GbmSurfaceInternal { .chain_err(|| ErrorKind::UnderlyingBackendError) } - fn current_mode(&self) -> Mode { + fn current_mode(&self) -> Option { self.crtc.current_mode() } - fn pending_mode(&self) -> Mode { + fn pending_mode(&self) -> Option { self.crtc.pending_mode() } - fn use_mode(&self, mode: Mode) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<()> { self.crtc .use_mode(mode) .chain_err(|| ErrorKind::UnderlyingBackendError) @@ -314,15 +314,15 @@ impl Surface for GbmSurface { self.0.remove_connector(connector) } - fn current_mode(&self) -> Mode { + fn current_mode(&self) -> Option { self.0.current_mode() } - fn pending_mode(&self) -> Mode { + fn pending_mode(&self) -> Option { self.0.pending_mode() } - fn use_mode(&self, mode: Mode) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<()> { self.0.use_mode(mode) } } diff --git a/src/backend/drm/legacy/mod.rs b/src/backend/drm/legacy/mod.rs index 2b46c7b..5a0d221 100644 --- a/src/backend/drm/legacy/mod.rs +++ b/src/backend/drm/legacy/mod.rs @@ -46,7 +46,7 @@ impl AsRawFd for Dev { } impl BasicDevice for Dev {} impl ControlDevice for Dev {} -impl Drop for Dev { +impl Drop for Dev { fn drop(&mut self) { info!(self.logger, "Dropping device: {:?}", self.dev_path()); if self.active.load(Ordering::SeqCst) { @@ -126,7 +126,7 @@ impl LegacyDrmDevice { } } } - + Ok(LegacyDrmDevice { // Open the drm device and create a context based on that dev: Rc::new(dev), @@ -163,12 +163,7 @@ impl Device for LegacyDrmDevice { let _ = self.handler.take(); } - fn create_surface( - &mut self, - crtc: crtc::Handle, - mode: Mode, - connectors: impl IntoIterator, - ) -> Result> { + fn create_surface(&mut self, crtc: crtc::Handle) -> Result> { if self.backends.borrow().contains_key(&crtc) { bail!(ErrorKind::CrtcAlreadyInUse(crtc)); } @@ -177,52 +172,38 @@ impl Device for LegacyDrmDevice { bail!(ErrorKind::DeviceInactive); } - let connectors = HashSet::from_iter(connectors); - // check if we have an encoder for every connector and the mode mode - for connector in &connectors { - let con_info = connector::Info::load_from_device(self, *connector).chain_err(|| { + let crtc_info = crtc::Info::load_from_device(self, crtc) + .chain_err(|| ErrorKind::DrmDev(format!("Error loading crtc info on {:?}", self.dev_path())))?; + + let mode = crtc_info.mode(); + + let mut connectors = HashSet::new(); + let res_handles = ControlDevice::resource_handles(self).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path())) + })?; + for &con in res_handles.connectors() { + let con_info = connector::Info::load_from_device(self, con).chain_err(|| { ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) })?; - - // check the mode - if !con_info.modes().contains(&mode) { - bail!(ErrorKind::ModeNotSuitable(mode)); - } - - // check for every connector which encoders it does support - let encoders = con_info - .encoders() - .iter() - .map(|encoder| { - encoder::Info::load_from_device(self, *encoder).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) - }) - }).collect::>>()?; - - // and if any encoder supports the selected crtc - let resource_handles = ControlDevice::resource_handles(self).chain_err(|| { - ErrorKind::DrmDev(format!("Error loading drm resources on {:?}", self.dev_path())) - })?; - if !encoders - .iter() - .map(|encoder| encoder.possible_crtcs()) - .any(|crtc_list| resource_handles.filter_crtcs(crtc_list).contains(&crtc)) - { - bail!(ErrorKind::NoSuitableEncoder(con_info, crtc)) + if let Some(enc) = con_info.current_encoder() { + let enc_info = encoder::Info::load_from_device(self, enc).chain_err(|| { + ErrorKind::DrmDev(format!("Error loading encoder info on {:?}", self.dev_path())) + })?; + if let Some(current_crtc) = enc_info.current_crtc() { + if crtc == current_crtc { + connectors.insert(con); + } + } } } - // configuration is valid, the kernel will figure out the rest - let logger = self.logger.new(o!("crtc" => format!("{:?}", crtc))); - let state = State { mode, connectors }; - let backend = Rc::new(LegacyDrmSurfaceInternal { dev: self.dev.clone(), crtc, state: RwLock::new(state.clone()), pending: RwLock::new(state), - logger, + logger: self.logger.new(o!("crtc" => format!("{:?}", crtc))), }); self.backends.borrow_mut().insert(crtc, Rc::downgrade(&backend)); diff --git a/src/backend/drm/legacy/surface.rs b/src/backend/drm/legacy/surface.rs index 36a58d7..e1ebbd4 100644 --- a/src/backend/drm/legacy/surface.rs +++ b/src/backend/drm/legacy/surface.rs @@ -15,7 +15,7 @@ use super::{error::*, Dev}; #[derive(Debug, PartialEq, Eq, Clone)] pub struct State { - pub mode: Mode, + pub mode: Option, pub connectors: HashSet, } @@ -77,11 +77,11 @@ impl Surface for LegacyDrmSurfaceInternal { self.pending.read().unwrap().connectors.clone() } - fn current_mode(&self) -> Mode { + fn current_mode(&self) -> Option { self.state.read().unwrap().mode.clone() } - fn pending_mode(&self) -> Mode { + fn pending_mode(&self) -> Option { self.pending.read().unwrap().mode.clone() } @@ -93,7 +93,7 @@ impl Surface for LegacyDrmSurfaceInternal { let mut pending = self.pending.write().unwrap(); // check if the connector can handle the current mode - if info.modes().contains(&pending.mode) { + if info.modes().contains(pending.mode.as_ref().unwrap()) { // check if there is a valid encoder let encoders = info .encoders() @@ -119,7 +119,7 @@ impl Surface for LegacyDrmSurfaceInternal { pending.connectors.insert(connector); Ok(()) } else { - bail!(ErrorKind::ModeNotSuitable(pending.mode)); + bail!(ErrorKind::ModeNotSuitable(pending.mode.unwrap())); } } @@ -128,18 +128,20 @@ impl Surface for LegacyDrmSurfaceInternal { Ok(()) } - fn use_mode(&self, mode: Mode) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<()> { let mut pending = self.pending.write().unwrap(); // check the connectors - for connector in &pending.connectors { - if !connector::Info::load_from_device(self, *connector) - .chain_err(|| { - ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) - })?.modes() - .contains(&mode) - { - bail!(ErrorKind::ModeNotSuitable(mode)); + if let Some(mode) = mode { + for connector in &pending.connectors { + if !connector::Info::load_from_device(self, *connector) + .chain_err(|| { + ErrorKind::DrmDev(format!("Error loading connector info on {:?}", self.dev_path())) + })?.modes() + .contains(&mode) + { + bail!(ErrorKind::ModeNotSuitable(mode)); + } } } @@ -179,7 +181,11 @@ impl RawSurface for LegacyDrmSurfaceInternal { } if current.mode != pending.mode { - info!(self.logger, "Setting new mode: {:?}", pending.mode.name()); + info!( + self.logger, + "Setting new mode: {:?}", + pending.mode.as_ref().unwrap().name() + ); } } @@ -194,7 +200,7 @@ impl RawSurface for LegacyDrmSurfaceInternal { .map(|x| *x) .collect::>(), (0, 0), - Some(pending.mode), + pending.mode, ).chain_err(|| { ErrorKind::DrmDev(format!( "Error setting crtc {:?} on {:?}", @@ -270,11 +276,11 @@ impl Surface for LegacyDrmSurface { self.0.pending_connectors() } - fn current_mode(&self) -> Mode { + fn current_mode(&self) -> Option { self.0.current_mode() } - fn pending_mode(&self) -> Mode { + fn pending_mode(&self) -> Option { self.0.pending_mode() } @@ -286,7 +292,7 @@ impl Surface for LegacyDrmSurface { self.0.remove_connector(connector) } - fn use_mode(&self, mode: Mode) -> Result<()> { + fn use_mode(&self, mode: Option) -> Result<()> { self.0.use_mode(mode) } } diff --git a/src/backend/drm/mod.rs b/src/backend/drm/mod.rs index 2b60f5d..82d3c54 100644 --- a/src/backend/drm/mod.rs +++ b/src/backend/drm/mod.rs @@ -38,8 +38,6 @@ pub trait Device: AsRawFd + DevPath { fn create_surface( &mut self, ctrc: crtc::Handle, - mode: Mode, - connectors: impl IntoIterator, ) -> Result::Error>; fn process_events(&mut self); fn resource_info( @@ -62,9 +60,9 @@ pub trait Surface { fn pending_connectors(&self) -> Self::Connectors; fn add_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>; fn remove_connector(&self, connector: connector::Handle) -> Result<(), Self::Error>; - fn current_mode(&self) -> Mode; - fn pending_mode(&self) -> Mode; - fn use_mode(&self, mode: Mode) -> Result<(), Self::Error>; + fn current_mode(&self) -> Option; + fn pending_mode(&self) -> Option; + fn use_mode(&self, mode: Option) -> Result<(), Self::Error>; } pub trait RawSurface: Surface + ControlDevice + BasicDevice {