Update to calloop 0.8, DrmDevice as an EventSource

This commit is contained in:
Victor Berger 2021-05-30 22:01:36 +02:00 committed by Victor Berger
parent e008360bde
commit aaa6e625e9
15 changed files with 175 additions and 181 deletions

View File

@ -12,7 +12,7 @@ members = [ "anvil" ]
[dependencies] [dependencies]
bitflags = "1" bitflags = "1"
calloop = "0.6.2" calloop = {version = "0.8.0" }
cgmath = "0.18.0" cgmath = "0.18.0"
dbus = { version = "0.9.0", optional = true } dbus = { version = "0.9.0", optional = true }
drm-fourcc = "^2.1.1" drm-fourcc = "^2.1.1"
@ -35,7 +35,7 @@ wayland-egl = { version = "0.28", optional = true }
wayland-protocols = { version = "0.28", features = ["unstable_protocols", "server"], optional = true } wayland-protocols = { version = "0.28", features = ["unstable_protocols", "server"], optional = true }
wayland-server = { version = "0.28.3", optional = true } wayland-server = { version = "0.28.3", optional = true }
wayland-sys = { version = "0.28", optional = true } wayland-sys = { version = "0.28", optional = true }
winit = { version = "0.24.0", optional = true } winit = { version = "0.25.0", optional = true }
xkbcommon = "0.4.0" xkbcommon = "0.4.0"
scan_fmt = { version = "0.2", default-features = false } scan_fmt = { version = "0.2", default-features = false }

View File

