From 3f1c9610aa43e298f4b5866d36e1c6215c81d896 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Fri, 13 Sep 2024 16:01:49 +0200 Subject: [PATCH] wayland: implement fifo-v1 --- src/backends/metal/present.rs | 2 +- src/client.rs | 4 +- src/compositor.rs | 4 +- src/globals.rs | 2 + src/ifs.rs | 1 + src/ifs/jay_screencast.rs | 2 +- src/ifs/wl_surface.rs | 35 +++++++++- src/ifs/wl_surface/commit_timeline.rs | 97 +++++++++++++++++++++++++-- src/ifs/wl_surface/wp_fifo_v1.rs | 77 +++++++++++++++++++++ src/ifs/wp_fifo_manager_v1.rs | 96 ++++++++++++++++++++++++++ src/state.rs | 14 ++-- src/tasks.rs | 12 +++- src/tasks/const_clock.rs | 49 ++++++++++++++ src/tree/output.rs | 6 +- src/utils/event_listener.rs | 4 ++ wire/wp_fifo_manager_v1.txt | 8 +++ wire/wp_fifo_v1.txt | 11 +++ 17 files changed, 403 insertions(+), 21 deletions(-) create mode 100644 src/ifs/wl_surface/wp_fifo_v1.rs create mode 100644 src/ifs/wp_fifo_manager_v1.rs create mode 100644 src/tasks/const_clock.rs create mode 100644 wire/wp_fifo_manager_v1.txt create mode 100644 wire/wp_fifo_v1.txt diff --git a/src/backends/metal/present.rs b/src/backends/metal/present.rs index 36ee87b4..9385ba28 100644 --- a/src/backends/metal/present.rs +++ b/src/backends/metal/present.rs @@ -174,7 +174,7 @@ impl MetalConnector { self.latch_cursor(&node)?; let cursor_programming = self.compute_cursor_programming(); let latched = self.latch(&node); - node.latched(); + node.latched(self.try_async_flip()); if cursor_programming.is_none() && latched.is_none() { return Ok(()); diff --git a/src/client.rs b/src/client.rs index 1e798af0..555800eb 100644 --- a/src/client.rs +++ b/src/client.rs @@ -148,7 +148,7 @@ impl Clients { bounding_caps: ClientCaps, is_xwayland: bool, ) -> Result, ClientError> { - let data = Rc::new(Client { + let data = Rc::new_cyclic(|slf| Client { id, state: global.clone(), checking_queue_size: Cell::new(false), @@ -171,6 +171,8 @@ impl Clients { commit_timelines: Rc::new(CommitTimelines::new( &global.wait_for_sync_obj, &global.ring, + &global.eng, + slf, )), }); track!(data, data); diff --git a/src/compositor.rs b/src/compositor.rs index 3389115d..d029f949 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -32,7 +32,7 @@ use { scale::Scale, sighand::{self, SighandError}, state::{ConnectorData, IdleState, ScreenlockState, State, XWaylandState}, - tasks::{self, idle}, + tasks::{self, handle_const_40hz_latch, idle}, tree::{ container_layout, container_render_data, float_layout, float_titles, output_render_data, DisplayNode, NodeIds, OutputNode, TearingMode, VrrMode, @@ -263,6 +263,7 @@ fn start_compositor2( ei_clients: EiClients::new(), slow_ei_clients: Default::default(), cpu_worker, + const_40hz_latch: Default::default(), }); state.tracker.register(ClientId::from_raw(0)); create_dummy_output(&state); @@ -368,6 +369,7 @@ fn start_global_event_handlers( eng.spawn2(Phase::PostLayout, perform_screencast_realloc(state.clone())), eng.spawn2(Phase::PostLayout, visualize_damage(state.clone())), eng.spawn(tasks::handle_slow_ei_clients(state.clone())), + eng.spawn2(Phase::Present, handle_const_40hz_latch(state.clone())), ] } diff --git a/src/globals.rs b/src/globals.rs index c8595388..2d12efd6 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -36,6 +36,7 @@ use { wp_alpha_modifier_v1::WpAlphaModifierV1Global, wp_content_type_manager_v1::WpContentTypeManagerV1Global, wp_cursor_shape_manager_v1::WpCursorShapeManagerV1Global, + wp_fifo_manager_v1::WpFifoManagerV1Global, wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global, wp_presentation::WpPresentationGlobal, wp_security_context_manager_v1::WpSecurityContextManagerV1Global, @@ -197,6 +198,7 @@ impl Globals { add_singleton!(ZwpPointerGesturesV1Global); add_singleton!(ZwpTabletManagerV2Global); add_singleton!(JayDamageTrackingGlobal); + add_singleton!(WpFifoManagerV1Global); } pub fn add_backend_singletons(&self, backend: &Rc) { diff --git a/src/ifs.rs b/src/ifs.rs index 3d81f770..4148a896 100644 --- a/src/ifs.rs +++ b/src/ifs.rs @@ -48,6 +48,7 @@ pub mod wp_drm_lease_connector_v1; pub mod wp_drm_lease_device_v1; pub mod wp_drm_lease_request_v1; pub mod wp_drm_lease_v1; +pub mod wp_fifo_manager_v1; pub mod wp_fractional_scale_manager_v1; pub mod wp_linux_drm_syncobj_manager_v1; pub mod wp_linux_drm_syncobj_timeline_v1; diff --git a/src/ifs/jay_screencast.rs b/src/ifs/jay_screencast.rs index 8e90ce53..fd0d69f0 100644 --- a/src/ifs/jay_screencast.rs +++ b/src/ifs/jay_screencast.rs @@ -87,7 +87,7 @@ enum Target { } impl LatchListener for JayScreencast { - fn after_latch(self: Rc) { + fn after_latch(self: Rc, _tearing: bool) { self.schedule_toplevel_screencast(); } } diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 478ba507..04e1341e 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -4,6 +4,7 @@ pub mod dnd_icon; pub mod ext_session_lock_surface_v1; pub mod wl_subsurface; pub mod wp_alpha_modifier_surface_v1; +pub mod wp_fifo_v1; pub mod wp_fractional_scale_v1; pub mod wp_linux_drm_syncobj_surface_v1; pub mod wp_tearing_control_v1; @@ -46,6 +47,7 @@ use { dnd_icon::DndIcon, wl_subsurface::{PendingSubsurfaceData, SubsurfaceId, WlSubsurface}, wp_alpha_modifier_surface_v1::WpAlphaModifierSurfaceV1, + wp_fifo_v1::WpFifoV1, wp_fractional_scale_v1::WpFractionalScaleV1, wp_linux_drm_syncobj_surface_v1::WpLinuxDrmSyncobjSurfaceV1, wp_tearing_control_v1::WpTearingControlV1, @@ -312,6 +314,8 @@ pub struct WlSurface { presentation_listener: EventListener, commit_version: NumCell, latched_commit_version: Cell, + fifo: CloneCell>>, + clear_fifo_on_vblank: Cell, } impl Debug for WlSurface { @@ -433,6 +437,8 @@ struct PendingState { release_point: Option<(Rc, SyncObjPoint)>, alpha_multiplier: Option>, explicit_sync: bool, + fifo_barrier_set: bool, + fifo_barrier_wait: bool, } struct AttachedSubsurfaceState { @@ -510,6 +516,8 @@ impl PendingState { &mut self.presentation_feedback, &mut next.presentation_feedback, ); + self.fifo_barrier_set |= mem::take(&mut next.fifo_barrier_set); + self.fifo_barrier_wait |= mem::take(&mut next.fifo_barrier_wait); macro_rules! merge_ext { ($name:ident) => { if let Some(e) = &mut self.$name { @@ -632,6 +640,8 @@ impl WlSurface { presentation_listener: EventListener::new(slf.clone()), commit_version: Default::default(), latched_commit_version: Default::default(), + fifo: Default::default(), + clear_fifo_on_vblank: Default::default(), } } @@ -1284,12 +1294,16 @@ impl WlSurface { } } self.ext.get().after_apply_commit(); + let fifo_barrier_set = mem::take(&mut pending.fifo_barrier_set); + if fifo_barrier_set { + self.commit_timeline.set_fifo_barrier(); + } if self.visible.get() { let output = self.output.get(); if has_frame_requests { self.vblank_listener.attach(&output.vblank_event); } - if has_presentation_feedback { + if has_presentation_feedback || fifo_barrier_set { self.latch_listener.attach(&output.latch_event); } if damage_full { @@ -1311,10 +1325,16 @@ impl WlSurface { let rect = output.global.pos.get(); self.client.state.damage(rect); } + } else { + if fifo_barrier_set { + self.latch_listener + .attach(&self.client.state.const_40hz_latch); + } } pending.buffer_damage.clear(); pending.surface_damage.clear(); pending.damage_full = false; + pending.fifo_barrier_wait = false; if tearing_changed { if let Some(tl) = self.toplevel.get() { if tl.tl_data().is_fullscreen.get() { @@ -2062,12 +2082,15 @@ impl VblankListener for WlSurface { let _ = fr.client.remove_obj(&*fr); } } + if self.clear_fifo_on_vblank.take() { + self.commit_timeline.clear_fifo_barrier(); + } self.vblank_listener.detach(); } } impl LatchListener for WlSurface { - fn after_latch(self: Rc) { + fn after_latch(self: Rc, tearing: bool) { if self.visible.get() { if self.latched_commit_version.get() < self.commit_version.get() { let latched = &mut *self.latched_presentation_feedback.borrow_mut(); @@ -2083,6 +2106,14 @@ impl LatchListener for WlSurface { self.latched_commit_version.set(self.commit_version.get()); } } + if tearing && self.visible.get() { + if self.commit_timeline.has_fifo_barrier() { + self.vblank_listener.attach(&self.output.get().vblank_event); + self.clear_fifo_on_vblank.set(true); + } + } else { + self.commit_timeline.clear_fifo_barrier(); + } self.latch_listener.detach(); } } diff --git a/src/ifs/wl_surface/commit_timeline.rs b/src/ifs/wl_surface/commit_timeline.rs index da4a2c46..479c7716 100644 --- a/src/ifs/wl_surface/commit_timeline.rs +++ b/src/ifs/wl_surface/commit_timeline.rs @@ -1,5 +1,7 @@ use { crate::{ + async_engine::{AsyncEngine, SpawnedFuture}, + client::Client, gfx_api::{AsyncShmGfxTextureCallback, GfxError, PendingShmUpload}, ifs::{ wl_buffer::WlBufferStorage, @@ -13,6 +15,7 @@ use { linkedlist::{LinkedList, LinkedNode, NodeRef}, numcell::NumCell, oserror::OsError, + queue::AsyncQueue, }, video::drm::{ sync_obj::{SyncObj, SyncObjPoint}, @@ -26,7 +29,7 @@ use { cell::{Cell, RefCell}, mem, ops::DerefMut, - rc::Rc, + rc::{Rc, Weak}, slice, }, thiserror::Error, @@ -43,6 +46,8 @@ pub struct CommitTimelines { ring: Rc, depth: NumCell, gc: CopyHashMap>, + flips: Rc, + _flips_future: SpawnedFuture<()>, } pub struct CommitTimeline { @@ -50,6 +55,8 @@ pub struct CommitTimeline { own_timeline: Rc, effective_timeline: CloneCell>, effective_timeline_id: Cell, + fifo_barrier_set: Cell, + fifo_waiter: Cell>>, } struct Inner { @@ -94,8 +101,17 @@ pub enum CommitTimelineError { } impl CommitTimelines { - pub fn new(wfs: &Rc, ring: &Rc) -> Self { + pub fn new( + wfs: &Rc, + ring: &Rc, + eng: &Rc, + client: &Weak, + ) -> Self { + let flips = Rc::new(Flips::default()); + let flips_future = eng.spawn(process_flips(client.clone(), flips.clone())); Self { + flips, + _flips_future: flips_future, next_id: Default::default(), depth: NumCell::new(0), wfs: wfs.clone(), @@ -115,10 +131,13 @@ impl CommitTimelines { own_timeline: timeline.clone(), effective_timeline: CloneCell::new(timeline), effective_timeline_id: Cell::new(id), + fifo_barrier_set: Cell::new(false), + fifo_waiter: Default::default(), } } pub fn clear(&self) { + self.flips.flip_waiters.clear(); for list in self.gc.lock().drain_values() { break_loops(&list); } @@ -144,8 +163,12 @@ fn break_loops(list: &LinkedList) { impl CommitTimeline { pub fn clear(&self, reason: ClearReason) { match reason { - ClearReason::BreakLoops => break_loops(&self.own_timeline.entries), + ClearReason::BreakLoops => { + self.fifo_waiter.take(); + break_loops(&self.own_timeline.entries) + } ClearReason::Destroy => { + self.clear_fifo_barrier(); if self.own_timeline.entries.is_not_empty() { let list = LinkedList::new(); list.append_all(&self.own_timeline.entries); @@ -172,7 +195,10 @@ impl CommitTimeline { ); let has_dependencies = points.is_not_empty() || pending_uploads > 0 || implicit_dmabufs.is_not_empty(); - if !has_dependencies && self.own_timeline.entries.is_empty() { + let must_be_queued = has_dependencies + || self.own_timeline.entries.is_not_empty() + || (pending.fifo_barrier_wait && self.fifo_barrier_set.get()); + if !must_be_queued { return surface .apply_state(pending) .map_err(CommitTimelineError::ImmediateCommit); @@ -181,6 +207,10 @@ impl CommitTimeline { return Err(CommitTimelineError::Depth); } set_effective_timeline(self, pending, &self.own_timeline); + let commit_fifo_state = match pending.fifo_barrier_wait { + true => CommitFifoState::Queued, + false => CommitFifoState::Mailbox, + }; let noderef = add_entry( &self.own_timeline.entries, &self.shared, @@ -193,9 +223,10 @@ impl CommitTimeline { shm_upload: RefCell::new(ShmUploadState::None), num_pending_polls: NumCell::new(implicit_dmabufs.len()), pending_polls: Cell::new(Default::default()), + fifo_state: Cell::new(commit_fifo_state), }), ); - let mut needs_flush = false; + let mut needs_flush = commit_fifo_state == CommitFifoState::Queued; if has_dependencies { let noderef = Rc::new(noderef.clone()); let EntryKind::Commit(commit) = &noderef.kind else { @@ -235,6 +266,21 @@ impl CommitTimeline { } Ok(()) } + + pub fn set_fifo_barrier(&self) { + self.fifo_barrier_set.set(true); + } + + pub fn clear_fifo_barrier(&self) { + self.fifo_barrier_set.set(false); + if let Some(waiter) = self.fifo_waiter.take() { + self.shared.flips.flip_waiters.push(waiter); + } + } + + pub fn has_fifo_barrier(&self) -> bool { + self.fifo_barrier_set.get() + } } impl SyncObjWaiter for NodeRef { @@ -322,6 +368,7 @@ struct Commit { shm_upload: RefCell, num_pending_polls: NumCell, pending_polls: Cell>, + fifo_state: Cell, } fn flush_from(mut point: NodeRef) -> Result<(), WlSurfaceError> { @@ -357,6 +404,20 @@ impl NodeRef { if c.num_pending_polls.get() > 0 { has_unmet_dependencies = true; } + let tl = &c.surface.commit_timeline; + if tl.fifo_barrier_set.get() { + match c.fifo_state.get() { + CommitFifoState::Queued => { + tl.fifo_waiter.set(Some(self.clone())); + c.fifo_state.set(CommitFifoState::Registered); + has_unmet_dependencies = true; + } + CommitFifoState::Registered => { + has_unmet_dependencies = true; + } + CommitFifoState::Mailbox => {} + } + } if has_unmet_dependencies { return Ok(false); } @@ -516,3 +577,29 @@ fn set_effective_timeline( } } } + +#[derive(Default)] +struct Flips { + flip_waiters: AsyncQueue>, +} + +async fn process_flips(client: Weak, flips: Rc) { + loop { + flips.flip_waiters.non_empty().await; + while let Some(entry) = flips.flip_waiters.try_pop() { + if let Err(e) = flush_from(entry) { + if let Some(client) = client.upgrade() { + client.error(e); + } + return; + } + } + } +} + +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +enum CommitFifoState { + Queued, + Registered, + Mailbox, +} diff --git a/src/ifs/wl_surface/wp_fifo_v1.rs b/src/ifs/wl_surface/wp_fifo_v1.rs new file mode 100644 index 00000000..d68e6734 --- /dev/null +++ b/src/ifs/wl_surface/wp_fifo_v1.rs @@ -0,0 +1,77 @@ +use { + crate::{ + client::{Client, ClientError}, + ifs::wl_surface::WlSurface, + leaks::Tracker, + object::{Object, Version}, + wire::{wp_fifo_v1::*, WpFifoV1Id}, + }, + std::rc::Rc, + thiserror::Error, +}; + +pub struct WpFifoV1 { + pub id: WpFifoV1Id, + pub client: Rc, + pub surface: Rc, + pub tracker: Tracker, + pub version: Version, +} + +impl WpFifoV1 { + pub fn new(id: WpFifoV1Id, version: Version, surface: &Rc) -> Self { + Self { + id, + client: surface.client.clone(), + surface: surface.clone(), + tracker: Default::default(), + version, + } + } + + pub fn install(self: &Rc) -> Result<(), WpFifoV1Error> { + if self.surface.fifo.is_some() { + return Err(WpFifoV1Error::Exists); + } + self.surface.fifo.set(Some(self.clone())); + Ok(()) + } +} + +impl WpFifoV1RequestHandler for WpFifoV1 { + type Error = WpFifoV1Error; + + fn set_barrier(&self, _req: SetBarrier, _slf: &Rc) -> Result<(), Self::Error> { + self.surface.pending.borrow_mut().fifo_barrier_set = true; + Ok(()) + } + + fn wait_barrier(&self, _req: WaitBarrier, _slf: &Rc) -> Result<(), Self::Error> { + self.surface.pending.borrow_mut().fifo_barrier_wait = true; + Ok(()) + } + + fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { + self.surface.fifo.take(); + self.client.remove_obj(self)?; + Ok(()) + } +} + +object_base! { + self = WpFifoV1; + version = self.version; +} + +impl Object for WpFifoV1 {} + +simple_add_obj!(WpFifoV1); + +#[derive(Debug, Error)] +pub enum WpFifoV1Error { + #[error(transparent)] + ClientError(Box), + #[error("The surface already has a fifo extension attached")] + Exists, +} +efrom!(WpFifoV1Error, ClientError); diff --git a/src/ifs/wp_fifo_manager_v1.rs b/src/ifs/wp_fifo_manager_v1.rs new file mode 100644 index 00000000..c0f47b59 --- /dev/null +++ b/src/ifs/wp_fifo_manager_v1.rs @@ -0,0 +1,96 @@ +use { + crate::{ + client::{Client, ClientError}, + globals::{Global, GlobalName}, + ifs::wl_surface::wp_fifo_v1::{WpFifoV1, WpFifoV1Error}, + leaks::Tracker, + object::{Object, Version}, + wire::{wp_fifo_manager_v1::*, WpFifoManagerV1Id}, + }, + std::rc::Rc, + thiserror::Error, +}; + +pub struct WpFifoManagerV1Global { + pub name: GlobalName, +} + +pub struct WpFifoManagerV1 { + pub id: WpFifoManagerV1Id, + pub client: Rc, + pub tracker: Tracker, + pub version: Version, +} + +impl WpFifoManagerV1Global { + pub fn new(name: GlobalName) -> Self { + Self { name } + } + + fn bind_( + self: Rc, + id: WpFifoManagerV1Id, + client: &Rc, + version: Version, + ) -> Result<(), WpFifoManagerV1Error> { + let obj = Rc::new(WpFifoManagerV1 { + id, + client: client.clone(), + tracker: Default::default(), + version, + }); + track!(client, obj); + client.add_client_obj(&obj)?; + Ok(()) + } +} + +global_base!(WpFifoManagerV1Global, WpFifoManagerV1, WpFifoManagerV1Error); + +impl Global for WpFifoManagerV1Global { + fn singleton(&self) -> bool { + true + } + + fn version(&self) -> u32 { + 1 + } +} + +simple_add_global!(WpFifoManagerV1Global); + +impl WpFifoManagerV1RequestHandler for WpFifoManagerV1 { + type Error = WpFifoManagerV1Error; + + fn destroy(&self, _req: Destroy, _slf: &Rc) -> Result<(), Self::Error> { + self.client.remove_obj(self)?; + Ok(()) + } + + fn get_fifo(&self, req: GetFifo, _slf: &Rc) -> Result<(), Self::Error> { + let surface = self.client.lookup(req.surface)?; + let fs = Rc::new(WpFifoV1::new(req.id, self.version, &surface)); + track!(self.client, fs); + fs.install()?; + self.client.add_client_obj(&fs)?; + Ok(()) + } +} + +object_base! { + self = WpFifoManagerV1; + version = self.version; +} + +impl Object for WpFifoManagerV1 {} + +simple_add_obj!(WpFifoManagerV1); + +#[derive(Debug, Error)] +pub enum WpFifoManagerV1Error { + #[error(transparent)] + ClientError(Box), + #[error(transparent)] + WpFifoV1Error(#[from] WpFifoV1Error), +} +efrom!(WpFifoManagerV1Error, ClientError); diff --git a/src/state.rs b/src/state.rs index be74949a..79df6a93 100644 --- a/src/state.rs +++ b/src/state.rs @@ -69,15 +69,16 @@ use { theme::{Color, Theme}, time::Time, tree::{ - ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, Node, NodeIds, - NodeVisitorBase, OutputNode, PlaceholderNode, TearingMode, ToplevelNode, + ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, LatchListener, Node, + NodeIds, NodeVisitorBase, OutputNode, PlaceholderNode, TearingMode, ToplevelNode, ToplevelNodeBase, VrrMode, WorkspaceNode, }, utils::{ activation_token::ActivationToken, asyncevent::AsyncEvent, bindings::Bindings, - clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, fdcloser::FdCloser, - hash_map_ext::HashMapExt, linkedlist::LinkedList, numcell::NumCell, queue::AsyncQueue, - refcounted::RefCounted, run_toplevel::RunToplevel, + clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, + event_listener::EventSource, fdcloser::FdCloser, hash_map_ext::HashMapExt, + linkedlist::LinkedList, numcell::NumCell, queue::AsyncQueue, refcounted::RefCounted, + run_toplevel::RunToplevel, }, video::{ dmabuf::DmaBufIds, @@ -216,6 +217,7 @@ pub struct State { pub ei_clients: EiClients, pub slow_ei_clients: AsyncQueue>, pub cpu_worker: Rc, + pub const_40hz_latch: EventSource, } // impl Drop for State { @@ -910,7 +912,7 @@ impl State { output.global.persistent.scale.get(), render_hw_cursor, )?; - output.latched(); + output.latched(false); output.perform_screencopies(tex, !render_hw_cursor, 0, 0, None); Ok(sync_file) } diff --git a/src/tasks.rs b/src/tasks.rs index 7ebb569b..3483f40d 100644 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -1,5 +1,6 @@ mod backend; mod connector; +mod const_clock; mod drmdev; mod hardware_cursor; mod idle; @@ -12,10 +13,11 @@ use { state::State, tasks::{ backend::BackendEventHandler, + const_clock::run_const_clock, slow_clients::{SlowClientHandler, SlowEiClientHandler}, }, }, - std::rc::Rc, + std::{rc::Rc, time::Duration}, }; pub use {hardware_cursor::handle_hardware_cursor_tick, idle::idle}; @@ -33,3 +35,11 @@ pub async fn handle_slow_ei_clients(state: Rc) { let mut sch = SlowEiClientHandler { state }; sch.handle_events().await; } + +pub async fn handle_const_40hz_latch(state: Rc) { + let duration = Duration::from_nanos(1_000_000_000 / 40); + run_const_clock(duration, &state.ring, &state.const_40hz_latch, |l| { + l.after_latch(false) + }) + .await; +} diff --git a/src/tasks/const_clock.rs b/src/tasks/const_clock.rs new file mode 100644 index 00000000..082b66ec --- /dev/null +++ b/src/tasks/const_clock.rs @@ -0,0 +1,49 @@ +use { + crate::{ + io_uring::IoUring, + utils::{ + asyncevent::AsyncEvent, errorfmt::ErrorFmt, event_listener::EventSource, timer::TimerFd, + }, + }, + std::{rc::Rc, time::Duration}, + uapi::c, +}; + +pub async fn run_const_clock( + duration: Duration, + ring: &Rc, + source: &EventSource, + mut f: F, +) where + T: ?Sized, + F: FnMut(Rc), +{ + let timer = match TimerFd::new(c::CLOCK_MONOTONIC) { + Ok(fd) => fd, + Err(e) => { + log::error!("Could not create timerfd: {}", ErrorFmt(e)); + return; + } + }; + if let Err(e) = timer.program(Some(duration), Some(duration)) { + log::error!("Could not program timerfd: {}", ErrorFmt(e)); + return; + } + let ae = Rc::new(AsyncEvent::default()); + loop { + if let Err(e) = timer.expired(&ring).await { + log::error!("Could not wait for timerfd to expire: {}", ErrorFmt(e)); + return; + } + let mut dispatched_any = false; + for el in source.iter() { + dispatched_any = true; + f(el); + } + if !dispatched_any { + let ae2 = ae.clone(); + source.on_attach(Box::new(move || ae2.trigger())); + ae.triggered().await; + } + } +} diff --git a/src/tree/output.rs b/src/tree/output.rs index f43e961c..10ed6dd2 100644 --- a/src/tree/output.rs +++ b/src/tree/output.rs @@ -86,7 +86,7 @@ pub struct OutputNode { } pub trait LatchListener { - fn after_latch(self: Rc); + fn after_latch(self: Rc, tearing: bool); } pub trait VblankListener { @@ -124,10 +124,10 @@ pub async fn output_render_data(state: Rc) { } impl OutputNode { - pub fn latched(&self) { + pub fn latched(&self, tearing: bool) { self.schedule.latched(); for listener in self.latch_event.iter() { - listener.after_latch(); + listener.after_latch(tearing); } } diff --git a/src/utils/event_listener.rs b/src/utils/event_listener.rs index aef88ff2..c328d5a8 100644 --- a/src/utils/event_listener.rs +++ b/src/utils/event_listener.rs @@ -30,6 +30,10 @@ impl EventSource { iter: self.listeners.iter(), } } + + pub fn on_attach(&self, ev: Box) { + self.on_attach.set(Some(ev)); + } } pub struct EventSourceIter { diff --git a/wire/wp_fifo_manager_v1.txt b/wire/wp_fifo_manager_v1.txt new file mode 100644 index 00000000..8d26f7a9 --- /dev/null +++ b/wire/wp_fifo_manager_v1.txt @@ -0,0 +1,8 @@ +request destroy { + +} + +request get_fifo { + id: id(wp_fifo_v1), + surface: id(wl_surface), +} diff --git a/wire/wp_fifo_v1.txt b/wire/wp_fifo_v1.txt new file mode 100644 index 00000000..60886232 --- /dev/null +++ b/wire/wp_fifo_v1.txt @@ -0,0 +1,11 @@ +request set_barrier { + +} + +request wait_barrier { + +} + +request destroy { + +}