diff --git a/Cargo.toml b/Cargo.toml index 2764cc67ac83..3f00e0ef95fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,6 +69,27 @@ profiling = "1.0" smallvec = "1.11" pixman = { version = "0.1.0", features = ["drm-fourcc"], optional = true } +[patch.crates-io] +wayland-egl = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" } +wayland-protocols = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" } +wayland-protocols-wlr = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" } +wayland-protocols-misc = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" } +wayland-server = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" } +wayland-client = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" } +wayland-sys = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" } +wayland-backend = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" } +wayland-scanner = { git = "https://github.com/ids1024/wayland-rs", branch = "wayland-protocols-1.34" } +# wayland-egl = { path = "../wayland-rs/wayland-egl/" } +# wayland-protocols = { path = "../wayland-rs/wayland-protocols/" } +# wayland-protocols-wlr = { path = "../wayland-rs/wayland-protocols-wlr/" } +# wayland-protocols-misc = { path = "../wayland-rs/wayland-protocols-misc/" } +# wayland-server = { path = "../wayland-rs/wayland-server/" } +# wayland-client = { path = "../wayland-rs/wayland-client/" } +# wayland-sys = { path = "../wayland-rs/wayland-sys/" } +# wayland-backend = { path = "../wayland-rs/wayland-backend/" } +# wayland-scanner = { path = "../wayland-rs/wayland-scanner/" } +drm = { git = "https://github.com/smithay/drm-rs" } +drm-ffi = { git = "https://github.com/smithay/drm-rs" } [dev-dependencies] clap = { version = "4", features = ["derive"] } diff --git a/anvil/src/shell/mod.rs b/anvil/src/shell/mod.rs index 69fdb0b70fed..8e1f3db3d078 100644 --- a/anvil/src/shell/mod.rs +++ b/anvil/src/shell/mod.rs @@ -25,6 +25,7 @@ use smithay::{ CompositorState, SurfaceAttributes, TraversalAction, }, dmabuf::get_dmabuf, + drm_syncobj::{DrmSyncobjCachedState, DrmSyncobjHandler}, shell::{ wlr_layer::{ Layer, LayerSurface as WlrLayerSurface, LayerSurfaceData, WlrLayerShellHandler, @@ -107,7 +108,13 @@ impl CompositorHandler for AnvilState { fn new_surface(&mut self, surface: &WlSurface) { add_pre_commit_hook::(surface, move |state, _dh, surface| { + let mut acquire_point = None; let maybe_dmabuf = with_states(surface, |surface_data| { + acquire_point = surface_data + .cached_state + .pending::() + .acquire_point + .clone(); surface_data .cached_state .pending::() @@ -119,6 +126,20 @@ impl CompositorHandler for AnvilState { }) }); if let Some(dmabuf) = maybe_dmabuf { + if let Some(acquire_point) = acquire_point { + if let Ok((blocker, source)) = acquire_point.generate_blocker(state.import_device()) { + let client = surface.client().unwrap(); + let res = state.handle.insert_source(source, move |_, _, data| { + let dh = data.display_handle.clone(); + data.client_compositor_state(&client).blocker_cleared(data, &dh); + Ok(()) + }); + if res.is_ok() { + add_blocker(surface, blocker); + return; + } + } + } if let Ok((blocker, source)) = dmabuf.generate_blocker(Interest::READ) { let client = surface.client().unwrap(); let res = state.handle.insert_source(source, move |_, _, data| { diff --git a/anvil/src/state.rs b/anvil/src/state.rs index 5679ba9bc3f9..db61a44ccf57 100644 --- a/anvil/src/state.rs +++ b/anvil/src/state.rs @@ -13,12 +13,13 @@ use smithay::{ default_primary_scanout_output_compare, utils::select_dmabuf_feedback, RenderElementStates, }, }, - delegate_compositor, delegate_data_control, delegate_data_device, delegate_fractional_scale, - delegate_input_method_manager, delegate_keyboard_shortcuts_inhibit, delegate_layer_shell, - delegate_output, delegate_pointer_constraints, delegate_pointer_gestures, delegate_presentation, - delegate_primary_selection, delegate_relative_pointer, delegate_seat, delegate_security_context, - delegate_shm, delegate_tablet_manager, delegate_text_input_manager, delegate_viewporter, - delegate_virtual_keyboard_manager, delegate_xdg_activation, delegate_xdg_decoration, delegate_xdg_shell, + delegate_compositor, delegate_data_control, delegate_data_device, delegate_drm_syncobj, + delegate_fractional_scale, delegate_input_method_manager, delegate_keyboard_shortcuts_inhibit, + delegate_layer_shell, delegate_output, delegate_pointer_constraints, delegate_pointer_gestures, + delegate_presentation, delegate_primary_selection, delegate_relative_pointer, delegate_seat, + delegate_security_context, delegate_shm, delegate_tablet_manager, delegate_text_input_manager, + delegate_viewporter, delegate_virtual_keyboard_manager, delegate_xdg_activation, delegate_xdg_decoration, + delegate_xdg_shell, desktop::{ space::SpaceElement, utils::{ @@ -48,6 +49,7 @@ use smithay::{ wayland::{ compositor::{get_parent, with_states, CompositorClientState, CompositorState}, dmabuf::DmabufFeedback, + drm_syncobj::{DrmSyncobjHandler, DrmSyncobjState}, fractional_scale::{with_fractional_scale, FractionalScaleHandler, FractionalScaleManagerState}, input_method::{InputMethodHandler, InputMethodManagerState, PopupSurface}, keyboard_shortcuts_inhibit::{ @@ -526,6 +528,24 @@ impl XdgForeignHandler for AnvilState { } smithay::delegate_xdg_foreign!(@ AnvilState); +impl DrmSyncobjHandler for AnvilState { + fn import_device(&self) -> &smithay::backend::drm::DrmDeviceFd { + use std::any::Any; + // XXX + let udev_data = &::downcast_ref::>(self) + .unwrap() + .backend_data; + udev_data.backends[&udev_data + .primary_gpu + .node_with_type(smithay::backend::drm::NodeType::Primary) + .unwrap() + .unwrap()] + .drm + .device_fd() + } +} +delegate_drm_syncobj!(@ AnvilState); + impl AnvilState { pub fn init( display: Display>, @@ -604,6 +624,7 @@ impl AnvilState { .get_data::() .map_or(true, |client_state| client_state.security_context.is_none()) }); + DrmSyncobjState::new::(&dh); // init input let seat_name = backend_data.seat_name(); diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 7d86ac293e80..71e4f0f8cbd1 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -125,9 +125,9 @@ pub struct UdevData { pub session: LibSeatSession, dh: DisplayHandle, dmabuf_state: Option<(DmabufState, DmabufGlobal)>, - primary_gpu: DrmNode, + pub primary_gpu: DrmNode, gpus: GpuManager>, - backends: HashMap, + pub backends: HashMap, pointer_images: Vec<(xcursor::parser::Image, MemoryRenderBuffer)>, pointer_element: PointerElement, #[cfg(feature = "debug")] @@ -737,13 +737,13 @@ impl Drop for SurfaceData { } } -struct BackendData { +pub struct BackendData { surfaces: HashMap, non_desktop_connectors: Vec<(connector::Handle, crtc::Handle)>, leasing_global: Option, active_leases: Vec, gbm: GbmDevice, - drm: DrmDevice, + pub drm: DrmDevice, drm_scanner: DrmScanner, render_node: DrmNode, registration_token: RegistrationToken, diff --git a/src/wayland/compositor/handlers.rs b/src/wayland/compositor/handlers.rs index 301f8b342bbb..1e1371dc1797 100644 --- a/src/wayland/compositor/handlers.rs +++ b/src/wayland/compositor/handlers.rs @@ -133,6 +133,7 @@ impl Cacheable for SurfaceAttributes { if Some(&buffer) != new_buffer { buffer.release(); + // TODO explicit sync? } } } diff --git a/src/wayland/compositor/tree.rs b/src/wayland/compositor/tree.rs index 4ad59209c363..ce89b9ef2f0a 100644 --- a/src/wayland/compositor/tree.rs +++ b/src/wayland/compositor/tree.rs @@ -138,6 +138,7 @@ impl PrivateSurfaceData { let mut child_guard = child_mutex.lock().unwrap(); child_guard.parent = None; } + // TODO explicit sync? if let Some(BufferAssignment::NewBuffer(buffer)) = my_data .public_data .cached_state diff --git a/src/wayland/drm_syncobj/mod.rs b/src/wayland/drm_syncobj/mod.rs new file mode 100644 index 000000000000..1daa03c68262 --- /dev/null +++ b/src/wayland/drm_syncobj/mod.rs @@ -0,0 +1,338 @@ +//! DRM syncobj protocol + +use std::{cell::RefCell, os::unix::io::AsFd}; +use wayland_protocols::wp::linux_drm_syncobj::v1::server::{ + wp_linux_drm_syncobj_manager_v1::{self, WpLinuxDrmSyncobjManagerV1}, + wp_linux_drm_syncobj_surface_v1::{self, WpLinuxDrmSyncobjSurfaceV1}, + wp_linux_drm_syncobj_timeline_v1::{self, WpLinuxDrmSyncobjTimelineV1}, +}; +use wayland_server::{ + protocol::wl_surface::WlSurface, Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, + Resource, Weak, +}; + +use super::compositor::{self, with_states, BufferAssignment, Cacheable, SurfaceAttributes}; +use crate::backend::drm::DrmDeviceFd; + +mod sync_point; +pub use sync_point::{DrmSyncPoint, DrmTimeline}; + +/// Handler trait for DRM syncobj protocol. +pub trait DrmSyncobjHandler { + // TODO better way to deal with this? + /// DRM device for importing syncobj file descriptors + fn import_device(&self) -> &DrmDeviceFd; +} + +/// Data associated with a drm syncobj global +#[allow(missing_debug_implementations)] +pub struct DrmSyncobjGlobalData { + filter: Box Fn(&'c Client) -> bool + Send + Sync>, +} + +/// Pending DRM syncobj sync point state +#[derive(Debug, Default)] +pub struct DrmSyncobjCachedState { + /// Timeline point signaled when buffer is ready to read + pub acquire_point: Option, + /// Timeline point to be signaled when server is done with buffer + pub release_point: Option, +} + +impl Cacheable for DrmSyncobjCachedState { + fn commit(&mut self, _dh: &DisplayHandle) -> Self { + Self { + acquire_point: None, + release_point: None, + } + } + + fn merge_into(self, into: &mut Self, _dh: &DisplayHandle) { + if self.acquire_point.is_some() && self.release_point.is_some() { + into.acquire_point = self.acquire_point; + into.release_point = self.release_point; + } else { + into.acquire_point = None; + into.release_point = None; + } + } +} + +/// Delegate type for a `wp_linux_drm_syncobj_manager_v1` global +#[derive(Debug)] +pub struct DrmSyncobjState {} + +impl DrmSyncobjState { + /// Create a new `wp_linux_drm_syncobj_manager_v1` global + pub fn new(display: &DisplayHandle) -> Self + where + D: GlobalDispatch, + D: 'static, + { + Self::new_with_filter::(display, |_| true) + } + + /// Create a new `wp_linuxdrm_syncobj_manager_v1` global with a client filter + pub fn new_with_filter(display: &DisplayHandle, filter: F) -> Self + where + D: GlobalDispatch, + D: 'static, + F: for<'c> Fn(&'c Client) -> bool + Send + Sync + 'static, + { + let _global = display.create_global::( + 1, + DrmSyncobjGlobalData { + filter: Box::new(filter), + }, + ); + + Self {} + } +} + +impl GlobalDispatch for DrmSyncobjState +where + D: Dispatch, +{ + fn bind( + _state: &mut D, + _dh: &DisplayHandle, + _client: &Client, + resource: New, + _global_data: &DrmSyncobjGlobalData, + data_init: &mut DataInit<'_, D>, + ) { + data_init.init::<_, _>(resource, ()); + } + + fn can_view(client: Client, global_data: &DrmSyncobjGlobalData) -> bool { + (global_data.filter)(&client) + } +} + +fn commit_hook(data: &mut D, _dh: &DisplayHandle, surface: &WlSurface) { + compositor::with_states(surface, |states| { + let cached = &states.cached_state; + let has_new_buffer = matches!( + cached.pending::().buffer, + Some(BufferAssignment::NewBuffer(_)) + ); + // TODO what if syncobj surface is destroyed? + if let Some(data) = states + .data_map + .get::>>() + { + if let Some(syncobj_surface) = data.borrow().as_ref() { + let pending = cached.pending::(); + if pending.acquire_point.is_some() && !has_new_buffer { + syncobj_surface.post_error( + wp_linux_drm_syncobj_surface_v1::Error::NoBuffer as u32, + "acquire point without buffer".to_string(), + ); + } else if pending.acquire_point.is_some() && pending.release_point.is_none() { + syncobj_surface.post_error( + wp_linux_drm_syncobj_surface_v1::Error::NoReleasePoint as u32, + "acquire point without release point".to_string(), + ); + } else if pending.acquire_point.is_none() && pending.release_point.is_some() { + syncobj_surface.post_error( + wp_linux_drm_syncobj_surface_v1::Error::NoAcquirePoint as u32, + "release point without acquire point".to_string(), + ); + } else if let (Some(acquire), Some(release)) = + (pending.acquire_point.as_ref(), pending.release_point.as_ref()) + { + if acquire.timeline == release.timeline && acquire.point <= release.point { + syncobj_surface.post_error( + wp_linux_drm_syncobj_surface_v1::Error::ConflictingPoints as u32, + format!( + "release point '{}' is not greater than acquire point '{}'", + release.point, acquire.point + ), + ); + } + } + // TODO unsupported buffer error + } + } + + // XXX wrong place to release + let current = cached.pending::(); + if let Some(release_point) = ¤t.release_point { + if let Err(err) = release_point.signal(data.import_device()) { + tracing::error!("Failed to signal syncobj release point: {}", err); + } + } + }); +} + +impl Dispatch for DrmSyncobjState +where + D: Dispatch, + D: Dispatch, + D: DrmSyncobjHandler, +{ + fn request( + state: &mut D, + _client: &Client, + resource: &WpLinuxDrmSyncobjManagerV1, + request: wp_linux_drm_syncobj_manager_v1::Request, + _data: &(), + _dh: &DisplayHandle, + data_init: &mut DataInit<'_, D>, + ) { + match request { + wp_linux_drm_syncobj_manager_v1::Request::GetSurface { id, surface } => { + let already_exists = with_states(&surface, |states| { + states + .data_map + .get::>>() + .map(|v| v.borrow().is_some()) + .unwrap_or(false) + }); + if already_exists { + resource.post_error( + wp_linux_drm_syncobj_manager_v1::Error::SurfaceExists as u32, + "the surface already has a syncobj_surface object associated".to_string(), + ); + return; + } + let syncobj_surface = data_init.init::<_, _>( + id, + DrmSyncobjSurfaceData { + surface: surface.downgrade(), + }, + ); + with_states(&surface, |states| { + states + .data_map + .insert_if_missing(|| RefCell::new(Some(syncobj_surface))) + }); + compositor::add_pre_commit_hook::(&surface, commit_hook); + } + wp_linux_drm_syncobj_manager_v1::Request::ImportTimeline { id, fd } => { + match DrmTimeline::new(state.import_device(), fd.as_fd()) { + Ok(timeline) => { + data_init.init::<_, _>(id, DrmSyncobjTimelineData { timeline }); + } + Err(err) => { + resource.post_error( + wp_linux_drm_syncobj_manager_v1::Error::InvalidTimeline as u32, + format!("failed to import syncobj timeline: {}", err), + ); + } + } + } + wp_linux_drm_syncobj_manager_v1::Request::Destroy => {} + _ => unreachable!(), + } + } +} + +/// Data attached to wp_linux_drm_syncobj_surface_v1 objects +#[derive(Debug)] +pub struct DrmSyncobjSurfaceData { + surface: Weak, +} + +impl Dispatch for DrmSyncobjState { + fn request( + _state: &mut D, + _client: &Client, + _resource: &WpLinuxDrmSyncobjSurfaceV1, + request: wp_linux_drm_syncobj_surface_v1::Request, + data: &DrmSyncobjSurfaceData, + _dh: &DisplayHandle, + _data_init: &mut DataInit<'_, D>, + ) { + let Ok(surface) = data.surface.upgrade() else { + return; + }; + match request { + wp_linux_drm_syncobj_surface_v1::Request::Destroy => { + // TODO + } + wp_linux_drm_syncobj_surface_v1::Request::SetAcquirePoint { + timeline, + point_hi, + point_lo, + } => { + let sync_point = DrmSyncPoint { + timeline: timeline + .data::() + .unwrap() + .timeline + .clone(), + point: ((point_hi as u64) << 32) + (point_lo as u64), + }; + with_states(&surface, |states| { + let mut cached_state = states.cached_state.pending::(); + cached_state.acquire_point = Some(sync_point); + }); + } + wp_linux_drm_syncobj_surface_v1::Request::SetReleasePoint { + timeline, + point_hi, + point_lo, + } => { + let sync_point = DrmSyncPoint { + timeline: timeline + .data::() + .unwrap() + .timeline + .clone(), + point: ((point_hi as u64) << 32) + (point_lo as u64), + }; + with_states(&surface, |states| { + let mut cached_state = states.cached_state.pending::(); + cached_state.release_point = Some(sync_point); + }); + } + _ => unreachable!(), + } + } +} + +/// Data attached to wp_linux_drm_syncobj_timeline_v1 objects +#[derive(Debug)] +pub struct DrmSyncobjTimelineData { + timeline: DrmTimeline, +} + +impl Dispatch for DrmSyncobjState { + fn request( + _state: &mut D, + _client: &Client, + _resource: &WpLinuxDrmSyncobjTimelineV1, + request: wp_linux_drm_syncobj_timeline_v1::Request, + _data: &DrmSyncobjTimelineData, + _dh: &DisplayHandle, + _data_init: &mut DataInit<'_, D>, + ) { + match request { + wp_linux_drm_syncobj_timeline_v1::Request::Destroy => {} + _ => unreachable!(), + } + } +} + +/// Macro to delegate implementation of the drm syncobj protocol to [`DrmSyncobjState`]. +/// +/// You must also implement [`DrmSyncobjHandler`] to use this. +#[macro_export] +macro_rules! delegate_drm_syncobj { + ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { + $crate::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ + $crate::reexports::wayland_protocols::wp::linux_drm_syncobj::v1::server::wp_linux_drm_syncobj_manager_v1::WpLinuxDrmSyncobjManagerV1: $crate::wayland::drm_syncobj::DrmSyncobjGlobalData + ] => $crate::wayland::drm_syncobj::DrmSyncobjState); + $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ + $crate::reexports::wayland_protocols::wp::linux_drm_syncobj::v1::server::wp_linux_drm_syncobj_manager_v1::WpLinuxDrmSyncobjManagerV1: () + ] => $crate::wayland::drm_syncobj::DrmSyncobjState); + $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ + $crate::reexports::wayland_protocols::wp::linux_drm_syncobj::v1::server::wp_linux_drm_syncobj_surface_v1::WpLinuxDrmSyncobjSurfaceV1: $crate::wayland::drm_syncobj::DrmSyncobjSurfaceData + ] => $crate::wayland::drm_syncobj::DrmSyncobjState); + $crate::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ + $crate::reexports::wayland_protocols::wp::linux_drm_syncobj::v1::server::wp_linux_drm_syncobj_timeline_v1::WpLinuxDrmSyncobjTimelineV1: $crate::wayland::drm_syncobj::DrmSyncobjTimelineData + ] => $crate::wayland::drm_syncobj::DrmSyncobjState); + } +} diff --git a/src/wayland/drm_syncobj/sync_point.rs b/src/wayland/drm_syncobj/sync_point.rs new file mode 100644 index 000000000000..efade4637f74 --- /dev/null +++ b/src/wayland/drm_syncobj/sync_point.rs @@ -0,0 +1,128 @@ +use calloop::generic::Generic; +use calloop::{EventSource, Interest, Mode, Poll, PostAction, Readiness, Token, TokenFactory}; +use drm::control::Device; +use std::{ + io, + os::unix::io::{AsFd, BorrowedFd, OwnedFd}, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, +}; + +use crate::backend::drm::DrmDeviceFd; +use crate::wayland::compositor::{Blocker, BlockerState}; + +// TODO destroy handle? +/// DRM timeline syncobj +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct DrmTimeline { + syncobj: drm::control::syncobj::Handle, +} + +impl DrmTimeline { + /// Import DRM timeline from file descriptor + pub fn new(device: &DrmDeviceFd, fd: BorrowedFd<'_>) -> io::Result { + Ok(Self { + syncobj: device.fd_to_syncobj(fd, false)?, + }) + } +} + +/// Point on a DRM timeline syncobj +#[derive(Clone, Debug)] +pub struct DrmSyncPoint { + pub(super) timeline: DrmTimeline, + pub(super) point: u64, +} + +impl DrmSyncPoint { + /// Create an eventfd that will be signaled by the syncpoint + pub fn eventfd(&self, device: &DrmDeviceFd) -> io::Result { + let fd = rustix::event::eventfd( + 0, + rustix::event::EventfdFlags::CLOEXEC | rustix::event::EventfdFlags::NONBLOCK, + )?; + // TODO wait_avialable? + device.syncobj_eventfd(self.timeline.syncobj, self.point, fd.as_fd(), false)?; + Ok(fd) + } + + /// Signal the syncpoint + pub fn signal(&self, device: &DrmDeviceFd) -> io::Result<()> { + device.syncobj_timeline_signal(&[self.timeline.syncobj], &[self.point]) + } + + /// Create an [`calloop::EventSource`] and [`crate::wayland::compositor::Blocker`] for this sync point. + pub fn generate_blocker( + &self, + device: &DrmDeviceFd, + ) -> io::Result<(DrmSyncPointBlocker, DrmSyncPointSource)> { + let fd = self.eventfd(device)?; + let signal = Arc::new(AtomicBool::new(false)); + let blocker = DrmSyncPointBlocker { + signal: signal.clone(), + }; + let source = DrmSyncPointSource { + source: Generic::new(fd, Interest::READ, Mode::Level), + signal, + }; + Ok((blocker, source)) + } +} + +#[derive(Debug)] +pub struct DrmSyncPointSource { + source: Generic, + signal: Arc, +} + +impl EventSource for DrmSyncPointSource { + type Event = (); + type Metadata = (); + type Ret = Result<(), std::io::Error>; + type Error = io::Error; + + fn process_events( + &mut self, + readiness: Readiness, + token: Token, + mut callback: C, + ) -> Result + where + C: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret, + { + self.signal.store(true, Ordering::SeqCst); + self.source + .process_events(readiness, token, |_, _| Ok(PostAction::Remove))?; + callback((), &mut ())?; + Ok(PostAction::Remove) + } + + fn register(&mut self, poll: &mut Poll, token_factory: &mut TokenFactory) -> calloop::Result<()> { + self.source.register(poll, token_factory) + } + + fn reregister(&mut self, poll: &mut Poll, token_factory: &mut TokenFactory) -> calloop::Result<()> { + self.source.reregister(poll, token_factory) + } + + fn unregister(&mut self, poll: &mut Poll) -> calloop::Result<()> { + self.source.unregister(poll) + } +} + +#[derive(Debug)] +pub struct DrmSyncPointBlocker { + signal: Arc, +} + +impl Blocker for DrmSyncPointBlocker { + fn state(&self) -> BlockerState { + if self.signal.load(Ordering::SeqCst) { + BlockerState::Released + } else { + BlockerState::Pending + } + } +} diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 6192c91ba8c6..c3245d5c9710 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -52,6 +52,8 @@ pub mod cursor_shape; pub mod dmabuf; #[cfg(feature = "backend_drm")] pub mod drm_lease; +#[cfg(feature = "backend_drm")] +pub mod drm_syncobj; pub mod fractional_scale; pub mod idle_inhibit; pub mod idle_notify;