backend: migrate drm & udev
This commit is contained in:
parent
f9dbabce56
commit
7f6af94733
|
@ -37,8 +37,11 @@ pub(crate) struct DrmBackendInternal<A: Device + 'static> {
|
|||
|
||||
impl<A: Device + 'static> DrmBackend<A> {
|
||||
pub(crate) fn new(
|
||||
context: Rc<EGLContext<Gbm<framebuffer::Info>, GbmDevice<A>>>, crtc: crtc::Handle, mode: Mode,
|
||||
connectors: Vec<connector::Handle>, log: ::slog::Logger,
|
||||
context: Rc<EGLContext<Gbm<framebuffer::Info>, GbmDevice<A>>>,
|
||||
crtc: crtc::Handle,
|
||||
mode: Mode,
|
||||
connectors: Vec<connector::Handle>,
|
||||
log: ::slog::Logger,
|
||||
) -> Result<Self> {
|
||||
// logger already initialized by the DrmDevice
|
||||
info!(log, "Initializing DrmBackend");
|
||||
|
@ -351,7 +354,8 @@ impl<A: Device + 'static> DrmBackendInternal<A> {
|
|||
}
|
||||
|
||||
pub(crate) fn page_flip(
|
||||
&self, fb: Option<&framebuffer::Info>
|
||||
&self,
|
||||
fb: Option<&framebuffer::Info>,
|
||||
) -> ::std::result::Result<(), SwapBuffersError> {
|
||||
trace!(self.logger, "Queueing Page flip");
|
||||
|
||||
|
@ -421,7 +425,9 @@ impl<A: Device + 'static> GraphicsBackend for DrmBackend<A> {
|
|||
}
|
||||
|
||||
fn set_cursor_representation(
|
||||
&self, buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>, hotspot: (u32, u32)
|
||||
&self,
|
||||
buffer: &ImageBuffer<Rgba<u8>, Vec<u8>>,
|
||||
hotspot: (u32, u32),
|
||||
) -> Result<()> {
|
||||
let (w, h) = buffer.dimensions();
|
||||
debug!(self.backend.logger, "Importing cursor");
|
||||
|
|
|
@ -233,8 +233,9 @@ use std::rc::{Rc, Weak};
|
|||
use std::sync::{Arc, Once, ONCE_INIT};
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::Duration;
|
||||
use wayland_server::{Display, EventLoopHandle};
|
||||
use wayland_server::sources::{FdEventSource, FdEventSourceImpl, FdInterest};
|
||||
use wayland_server::{Display, LoopToken};
|
||||
use wayland_server::commons::{downcast_impl, Implementation};
|
||||
use wayland_server::sources::{FdEvent, FdInterest, Source};
|
||||
|
||||
mod backend;
|
||||
pub mod error;
|
||||
|
@ -378,7 +379,10 @@ impl<A: ControlDevice + 'static> DrmDevice<A> {
|
|||
/// Errors if initialization fails or the mode is not available on all given
|
||||
/// connectors.
|
||||
pub fn create_backend<I>(
|
||||
&mut self, crtc: crtc::Handle, mode: Mode, connectors: I
|
||||
&mut self,
|
||||
crtc: crtc::Handle,
|
||||
mode: Mode,
|
||||
connectors: I,
|
||||
) -> Result<DrmBackend<A>>
|
||||
where
|
||||
I: Into<Vec<connector::Handle>>,
|
||||
|
@ -532,44 +536,66 @@ impl<A: ControlDevice + 'static> Drop for DrmDevice<A> {
|
|||
pub trait DrmHandler<A: ControlDevice + 'static> {
|
||||
/// The `DrmBackend` of crtc has finished swapping buffers and new frame can now
|
||||
/// (and should be immediately) be rendered.
|
||||
fn ready(
|
||||
&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<A>, crtc: crtc::Handle, frame: u32,
|
||||
duration: Duration,
|
||||
);
|
||||
fn ready(&mut self, device: &mut DrmDevice<A>, crtc: crtc::Handle, frame: u32, duration: Duration);
|
||||
/// The `DrmDevice` has thrown an error.
|
||||
///
|
||||
/// The related backends are most likely *not* usable anymore and
|
||||
/// the whole stack has to be recreated..
|
||||
fn error(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<A>, error: DrmError);
|
||||
fn error(&mut self, device: &mut DrmDevice<A>, error: DrmError);
|
||||
}
|
||||
|
||||
/// Bind a `DrmDevice` to an `EventLoop`,
|
||||
///
|
||||
/// This will cause it to recieve events and feed them into an `DrmHandler`
|
||||
pub fn drm_device_bind<A, H>(
|
||||
evlh: &mut EventLoopHandle, device: DrmDevice<A>, handler: H
|
||||
) -> ::std::result::Result<FdEventSource<(DrmDevice<A>, H)>, (IoError, (DrmDevice<A>, H))>
|
||||
token: &LoopToken,
|
||||
device: DrmDevice<A>,
|
||||
handler: H,
|
||||
) -> ::std::result::Result<(Source<FdEvent>, Rc<RefCell<DrmDevice<A>>>), (IoError, (DrmDevice<A>, H))>
|
||||
where
|
||||
A: ControlDevice + 'static,
|
||||
H: DrmHandler<A> + 'static,
|
||||
{
|
||||
let fd = device.as_raw_fd();
|
||||
evlh.add_fd_event_source(
|
||||
let device = Rc::new(RefCell::new(device));
|
||||
match token.add_fd_event_source(
|
||||
fd,
|
||||
fd_event_source_implementation(),
|
||||
(device, handler),
|
||||
FdInterest::READ,
|
||||
)
|
||||
DrmFdImpl {
|
||||
device: device.clone(),
|
||||
handler,
|
||||
},
|
||||
) {
|
||||
Ok(source) => Ok((source, device)),
|
||||
Err((
|
||||
ioerror,
|
||||
DrmFdImpl {
|
||||
device: device2,
|
||||
handler,
|
||||
},
|
||||
)) => {
|
||||
// make the Rc unique again
|
||||
::std::mem::drop(device2);
|
||||
let device = Rc::try_unwrap(device).unwrap_or_else(|_| unreachable!());
|
||||
Err((ioerror, (device.into_inner(), handler)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fd_event_source_implementation<A, H>() -> FdEventSourceImpl<(DrmDevice<A>, H)>
|
||||
struct DrmFdImpl<A: ControlDevice + 'static, H> {
|
||||
device: Rc<RefCell<DrmDevice<A>>>,
|
||||
handler: H,
|
||||
}
|
||||
|
||||
impl<A, H> Implementation<(), FdEvent> for DrmFdImpl<A, H>
|
||||
where
|
||||
A: ControlDevice + 'static,
|
||||
H: DrmHandler<A> + 'static,
|
||||
{
|
||||
FdEventSourceImpl {
|
||||
ready: |evlh, &mut (ref mut device, ref mut handler), _, _| {
|
||||
match crtc::receive_events(device) {
|
||||
fn receive(&mut self, event: FdEvent, (): ()) {
|
||||
let mut device = self.device.borrow_mut();
|
||||
match event {
|
||||
FdEvent::Ready { .. } => match crtc::receive_events(&mut *device) {
|
||||
Ok(events) => for event in events {
|
||||
if let crtc::Event::PageFlip(event) = event {
|
||||
if device.active.load(Ordering::SeqCst) {
|
||||
|
@ -584,20 +610,21 @@ where
|
|||
backend.unlock_buffer();
|
||||
trace!(device.logger, "Handling event for backend {:?}", event.crtc);
|
||||
// and then call the user to render the next frame
|
||||
handler.ready(evlh, device, event.crtc, event.frame, event.duration);
|
||||
self.handler
|
||||
.ready(&mut device, event.crtc, event.frame, event.duration);
|
||||
} else {
|
||||
device.backends.borrow_mut().remove(&event.crtc);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(err) => handler.error(evlh, device, err),
|
||||
};
|
||||
},
|
||||
error: |evlh, &mut (ref mut device, ref mut handler), _, error| {
|
||||
warn!(device.logger, "DrmDevice errored: {}", error);
|
||||
handler.error(evlh, device, error.into());
|
||||
},
|
||||
Err(err) => self.handler.error(&mut device, err),
|
||||
},
|
||||
FdEvent::Error { error, .. } => {
|
||||
warn!(device.logger, "DrmDevice errored: {}", error);
|
||||
self.handler.error(&mut device, error.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -629,7 +656,7 @@ impl<A: ControlDevice + 'static> AsSessionObserver<DrmDeviceObserver<A>> for Drm
|
|||
|
||||
#[cfg(feature = "backend_session")]
|
||||
impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
|
||||
fn pause(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) {
|
||||
fn pause(&mut self, devnum: Option<(u32, u32)>) {
|
||||
if let Some((major, minor)) = devnum {
|
||||
if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) {
|
||||
return;
|
||||
|
@ -665,7 +692,7 @@ impl<A: ControlDevice + 'static> SessionObserver for DrmDeviceObserver<A> {
|
|||
}
|
||||
}
|
||||
|
||||
fn activate(&mut self, _evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option<RawFd>)>) {
|
||||
fn activate(&mut self, devnum: Option<(u32, u32, Option<RawFd>)>) {
|
||||
if let Some((major, minor, fd)) = devnum {
|
||||
if major as u64 != stat::major(self.device_id) || minor as u64 != stat::minor(self.device_id) {
|
||||
return;
|
||||
|
|
|
@ -50,7 +50,10 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> DerefMut for EGLContext<B,
|
|||
impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
||||
/// Create a new `EGLContext` from a given `NativeDisplay`
|
||||
pub fn new<L>(
|
||||
native: N, attributes: GlAttributes, reqs: PixelFormatRequirements, logger: L
|
||||
native: N,
|
||||
attributes: GlAttributes,
|
||||
reqs: PixelFormatRequirements,
|
||||
logger: L,
|
||||
) -> Result<EGLContext<B, N>>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
|
@ -82,7 +85,9 @@ impl<B: native::Backend, N: native::NativeDisplay<B>> EGLContext<B, N> {
|
|||
}
|
||||
|
||||
unsafe fn new_internal(
|
||||
ptr: ffi::NativeDisplayType, mut attributes: GlAttributes, reqs: PixelFormatRequirements,
|
||||
ptr: ffi::NativeDisplayType,
|
||||
mut attributes: GlAttributes,
|
||||
reqs: PixelFormatRequirements,
|
||||
log: ::slog::Logger,
|
||||
) -> Result<
|
||||
(
|
||||
|
|
|
@ -42,7 +42,8 @@ pub mod egl {
|
|||
#[allow(non_snake_case, unused_variables, dead_code)]
|
||||
#[inline]
|
||||
pub unsafe fn BindWaylandDisplayWL(
|
||||
dpy: types::EGLDisplay, display: *mut __gl_imports::raw::c_void
|
||||
dpy: types::EGLDisplay,
|
||||
display: *mut __gl_imports::raw::c_void,
|
||||
) -> types::EGLBoolean {
|
||||
__gl_imports::mem::transmute::<
|
||||
_,
|
||||
|
@ -53,7 +54,8 @@ pub mod egl {
|
|||
#[allow(non_snake_case, unused_variables, dead_code)]
|
||||
#[inline]
|
||||
pub unsafe fn UnbindWaylandDisplayWL(
|
||||
dpy: types::EGLDisplay, display: *mut __gl_imports::raw::c_void
|
||||
dpy: types::EGLDisplay,
|
||||
display: *mut __gl_imports::raw::c_void,
|
||||
) -> types::EGLBoolean {
|
||||
__gl_imports::mem::transmute::<
|
||||
_,
|
||||
|
@ -64,7 +66,9 @@ pub mod egl {
|
|||
#[allow(non_snake_case, unused_variables, dead_code)]
|
||||
#[inline]
|
||||
pub unsafe fn QueryWaylandBufferWL(
|
||||
dpy: types::EGLDisplay, buffer: *mut __gl_imports::raw::c_void, attribute: types::EGLint,
|
||||
dpy: types::EGLDisplay,
|
||||
buffer: *mut __gl_imports::raw::c_void,
|
||||
attribute: types::EGLint,
|
||||
value: *mut types::EGLint,
|
||||
) -> types::EGLBoolean {
|
||||
__gl_imports::mem::transmute::<
|
||||
|
|
|
@ -31,7 +31,9 @@ pub trait Backend {
|
|||
/// The returned `EGLDisplay` needs to be a valid ptr for egl,
|
||||
/// but there is no way to test that.
|
||||
unsafe fn get_display<F: Fn(&str) -> bool>(
|
||||
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger
|
||||
display: ffi::NativeDisplayType,
|
||||
has_dp_extension: F,
|
||||
log: ::slog::Logger,
|
||||
) -> ffi::egl::types::EGLDisplay;
|
||||
}
|
||||
|
||||
|
@ -43,7 +45,9 @@ impl Backend for Wayland {
|
|||
type Surface = wegl::WlEglSurface;
|
||||
|
||||
unsafe fn get_display<F>(
|
||||
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger
|
||||
display: ffi::NativeDisplayType,
|
||||
has_dp_extension: F,
|
||||
log: ::slog::Logger,
|
||||
) -> ffi::egl::types::EGLDisplay
|
||||
where
|
||||
F: Fn(&str) -> bool,
|
||||
|
@ -87,7 +91,9 @@ impl Backend for X11 {
|
|||
type Surface = XlibWindow;
|
||||
|
||||
unsafe fn get_display<F>(
|
||||
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger
|
||||
display: ffi::NativeDisplayType,
|
||||
has_dp_extension: F,
|
||||
log: ::slog::Logger,
|
||||
) -> ffi::egl::types::EGLDisplay
|
||||
where
|
||||
F: Fn(&str) -> bool,
|
||||
|
@ -114,7 +120,9 @@ impl<T: 'static> Backend for Gbm<T> {
|
|||
type Surface = GbmSurface<T>;
|
||||
|
||||
unsafe fn get_display<F>(
|
||||
display: ffi::NativeDisplayType, has_dp_extension: F, log: ::slog::Logger
|
||||
display: ffi::NativeDisplayType,
|
||||
has_dp_extension: F,
|
||||
log: ::slog::Logger,
|
||||
) -> ffi::egl::types::EGLDisplay
|
||||
where
|
||||
F: Fn(&str) -> bool,
|
||||
|
|
|
@ -30,7 +30,8 @@ impl<N: native::NativeSurface> DerefMut for EGLSurface<N> {
|
|||
|
||||
impl<N: native::NativeSurface> EGLSurface<N> {
|
||||
pub(crate) fn new<B: native::Backend<Surface = N>, D: native::NativeDisplay<B>>(
|
||||
context: &EGLContext<B, D>, native: N
|
||||
context: &EGLContext<B, D>,
|
||||
native: N,
|
||||
) -> Result<EGLSurface<N>> {
|
||||
let surface = unsafe {
|
||||
ffi::egl::CreateWindowSurface(
|
||||
|
|
|
@ -192,7 +192,9 @@ impl EGLImages {
|
|||
///
|
||||
/// The given `tex_id` needs to be a valid GL texture otherwise undefined behavior might occur.
|
||||
pub unsafe fn bind_to_texture(
|
||||
&self, plane: usize, tex_id: c_uint
|
||||
&self,
|
||||
plane: usize,
|
||||
tex_id: c_uint,
|
||||
) -> ::std::result::Result<(), TextureCreationError> {
|
||||
if self.display.upgrade().is_some() {
|
||||
let mut old_tex_id: i32 = 0;
|
||||
|
@ -255,7 +257,8 @@ pub struct EGLDisplay(Weak<ffi::egl::types::EGLDisplay>, *mut wl_display);
|
|||
|
||||
impl EGLDisplay {
|
||||
fn new<B: native::Backend, N: native::NativeDisplay<B>>(
|
||||
context: &EGLContext<B, N>, display: *mut wl_display
|
||||
context: &EGLContext<B, N>,
|
||||
display: *mut wl_display,
|
||||
) -> EGLDisplay {
|
||||
EGLDisplay(Rc::downgrade(&context.display), display)
|
||||
}
|
||||
|
@ -266,7 +269,8 @@ impl EGLDisplay {
|
|||
/// a `BufferAccessError::NotManaged(WlBuffer)` is returned with the original buffer
|
||||
/// to render it another way.
|
||||
pub fn egl_buffer_contents(
|
||||
&self, buffer: Resource<WlBuffer>
|
||||
&self,
|
||||
buffer: Resource<WlBuffer>,
|
||||
) -> ::std::result::Result<EGLImages, BufferAccessError> {
|
||||
if let Some(display) = self.0.upgrade() {
|
||||
let mut format: i32 = 0;
|
||||
|
|
|
@ -30,7 +30,9 @@ pub trait GraphicsBackend {
|
|||
/// from raw image buffers over a fixed list of possible cursor types to simply the
|
||||
/// void type () to represent no possible customization of the cursor itself.
|
||||
fn set_cursor_representation(
|
||||
&self, cursor: &Self::CursorFormat, hotspot: (u32, u32)
|
||||
&self,
|
||||
cursor: &Self::CursorFormat,
|
||||
hotspot: (u32, u32),
|
||||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,11 +19,11 @@ pub mod graphics;
|
|||
|
||||
//#[cfg(feature = "backend_winit")]
|
||||
//pub mod winit;
|
||||
//#[cfg(feature = "backend_drm")]
|
||||
//pub mod drm;
|
||||
#[cfg(feature = "backend_drm")]
|
||||
pub mod drm;
|
||||
//#[cfg(feature = "backend_libinput")]
|
||||
//pub mod libinput;
|
||||
#[cfg(feature = "backend_session")]
|
||||
pub mod session;
|
||||
//#[cfg(feature = "backend_udev")]
|
||||
//pub mod udev;
|
||||
#[cfg(feature = "backend_udev")]
|
||||
pub mod udev;
|
||||
|
|
|
@ -451,11 +451,7 @@ pub fn logind_session_bind(
|
|||
let mut interest = FdInterest::empty();
|
||||
interest.set(FdInterest::READ, watch.readable());
|
||||
interest.set(FdInterest::WRITE, watch.writable());
|
||||
token.add_fd_event_source(
|
||||
watch.fd(),
|
||||
interest,
|
||||
notifier.clone(),
|
||||
)
|
||||
token.add_fd_event_source(watch.fd(), interest, notifier.clone())
|
||||
})
|
||||
.collect::<::std::result::Result<Vec<Source<FdEvent>>, (IoError, _)>>()
|
||||
.map_err(|(err, _)| {
|
||||
|
|
|
@ -24,8 +24,9 @@ use std::os::unix::io::{AsRawFd, RawFd};
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::rc::{Rc, Weak};
|
||||
use udev::{Context, Enumerator, Event, EventType, MonitorBuilder, MonitorSocket, Result as UdevResult};
|
||||
use wayland_server::EventLoopHandle;
|
||||
use wayland_server::sources::{EventSource, FdEventSource, FdEventSourceImpl, FdInterest};
|
||||
use wayland_server::LoopToken;
|
||||
use wayland_server::commons::Implementation;
|
||||
use wayland_server::sources::{FdEvent, FdInterest, Source};
|
||||
|
||||
/// Udev's `DrmDevice` type based on the underlying session
|
||||
pub struct SessionFdDrmDevice(RawFd);
|
||||
|
@ -48,11 +49,13 @@ pub struct UdevBackend<
|
|||
S: Session + 'static,
|
||||
T: UdevHandler<H> + 'static,
|
||||
> {
|
||||
devices: Rc<RefCell<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>>,
|
||||
_handler: ::std::marker::PhantomData<H>,
|
||||
devices: Rc<RefCell<HashMap<dev_t, (Source<FdEvent>, Rc<RefCell<DrmDevice<SessionFdDrmDevice>>>)>>>,
|
||||
monitor: MonitorSocket,
|
||||
session: S,
|
||||
handler: T,
|
||||
logger: ::slog::Logger,
|
||||
token: LoopToken,
|
||||
}
|
||||
|
||||
impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevHandler<H> + 'static>
|
||||
|
@ -67,7 +70,11 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
|||
/// `handler` - User-provided handler to respond to any detected changes
|
||||
/// `logger` - slog Logger to be used by the backend and its `DrmDevices`.
|
||||
pub fn new<'a, L>(
|
||||
mut evlh: &mut EventLoopHandle, context: &Context, mut session: S, mut handler: T, logger: L
|
||||
token: LoopToken,
|
||||
context: &Context,
|
||||
mut session: S,
|
||||
mut handler: T,
|
||||
logger: L,
|
||||
) -> Result<UdevBackend<H, S, T>>
|
||||
where
|
||||
L: Into<Option<::slog::Logger>>,
|
||||
|
@ -81,7 +88,7 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
|||
.flat_map(|path| {
|
||||
match DrmDevice::new(
|
||||
{
|
||||
match session.open(&path, fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY | fcntl::O_NONBLOCK) {
|
||||
match session.open(&path, fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC | fcntl::OFlag::O_NOCTTY | fcntl::OFlag::O_NONBLOCK) {
|
||||
Ok(fd) => SessionFdDrmDevice(fd),
|
||||
Err(err) => {
|
||||
warn!(logger, "Unable to open drm device {:?}, Error: {:?}. Skipping", path, err);
|
||||
|
@ -94,13 +101,13 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
|||
Ok(mut device) => {
|
||||
let devnum = device.device_id();
|
||||
let fd = device.as_raw_fd();
|
||||
match handler.device_added(evlh, &mut device) {
|
||||
match handler.device_added(&mut device) {
|
||||
Some(drm_handler) => {
|
||||
match drm_device_bind(&mut evlh, device, drm_handler) {
|
||||
Ok(event_source) => Some((devnum, event_source)),
|
||||
match drm_device_bind(&token, device, drm_handler) {
|
||||
Ok((event_source, device)) => Some((devnum, (event_source, device))),
|
||||
Err((err, (mut device, _))) => {
|
||||
warn!(logger, "Failed to bind device. Error: {:?}.", err);
|
||||
handler.device_removed(evlh, &mut device);
|
||||
handler.device_removed(&mut device);
|
||||
drop(device);
|
||||
if let Err(err) = session.close(fd) {
|
||||
warn!(logger, "Failed to close dropped device. Error: {:?}. Ignoring", err);
|
||||
|
@ -124,7 +131,7 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
|||
}
|
||||
}
|
||||
})
|
||||
.collect::<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>();
|
||||
.collect::<HashMap<dev_t, _>>();
|
||||
|
||||
let mut builder = MonitorBuilder::new(context).chain_err(|| ErrorKind::FailedToInitMonitor)?;
|
||||
builder
|
||||
|
@ -135,20 +142,25 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
|||
.chain_err(|| ErrorKind::FailedToInitMonitor)?;
|
||||
|
||||
Ok(UdevBackend {
|
||||
_handler: ::std::marker::PhantomData,
|
||||
devices: Rc::new(RefCell::new(devices)),
|
||||
monitor,
|
||||
session,
|
||||
handler,
|
||||
logger,
|
||||
token,
|
||||
})
|
||||
}
|
||||
|
||||
/// Closes the udev backend and frees all remaining open devices.
|
||||
pub fn close(&mut self, evlh: &mut EventLoopHandle) {
|
||||
pub fn close(&mut self) {
|
||||
let mut devices = self.devices.borrow_mut();
|
||||
for (_, event_source) in devices.drain() {
|
||||
let (mut device, _) = event_source.remove();
|
||||
self.handler.device_removed(evlh, &mut device);
|
||||
for (_, (event_source, device)) in devices.drain() {
|
||||
event_source.remove();
|
||||
let mut device = Rc::try_unwrap(device)
|
||||
.unwrap_or_else(|_| unreachable!())
|
||||
.into_inner();
|
||||
self.handler.device_removed(&mut device);
|
||||
let fd = device.as_raw_fd();
|
||||
drop(device);
|
||||
if let Err(err) = self.session.close(fd) {
|
||||
|
@ -163,8 +175,8 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static, S: Session + 'static, T: UdevH
|
|||
}
|
||||
|
||||
/// `SessionObserver` linked to the `UdevBackend` it was created from.
|
||||
pub struct UdevBackendObserver<H: DrmHandler<SessionFdDrmDevice> + 'static> {
|
||||
devices: Weak<RefCell<HashMap<dev_t, FdEventSource<(DrmDevice<SessionFdDrmDevice>, H)>>>>,
|
||||
pub struct UdevBackendObserver {
|
||||
devices: Weak<RefCell<HashMap<dev_t, (Source<FdEvent>, Rc<RefCell<DrmDevice<SessionFdDrmDevice>>>)>>>,
|
||||
logger: ::slog::Logger,
|
||||
}
|
||||
|
||||
|
@ -172,9 +184,9 @@ impl<
|
|||
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
||||
S: Session + 'static,
|
||||
T: UdevHandler<H> + 'static,
|
||||
> AsSessionObserver<UdevBackendObserver<H>> for UdevBackend<H, S, T>
|
||||
> AsSessionObserver<UdevBackendObserver> for UdevBackend<H, S, T>
|
||||
{
|
||||
fn observer(&mut self) -> UdevBackendObserver<H> {
|
||||
fn observer(&mut self) -> UdevBackendObserver {
|
||||
UdevBackendObserver {
|
||||
devices: Rc::downgrade(&self.devices),
|
||||
logger: self.logger.clone(),
|
||||
|
@ -182,25 +194,21 @@ impl<
|
|||
}
|
||||
}
|
||||
|
||||
impl<H: DrmHandler<SessionFdDrmDevice> + 'static> SessionObserver for UdevBackendObserver<H> {
|
||||
fn pause<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32)>) {
|
||||
impl SessionObserver for UdevBackendObserver {
|
||||
fn pause<'a>(&mut self, devnum: Option<(u32, u32)>) {
|
||||
if let Some(devices) = self.devices.upgrade() {
|
||||
for fd_event_source in devices.borrow_mut().values_mut() {
|
||||
fd_event_source.with_idata(evlh, |&mut (ref mut device, _), evlh| {
|
||||
info!(self.logger, "changed successful");
|
||||
device.observer().pause(evlh, devnum);
|
||||
})
|
||||
for &mut (_, ref device) in devices.borrow_mut().values_mut() {
|
||||
info!(self.logger, "changed successful");
|
||||
device.borrow_mut().observer().pause(devnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn activate<'a>(&mut self, evlh: &mut EventLoopHandle, devnum: Option<(u32, u32, Option<RawFd>)>) {
|
||||
fn activate<'a>(&mut self, devnum: Option<(u32, u32, Option<RawFd>)>) {
|
||||
if let Some(devices) = self.devices.upgrade() {
|
||||
for fd_event_source in devices.borrow_mut().values_mut() {
|
||||
fd_event_source.with_idata(evlh, |&mut (ref mut device, _), evlh| {
|
||||
info!(self.logger, "changed successful");
|
||||
device.observer().activate(evlh, devnum);
|
||||
})
|
||||
for &mut (_, ref device) in devices.borrow_mut().values_mut() {
|
||||
info!(self.logger, "changed successful");
|
||||
device.borrow_mut().observer().activate(devnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -210,143 +218,154 @@ impl<H: DrmHandler<SessionFdDrmDevice> + 'static> SessionObserver for UdevBacken
|
|||
///
|
||||
/// Allows the backend to recieve kernel events and thus to drive the `UdevHandler`.
|
||||
/// No runtime functionality can be provided without using this function.
|
||||
pub fn udev_backend_bind<S, H, T>(
|
||||
evlh: &mut EventLoopHandle, udev: UdevBackend<H, S, T>
|
||||
) -> ::std::result::Result<FdEventSource<UdevBackend<H, S, T>>, (IoError, UdevBackend<H, S, T>)>
|
||||
pub fn udev_backend_bind<H, S, T>(
|
||||
token: &LoopToken,
|
||||
udev: UdevBackend<H, S, T>,
|
||||
) -> ::std::result::Result<Source<FdEvent>, (IoError, UdevBackend<H, S, T>)>
|
||||
where
|
||||
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
||||
T: UdevHandler<H> + 'static,
|
||||
S: Session + 'static,
|
||||
{
|
||||
let fd = udev.monitor.as_raw_fd();
|
||||
evlh.add_fd_event_source(fd, fd_event_source_implementation(), udev, FdInterest::READ)
|
||||
token.add_fd_event_source(fd, FdInterest::READ, udev)
|
||||
}
|
||||
|
||||
fn fd_event_source_implementation<S, H, T>() -> FdEventSourceImpl<UdevBackend<H, S, T>>
|
||||
impl<H, S, T> Implementation<(), FdEvent> for UdevBackend<H, S, T>
|
||||
where
|
||||
H: DrmHandler<SessionFdDrmDevice> + 'static,
|
||||
T: UdevHandler<H> + 'static,
|
||||
S: Session + 'static,
|
||||
{
|
||||
FdEventSourceImpl {
|
||||
ready: |mut evlh, udev, _, _| {
|
||||
let events = udev.monitor.clone().collect::<Vec<Event>>();
|
||||
for event in events {
|
||||
match event.event_type() {
|
||||
// New device
|
||||
EventType::Add => {
|
||||
info!(udev.logger, "Device Added");
|
||||
if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) {
|
||||
let mut device = {
|
||||
match DrmDevice::new(
|
||||
{
|
||||
let logger = udev.logger.clone();
|
||||
match udev.session.open(
|
||||
path,
|
||||
fcntl::O_RDWR | fcntl::O_CLOEXEC | fcntl::O_NOCTTY
|
||||
| fcntl::O_NONBLOCK,
|
||||
) {
|
||||
Ok(fd) => SessionFdDrmDevice(fd),
|
||||
Err(err) => {
|
||||
fn receive(&mut self, event: FdEvent, (): ()) {
|
||||
match event {
|
||||
FdEvent::Ready { .. } => {
|
||||
let events = self.monitor.clone().collect::<Vec<Event>>();
|
||||
for event in events {
|
||||
match event.event_type() {
|
||||
// New device
|
||||
EventType::Add => {
|
||||
info!(self.logger, "Device Added");
|
||||
if let (Some(path), Some(devnum)) = (event.devnode(), event.devnum()) {
|
||||
let mut device = {
|
||||
match DrmDevice::new(
|
||||
{
|
||||
let logger = self.logger.clone();
|
||||
match self.session.open(
|
||||
path,
|
||||
fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC
|
||||
| fcntl::OFlag::O_NOCTTY
|
||||
| fcntl::OFlag::O_NONBLOCK,
|
||||
) {
|
||||
Ok(fd) => SessionFdDrmDevice(fd),
|
||||
Err(err) => {
|
||||
warn!(
|
||||
logger,
|
||||
"Unable to open drm device {:?}, Error: {:?}. Skipping",
|
||||
path,
|
||||
err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
},
|
||||
self.logger.clone(),
|
||||
) {
|
||||
Ok(dev) => dev,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
self.logger,
|
||||
"Failed to initialize device {:?}. Error: {}. Skipping",
|
||||
path,
|
||||
err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
let fd = device.as_raw_fd();
|
||||
match self.handler.device_added(&mut device) {
|
||||
Some(drm_handler) => {
|
||||
match drm_device_bind(&self.token, device, drm_handler) {
|
||||
Ok(fd_event_source) => {
|
||||
self.devices.borrow_mut().insert(devnum, fd_event_source);
|
||||
}
|
||||
Err((err, (mut device, _))) => {
|
||||
warn!(
|
||||
logger,
|
||||
"Unable to open drm device {:?}, Error: {:?}. Skipping",
|
||||
path,
|
||||
err
|
||||
self.logger,
|
||||
"Failed to bind device. Error: {:?}.", err
|
||||
);
|
||||
continue;
|
||||
self.handler.device_removed(&mut device);
|
||||
drop(device);
|
||||
if let Err(err) = self.session.close(fd) {
|
||||
warn!(
|
||||
self.logger,
|
||||
"Failed to close dropped device. Error: {:?}. Ignoring", err
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
udev.logger.clone(),
|
||||
) {
|
||||
Ok(dev) => dev,
|
||||
Err(err) => {
|
||||
warn!(
|
||||
udev.logger,
|
||||
"Failed to initialize device {:?}. Error: {}. Skipping",
|
||||
path,
|
||||
err
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
let fd = device.as_raw_fd();
|
||||
match udev.handler.device_added(evlh, &mut device) {
|
||||
Some(drm_handler) => match drm_device_bind(&mut evlh, device, drm_handler) {
|
||||
Ok(fd_event_source) => {
|
||||
udev.devices.borrow_mut().insert(devnum, fd_event_source);
|
||||
}
|
||||
Err((err, (mut device, _))) => {
|
||||
warn!(udev.logger, "Failed to bind device. Error: {:?}.", err);
|
||||
udev.handler.device_removed(evlh, &mut device);
|
||||
None => {
|
||||
self.handler.device_removed(&mut device);
|
||||
drop(device);
|
||||
if let Err(err) = udev.session.close(fd) {
|
||||
if let Err(err) = self.session.close(fd) {
|
||||
warn!(
|
||||
udev.logger,
|
||||
"Failed to close dropped device. Error: {:?}. Ignoring", err
|
||||
self.logger,
|
||||
"Failed to close unused device. Error: {:?}", err
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
None => {
|
||||
udev.handler.device_removed(evlh, &mut device);
|
||||
drop(device);
|
||||
if let Err(err) = udev.session.close(fd) {
|
||||
warn!(
|
||||
udev.logger,
|
||||
"Failed to close unused device. Error: {:?}", err
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
// Device removed
|
||||
EventType::Remove => {
|
||||
info!(udev.logger, "Device Remove");
|
||||
if let Some(devnum) = event.devnum() {
|
||||
if let Some(fd_event_source) = udev.devices.borrow_mut().remove(&devnum) {
|
||||
let (mut device, _) = fd_event_source.remove();
|
||||
udev.handler.device_removed(evlh, &mut device);
|
||||
let fd = device.as_raw_fd();
|
||||
drop(device);
|
||||
if let Err(err) = udev.session.close(fd) {
|
||||
warn!(
|
||||
udev.logger,
|
||||
"Failed to close device {:?}. Error: {:?}. Ignoring",
|
||||
event.sysname(),
|
||||
err
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
// New connector
|
||||
EventType::Change => {
|
||||
info!(udev.logger, "Device Changed");
|
||||
if let Some(devnum) = event.devnum() {
|
||||
info!(udev.logger, "Devnum: {:b}", devnum);
|
||||
if let Some(fd_event_source) = udev.devices.borrow_mut().get_mut(&devnum) {
|
||||
let handler = &mut udev.handler;
|
||||
let logger = &udev.logger;
|
||||
fd_event_source.with_idata(evlh, move |&mut (ref mut device, _), evlh| {
|
||||
info!(logger, "changed successful");
|
||||
handler.device_changed(evlh, device);
|
||||
})
|
||||
} else {
|
||||
info!(udev.logger, "changed, but device not tracked by backend");
|
||||
};
|
||||
} else {
|
||||
info!(udev.logger, "changed, but no devnum");
|
||||
// Device removed
|
||||
EventType::Remove => {
|
||||
info!(self.logger, "Device Remove");
|
||||
if let Some(devnum) = event.devnum() {
|
||||
if let Some((fd_event_source, device)) =
|
||||
self.devices.borrow_mut().remove(&devnum)
|
||||
{
|
||||
fd_event_source.remove();
|
||||
let mut device = Rc::try_unwrap(device)
|
||||
.unwrap_or_else(|_| unreachable!())
|
||||
.into_inner();
|
||||
self.handler.device_removed(&mut device);
|
||||
let fd = device.as_raw_fd();
|
||||
drop(device);
|
||||
if let Err(err) = self.session.close(fd) {
|
||||
warn!(
|
||||
self.logger,
|
||||
"Failed to close device {:?}. Error: {:?}. Ignoring",
|
||||
event.sysname(),
|
||||
err
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
// New connector
|
||||
EventType::Change => {
|
||||
info!(self.logger, "Device Changed");
|
||||
if let Some(devnum) = event.devnum() {
|
||||
info!(self.logger, "Devnum: {:b}", devnum);
|
||||
if let Some(&(_, ref device)) = self.devices.borrow_mut().get(&devnum) {
|
||||
let handler = &mut self.handler;
|
||||
let logger = &self.logger;
|
||||
handler.device_changed(&mut device.borrow_mut());
|
||||
} else {
|
||||
info!(self.logger, "changed, but device not tracked by backend");
|
||||
};
|
||||
} else {
|
||||
info!(self.logger, "changed, but no devnum");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
},
|
||||
error: |evlh, udev, _, err| udev.handler.error(evlh, err),
|
||||
FdEvent::Error { error, .. } => self.handler.error(error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -358,9 +377,7 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
|
|||
///
|
||||
/// ## Panics
|
||||
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
|
||||
fn device_added(
|
||||
&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>
|
||||
) -> Option<H>;
|
||||
fn device_added(&mut self, device: &mut DrmDevice<SessionFdDrmDevice>) -> Option<H>;
|
||||
/// Called when an open device is changed.
|
||||
///
|
||||
/// This usually indicates that some connectors did become available or were unplugged. The handler
|
||||
|
@ -368,7 +385,7 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
|
|||
///
|
||||
/// ## Panics
|
||||
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
|
||||
fn device_changed(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>);
|
||||
fn device_changed(&mut self, device: &mut DrmDevice<SessionFdDrmDevice>);
|
||||
/// Called when a device was removed.
|
||||
///
|
||||
/// The device will not accept any operations anymore and its file descriptor will be closed once
|
||||
|
@ -376,12 +393,12 @@ pub trait UdevHandler<H: DrmHandler<SessionFdDrmDevice> + 'static> {
|
|||
///
|
||||
/// ## Panics
|
||||
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
|
||||
fn device_removed(&mut self, evlh: &mut EventLoopHandle, device: &mut DrmDevice<SessionFdDrmDevice>);
|
||||
fn device_removed(&mut self, device: &mut DrmDevice<SessionFdDrmDevice>);
|
||||
/// Called when the udev context has encountered and error.
|
||||
///
|
||||
/// ## Panics
|
||||
/// Panics if you try to borrow the token of the belonging `UdevBackend` using this `StateProxy`.
|
||||
fn error(&mut self, evlh: &mut EventLoopHandle, error: IoError);
|
||||
fn error(&mut self, error: IoError);
|
||||
}
|
||||
|
||||
/// Returns the path of the primary gpu device if any
|
||||
|
|
Loading…
Reference in New Issue