drm: Require all surfaces to always have a mode set

This commit is contained in:
Victor Brekenfeld 2020-04-26 16:32:44 +02:00
parent b6087bf2d2
commit d6fa2e96cf
16 changed files with 201 additions and 153 deletions

View File

@ -319,7 +319,7 @@ impl<S: SessionNotifier, Data: 'static> UdevHandlerImpl<S, Data> {
for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) { for crtc in res_handles.filter_crtcs(encoder_info.possible_crtcs()) {
if let Entry::Vacant(entry) = backends.entry(crtc) { if let Entry::Vacant(entry) = backends.entry(crtc) {
let renderer = GliumDrawer::init( let renderer = GliumDrawer::init(
device.create_surface(crtc).unwrap(), device.create_surface(crtc, connector_info.modes()[0], &[connector_info.handle()]).unwrap(),
egl_buffer_reader.clone(), egl_buffer_reader.clone(),
logger.clone(), logger.clone(),
); );

View File

@ -96,9 +96,7 @@ fn main() {
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.) 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.)
// Initialize the hardware backend // Initialize the hardware backend
let surface = Rc::new(device.create_surface(crtc).unwrap()); let surface = Rc::new(device.create_surface(crtc, mode, &[connector_info.handle()]).unwrap());
surface.set_connectors(&[connector_info.handle()]).unwrap();
surface.use_mode(Some(mode)).unwrap();
for conn in surface.current_connectors().into_iter() { for conn in surface.current_connectors().into_iter() {
if conn != connector_info.handle() { if conn != connector_info.handle() {

View File

@ -78,10 +78,8 @@ fn main() {
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.) 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.)
// Initialize the hardware backend // Initialize the hardware backend
let surface = Rc::new(device.create_surface(crtc).unwrap()); let surface = Rc::new(device.create_surface(crtc, mode, &[connector_info.handle()]).unwrap());
surface.use_mode(Some(mode)).unwrap();
surface.set_connectors(&[connector_info.handle()]).unwrap();
/* /*
* Lets create buffers and framebuffers. * Lets create buffers and framebuffers.
* We use drm-rs DumbBuffers, because they always work and require little to no setup. * We use drm-rs DumbBuffers, because they always work and require little to no setup.

View File

@ -19,7 +19,7 @@ use std::sync::{
use drm::control::{atomic::AtomicModeReq, AtomicCommitFlags, Device as ControlDevice, Event}; use drm::control::{atomic::AtomicModeReq, AtomicCommitFlags, Device as ControlDevice, Event};
use drm::control::{ use drm::control::{
connector, crtc, encoder, framebuffer, plane, property, PropertyValueSet, ResourceHandle, ResourceHandles, connector, crtc, encoder, framebuffer, plane, property, Mode, PropertyValueSet, ResourceHandle, ResourceHandles,
}; };
use drm::SystemError as DrmError; use drm::SystemError as DrmError;
use drm::{ClientCapability, Device as BasicDevice}; use drm::{ClientCapability, Device as BasicDevice};
@ -339,7 +339,7 @@ impl<A: AsRawFd + 'static> Device for AtomicDrmDevice<A> {
let _ = self.handler.take(); let _ = self.handler.take();
} }
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<AtomicDrmSurface<A>, Error> { fn create_surface(&mut self, crtc: crtc::Handle, mode: Mode, connectors: &[connector::Handle]) -> Result<AtomicDrmSurface<A>, Error> {
if self.backends.borrow().contains_key(&crtc) { if self.backends.borrow().contains_key(&crtc) {
return Err(Error::CrtcAlreadyInUse(crtc)); return Err(Error::CrtcAlreadyInUse(crtc));
} }
@ -348,9 +348,15 @@ impl<A: AsRawFd + 'static> Device for AtomicDrmDevice<A> {
return Err(Error::DeviceInactive); return Err(Error::DeviceInactive);
} }
if connectors.is_empty() {
return Err(Error::SurfaceWithoutConnectors(crtc));
}
let backend = Rc::new(AtomicDrmSurfaceInternal::new( let backend = Rc::new(AtomicDrmSurfaceInternal::new(
self.dev.clone(), self.dev.clone(),
crtc, crtc,
mode,
connectors,
self.logger.new(o!("crtc" => format!("{:?}", crtc))), self.logger.new(o!("crtc" => format!("{:?}", crtc))),
)?); )?);

View File

@ -1,7 +1,7 @@
use drm::buffer::Buffer; use drm::buffer::Buffer;
use drm::control::atomic::AtomicModeReq; use drm::control::atomic::AtomicModeReq;
use drm::control::Device as ControlDevice; use drm::control::Device as ControlDevice;
use drm::control::{connector, crtc, framebuffer, plane, property, AtomicCommitFlags, Mode, PlaneType}; use drm::control::{connector, crtc, dumbbuffer::DumbBuffer, framebuffer, plane, property, AtomicCommitFlags, Mode, PlaneType};
use drm::Device as BasicDevice; use drm::Device as BasicDevice;
use std::cell::Cell; use std::cell::Cell;
@ -26,8 +26,8 @@ pub struct CursorState {
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub struct State { pub struct State {
pub mode: Option<Mode>, pub mode: Mode,
pub blob: Option<property::Value<'static>>, pub blob: property::Value<'static>,
pub connectors: HashSet<connector::Handle>, pub connectors: HashSet<connector::Handle>,
} }
@ -45,6 +45,7 @@ pub(super) struct AtomicDrmSurfaceInternal<A: AsRawFd + 'static> {
pub(super) state: RwLock<State>, pub(super) state: RwLock<State>,
pub(super) pending: RwLock<State>, pub(super) pending: RwLock<State>,
pub(super) logger: ::slog::Logger, pub(super) logger: ::slog::Logger,
init_buffer: Cell<Option<(DumbBuffer, framebuffer::Handle)>>,
} }
impl<A: AsRawFd + 'static> AsRawFd for AtomicDrmSurfaceInternal<A> { impl<A: AsRawFd + 'static> AsRawFd for AtomicDrmSurfaceInternal<A> {
@ -57,26 +58,36 @@ impl<A: AsRawFd + 'static> BasicDevice for AtomicDrmSurfaceInternal<A> {}
impl<A: AsRawFd + 'static> ControlDevice for AtomicDrmSurfaceInternal<A> {} impl<A: AsRawFd + 'static> ControlDevice for AtomicDrmSurfaceInternal<A> {}
impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> { impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
pub(crate) fn new(dev: Rc<Dev<A>>, crtc: crtc::Handle, logger: ::slog::Logger) -> Result<Self, Error> { pub(crate) fn new(dev: Rc<Dev<A>>, crtc: crtc::Handle, mode: Mode, connectors: &[connector::Handle], logger: ::slog::Logger) -> Result<Self, Error> {
let crtc_info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access { let crtc_info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access {
errmsg: "Error loading crtc info", errmsg: "Error loading crtc info",
dev: dev.dev_path(), dev: dev.dev_path(),
source, source,
})?; })?;
let mode = crtc_info.mode(); // If we have no current mode, we create a fake one, which will not match (and thus gets overriden on the commit below).
let blob = match mode { // A better fix would probably be making mode an `Option`, but that would mean
Some(mode) => Some( // we need to be sure, we require a mode to always be set without relying on the compiler.
dev.create_property_blob(mode) // So we cheat, because it works and is easier to handle later.
.compat() let current_mode = crtc_info.mode().unwrap_or_else(|| unsafe { std::mem::zeroed() });
.map_err(|source| Error::Access { let current_blob = match crtc_info.mode() {
errmsg: "Failed to create Property Blob for mode", Some(mode) => dev.create_property_blob(mode)
dev: dev.dev_path(), .compat()
source, .map_err(|source| Error::Access {
})?, errmsg: "Failed to create Property Blob for mode",
), dev: dev.dev_path(),
None => None, source,
})?,
None => property::Value::Unknown(0),
}; };
let blob = dev.create_property_blob(mode)
.compat()
.map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode",
dev: dev.dev_path(),
source,
})?;
let res_handles = ControlDevice::resource_handles(&*dev) let res_handles = ControlDevice::resource_handles(&*dev)
.compat() .compat()
@ -86,12 +97,8 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
source, source,
})?; })?;
let mut state = State {
mode,
blob,
connectors: HashSet::new(),
};
let mut current_connectors = HashSet::new();
for conn in res_handles.connectors() { for conn in res_handles.connectors() {
let crtc_prop = dev let crtc_prop = dev
.prop_mapping .prop_mapping
@ -113,7 +120,7 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
crtc_prop_info.value_type().convert_value(val) crtc_prop_info.value_type().convert_value(val)
{ {
if conn_crtc == crtc { if conn_crtc == crtc {
state.connectors.insert(*conn); current_connectors.insert(*conn);
} }
} }
break; break;
@ -121,13 +128,23 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
} }
} }
} }
let state = State {
mode: current_mode,
blob: current_blob,
connectors: current_connectors,
};
let pending = State {
mode,
blob,
connectors: connectors.into_iter().copied().collect(),
};
let (primary, cursor) = let (primary, cursor) =
AtomicDrmSurfaceInternal::find_planes(&dev, crtc).ok_or(Error::NoSuitablePlanes { AtomicDrmSurfaceInternal::find_planes(&dev, crtc).ok_or(Error::NoSuitablePlanes {
crtc, crtc,
dev: dev.dev_path(), dev: dev.dev_path(),
})?; })?;
Ok(AtomicDrmSurfaceInternal { let surface = AtomicDrmSurfaceInternal {
dev, dev,
crtc, crtc,
cursor: CursorState { cursor: CursorState {
@ -136,10 +153,22 @@ impl<A: AsRawFd + 'static> AtomicDrmSurfaceInternal<A> {
hotspot: Cell::new((0, 0)), hotspot: Cell::new((0, 0)),
}, },
planes: Planes { primary, cursor }, planes: Planes { primary, cursor },
state: RwLock::new(state.clone()), state: RwLock::new(state),
pending: RwLock::new(state), pending: RwLock::new(pending),
logger, logger,
}) init_buffer: Cell::new(None),
};
Ok(surface)
}
}
impl<A: AsRawFd + 'static> Drop for AtomicDrmSurfaceInternal<A> {
fn drop(&mut self) {
if let Some((db, fb)) = self.init_buffer.take() {
let _ = self.destroy_framebuffer(fb);
let _ = self.destroy_dumb_buffer(db);
}
} }
} }
@ -159,11 +188,11 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
self.pending.read().unwrap().connectors.clone() self.pending.read().unwrap().connectors.clone()
} }
fn current_mode(&self) -> Option<Mode> { fn current_mode(&self) -> Mode {
self.state.read().unwrap().mode self.state.read().unwrap().mode
} }
fn pending_mode(&self) -> Option<Mode> { fn pending_mode(&self) -> Mode {
self.pending.read().unwrap().mode self.pending.read().unwrap().mode
} }
@ -180,15 +209,15 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
let mut pending = self.pending.write().unwrap(); let mut pending = self.pending.write().unwrap();
// check if the connector can handle the current mode // check if the connector can handle the current mode
if info.modes().contains(pending.mode.as_ref().unwrap()) { if info.modes().contains(&pending.mode) {
// check if config is supported // check if config is supported
let req = self.build_request( let req = self.build_request(
&mut [conn].iter(), &mut [conn].iter(),
&mut [].iter(), &mut [].iter(),
&self.planes, &self.planes,
None, None,
pending.mode, Some(pending.mode),
pending.blob, Some(pending.blob),
)?; )?;
self.atomic_commit( self.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], &[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
@ -202,7 +231,7 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
Ok(()) Ok(())
} else { } else {
Err(Error::ModeNotSuitable(pending.mode.unwrap())) Err(Error::ModeNotSuitable(pending.mode))
} }
} }
@ -215,8 +244,8 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
&mut [conn].iter(), &mut [conn].iter(),
&self.planes, &self.planes,
None, None,
pending.mode, Some(pending.mode),
pending.blob, Some(pending.blob),
)?; )?;
self.atomic_commit( self.atomic_commit(
&[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly], &[AtomicCommitFlags::AllowModeset, AtomicCommitFlags::TestOnly],
@ -244,8 +273,8 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
&mut removed, &mut removed,
&self.planes, &self.planes,
None, None,
pending.mode, Some(pending.mode),
pending.blob, Some(pending.blob),
)?; )?;
self.atomic_commit( self.atomic_commit(
@ -259,30 +288,26 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
Ok(()) Ok(())
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> { fn use_mode(&self, mode: Mode) -> Result<(), Error> {
let mut pending = self.pending.write().unwrap(); let mut pending = self.pending.write().unwrap();
// check if new config is supported // check if new config is supported
let new_blob = Some(match mode { let new_blob = self
Some(mode) => self
.dev
.create_property_blob(mode) .create_property_blob(mode)
.compat() .compat()
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
errmsg: "Failed to create Property Blob for mode", errmsg: "Failed to create Property Blob for mode",
dev: self.dev_path(), dev: self.dev_path(),
source, source,
})?, })?;
None => property::Value::Unknown(0),
});
let req = self.build_request( let req = self.build_request(
&mut pending.connectors.iter(), &mut pending.connectors.iter(),
&mut [].iter(), &mut [].iter(),
&self.planes, &self.planes,
None, None,
mode, Some(mode),
new_blob, Some(new_blob),
)?; )?;
if let Err(err) = self if let Err(err) = self
.atomic_commit( .atomic_commit(
@ -292,7 +317,7 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurfaceInternal<A> {
.compat() .compat()
.map_err(|_| Error::TestFailed(self.crtc)) .map_err(|_| Error::TestFailed(self.crtc))
{ {
let _ = self.dev.destroy_property_blob(new_blob.unwrap().into()); let _ = self.dev.destroy_property_blob(new_blob.into());
return Err(err); return Err(err);
} }
@ -343,7 +368,7 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurfaceInternal<A> {
info!( info!(
self.logger, self.logger,
"Setting new mode: {:?}", "Setting new mode: {:?}",
pending.mode.as_ref().unwrap().name() pending.mode.name()
); );
} }
@ -355,8 +380,8 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurfaceInternal<A> {
&mut removed, &mut removed,
&self.planes, &self.planes,
Some(framebuffer), Some(framebuffer),
pending.mode, Some(pending.mode),
pending.blob, Some(pending.blob),
)?; )?;
if let Err(err) = self if let Err(err) = self
@ -380,15 +405,13 @@ impl<A: AsRawFd + 'static> RawSurface for AtomicDrmSurfaceInternal<A> {
&mut [].iter(), &mut [].iter(),
&self.planes, &self.planes,
Some(framebuffer), Some(framebuffer),
current.mode, Some(current.mode),
current.blob, Some(current.blob),
)? )?
} else { } else {
if current.mode != pending.mode { if current.mode != pending.mode {
if let Some(blob) = current.blob { if let Err(err) = self.dev.destroy_property_blob(current.blob.into()) {
if let Err(err) = self.dev.destroy_property_blob(blob.into()) { warn!(self.logger, "Failed to destory old mode property blob: {}", err);
warn!(self.logger, "Failed to destory old mode property blob: {}", err);
}
} }
} }
*current = pending.clone(); *current = pending.clone();
@ -834,11 +857,11 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurface<A> {
self.0.pending_connectors() self.0.pending_connectors()
} }
fn current_mode(&self) -> Option<Mode> { fn current_mode(&self) -> Mode {
self.0.current_mode() self.0.current_mode()
} }
fn pending_mode(&self) -> Option<Mode> { fn pending_mode(&self) -> Mode {
self.0.pending_mode() self.0.pending_mode()
} }
@ -854,7 +877,7 @@ impl<A: AsRawFd + 'static> Surface for AtomicDrmSurface<A> {
self.0.set_connectors(connectors) self.0.set_connectors(connectors)
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> { fn use_mode(&self, mode: Mode) -> Result<(), Error> {
self.0.use_mode(mode) self.0.use_mode(mode)
} }
} }

View File

@ -244,10 +244,10 @@ where
} }
} }
fallback_device_impl!(clear_handler, &mut Self); fallback_device_impl!(clear_handler, &mut Self);
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<Self::Surface, E> { fn create_surface(&mut self, crtc: crtc::Handle, mode: Mode, connectors: &[connector::Handle]) -> Result<Self::Surface, E> {
match self { match self {
FallbackDevice::Preference(dev) => Ok(FallbackSurface::Preference(dev.create_surface(crtc)?)), FallbackDevice::Preference(dev) => Ok(FallbackSurface::Preference(dev.create_surface(crtc, mode, connectors)?)),
FallbackDevice::Fallback(dev) => Ok(FallbackSurface::Fallback(dev.create_surface(crtc)?)), FallbackDevice::Fallback(dev) => Ok(FallbackSurface::Fallback(dev.create_surface(crtc, mode, connectors)?)),
} }
} }
fallback_device_impl!(process_events, &mut Self); fallback_device_impl!(process_events, &mut Self);
@ -297,9 +297,9 @@ where
fallback_surface_impl!(add_connector, &Self, Result<(), E>, conn: connector::Handle); fallback_surface_impl!(add_connector, &Self, Result<(), E>, conn: connector::Handle);
fallback_surface_impl!(remove_connector, &Self, Result<(), E>, conn: connector::Handle); fallback_surface_impl!(remove_connector, &Self, Result<(), E>, conn: connector::Handle);
fallback_surface_impl!(set_connectors, &Self, Result<(), E>, conns: &[connector::Handle]); fallback_surface_impl!(set_connectors, &Self, Result<(), E>, conns: &[connector::Handle]);
fallback_surface_impl!(current_mode, &Self, Option<Mode>); fallback_surface_impl!(current_mode, &Self, Mode);
fallback_surface_impl!(pending_mode, &Self, Option<Mode>); fallback_surface_impl!(pending_mode, &Self, Mode);
fallback_surface_impl!(use_mode, &Self, Result<(), E>, mode: Option<Mode>); fallback_surface_impl!(use_mode, &Self, Result<(), E>, mode: Mode);
} }
impl<E, C, S1, S2> RawSurface for FallbackSurface<S1, S2> impl<E, C, S1, S2> RawSurface for FallbackSurface<S1, S2>

View File

@ -40,6 +40,9 @@ pub enum Error {
/// The given crtc is already in use by another backend /// The given crtc is already in use by another backend
#[error("Crtc `{0:?}` is already in use by another backend")] #[error("Crtc `{0:?}` is already in use by another backend")]
CrtcAlreadyInUse(crtc::Handle), CrtcAlreadyInUse(crtc::Handle),
/// This operation would result in a surface without connectors.
#[error("Surface of crtc `{0:?}` would have no connectors, which is not accepted")]
SurfaceWithoutConnectors(crtc::Handle),
/// No encoder was found for a given connector on the set crtc /// No encoder was found for a given connector on the set crtc
#[error("No encoder found for the given connector '{connector:?}' on crtc `{crtc:?}`")] #[error("No encoder found for the given connector '{connector:?}' on crtc `{crtc:?}`")]
NoSuitableEncoder { NoSuitableEncoder {

View File

@ -8,7 +8,7 @@
//! Take a look at `anvil`s source code for an example of this. //! Take a look at `anvil`s source code for an example of this.
//! //!
use drm::control::{connector, crtc, encoder, framebuffer, plane, ResourceHandles}; use drm::control::{connector, crtc, encoder, framebuffer, plane, Mode, ResourceHandles};
use drm::SystemError as DrmError; use drm::SystemError as DrmError;
use nix::libc::dev_t; use nix::libc::dev_t;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
@ -40,11 +40,13 @@ pub enum Error<U: std::error::Error + std::fmt::Debug + std::fmt::Display + 'sta
Underlying(#[source] U), Underlying(#[source] U),
} }
type Arguments = (crtc::Handle, Mode, Vec<connector::Handle>);
/// Representation of an egl device to create egl rendering surfaces /// Representation of an egl device to create egl rendering surfaces
pub struct EglDevice<B, D> pub struct EglDevice<B, D>
where where
B: Backend<Surface = <D as Device>::Surface> + 'static, B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static, D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
dev: EGLDisplay<B, D>, dev: EGLDisplay<B, D>,
@ -56,7 +58,7 @@ where
impl<B, D> AsRawFd for EglDevice<B, D> impl<B, D> AsRawFd for EglDevice<B, D>
where where
B: Backend<Surface = <D as Device>::Surface> + 'static, B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static, D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
fn as_raw_fd(&self) -> RawFd { fn as_raw_fd(&self) -> RawFd {
@ -67,7 +69,7 @@ where
impl<B, D> EglDevice<B, D> impl<B, D> EglDevice<B, D>
where where
B: Backend<Surface = <D as Device>::Surface> + 'static, B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static, D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
/// Try to create a new [`EglDevice`] from an open device. /// Try to create a new [`EglDevice`] from an open device.
@ -122,7 +124,7 @@ where
struct InternalDeviceHandler<B, D> struct InternalDeviceHandler<B, D>
where where
B: Backend<Surface = <D as Device>::Surface> + 'static, B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static, D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
handler: Box<dyn DeviceHandler<Device = EglDevice<B, D>> + 'static>, handler: Box<dyn DeviceHandler<Device = EglDevice<B, D>> + 'static>,
@ -131,7 +133,7 @@ where
impl<B, D> DeviceHandler for InternalDeviceHandler<B, D> impl<B, D> DeviceHandler for InternalDeviceHandler<B, D>
where where
B: Backend<Surface = <D as Device>::Surface> + 'static, B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static, D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
type Device = D; type Device = D;
@ -147,7 +149,7 @@ where
impl<B, D> Device for EglDevice<B, D> impl<B, D> Device for EglDevice<B, D>
where where
B: Backend<Surface = <D as Device>::Surface> + 'static, B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static, D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
type Surface = EglSurface<<D as Device>::Surface>; type Surface = EglSurface<<D as Device>::Surface>;
@ -169,6 +171,8 @@ where
fn create_surface( fn create_surface(
&mut self, &mut self,
crtc: crtc::Handle, crtc: crtc::Handle,
mode: Mode,
connectors: &[connector::Handle],
) -> Result<Self::Surface, <Self::Surface as Surface>::Error> { ) -> Result<Self::Surface, <Self::Surface as Surface>::Error> {
info!(self.logger, "Initializing EglSurface"); info!(self.logger, "Initializing EglSurface");
@ -182,7 +186,7 @@ where
context.get_pixel_format(), context.get_pixel_format(),
self.default_requirements.double_buffer, self.default_requirements.double_buffer,
context.get_config_id(), context.get_config_id(),
crtc, (crtc, mode, Vec::from(connectors)),
) )
.map_err(Error::EGL)?; .map_err(Error::EGL)?;
@ -221,7 +225,7 @@ where
impl<B, D> EGLGraphicsBackend for EglDevice<B, D> impl<B, D> EGLGraphicsBackend for EglDevice<B, D>
where where
B: Backend<Surface = <D as Device>::Surface> + 'static, B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static, D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
fn bind_wl_display(&self, display: &Display) -> Result<EGLBufferReader, EGLError> { fn bind_wl_display(&self, display: &Display) -> Result<EGLBufferReader, EGLError> {
@ -232,7 +236,7 @@ where
impl<B, D> Drop for EglDevice<B, D> impl<B, D> Drop for EglDevice<B, D>
where where
B: Backend<Surface = <D as Device>::Surface> + 'static, B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + 'static, D: Device + NativeDisplay<B, Arguments = Arguments> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
fn drop(&mut self) { fn drop(&mut self) {

View File

@ -3,7 +3,7 @@
//! to an open [`Session`](::backend::session::Session). //! to an open [`Session`](::backend::session::Session).
//! //!
use drm::control::crtc; use drm::control::{crtc, connector, Mode};
use std::os::unix::io::RawFd; use std::os::unix::io::RawFd;
use super::EglDevice; use super::EglDevice;
@ -22,7 +22,7 @@ impl<S, B, D> AsSessionObserver<EglDeviceObserver<S>> for EglDevice<B, D>
where where
S: SessionObserver + 'static, S: SessionObserver + 'static,
B: Backend<Surface = <D as Device>::Surface> + 'static, B: Backend<Surface = <D as Device>::Surface> + 'static,
D: Device + NativeDisplay<B, Arguments = crtc::Handle> + AsSessionObserver<S> + 'static, D: Device + NativeDisplay<B, Arguments = (crtc::Handle, Mode, Vec<connector::Handle>)> + AsSessionObserver<S> + 'static,
<D as Device>::Surface: NativeSurface, <D as Device>::Surface: NativeSurface,
{ {
fn observer(&mut self) -> EglDeviceObserver<S> { fn observer(&mut self) -> EglDeviceObserver<S> {

View File

@ -53,15 +53,15 @@ where
self.surface.set_connectors(connectors).map_err(Error::Underlying) self.surface.set_connectors(connectors).map_err(Error::Underlying)
} }
fn current_mode(&self) -> Option<Mode> { fn current_mode(&self) -> Mode {
self.surface.current_mode() self.surface.current_mode()
} }
fn pending_mode(&self) -> Option<Mode> { fn pending_mode(&self) -> Mode {
self.surface.pending_mode() self.surface.pending_mode()
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> { fn use_mode(&self, mode: Mode) -> Result<(), Self::Error> {
self.surface.use_mode(mode).map_err(Error::Underlying) self.surface.use_mode(mode).map_err(Error::Underlying)
} }
} }
@ -100,7 +100,7 @@ where
} }
fn get_framebuffer_dimensions(&self) -> (u32, u32) { fn get_framebuffer_dimensions(&self) -> (u32, u32) {
let (w, h) = self.pending_mode().map(|mode| mode.size()).unwrap_or((1, 1)); let (w, h) = self.pending_mode().size();
(w as u32, h as u32) (w as u32, h as u32)
} }

View File

@ -12,7 +12,7 @@ use crate::backend::graphics::SwapBuffersError;
use super::{Error, GbmDevice, GbmSurface}; use super::{Error, GbmDevice, GbmSurface};
use drm::control::{crtc, Device as ControlDevice}; use drm::control::{crtc, connector, Device as ControlDevice, Mode};
use gbm::AsRaw; use gbm::AsRaw;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::ptr; use std::ptr;
@ -52,7 +52,7 @@ impl<D: RawDevice + 'static> Backend for Gbm<D> {
} }
unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for GbmDevice<D> { unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for GbmDevice<D> {
type Arguments = crtc::Handle; type Arguments = (crtc::Handle, Mode, Vec<connector::Handle>);
type Error = Error<<<D as Device>::Surface as Surface>::Error>; type Error = Error<<<D as Device>::Surface as Surface>::Error>;
fn is_backend(&self) -> bool { fn is_backend(&self) -> bool {
@ -63,8 +63,8 @@ unsafe impl<D: RawDevice + ControlDevice + 'static> NativeDisplay<Gbm<D>> for Gb
Ok(self.dev.borrow().as_raw() as *const _) Ok(self.dev.borrow().as_raw() as *const _)
} }
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<GbmSurface<D>, Self::Error> { fn create_surface(&mut self, args: Self::Arguments) -> Result<GbmSurface<D>, Self::Error> {
Device::create_surface(self, crtc) Device::create_surface(self, args.0, args.1, &args.2)
} }
} }

View File

@ -11,7 +11,7 @@
use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface}; use super::{Device, DeviceHandler, RawDevice, ResourceHandles, Surface};
use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice}; use drm::control::{connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Mode};
use drm::SystemError as DrmError; use drm::SystemError as DrmError;
use gbm::{self, BufferObjectFlags, Format as GbmFormat}; use gbm::{self, BufferObjectFlags, Format as GbmFormat};
use nix::libc::dev_t; use nix::libc::dev_t;
@ -33,9 +33,6 @@ pub enum Error<U: std::error::Error + std::fmt::Debug + std::fmt::Display + 'sta
/// Creation of GBM surface failed /// Creation of GBM surface failed
#[error("Creation of GBM surface failed")] #[error("Creation of GBM surface failed")]
SurfaceCreationFailed(#[source] io::Error), SurfaceCreationFailed(#[source] io::Error),
/// No mode is set, blocking the current operation
#[error("No mode is currently set")]
NoModeSet,
/// Creation of GBM buffer object failed /// Creation of GBM buffer object failed
#[error("Creation of GBM buffer object failed")] #[error("Creation of GBM buffer object failed")]
BufferCreationFailed(#[source] io::Error), BufferCreationFailed(#[source] io::Error),
@ -159,17 +156,18 @@ impl<D: RawDevice + ControlDevice + 'static> Device for GbmDevice<D> {
fn create_surface( fn create_surface(
&mut self, &mut self,
crtc: crtc::Handle, crtc: crtc::Handle,
mode: Mode,
connectors: &[connector::Handle],
) -> Result<GbmSurface<D>, Error<<<D as Device>::Surface as Surface>::Error>> { ) -> Result<GbmSurface<D>, Error<<<D as Device>::Surface as Surface>::Error>> {
info!(self.logger, "Initializing GbmSurface"); info!(self.logger, "Initializing GbmSurface");
let drm_surface = let drm_surface =
Device::create_surface(&mut **self.dev.borrow_mut(), crtc).map_err(Error::Underlying)?; Device::create_surface(&mut **self.dev.borrow_mut(), crtc, mode, connectors).map_err(Error::Underlying)?;
// initialize the surface // initialize the surface
let (w, h) = drm_surface let (w, h) = drm_surface
.pending_mode() .pending_mode()
.map(|mode| mode.size()) .size();
.unwrap_or((1, 1));
let surface = self let surface = self
.dev .dev
.borrow() .borrow()

View File

@ -93,8 +93,6 @@ impl<D: RawDevice + 'static> GbmSurfaceInternal<D> {
pub fn recreate(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> { pub fn recreate(&self) -> Result<(), Error<<<D as Device>::Surface as Surface>::Error>> {
let (w, h) = self let (w, h) = self
.pending_mode() .pending_mode()
.or_else(|| self.current_mode())
.ok_or(Error::NoModeSet)?
.size(); .size();
// Recreate the surface and the related resources to match the new // Recreate the surface and the related resources to match the new
@ -167,15 +165,15 @@ impl<D: RawDevice + 'static> Surface for GbmSurfaceInternal<D> {
self.crtc.set_connectors(connectors).map_err(Error::Underlying) self.crtc.set_connectors(connectors).map_err(Error::Underlying)
} }
fn current_mode(&self) -> Option<Mode> { fn current_mode(&self) -> Mode {
self.crtc.current_mode() self.crtc.current_mode()
} }
fn pending_mode(&self) -> Option<Mode> { fn pending_mode(&self) -> Mode {
self.crtc.pending_mode() self.crtc.pending_mode()
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> { fn use_mode(&self, mode: Mode) -> Result<(), Self::Error> {
self.crtc.use_mode(mode).map_err(Error::Underlying) self.crtc.use_mode(mode).map_err(Error::Underlying)
} }
} }
@ -325,15 +323,15 @@ impl<D: RawDevice + 'static> Surface for GbmSurface<D> {
self.0.set_connectors(connectors) self.0.set_connectors(connectors)
} }
fn current_mode(&self) -> Option<Mode> { fn current_mode(&self) -> Mode {
self.0.current_mode() self.0.current_mode()
} }
fn pending_mode(&self) -> Option<Mode> { fn pending_mode(&self) -> Mode {
self.0.pending_mode() self.0.pending_mode()
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error> { fn use_mode(&self, mode: Mode) -> Result<(), Self::Error> {
self.0.use_mode(mode) self.0.use_mode(mode)
} }
} }

View File

@ -11,24 +11,24 @@
use super::{common::Error, DevPath, Device, DeviceHandler, RawDevice}; use super::{common::Error, DevPath, Device, DeviceHandler, RawDevice};
use drm::control::{ use drm::control::{
connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Event, ResourceHandles, connector, crtc, encoder, framebuffer, plane, Device as ControlDevice, Event, Mode, ResourceHandles,
}; };
use drm::{Device as BasicDevice, SystemError as DrmError}; use drm::{Device as BasicDevice, SystemError as DrmError};
use nix::libc::dev_t; use nix::libc::dev_t;
use nix::sys::stat::fstat; use nix::sys::stat::fstat;
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::{HashMap, HashSet}; use std::collections::HashMap;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::{Rc, Weak}; use std::rc::{Rc, Weak};
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, RwLock}; use std::sync::Arc;
use failure::{Fail, ResultExt}; use failure::{Fail, ResultExt};
mod surface; mod surface;
pub use self::surface::LegacyDrmSurface; pub use self::surface::LegacyDrmSurface;
use self::surface::{LegacyDrmSurfaceInternal, State}; use self::surface::LegacyDrmSurfaceInternal;
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
pub mod session; pub mod session;
@ -241,7 +241,7 @@ impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
let _ = self.handler.take(); let _ = self.handler.take();
} }
fn create_surface(&mut self, crtc: crtc::Handle) -> Result<LegacyDrmSurface<A>, Error> { fn create_surface(&mut self, crtc: crtc::Handle, mode: Mode, connectors: &[connector::Handle]) -> Result<LegacyDrmSurface<A>, Error> {
if self.backends.borrow().contains_key(&crtc) { if self.backends.borrow().contains_key(&crtc) {
return Err(Error::CrtcAlreadyInUse(crtc)); return Err(Error::CrtcAlreadyInUse(crtc));
} }
@ -250,8 +250,12 @@ impl<A: AsRawFd + 'static> Device for LegacyDrmDevice<A> {
return Err(Error::DeviceInactive); return Err(Error::DeviceInactive);
} }
if connectors.is_empty() {
return Err(Error::SurfaceWithoutConnectors(crtc));
}
let backend = Rc::new(LegacyDrmSurfaceInternal::new( let backend = Rc::new(LegacyDrmSurfaceInternal::new(
self.dev.clone(), crtc, self.dev.clone(), crtc, mode, connectors,
self.logger.new(o!("crtc" => format!("{:?}", crtc))), self.logger.new(o!("crtc" => format!("{:?}", crtc))),
)?); )?);

View File

@ -5,6 +5,7 @@ use drm::control::{
}; };
use drm::Device as BasicDevice; use drm::Device as BasicDevice;
use std::cell::Cell;
use std::collections::HashSet; use std::collections::HashSet;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::rc::Rc; use std::rc::Rc;
@ -20,7 +21,7 @@ use failure::{Fail, ResultExt};
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub struct State { pub struct State {
pub mode: Option<Mode>, pub mode: Mode,
pub connectors: HashSet<connector::Handle>, pub connectors: HashSet<connector::Handle>,
} }
@ -30,6 +31,7 @@ pub(super) struct LegacyDrmSurfaceInternal<A: AsRawFd + 'static> {
pub(super) state: RwLock<State>, pub(super) state: RwLock<State>,
pub(super) pending: RwLock<State>, pub(super) pending: RwLock<State>,
pub(super) logger: ::slog::Logger, pub(super) logger: ::slog::Logger,
init_buffer: Cell<Option<(DumbBuffer, framebuffer::Handle)>>,
} }
impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmSurfaceInternal<A> { impl<A: AsRawFd + 'static> AsRawFd for LegacyDrmSurfaceInternal<A> {
@ -96,18 +98,18 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
self.pending.read().unwrap().connectors.clone() self.pending.read().unwrap().connectors.clone()
} }
fn current_mode(&self) -> Option<Mode> { fn current_mode(&self) -> Mode {
self.state.read().unwrap().mode self.state.read().unwrap().mode
} }
fn pending_mode(&self) -> Option<Mode> { fn pending_mode(&self) -> Mode {
self.pending.read().unwrap().mode self.pending.read().unwrap().mode
} }
fn add_connector(&self, conn: connector::Handle) -> Result<(), Error> { fn add_connector(&self, conn: connector::Handle) -> Result<(), Error> {
let mut pending = self.pending.write().unwrap(); let mut pending = self.pending.write().unwrap();
if self.check_connector(conn, pending.mode.as_ref().unwrap())? { if self.check_connector(conn, &pending.mode)? {
pending.connectors.insert(conn); pending.connectors.insert(conn);
} }
@ -124,7 +126,7 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
if connectors if connectors
.iter() .iter()
.map(|conn| self.check_connector(*conn, pending.mode.as_ref().unwrap())) .map(|conn| self.check_connector(*conn, &pending.mode))
.collect::<Result<Vec<bool>, _>>()? .collect::<Result<Vec<bool>, _>>()?
.iter() .iter()
.all(|v| *v) .all(|v| *v)
@ -135,25 +137,23 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurfaceInternal<A> {
Ok(()) Ok(())
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> { fn use_mode(&self, mode: Mode) -> Result<(), Error> {
let mut pending = self.pending.write().unwrap(); let mut pending = self.pending.write().unwrap();
// check the connectors to see if this mode is supported // check the connectors to see if this mode is supported
if let Some(mode) = mode { for connector in &pending.connectors {
for connector in &pending.connectors { if !self
if !self .get_connector(*connector)
.get_connector(*connector) .compat()
.compat() .map_err(|source| Error::Access {
.map_err(|source| Error::Access { errmsg: "Error loading connector info",
errmsg: "Error loading connector info", dev: self.dev_path(),
dev: self.dev_path(), source,
source, })?
})? .modes()
.modes() .contains(&mode)
.contains(&mode) {
{ return Err(Error::ModeNotSuitable(mode));
return Err(Error::ModeNotSuitable(mode));
}
} }
} }
@ -211,7 +211,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
info!( info!(
self.logger, self.logger,
"Setting new mode: {:?}", "Setting new mode: {:?}",
pending.mode.as_ref().unwrap().name() pending.mode.name()
); );
} }
} }
@ -226,7 +226,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
.iter() .iter()
.copied() .copied()
.collect::<Vec<connector::Handle>>(), .collect::<Vec<connector::Handle>>(),
pending.mode, Some(pending.mode),
) )
.compat() .compat()
.map_err(|source| Error::Access { .map_err(|source| Error::Access {
@ -266,7 +266,7 @@ impl<A: AsRawFd + 'static> RawSurface for LegacyDrmSurfaceInternal<A> {
} }
impl<A: AsRawFd + 'static> LegacyDrmSurfaceInternal<A> { impl<A: AsRawFd + 'static> LegacyDrmSurfaceInternal<A> {
pub(crate) fn new(dev: Rc<Dev<A>>, crtc: crtc::Handle, logger: ::slog::Logger) -> Result<LegacyDrmSurfaceInternal<A>, Error> { pub(crate) fn new(dev: Rc<Dev<A>>, crtc: crtc::Handle, mode: Mode, connectors: &[connector::Handle], logger: ::slog::Logger) -> Result<LegacyDrmSurfaceInternal<A>, Error> {
// Try to enumarate the current state to set the initial state variable correctly // Try to enumarate the current state to set the initial state variable correctly
let crtc_info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access { let crtc_info = dev.get_crtc(crtc).compat().map_err(|source| Error::Access {
errmsg: "Error loading crtc info", errmsg: "Error loading crtc info",
@ -304,14 +304,20 @@ impl<A: AsRawFd + 'static> LegacyDrmSurfaceInternal<A> {
} }
} }
let state = State { current_mode, current_connectors }; // If we have no current mode, we create a fake one, which will not match (and thus gets overriden on the commit below).
// A better fix would probably be making mode an `Option`, but that would mean
// we need to be sure, we require a mode to always be set without relying on the compiler.
// So we cheat, because it works and is easier to handle later.
let state = State { mode: current_mode.unwrap_or_else(|| unsafe { std::mem::zeroed() }), connectors: current_connectors };
let pending = State { mode, connectors: connectors.into_iter().copied().collect() };
let surface = LegacyDrmSurfaceInternal { let surface = LegacyDrmSurfaceInternal {
dev, dev,
crtc, crtc,
state: RwLock::new(state), state: RwLock::new(state),
pending: RwLock::new(state.clone()), pending: RwLock::new(pending),
logger, logger,
init_buffer: Cell::new(None),
}; };
Ok(surface) Ok(surface)
@ -371,6 +377,10 @@ impl<A: AsRawFd + 'static> Drop for LegacyDrmSurfaceInternal<A> {
fn drop(&mut self) { fn drop(&mut self) {
// ignore failure at this point // ignore failure at this point
let _ = self.set_cursor(self.crtc, Option::<&DumbBuffer>::None); let _ = self.set_cursor(self.crtc, Option::<&DumbBuffer>::None);
if let Some((db, fb)) = self.init_buffer.take() {
let _ = self.destroy_framebuffer(fb);
let _ = self.destroy_dumb_buffer(db);
}
} }
} }
@ -419,11 +429,11 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurface<A> {
self.0.pending_connectors() self.0.pending_connectors()
} }
fn current_mode(&self) -> Option<Mode> { fn current_mode(&self) -> Mode {
self.0.current_mode() self.0.current_mode()
} }
fn pending_mode(&self) -> Option<Mode> { fn pending_mode(&self) -> Mode {
self.0.pending_mode() self.0.pending_mode()
} }
@ -439,7 +449,7 @@ impl<A: AsRawFd + 'static> Surface for LegacyDrmSurface<A> {
self.0.set_connectors(connectors) self.0.set_connectors(connectors)
} }
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Error> { fn use_mode(&self, mode: Mode) -> Result<(), Error> {
self.0.use_mode(mode) self.0.use_mode(mode)
} }
} }

View File

@ -94,16 +94,23 @@ pub trait Device: AsRawFd + DevPath {
/// Creates a new rendering surface. /// Creates a new rendering surface.
/// ///
/// # Arguments
///
/// Initialization of surfaces happens through the types provided by /// Initialization of surfaces happens through the types provided by
/// [`drm-rs`](drm). /// [`drm-rs`](drm).
/// ///
/// [`crtc`](drm::control::crtc)s represent scanout engines /// - [`crtc`](drm::control::crtc)s represent scanout engines of the device pointing to one framebuffer. \
/// of the device pointer to one framebuffer. /// Their responsibility is to read the data of the framebuffer and export it into an "Encoder". \
/// Their responsibility is to read the data of the framebuffer and export it into an "Encoder". /// The number of crtc's represent the number of independant output devices the hardware may handle.
/// The number of crtc's represent the number of independant output devices the hardware may handle. /// - [`mode`](drm::control::Mode) describes the resolution and rate of images produced by the crtc and \
/// has to be compatible with the provided `connectors`.
/// - [`connectors`] - List of connectors driven by the crtc. At least one(!) connector needs to be \
/// attached to a crtc in smithay.
fn create_surface( fn create_surface(
&mut self, &mut self,
crtc: crtc::Handle, crtc: crtc::Handle,
mode: Mode,
connectors: &[connector::Handle]
) -> Result<Self::Surface, <Self::Surface as Surface>::Error>; ) -> Result<Self::Surface, <Self::Surface as Surface>::Error>;
/// Processes any open events of the underlying file descriptor. /// Processes any open events of the underlying file descriptor.
@ -181,11 +188,10 @@ pub trait Surface {
fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Self::Error>; fn set_connectors(&self, connectors: &[connector::Handle]) -> Result<(), Self::Error>;
/// Returns the currently active [`Mode`](drm::control::Mode) /// Returns the currently active [`Mode`](drm::control::Mode)
/// of the underlying [`crtc`](drm::control::crtc) /// of the underlying [`crtc`](drm::control::crtc)
/// if any. fn current_mode(&self) -> Mode;
fn current_mode(&self) -> Option<Mode>;
/// Returns the currently pending [`Mode`](drm::control::Mode) /// Returns the currently pending [`Mode`](drm::control::Mode)
/// to be used after the next commit, if any. /// to be used after the next commit.
fn pending_mode(&self) -> Option<Mode>; fn pending_mode(&self) -> Mode;
/// Tries to set a new [`Mode`](drm::control::Mode) /// Tries to set a new [`Mode`](drm::control::Mode)
/// to be used after the next commit. /// to be used after the next commit.
/// ///
@ -196,7 +202,7 @@ pub trait Surface {
/// *Note*: Only on a [`RawSurface`] you may directly trigger /// *Note*: Only on a [`RawSurface`] you may directly trigger
/// a [`commit`](RawSurface::commit). Other [`Surface`]s provide their /// a [`commit`](RawSurface::commit). Other [`Surface`]s provide their
/// own methods that *may* trigger a commit, you will need to read their docs. /// own methods that *may* trigger a commit, you will need to read their docs.
fn use_mode(&self, mode: Option<Mode>) -> Result<(), Self::Error>; fn use_mode(&self, mode: Mode) -> Result<(), Self::Error>;
} }
/// An open bare crtc without any rendering abstractions /// An open bare crtc without any rendering abstractions