@ -16,7 +16,7 @@ use smithay::{
}, },
}; };
impl AnvilState { impl<Backend> AnvilState<Backend> {
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) { pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
match event { match event {
InputEvent::Keyboard { event, .. } => self.on_keyboard_key::<B>(event), InputEvent::Keyboard { event, .. } => self.on_keyboard_key::<B>(event),

View File

@ -39,14 +39,13 @@ fn main() {
o!(), o!(),
); );
let mut event_loop = EventLoop::<AnvilState>::new().unwrap();
let display = Rc::new(RefCell::new(Display::new()));
let arg = ::std::env::args().nth(1); let arg = ::std::env::args().nth(1);
match arg.as_ref().map(|s| &s[..]) { match arg.as_ref().map(|s| &s[..]) {
#[cfg(feature = "winit")] #[cfg(feature = "winit")]
Some("--winit") => { Some("--winit") => {
info!(log, "Starting anvil with winit backend"); info!(log, "Starting anvil with winit backend");
let mut event_loop = EventLoop::try_new().unwrap();
let display = Rc::new(RefCell::new(Display::new()));
if let Err(()) = winit::run_winit(display, &mut event_loop, log.clone()) { if let Err(()) = winit::run_winit(display, &mut event_loop, log.clone()) {
crit!(log, "Failed to initialize winit backend."); crit!(log, "Failed to initialize winit backend.");
} }
@ -54,6 +53,8 @@ fn main() {
#[cfg(feature = "udev")] #[cfg(feature = "udev")]
Some("--tty-udev") => { Some("--tty-udev") => {
info!(log, "Starting anvil on a tty using udev"); info!(log, "Starting anvil on a tty using udev");
let mut event_loop = EventLoop::try_new().unwrap();
let display = Rc::new(RefCell::new(Display::new()));
if let Err(()) = udev::run_udev(display, &mut event_loop, log.clone()) { if let Err(()) = udev::run_udev(display, &mut event_loop, log.clone()) {
crit!(log, "Failed to initialize tty backend."); crit!(log, "Failed to initialize tty backend.");
} }

View File

@ -9,10 +9,7 @@ use std::{
use smithay::{ use smithay::{
reexports::{ reexports::{
calloop::{ calloop::{generic::Generic, Interest, LoopHandle, Mode, RegistrationToken},
generic::{Fd, Generic},
Interest, LoopHandle, Mode, Source,
},
wayland_server::{protocol::wl_surface::WlSurface, Display}, wayland_server::{protocol::wl_surface::WlSurface, Display},
}, },
wayland::{ wayland::{
@ -36,11 +33,12 @@ use crate::udev::MyOutput;
#[cfg(feature = "xwayland")] #[cfg(feature = "xwayland")]
use crate::xwayland::XWm; use crate::xwayland::XWm;
pub struct AnvilState { pub struct AnvilState<Backend> {
pub backend: Backend,
pub socket_name: String, pub socket_name: String,
pub running: Arc<AtomicBool>, pub running: Arc<AtomicBool>,
pub display: Rc<RefCell<Display>>, pub display: Rc<RefCell<Display>>,
pub handle: LoopHandle<AnvilState>, pub handle: LoopHandle<'static, AnvilState<Backend>>,
pub ctoken: CompositorToken<crate::shell::Roles>, pub ctoken: CompositorToken<crate::shell::Roles>,
pub window_map: Rc<RefCell<crate::window_map::WindowMap<crate::shell::Roles>>>, pub window_map: Rc<RefCell<crate::window_map::WindowMap<crate::shell::Roles>>>,
pub dnd_icon: Arc<Mutex<Option<WlSurface>>>, pub dnd_icon: Arc<Mutex<Option<WlSurface>>>,
@ -56,30 +54,30 @@ pub struct AnvilState {
#[cfg(feature = "udev")] #[cfg(feature = "udev")]
pub session: Option<AutoSession>, pub session: Option<AutoSession>,
// things we must keep alive // things we must keep alive
_wayland_event_source: Source<Generic<Fd>>, _wayland_event_source: RegistrationToken,
#[cfg(feature = "xwayland")] #[cfg(feature = "xwayland")]
_xwayland: XWayland<XWm>, _xwayland: XWayland<XWm<Backend>>,
} }
impl AnvilState { impl<Backend: Default + 'static> AnvilState<Backend> {
pub fn init( pub fn init(
display: Rc<RefCell<Display>>, display: Rc<RefCell<Display>>,
handle: LoopHandle<AnvilState>, handle: LoopHandle<'static, AnvilState<Backend>>,
#[cfg(feature = "egl")] egl_reader: Rc<RefCell<Option<EGLBufferReader>>>, #[cfg(feature = "egl")] egl_reader: Rc<RefCell<Option<EGLBufferReader>>>,
#[cfg(feature = "udev")] session: Option<AutoSession>, #[cfg(feature = "udev")] session: Option<AutoSession>,
#[cfg(not(feature = "udev"))] _session: Option<()>, #[cfg(not(feature = "udev"))] _session: Option<()>,
#[cfg(feature = "udev")] output_map: Option<Rc<RefCell<Vec<MyOutput>>>>, #[cfg(feature = "udev")] output_map: Option<Rc<RefCell<Vec<MyOutput>>>>,
#[cfg(not(feature = "udev"))] _output_map: Option<()>, #[cfg(not(feature = "udev"))] _output_map: Option<()>,
log: slog::Logger, log: slog::Logger,
) -> AnvilState { ) -> AnvilState<Backend> {
// init the wayland connection // init the wayland connection
let _wayland_event_source = handle let _wayland_event_source = handle
.insert_source( .insert_source(
Generic::from_fd(display.borrow().get_poll_fd(), Interest::Readable, Mode::Level), Generic::from_fd(display.borrow().get_poll_fd(), Interest::READ, Mode::Level),
{ {
let display = display.clone(); let display = display.clone();
let log = log.clone(); let log = log.clone();
move |_, _, state: &mut AnvilState| { move |_, _, state: &mut AnvilState<Backend>| {
let mut display = display.borrow_mut(); let mut display = display.borrow_mut();
match display.dispatch(std::time::Duration::from_millis(0), state) { match display.dispatch(std::time::Duration::from_millis(0), state) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
@ -176,6 +174,7 @@ impl AnvilState {
}; };
AnvilState { AnvilState {
backend: Default::default(),
running: Arc::new(AtomicBool::new(true)), running: Arc::new(AtomicBool::new(true)),
display, display,
handle, handle,

View File

@ -16,7 +16,7 @@ use slog::Logger;
use smithay::backend::{drm::DevPath, egl::display::EGLBufferReader, udev::primary_gpu}; use smithay::backend::{drm::DevPath, egl::display::EGLBufferReader, udev::primary_gpu};
use smithay::{ use smithay::{
backend::{ backend::{
drm::{device_bind, DeviceHandler, DrmDevice, DrmError, DrmRenderSurface}, drm::{DrmDevice, DrmError, DrmEvent, DrmRenderSurface},
egl::{EGLContext, EGLDisplay}, egl::{EGLContext, EGLDisplay},
libinput::{LibinputInputBackend, LibinputSessionInterface}, libinput::{LibinputInputBackend, LibinputSessionInterface},
renderer::{ renderer::{
@ -29,9 +29,8 @@ use smithay::{
}, },
reexports::{ reexports::{
calloop::{ calloop::{
generic::Generic,
timer::{Timer, TimerHandle}, timer::{Timer, TimerHandle},
EventLoop, LoopHandle, Source, Dispatcher, EventLoop, LoopHandle, RegistrationToken,
}, },
drm::{ drm::{
self, self,
@ -71,9 +70,17 @@ impl AsRawFd for SessionFd {
} }
} }
pub struct UdevData {}
impl Default for UdevData {
fn default() -> UdevData {
UdevData {}
}
}
pub fn run_udev( pub fn run_udev(
display: Rc<RefCell<Display>>, display: Rc<RefCell<Display>>,
event_loop: &mut EventLoop<AnvilState>, event_loop: &mut EventLoop<'static, AnvilState<UdevData>>,
log: Logger, log: Logger,
) -> Result<(), ()> { ) -> Result<(), ()> {
let name = display let name = display
@ -272,10 +279,11 @@ struct BackendData {
context: EGLContext, context: EGLContext,
egl: EGLDisplay, egl: EGLDisplay,
gbm: GbmDevice<SessionFd>, gbm: GbmDevice<SessionFd>,
event_source: Source<Generic<DrmDevice<SessionFd>>>, registration_token: RegistrationToken,
event_dispatcher: Dispatcher<'static, DrmDevice<SessionFd>, AnvilState<UdevData>>,
} }
struct UdevHandlerImpl<Data: 'static> { struct UdevHandlerImpl {
compositor_token: CompositorToken<Roles>, compositor_token: CompositorToken<Roles>,
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>, egl_buffer_reader: Rc<RefCell<Option<EGLBufferReader>>>,
@ -290,12 +298,12 @@ struct UdevHandlerImpl<Data: 'static> {
pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>, pointer_image: ImageBuffer<Rgba<u8>, Vec<u8>>,
cursor_status: Arc<Mutex<CursorImageStatus>>, cursor_status: Arc<Mutex<CursorImageStatus>>,
dnd_icon: Arc<Mutex<Option<wl_surface::WlSurface>>>, dnd_icon: Arc<Mutex<Option<wl_surface::WlSurface>>>,
loop_handle: LoopHandle<Data>, loop_handle: LoopHandle<'static, AnvilState<UdevData>>,
signaler: Signaler<SessionSignal>, signaler: Signaler<SessionSignal>,
logger: ::slog::Logger, logger: ::slog::Logger,
} }
impl<Data: 'static> UdevHandlerImpl<Data> { impl UdevHandlerImpl {
pub fn scan_connectors( pub fn scan_connectors(
device: &mut DrmDevice<SessionFd>, device: &mut DrmDevice<SessionFd>,
gbm: &GbmDevice<SessionFd>, gbm: &GbmDevice<SessionFd>,
@ -392,7 +400,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
} }
} }
impl<Data: 'static> UdevHandlerImpl<Data> { impl UdevHandlerImpl {
fn device_added(&mut self, device_id: dev_t, path: PathBuf) { fn device_added(&mut self, device_id: dev_t, path: PathBuf) {
// Try to open the device // Try to open the device
if let Some((mut device, gbm)) = self if let Some((mut device, gbm)) = self
@ -465,7 +473,7 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
} }
}; };
let backends = Rc::new(RefCell::new(UdevHandlerImpl::<Data>::scan_connectors( let backends = Rc::new(RefCell::new(UdevHandlerImpl::scan_connectors(
&mut device, &mut device,
&gbm, &gbm,
&egl, &egl,
@ -516,15 +524,22 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => listener.activate(), SessionSignal::ActivateSession | SessionSignal::ActivateDevice { .. } => listener.activate(),
_ => {} _ => {}
}); });
device.set_handler(DrmHandlerImpl { let mut drm_handler = DrmHandlerImpl {
renderer, renderer,
loop_handle: self.loop_handle.clone(), loop_handle: self.loop_handle.clone(),
}); };
device.link(self.signaler.clone()); device.link(self.signaler.clone());
let dev_id = device.device_id(); let dev_id = device.device_id();
let event_source = device_bind(&self.loop_handle, device) let event_dispatcher = Dispatcher::new(device, move |event, _, _| match event {
.map_err(|e| -> IoError { e.into() }) DrmEvent::VBlank(crtc) => drm_handler.vblank(crtc),
DrmEvent::Error(error) => {
error!(drm_handler.renderer.logger, "{:?}", error);
}
});
let registration_token = self
.loop_handle
.register_dispatcher(event_dispatcher.clone())
.unwrap(); .unwrap();
trace!(self.logger, "Backends: {:?}", backends.borrow().keys()); trace!(self.logger, "Backends: {:?}", backends.borrow().keys());
@ -538,7 +553,8 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
dev_id, dev_id,
BackendData { BackendData {
_restart_token: restart_token, _restart_token: restart_token,
event_source, registration_token,
event_dispatcher,
surfaces: backends, surfaces: backends,
egl, egl,
context, context,
@ -557,26 +573,25 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
let mut output_map = self.output_map.borrow_mut(); let mut output_map = self.output_map.borrow_mut();
let signaler = self.signaler.clone(); let signaler = self.signaler.clone();
output_map.retain(|output| output.device_id != device); output_map.retain(|output| output.device_id != device);
self.loop_handle
.with_source(&backend_data.event_source, |source| {
let mut backends = backend_data.surfaces.borrow_mut();
*backends = UdevHandlerImpl::<Data>::scan_connectors(
&mut source.file,
&backend_data.gbm,
&backend_data.egl,
&backend_data.context,
&mut *display,
&mut *output_map,
&signaler,
&logger,
);
for renderer in backends.values() { let mut source = backend_data.event_dispatcher.as_source_mut();
let logger = logger.clone(); let mut backends = backend_data.surfaces.borrow_mut();
// render first frame *backends = UdevHandlerImpl::scan_connectors(
schedule_initial_render(renderer.clone(), &loop_handle, logger); &mut *source,
} &backend_data.gbm,
}); &backend_data.egl,
&backend_data.context,
&mut *display,
&mut *output_map,
&signaler,
&logger,
);
for renderer in backends.values() {
let logger = logger.clone();
// render first frame
schedule_initial_render(renderer.clone(), &loop_handle, logger);
}
} }
} }
@ -591,7 +606,8 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
.borrow_mut() .borrow_mut()
.retain(|output| output.device_id != device); .retain(|output| output.device_id != device);
let _device = self.loop_handle.remove(backend_data.event_source).unwrap(); let _device = self.loop_handle.remove(backend_data.registration_token);
let _device = backend_data.event_dispatcher.into_source_inner();
// don't use hardware acceleration anymore, if this was the primary gpu // don't use hardware acceleration anymore, if this was the primary gpu
#[cfg(feature = "egl")] #[cfg(feature = "egl")]
@ -607,22 +623,18 @@ impl<Data: 'static> UdevHandlerImpl<Data> {
pub struct DrmHandlerImpl<Data: 'static> { pub struct DrmHandlerImpl<Data: 'static> {
renderer: Rc<DrmRenderer>, renderer: Rc<DrmRenderer>,
loop_handle: LoopHandle<Data>, loop_handle: LoopHandle<'static, Data>,
} }
impl<Data: 'static> DeviceHandler for DrmHandlerImpl<Data> { impl<Data: 'static> DrmHandlerImpl<Data> {
fn vblank(&mut self, crtc: crtc::Handle) { fn vblank(&mut self, crtc: crtc::Handle) {
self.renderer.clone().render(crtc, None, Some(&self.loop_handle)) self.renderer.clone().render(crtc, None, Some(&self.loop_handle))
} }
fn error(&mut self, error: DrmError) {
error!(self.renderer.logger, "{:?}", error);
}
} }
pub struct DrmRendererSessionListener<Data: 'static> { pub struct DrmRendererSessionListener<Data: 'static> {
renderer: Rc<DrmRenderer>, renderer: Rc<DrmRenderer>,
loop_handle: LoopHandle<Data>, loop_handle: LoopHandle<'static, Data>,
} }
impl<Data: 'static> DrmRendererSessionListener<Data> { impl<Data: 'static> DrmRendererSessionListener<Data> {
@ -652,7 +664,7 @@ pub struct DrmRenderer {
} }
impl DrmRenderer { impl DrmRenderer {
fn render_all<Data: 'static>(self: Rc<Self>, evt_handle: Option<&LoopHandle<Data>>) { fn render_all<Data: 'static>(self: Rc<Self>, evt_handle: Option<&LoopHandle<'static, Data>>) {
for crtc in self.backends.borrow().keys() { for crtc in self.backends.borrow().keys() {
self.clone().render(*crtc, None, evt_handle); self.clone().render(*crtc, None, evt_handle);
} }
@ -661,7 +673,7 @@ impl DrmRenderer {
self: Rc<Self>, self: Rc<Self>,
crtc: crtc::Handle, crtc: crtc::Handle,
timer: Option<TimerHandle<(std::rc::Weak<DrmRenderer>, crtc::Handle)>>, timer: Option<TimerHandle<(std::rc::Weak<DrmRenderer>, crtc::Handle)>>,
evt_handle: Option<&LoopHandle<Data>>, evt_handle: Option<&LoopHandle<'static, Data>>,
) { ) {
if let Some(surface) = self.backends.borrow().get(&crtc) { if let Some(surface) = self.backends.borrow().get(&crtc) {
let result = DrmRenderer::render_surface( let result = DrmRenderer::render_surface(
@ -716,7 +728,7 @@ impl DrmRenderer {
renderer.render( renderer.render(
crtc, crtc,
Some(handle.clone()), Some(handle.clone()),
Option::<&LoopHandle<Data>>::None, Option::<&LoopHandle<'static, Data>>::None,
); );
} }
}) })
@ -846,7 +858,7 @@ impl DrmRenderer {
fn schedule_initial_render<Data: 'static>( fn schedule_initial_render<Data: 'static>(
renderer: Rc<RefCell<RenderSurface>>, renderer: Rc<RefCell<RenderSurface>>,
evt_handle: &LoopHandle<Data>, evt_handle: &LoopHandle<'static, Data>,
logger: ::slog::Logger, logger: ::slog::Logger,
) { ) {
let result = { let result = {

View File

@ -17,9 +17,17 @@ use slog::Logger;
use crate::drawing::*; use crate::drawing::*;
use crate::state::AnvilState; use crate::state::AnvilState;
pub struct WinitData;
impl Default for WinitData {
fn default() -> WinitData {
WinitData
}
}
pub fn run_winit( pub fn run_winit(
display: Rc<RefCell<Display>>, display: Rc<RefCell<Display>>,
event_loop: &mut EventLoop<AnvilState>, event_loop: &mut EventLoop<'static, AnvilState<WinitData>>,
log: Logger, log: Logger,
) -> Result<(), ()> { ) -> Result<(), ()> {
let (renderer, mut input) = winit::init(log.clone()).map_err(|err| { let (renderer, mut input) = winit::init(log.clone()).map_err(|err| {

View File

@ -35,16 +35,16 @@ mod x11rb_event_source;
/// Implementation of [`smithay::xwayland::XWindowManager`] that is used for starting XWayland. /// Implementation of [`smithay::xwayland::XWindowManager`] that is used for starting XWayland.
/// After XWayland was started, the actual state is kept in `X11State`. /// After XWayland was started, the actual state is kept in `X11State`.
pub struct XWm { pub struct XWm<Backend> {
handle: LoopHandle<AnvilState>, handle: LoopHandle<'static, AnvilState<Backend>>,
token: CompositorToken<Roles>, token: CompositorToken<Roles>,
window_map: Rc<RefCell<MyWindowMap>>, window_map: Rc<RefCell<MyWindowMap>>,
log: slog::Logger, log: slog::Logger,
} }
impl XWm { impl<Backend> XWm<Backend> {
pub fn new( pub fn new(
handle: LoopHandle<AnvilState>, handle: LoopHandle<'static, AnvilState<Backend>>,
token: CompositorToken<Roles>, token: CompositorToken<Roles>,
window_map: Rc<RefCell<MyWindowMap>>, window_map: Rc<RefCell<MyWindowMap>>,
log: slog::Logger, log: slog::Logger,
@ -58,7 +58,7 @@ impl XWm {
} }
} }
impl XWindowManager for XWm { impl<Backend> XWindowManager for XWm<Backend> {
fn xwayland_ready(&mut self, connection: UnixStream, client: Client) { fn xwayland_ready(&mut self, connection: UnixStream, client: Client) {
let (wm, source) = let (wm, source) =
X11State::start_wm(connection, self.token, self.window_map.clone(), self.log.clone()).unwrap(); X11State::start_wm(connection, self.token, self.window_map.clone(), self.log.clone()).unwrap();

View File

@ -21,7 +21,7 @@ pub struct X11Source {
impl X11Source { impl X11Source {
pub fn new(connection: Rc<RustConnection>) -> Self { pub fn new(connection: Rc<RustConnection>) -> Self {
let fd = Fd(connection.stream().as_raw_fd()); let fd = Fd(connection.stream().as_raw_fd());
let generic = Generic::new(fd, Interest::Readable, Mode::Level); let generic = Generic::new(fd, Interest::READ, Mode::Level);
Self { connection, generic } Self { connection, generic }
} }
} }

View File

@ -7,7 +7,7 @@ use slog::Drain;
use smithay::{ use smithay::{
backend::{ backend::{
allocator::{dumb::DumbBuffer, Fourcc, Slot, Swapchain}, allocator::{dumb::DumbBuffer, Fourcc, Slot, Swapchain},
drm::{device_bind, DeviceHandler, DrmDevice, DrmError, DrmSurface}, drm::{DrmDevice, DrmEvent, DrmSurface},
}, },
reexports::{ reexports::{
calloop::EventLoop, calloop::EventLoop,
@ -16,7 +16,6 @@ use smithay::{
}; };
use std::{ use std::{
fs::{File, OpenOptions}, fs::{File, OpenOptions},
io::Error as IoError,
os::unix::io::{AsRawFd, RawFd}, os::unix::io::{AsRawFd, RawFd},
rc::Rc, rc::Rc,
sync::Mutex, sync::Mutex,
@ -48,7 +47,7 @@ fn main() {
file: Rc::new(options.open("/dev/dri/card0").unwrap()), file: Rc::new(options.open("/dev/dri/card0").unwrap()),
}; };
let mut device = DrmDevice::new(fd.clone(), true, log.clone()).unwrap(); let device = DrmDevice::new(fd.clone(), true, log.clone()).unwrap();
// Get a set of all modesetting resource handles (excluding planes): // Get a set of all modesetting resource handles (excluding planes):
let res_handles = ControlDevice::resource_handles(&device).unwrap(); let res_handles = ControlDevice::resource_handles(&device).unwrap();
@ -111,20 +110,23 @@ fn main() {
*first_buffer.userdata() = Some(framebuffer); *first_buffer.userdata() = Some(framebuffer);
// Get the device as an allocator into the // Get the device as an allocator into the
device.set_handler(DrmHandlerImpl { let mut vblank_handler = VBlankHandler {
swapchain, swapchain,
current: first_buffer, current: first_buffer,
surface: surface.clone(), surface: surface.clone(),
}); };
/* /*
* Register the DrmDevice on the EventLoop * Register the DrmDevice on the EventLoop
*/ */
let mut event_loop = EventLoop::<()>::new().unwrap(); let mut event_loop = EventLoop::<()>::try_new().unwrap();
let _source = device_bind(&event_loop.handle(), device) event_loop
.map_err(|err| -> IoError { err.into() }) .handle()
.insert_source(device, move |event, _: &mut (), _: &mut ()| match event {
DrmEvent::VBlank(crtc) => vblank_handler.vblank(crtc),
DrmEvent::Error(e) => panic!("{}", e),
})
.unwrap(); .unwrap();
// Start rendering // Start rendering
surface surface
.commit([(framebuffer, surface.plane())].iter(), true) .commit([(framebuffer, surface.plane())].iter(), true)
@ -134,13 +136,13 @@ fn main() {
event_loop.run(None, &mut (), |_| {}).unwrap(); event_loop.run(None, &mut (), |_| {}).unwrap();
} }
pub struct DrmHandlerImpl { pub struct VBlankHandler {
swapchain: Swapchain<DrmDevice<FdWrapper>, DumbBuffer<FdWrapper>, framebuffer::Handle>, swapchain: Swapchain<DrmDevice<FdWrapper>, DumbBuffer<FdWrapper>, framebuffer::Handle>,
current: Slot<DumbBuffer<FdWrapper>, framebuffer::Handle>, current: Slot<DumbBuffer<FdWrapper>, framebuffer::Handle>,
surface: Rc<DrmSurface<FdWrapper>>, surface: Rc<DrmSurface<FdWrapper>>,
} }
impl DeviceHandler for DrmHandlerImpl { impl VBlankHandler {
fn vblank(&mut self, _crtc: crtc::Handle) { fn vblank(&mut self, _crtc: crtc::Handle) {
{ {
// Next buffer // Next buffer
@ -168,8 +170,4 @@ impl DeviceHandler for DrmHandlerImpl {
.page_flip([(fb, self.surface.plane())].iter(), true) .page_flip([(fb, self.surface.plane())].iter(), true)
.unwrap(); .unwrap();
} }
fn error(&mut self, error: DrmError) {
panic!("{:?}", error);
}
} }

View File

@ -1,10 +1,9 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::os::unix::io::{AsRawFd, RawFd}; use std::os::unix::io::{AsRawFd, RawFd};
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc;
use std::sync::{atomic::AtomicBool, Arc}; use std::sync::{atomic::AtomicBool, Arc};
use calloop::{generic::Generic, InsertError, LoopHandle, Source}; use calloop::{EventSource, Interest, Poll, Readiness, Token};
use drm::control::{connector, crtc, Device as ControlDevice, Event, Mode, ResourceHandles}; use drm::control::{connector, crtc, Device as ControlDevice, Event, Mode, ResourceHandles};
use drm::{ClientCapability, Device as BasicDevice}; use drm::{ClientCapability, Device as BasicDevice};
use nix::libc::dev_t; use nix::libc::dev_t;
@ -21,7 +20,6 @@ use legacy::LegacyDrmDevice;
pub struct DrmDevice<A: AsRawFd + 'static> { pub struct DrmDevice<A: AsRawFd + 'static> {
pub(super) dev_id: dev_t, pub(super) dev_id: dev_t,
pub(crate) internal: Arc<DrmDeviceInternal<A>>, pub(crate) internal: Arc<DrmDeviceInternal<A>>,
handler: Rc<RefCell<Option<Box<dyn DeviceHandler>>>>,
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
pub(super) links: RefCell<Vec<crate::signaling::SignalToken>>, pub(super) links: RefCell<Vec<crate::signaling::SignalToken>>,
has_universal_planes: bool, has_universal_planes: bool,
@ -145,7 +143,6 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
Ok(DrmDevice { Ok(DrmDevice {
dev_id, dev_id,
internal, internal,
handler: Rc::new(RefCell::new(None)),
#[cfg(feature = "backend_session")] #[cfg(feature = "backend_session")]
links: RefCell::new(Vec::new()), links: RefCell::new(Vec::new()),
has_universal_planes, has_universal_planes,
@ -180,43 +177,6 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
) )
} }
/// Processes any open events of the underlying file descriptor.
///
/// You should not call this function manually, but rather use
/// [`device_bind`] to register the device
/// to an [`EventLoop`](calloop::EventLoop)
/// and call this function when the device becomes readable
/// to synchronize your rendering to the vblank events of the open crtc's
pub fn process_events(&mut self) {
match self.receive_events() {
Ok(events) => {
for event in events {
if let Event::PageFlip(event) = event {
trace!(self.logger, "Got a page-flip event for crtc ({:?})", event.crtc);
if let Some(handler) = self.handler.borrow_mut().as_mut() {
handler.vblank(event.crtc);
}
} else {
trace!(
self.logger,
"Got a non-page-flip event of device '{:?}'.",
self.dev_path()
);
}
}
}
Err(source) => {
if let Some(handler) = self.handler.borrow_mut().as_mut() {
handler.error(Error::Access {
errmsg: "Error processing drm events",
dev: self.dev_path(),
source,
});
}
}
}
}
/// Returns if the underlying implementation uses atomic-modesetting or not. /// Returns if the underlying implementation uses atomic-modesetting or not.
pub fn is_atomic(&self) -> bool { pub fn is_atomic(&self) -> bool {
match *self.internal { match *self.internal {
@ -225,19 +185,6 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
} }
} }
/// Assigns a [`DeviceHandler`] called during event processing.
///
/// See [`device_bind`] and [`DeviceHandler`]
pub fn set_handler(&mut self, handler: impl DeviceHandler + 'static) {
let handler = Some(Box::new(handler) as Box<dyn DeviceHandler + 'static>);
*self.handler.borrow_mut() = handler;
}
/// Clear a set [`DeviceHandler`](trait.DeviceHandler.html), if any
pub fn clear_handler(&mut self) {
self.handler.borrow_mut().take();
}
/// Returns a list of crtcs for this device /// Returns a list of crtcs for this device
pub fn crtcs(&self) -> &[crtc::Handle] { pub fn crtcs(&self) -> &[crtc::Handle] {
self.resources.crtcs() self.resources.crtcs()
@ -334,16 +281,6 @@ impl<A: AsRawFd + 'static> DrmDevice<A> {
} }
} }
/// Trait to receive events of a bound [`DrmDevice`]
///
/// See [`device_bind`]
pub trait DeviceHandler {
/// A vblank blank event on the provided crtc has happend
fn vblank(&mut self, crtc: crtc::Handle);
/// An error happend while processing events
fn error(&mut self, error: Error);
}
/// Trait representing open devices that *may* return a `Path` /// Trait representing open devices that *may* return a `Path`
pub trait DevPath { pub trait DevPath {
/// Returns the path of the open device if possible /// Returns the path of the open device if possible
@ -358,25 +295,64 @@ impl<A: AsRawFd> DevPath for A {
} }
} }
/// calloop source associated with a Device /// Events that can be generated by a DrmDevice
pub type DrmSource<A> = Generic<DrmDevice<A>>; pub enum DrmEvent {
/// A vblank blank event on the provided crtc has happend
VBlank(crtc::Handle),
/// An error happend while processing events
Error(Error),
}
/// Bind a `Device` to an [`EventLoop`](calloop::EventLoop), impl<A> EventSource for DrmDevice<A>
///
/// This will cause it to recieve events and feed them into a previously
/// set [`DeviceHandler`](DeviceHandler).
pub fn device_bind<A, Data>(
handle: &LoopHandle<Data>,
device: DrmDevice<A>,
) -> ::std::result::Result<Source<DrmSource<A>>, InsertError<DrmSource<A>>>
where where
A: AsRawFd + 'static, A: AsRawFd + 'static,
Data: 'static,
{ {
let source = Generic::new(device, calloop::Interest::Readable, calloop::Mode::Level); type Event = DrmEvent;
type Metadata = ();
type Ret = ();
handle.insert_source(source, |_, source, _| { fn process_events<F>(&mut self, _: Readiness, _: Token, mut callback: F) -> std::io::Result<()>
source.process_events(); where
F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
{
match self.receive_events() {
Ok(events) => {
for event in events {
if let Event::PageFlip(event) = event {
trace!(self.logger, "Got a page-flip event for crtc ({:?})", event.crtc);
callback(DrmEvent::VBlank(event.crtc), &mut ());
} else {
trace!(
self.logger,
"Got a non-page-flip event of device '{:?}'.",
self.dev_path()
);
}
}
}
Err(source) => {
callback(
DrmEvent::Error(Error::Access {
errmsg: "Error processing drm events",
dev: self.dev_path(),
source,
}),
&mut (),
);
}
}
Ok(()) Ok(())
}) }
fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
poll.register(self.as_raw_fd(), Interest::READ, calloop::Mode::Level, token)
}
fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
poll.reregister(self.as_raw_fd(), Interest::READ, calloop::Mode::Level, token)
}
fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> {
poll.unregister(self.as_raw_fd())
}
} }

View File

@ -68,7 +68,7 @@ mod render;
pub(self) mod session; pub(self) mod session;
pub(self) mod surface; pub(self) mod surface;
pub use device::{device_bind, DevPath, DeviceHandler, DrmDevice, DrmSource}; pub use device::{DevPath, DrmDevice, DrmEvent};
pub use error::Error as DrmError; pub use error::Error as DrmError;
#[cfg(feature = "backend_gbm")] #[cfg(feature = "backend_gbm")]
pub use render::{DrmRenderSurface, Error as DrmRenderError}; pub use render::{DrmRenderSurface, Error as DrmRenderError};

View File

@ -469,11 +469,11 @@ impl EventSource for LibinputInputBackend {
} }
fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
poll.register(self.as_raw_fd(), Interest::Readable, Mode::Level, token) poll.register(self.as_raw_fd(), Interest::READ, Mode::Level, token)
} }
fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
poll.reregister(self.as_raw_fd(), Interest::Readable, Mode::Level, token) poll.reregister(self.as_raw_fd(), Interest::READ, Mode::Level, token)
} }
fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> { fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> {

View File

@ -76,9 +76,9 @@ impl EventSource for DBusConnection {
fn reregister(&mut self, poll: &mut Poll, token: Token) -> io::Result<()> { fn reregister(&mut self, poll: &mut Poll, token: Token) -> io::Result<()> {
let new_watch = self.cx.channel().watch(); let new_watch = self.cx.channel().watch();
let new_interest = match (new_watch.read, new_watch.write) { let new_interest = match (new_watch.read, new_watch.write) {
(true, true) => Some(Interest::Both), (true, true) => Some(Interest::BOTH),
(true, false) => Some(Interest::Readable), (true, false) => Some(Interest::READ),
(false, true) => Some(Interest::Writable), (false, true) => Some(Interest::WRITE),
(false, false) => None, (false, false) => None,
}; };
if new_watch.fd != self.current_watch.fd { if new_watch.fd != self.current_watch.fd {

View File

@ -18,7 +18,7 @@
//! // process the initial list of devices //! // process the initial list of devices
//! } //! }
//! //!
//! # let event_loop = smithay::reexports::calloop::EventLoop::<()>::new().unwrap(); //! # let event_loop = smithay::reexports::calloop::EventLoop::<()>::try_new().unwrap();
//! # let loop_handle = event_loop.handle(); //! # let loop_handle = event_loop.handle();
//! // setup the event source for long-term monitoring //! // setup the event source for long-term monitoring
//! loop_handle.insert_source(udev, |event, _, _dispatch_data| match event { //! loop_handle.insert_source(udev, |event, _, _dispatch_data| match event {
@ -182,11 +182,11 @@ impl EventSource for UdevBackend {
} }
fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { fn register(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
poll.register(self.as_raw_fd(), Interest::Readable, Mode::Level, token) poll.register(self.as_raw_fd(), Interest::READ, Mode::Level, token)
} }
fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> { fn reregister(&mut self, poll: &mut Poll, token: Token) -> std::io::Result<()> {
poll.reregister(self.as_raw_fd(), Interest::Readable, Mode::Level, token) poll.reregister(self.as_raw_fd(), Interest::READ, Mode::Level, token)
} }
fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> { fn unregister(&mut self, poll: &mut Poll) -> std::io::Result<()> {

View File

@ -55,7 +55,7 @@ use std::{
use calloop::{ use calloop::{
generic::{Fd, Generic}, generic::{Fd, Generic},
Interest, LoopHandle, Mode, Source, Interest, LoopHandle, Mode, RegistrationToken,
}; };
use nix::Error as NixError; use nix::Error as NixError;
@ -91,7 +91,7 @@ impl<WM: XWindowManager + 'static> XWayland<WM> {
/// Start the XWayland server /// Start the XWayland server
pub fn init<L, T: Any, Data: 'static>( pub fn init<L, T: Any, Data: 'static>(
wm: WM, wm: WM,
handle: LoopHandle<Data>, handle: LoopHandle<'static, Data>,
display: Rc<RefCell<Display>>, display: Rc<RefCell<Display>>,
data: &mut T, data: &mut T,
logger: L, logger: L,
@ -109,7 +109,7 @@ impl<WM: XWindowManager + 'static> XWayland<WM> {
source_maker: Box::new(move |inner, fd| { source_maker: Box::new(move |inner, fd| {
handle handle
.insert_source( .insert_source(
Generic::new(Fd(fd), Interest::Readable, Mode::Level), Generic::new(Fd(fd), Interest::READ, Mode::Level),
move |evt, _, _| { move |evt, _, _| {
debug_assert!(evt.readable); debug_assert!(evt.readable);
xwayland_ready(&inner); xwayland_ready(&inner);
@ -136,13 +136,13 @@ impl<WM: XWindowManager> Drop for XWayland<WM> {
struct XWaylandInstance { struct XWaylandInstance {
display_lock: X11Lock, display_lock: X11Lock,
wayland_client: Client, wayland_client: Client,
startup_handler: Option<Source<Generic<Fd>>>, startup_handler: Option<RegistrationToken>,
wm_fd: Option<UnixStream>, wm_fd: Option<UnixStream>,
started_at: ::std::time::Instant, started_at: ::std::time::Instant,
child_stdout: Option<ChildStdout>, child_stdout: Option<ChildStdout>,
} }
type SourceMaker<WM> = dyn FnMut(Rc<RefCell<Inner<WM>>>, RawFd) -> Result<Source<Generic<Fd>>, ()>; type SourceMaker<WM> = dyn FnMut(Rc<RefCell<Inner<WM>>>, RawFd) -> Result<RegistrationToken, ()>;
// Inner implementation of the XWayland manager // Inner implementation of the XWayland manager
struct Inner<WM: XWindowManager> { struct Inner<WM: XWindowManager> {
@ -150,7 +150,7 @@ struct Inner<WM: XWindowManager> {
source_maker: Box<SourceMaker<WM>>, source_maker: Box<SourceMaker<WM>>,
wayland_display: Rc<RefCell<Display>>, wayland_display: Rc<RefCell<Display>>,
instance: Option<XWaylandInstance>, instance: Option<XWaylandInstance>,
kill_source: Box<dyn Fn(Source<Generic<Fd>>)>, kill_source: Box<dyn Fn(RegistrationToken)>,
log: ::slog::Logger, log: ::slog::Logger,
} }