Merge pull request #141 from mahkoh/jorth/fifo
wayland: implement fifo-v1
This commit is contained in:
commit
4742c0f5b3
19 changed files with 416 additions and 23 deletions
|
|
@ -159,6 +159,7 @@ Jay supports the following wayland protocols:
|
||||||
| wp_content_type_manager_v1 | 1 | |
|
| wp_content_type_manager_v1 | 1 | |
|
||||||
| wp_cursor_shape_manager_v1 | 1 | |
|
| wp_cursor_shape_manager_v1 | 1 | |
|
||||||
| wp_drm_lease_device_v1 | 1 | |
|
| wp_drm_lease_device_v1 | 1 | |
|
||||||
|
| wp_fifo_manager_v1 | 1 | |
|
||||||
| wp_fractional_scale_manager_v1 | 1 | |
|
| wp_fractional_scale_manager_v1 | 1 | |
|
||||||
| wp_linux_drm_syncobj_manager_v1 | 1 | |
|
| wp_linux_drm_syncobj_manager_v1 | 1 | |
|
||||||
| wp_presentation | 1 | |
|
| wp_presentation | 1 | |
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
- Implement ext-image-copy-capture-v1.
|
- Implement ext-image-copy-capture-v1.
|
||||||
- Implement screencast session restoration.
|
- Implement screencast session restoration.
|
||||||
- Fix screen sharing in zoom.
|
- Fix screen sharing in zoom.
|
||||||
|
- Implement wp-fifo-v1.
|
||||||
|
|
||||||
# 1.6.0 (2024-09-25)
|
# 1.6.0 (2024-09-25)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ impl MetalConnector {
|
||||||
self.latch_cursor(&node)?;
|
self.latch_cursor(&node)?;
|
||||||
let cursor_programming = self.compute_cursor_programming();
|
let cursor_programming = self.compute_cursor_programming();
|
||||||
let latched = self.latch(&node);
|
let latched = self.latch(&node);
|
||||||
node.latched();
|
node.latched(self.try_async_flip());
|
||||||
|
|
||||||
if cursor_programming.is_none() && latched.is_none() {
|
if cursor_programming.is_none() && latched.is_none() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ impl Clients {
|
||||||
bounding_caps: ClientCaps,
|
bounding_caps: ClientCaps,
|
||||||
is_xwayland: bool,
|
is_xwayland: bool,
|
||||||
) -> Result<Rc<Client>, ClientError> {
|
) -> Result<Rc<Client>, ClientError> {
|
||||||
let data = Rc::new(Client {
|
let data = Rc::new_cyclic(|slf| Client {
|
||||||
id,
|
id,
|
||||||
state: global.clone(),
|
state: global.clone(),
|
||||||
checking_queue_size: Cell::new(false),
|
checking_queue_size: Cell::new(false),
|
||||||
|
|
@ -171,6 +171,8 @@ impl Clients {
|
||||||
commit_timelines: Rc::new(CommitTimelines::new(
|
commit_timelines: Rc::new(CommitTimelines::new(
|
||||||
&global.wait_for_sync_obj,
|
&global.wait_for_sync_obj,
|
||||||
&global.ring,
|
&global.ring,
|
||||||
|
&global.eng,
|
||||||
|
slf,
|
||||||
)),
|
)),
|
||||||
wire_scale: Default::default(),
|
wire_scale: Default::default(),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ use {
|
||||||
scale::Scale,
|
scale::Scale,
|
||||||
sighand::{self, SighandError},
|
sighand::{self, SighandError},
|
||||||
state::{ConnectorData, IdleState, ScreenlockState, State, XWaylandState},
|
state::{ConnectorData, IdleState, ScreenlockState, State, XWaylandState},
|
||||||
tasks::{self, idle},
|
tasks::{self, handle_const_40hz_latch, idle},
|
||||||
tracy::enable_profiler,
|
tracy::enable_profiler,
|
||||||
tree::{
|
tree::{
|
||||||
container_layout, container_render_positions, container_render_titles, float_layout,
|
container_layout, container_render_positions, container_render_titles, float_layout,
|
||||||
|
|
@ -272,6 +272,7 @@ fn start_compositor2(
|
||||||
ui_drag_enabled: Cell::new(true),
|
ui_drag_enabled: Cell::new(true),
|
||||||
ui_drag_threshold_squared: Cell::new(10),
|
ui_drag_threshold_squared: Cell::new(10),
|
||||||
toplevels: Default::default(),
|
toplevels: Default::default(),
|
||||||
|
const_40hz_latch: Default::default(),
|
||||||
});
|
});
|
||||||
state.tracker.register(ClientId::from_raw(0));
|
state.tracker.register(ClientId::from_raw(0));
|
||||||
create_dummy_output(&state);
|
create_dummy_output(&state);
|
||||||
|
|
@ -435,6 +436,11 @@ fn start_global_event_handlers(
|
||||||
"slow ei clients",
|
"slow ei clients",
|
||||||
tasks::handle_slow_ei_clients(state.clone()),
|
tasks::handle_slow_ei_clients(state.clone()),
|
||||||
),
|
),
|
||||||
|
eng.spawn2(
|
||||||
|
"const 40hz latch",
|
||||||
|
Phase::Present,
|
||||||
|
handle_const_40hz_latch(state.clone()),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ use {
|
||||||
wp_alpha_modifier_v1::WpAlphaModifierV1Global,
|
wp_alpha_modifier_v1::WpAlphaModifierV1Global,
|
||||||
wp_content_type_manager_v1::WpContentTypeManagerV1Global,
|
wp_content_type_manager_v1::WpContentTypeManagerV1Global,
|
||||||
wp_cursor_shape_manager_v1::WpCursorShapeManagerV1Global,
|
wp_cursor_shape_manager_v1::WpCursorShapeManagerV1Global,
|
||||||
|
wp_fifo_manager_v1::WpFifoManagerV1Global,
|
||||||
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global,
|
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global,
|
||||||
wp_presentation::WpPresentationGlobal,
|
wp_presentation::WpPresentationGlobal,
|
||||||
wp_security_context_manager_v1::WpSecurityContextManagerV1Global,
|
wp_security_context_manager_v1::WpSecurityContextManagerV1Global,
|
||||||
|
|
@ -203,6 +204,7 @@ impl Globals {
|
||||||
add_singleton!(ExtOutputImageCaptureSourceManagerV1Global);
|
add_singleton!(ExtOutputImageCaptureSourceManagerV1Global);
|
||||||
add_singleton!(ExtForeignToplevelImageCaptureSourceManagerV1Global);
|
add_singleton!(ExtForeignToplevelImageCaptureSourceManagerV1Global);
|
||||||
add_singleton!(ExtImageCopyCaptureManagerV1Global);
|
add_singleton!(ExtImageCopyCaptureManagerV1Global);
|
||||||
|
add_singleton!(WpFifoManagerV1Global);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
pub fn add_backend_singletons(&self, backend: &Rc<dyn Backend>) {
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@ pub mod wp_drm_lease_connector_v1;
|
||||||
pub mod wp_drm_lease_device_v1;
|
pub mod wp_drm_lease_device_v1;
|
||||||
pub mod wp_drm_lease_request_v1;
|
pub mod wp_drm_lease_request_v1;
|
||||||
pub mod wp_drm_lease_v1;
|
pub mod wp_drm_lease_v1;
|
||||||
|
pub mod wp_fifo_manager_v1;
|
||||||
pub mod wp_fractional_scale_manager_v1;
|
pub mod wp_fractional_scale_manager_v1;
|
||||||
pub mod wp_linux_drm_syncobj_manager_v1;
|
pub mod wp_linux_drm_syncobj_manager_v1;
|
||||||
pub mod wp_linux_drm_syncobj_timeline_v1;
|
pub mod wp_linux_drm_syncobj_timeline_v1;
|
||||||
|
|
|
||||||
|
|
@ -269,7 +269,7 @@ impl ExtImageCopyCaptureSessionV1RequestHandler for ExtImageCopyCaptureSessionV1
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LatchListener for ExtImageCopyCaptureSessionV1 {
|
impl LatchListener for ExtImageCopyCaptureSessionV1 {
|
||||||
fn after_latch(self: Rc<Self>, on: &OutputNode) {
|
fn after_latch(self: Rc<Self>, on: &OutputNode, _tearing: bool) {
|
||||||
let ImageCaptureSource::Toplevel(tl) = &self.source else {
|
let ImageCaptureSource::Toplevel(tl) = &self.source else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,7 @@ enum Target {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LatchListener for JayScreencast {
|
impl LatchListener for JayScreencast {
|
||||||
fn after_latch(self: Rc<Self>, _on: &OutputNode) {
|
fn after_latch(self: Rc<Self>, _on: &OutputNode, _tearing: bool) {
|
||||||
self.schedule_toplevel_screencast();
|
self.schedule_toplevel_screencast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ pub mod dnd_icon;
|
||||||
pub mod ext_session_lock_surface_v1;
|
pub mod ext_session_lock_surface_v1;
|
||||||
pub mod wl_subsurface;
|
pub mod wl_subsurface;
|
||||||
pub mod wp_alpha_modifier_surface_v1;
|
pub mod wp_alpha_modifier_surface_v1;
|
||||||
|
pub mod wp_fifo_v1;
|
||||||
pub mod wp_fractional_scale_v1;
|
pub mod wp_fractional_scale_v1;
|
||||||
pub mod wp_linux_drm_syncobj_surface_v1;
|
pub mod wp_linux_drm_syncobj_surface_v1;
|
||||||
pub mod wp_tearing_control_v1;
|
pub mod wp_tearing_control_v1;
|
||||||
|
|
@ -46,6 +47,7 @@ use {
|
||||||
dnd_icon::DndIcon,
|
dnd_icon::DndIcon,
|
||||||
wl_subsurface::{PendingSubsurfaceData, SubsurfaceId, WlSubsurface},
|
wl_subsurface::{PendingSubsurfaceData, SubsurfaceId, WlSubsurface},
|
||||||
wp_alpha_modifier_surface_v1::WpAlphaModifierSurfaceV1,
|
wp_alpha_modifier_surface_v1::WpAlphaModifierSurfaceV1,
|
||||||
|
wp_fifo_v1::WpFifoV1,
|
||||||
wp_fractional_scale_v1::WpFractionalScaleV1,
|
wp_fractional_scale_v1::WpFractionalScaleV1,
|
||||||
wp_linux_drm_syncobj_surface_v1::WpLinuxDrmSyncobjSurfaceV1,
|
wp_linux_drm_syncobj_surface_v1::WpLinuxDrmSyncobjSurfaceV1,
|
||||||
wp_tearing_control_v1::WpTearingControlV1,
|
wp_tearing_control_v1::WpTearingControlV1,
|
||||||
|
|
@ -317,6 +319,8 @@ pub struct WlSurface {
|
||||||
presentation_listener: EventListener<dyn PresentationListener>,
|
presentation_listener: EventListener<dyn PresentationListener>,
|
||||||
commit_version: NumCell<u64>,
|
commit_version: NumCell<u64>,
|
||||||
latched_commit_version: Cell<u64>,
|
latched_commit_version: Cell<u64>,
|
||||||
|
fifo: CloneCell<Option<Rc<WpFifoV1>>>,
|
||||||
|
clear_fifo_on_vblank: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for WlSurface {
|
impl Debug for WlSurface {
|
||||||
|
|
@ -438,6 +442,8 @@ struct PendingState {
|
||||||
release_point: Option<(Rc<SyncObj>, SyncObjPoint)>,
|
release_point: Option<(Rc<SyncObj>, SyncObjPoint)>,
|
||||||
alpha_multiplier: Option<Option<f32>>,
|
alpha_multiplier: Option<Option<f32>>,
|
||||||
explicit_sync: bool,
|
explicit_sync: bool,
|
||||||
|
fifo_barrier_set: bool,
|
||||||
|
fifo_barrier_wait: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AttachedSubsurfaceState {
|
struct AttachedSubsurfaceState {
|
||||||
|
|
@ -515,6 +521,8 @@ impl PendingState {
|
||||||
&mut self.presentation_feedback,
|
&mut self.presentation_feedback,
|
||||||
&mut next.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 {
|
macro_rules! merge_ext {
|
||||||
($name:ident) => {
|
($name:ident) => {
|
||||||
if let Some(e) = &mut self.$name {
|
if let Some(e) = &mut self.$name {
|
||||||
|
|
@ -638,6 +646,8 @@ impl WlSurface {
|
||||||
presentation_listener: EventListener::new(slf.clone()),
|
presentation_listener: EventListener::new(slf.clone()),
|
||||||
commit_version: Default::default(),
|
commit_version: Default::default(),
|
||||||
latched_commit_version: Default::default(),
|
latched_commit_version: Default::default(),
|
||||||
|
fifo: Default::default(),
|
||||||
|
clear_fifo_on_vblank: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1314,14 +1324,22 @@ impl WlSurface {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.ext.get().after_apply_commit();
|
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() {
|
if self.visible.get() {
|
||||||
let output = self.output.get();
|
let output = self.output.get();
|
||||||
if has_frame_requests {
|
if has_frame_requests {
|
||||||
self.vblank_listener.attach(&output.vblank_event);
|
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);
|
self.latch_listener.attach(&output.latch_event);
|
||||||
}
|
}
|
||||||
|
if fifo_barrier_set {
|
||||||
|
// If we have a fifo barrier, must trigger latching.
|
||||||
|
output.global.connector.damage();
|
||||||
|
}
|
||||||
if damage_full {
|
if damage_full {
|
||||||
let mut damage = buffer_abs_pos
|
let mut damage = buffer_abs_pos
|
||||||
.with_size(max_surface_size.0, max_surface_size.1)
|
.with_size(max_surface_size.0, max_surface_size.1)
|
||||||
|
|
@ -1341,10 +1359,16 @@ impl WlSurface {
|
||||||
let rect = output.global.pos.get();
|
let rect = output.global.pos.get();
|
||||||
self.client.state.damage(rect);
|
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.buffer_damage.clear();
|
||||||
pending.surface_damage.clear();
|
pending.surface_damage.clear();
|
||||||
pending.damage_full = false;
|
pending.damage_full = false;
|
||||||
|
pending.fifo_barrier_wait = false;
|
||||||
if tearing_changed {
|
if tearing_changed {
|
||||||
if let Some(tl) = self.toplevel.get() {
|
if let Some(tl) = self.toplevel.get() {
|
||||||
if tl.tl_data().is_fullscreen.get() {
|
if tl.tl_data().is_fullscreen.get() {
|
||||||
|
|
@ -1631,6 +1655,8 @@ impl Object for WlSurface {
|
||||||
self.drm_feedback.clear();
|
self.drm_feedback.clear();
|
||||||
self.commit_timeline.clear(ClearReason::BreakLoops);
|
self.commit_timeline.clear(ClearReason::BreakLoops);
|
||||||
self.alpha_modifier.take();
|
self.alpha_modifier.take();
|
||||||
|
self.text_input_connections.clear();
|
||||||
|
self.fifo.take();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2101,12 +2127,15 @@ impl VblankListener for WlSurface {
|
||||||
let _ = fr.client.remove_obj(&*fr);
|
let _ = fr.client.remove_obj(&*fr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if self.clear_fifo_on_vblank.take() {
|
||||||
|
self.commit_timeline.clear_fifo_barrier();
|
||||||
|
}
|
||||||
self.vblank_listener.detach();
|
self.vblank_listener.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LatchListener for WlSurface {
|
impl LatchListener for WlSurface {
|
||||||
fn after_latch(self: Rc<Self>, _on: &OutputNode) {
|
fn after_latch(self: Rc<Self>, _on: &OutputNode, tearing: bool) {
|
||||||
if self.visible.get() {
|
if self.visible.get() {
|
||||||
if self.latched_commit_version.get() < self.commit_version.get() {
|
if self.latched_commit_version.get() < self.commit_version.get() {
|
||||||
let latched = &mut *self.latched_presentation_feedback.borrow_mut();
|
let latched = &mut *self.latched_presentation_feedback.borrow_mut();
|
||||||
|
|
@ -2122,6 +2151,14 @@ impl LatchListener for WlSurface {
|
||||||
self.latched_commit_version.set(self.commit_version.get());
|
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();
|
self.latch_listener.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
async_engine::{AsyncEngine, SpawnedFuture},
|
||||||
|
client::Client,
|
||||||
gfx_api::{AsyncShmGfxTextureCallback, GfxError, PendingShmTransfer, STAGING_UPLOAD},
|
gfx_api::{AsyncShmGfxTextureCallback, GfxError, PendingShmTransfer, STAGING_UPLOAD},
|
||||||
ifs::{
|
ifs::{
|
||||||
wl_buffer::WlBufferStorage,
|
wl_buffer::WlBufferStorage,
|
||||||
|
|
@ -13,6 +15,7 @@ use {
|
||||||
linkedlist::{LinkedList, LinkedNode, NodeRef},
|
linkedlist::{LinkedList, LinkedNode, NodeRef},
|
||||||
numcell::NumCell,
|
numcell::NumCell,
|
||||||
oserror::OsError,
|
oserror::OsError,
|
||||||
|
queue::AsyncQueue,
|
||||||
},
|
},
|
||||||
video::drm::{
|
video::drm::{
|
||||||
sync_obj::{SyncObj, SyncObjPoint},
|
sync_obj::{SyncObj, SyncObjPoint},
|
||||||
|
|
@ -26,7 +29,7 @@ use {
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
mem,
|
mem,
|
||||||
ops::DerefMut,
|
ops::DerefMut,
|
||||||
rc::Rc,
|
rc::{Rc, Weak},
|
||||||
slice,
|
slice,
|
||||||
},
|
},
|
||||||
thiserror::Error,
|
thiserror::Error,
|
||||||
|
|
@ -43,6 +46,8 @@ pub struct CommitTimelines {
|
||||||
ring: Rc<IoUring>,
|
ring: Rc<IoUring>,
|
||||||
depth: NumCell<usize>,
|
depth: NumCell<usize>,
|
||||||
gc: CopyHashMap<CommitTimelineId, LinkedList<Entry>>,
|
gc: CopyHashMap<CommitTimelineId, LinkedList<Entry>>,
|
||||||
|
flush_requests: Rc<FlushRequests>,
|
||||||
|
_flush_requests_future: SpawnedFuture<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CommitTimeline {
|
pub struct CommitTimeline {
|
||||||
|
|
@ -50,6 +55,8 @@ pub struct CommitTimeline {
|
||||||
own_timeline: Rc<Inner>,
|
own_timeline: Rc<Inner>,
|
||||||
effective_timeline: CloneCell<Rc<Inner>>,
|
effective_timeline: CloneCell<Rc<Inner>>,
|
||||||
effective_timeline_id: Cell<CommitTimelineId>,
|
effective_timeline_id: Cell<CommitTimelineId>,
|
||||||
|
fifo_barrier_set: Cell<bool>,
|
||||||
|
fifo_waiter: Cell<Option<NodeRef<Entry>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Inner {
|
struct Inner {
|
||||||
|
|
@ -94,8 +101,20 @@ pub enum CommitTimelineError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommitTimelines {
|
impl CommitTimelines {
|
||||||
pub fn new(wfs: &Rc<WaitForSyncObj>, ring: &Rc<IoUring>) -> Self {
|
pub fn new(
|
||||||
|
wfs: &Rc<WaitForSyncObj>,
|
||||||
|
ring: &Rc<IoUring>,
|
||||||
|
eng: &Rc<AsyncEngine>,
|
||||||
|
client: &Weak<Client>,
|
||||||
|
) -> Self {
|
||||||
|
let flush_requests = Rc::new(FlushRequests::default());
|
||||||
|
let flush_request_future = eng.spawn(
|
||||||
|
"wl_surface flush requests",
|
||||||
|
process_flush_requests(client.clone(), flush_requests.clone()),
|
||||||
|
);
|
||||||
Self {
|
Self {
|
||||||
|
flush_requests,
|
||||||
|
_flush_requests_future: flush_request_future,
|
||||||
next_id: Default::default(),
|
next_id: Default::default(),
|
||||||
depth: NumCell::new(0),
|
depth: NumCell::new(0),
|
||||||
wfs: wfs.clone(),
|
wfs: wfs.clone(),
|
||||||
|
|
@ -115,10 +134,13 @@ impl CommitTimelines {
|
||||||
own_timeline: timeline.clone(),
|
own_timeline: timeline.clone(),
|
||||||
effective_timeline: CloneCell::new(timeline),
|
effective_timeline: CloneCell::new(timeline),
|
||||||
effective_timeline_id: Cell::new(id),
|
effective_timeline_id: Cell::new(id),
|
||||||
|
fifo_barrier_set: Cell::new(false),
|
||||||
|
fifo_waiter: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&self) {
|
pub fn clear(&self) {
|
||||||
|
self.flush_requests.flush_waiters.clear();
|
||||||
for list in self.gc.lock().drain_values() {
|
for list in self.gc.lock().drain_values() {
|
||||||
break_loops(&list);
|
break_loops(&list);
|
||||||
}
|
}
|
||||||
|
|
@ -144,8 +166,12 @@ fn break_loops(list: &LinkedList<Entry>) {
|
||||||
impl CommitTimeline {
|
impl CommitTimeline {
|
||||||
pub fn clear(&self, reason: ClearReason) {
|
pub fn clear(&self, reason: ClearReason) {
|
||||||
match reason {
|
match reason {
|
||||||
ClearReason::BreakLoops => break_loops(&self.own_timeline.entries),
|
ClearReason::BreakLoops => {
|
||||||
|
self.fifo_waiter.take();
|
||||||
|
break_loops(&self.own_timeline.entries)
|
||||||
|
}
|
||||||
ClearReason::Destroy => {
|
ClearReason::Destroy => {
|
||||||
|
self.clear_fifo_barrier();
|
||||||
if self.own_timeline.entries.is_not_empty() {
|
if self.own_timeline.entries.is_not_empty() {
|
||||||
let list = LinkedList::new();
|
let list = LinkedList::new();
|
||||||
list.append_all(&self.own_timeline.entries);
|
list.append_all(&self.own_timeline.entries);
|
||||||
|
|
@ -172,7 +198,10 @@ impl CommitTimeline {
|
||||||
);
|
);
|
||||||
let has_dependencies =
|
let has_dependencies =
|
||||||
points.is_not_empty() || pending_uploads > 0 || implicit_dmabufs.is_not_empty();
|
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
|
return surface
|
||||||
.apply_state(pending)
|
.apply_state(pending)
|
||||||
.map_err(CommitTimelineError::ImmediateCommit);
|
.map_err(CommitTimelineError::ImmediateCommit);
|
||||||
|
|
@ -181,6 +210,10 @@ impl CommitTimeline {
|
||||||
return Err(CommitTimelineError::Depth);
|
return Err(CommitTimelineError::Depth);
|
||||||
}
|
}
|
||||||
set_effective_timeline(self, pending, &self.own_timeline);
|
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(
|
let noderef = add_entry(
|
||||||
&self.own_timeline.entries,
|
&self.own_timeline.entries,
|
||||||
&self.shared,
|
&self.shared,
|
||||||
|
|
@ -193,9 +226,10 @@ impl CommitTimeline {
|
||||||
shm_upload: RefCell::new(ShmUploadState::None),
|
shm_upload: RefCell::new(ShmUploadState::None),
|
||||||
num_pending_polls: NumCell::new(implicit_dmabufs.len()),
|
num_pending_polls: NumCell::new(implicit_dmabufs.len()),
|
||||||
pending_polls: Cell::new(Default::default()),
|
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 {
|
if has_dependencies {
|
||||||
let noderef = Rc::new(noderef.clone());
|
let noderef = Rc::new(noderef.clone());
|
||||||
let EntryKind::Commit(commit) = &noderef.kind else {
|
let EntryKind::Commit(commit) = &noderef.kind else {
|
||||||
|
|
@ -235,6 +269,21 @@ impl CommitTimeline {
|
||||||
}
|
}
|
||||||
Ok(())
|
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.flush_requests.flush_waiters.push(waiter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_fifo_barrier(&self) -> bool {
|
||||||
|
self.fifo_barrier_set.get()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SyncObjWaiter for NodeRef<Entry> {
|
impl SyncObjWaiter for NodeRef<Entry> {
|
||||||
|
|
@ -322,6 +371,7 @@ struct Commit {
|
||||||
shm_upload: RefCell<ShmUploadState>,
|
shm_upload: RefCell<ShmUploadState>,
|
||||||
num_pending_polls: NumCell<usize>,
|
num_pending_polls: NumCell<usize>,
|
||||||
pending_polls: Cell<SmallVec<[PendingPoll; 1]>>,
|
pending_polls: Cell<SmallVec<[PendingPoll; 1]>>,
|
||||||
|
fifo_state: Cell<CommitFifoState>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_from(mut point: NodeRef<Entry>) -> Result<(), WlSurfaceError> {
|
fn flush_from(mut point: NodeRef<Entry>) -> Result<(), WlSurfaceError> {
|
||||||
|
|
@ -357,6 +407,20 @@ impl NodeRef<Entry> {
|
||||||
if c.num_pending_polls.get() > 0 {
|
if c.num_pending_polls.get() > 0 {
|
||||||
has_unmet_dependencies = true;
|
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 {
|
if has_unmet_dependencies {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
@ -536,3 +600,29 @@ fn set_effective_timeline(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct FlushRequests {
|
||||||
|
flush_waiters: AsyncQueue<NodeRef<Entry>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn process_flush_requests(client: Weak<Client>, requests: Rc<FlushRequests>) {
|
||||||
|
loop {
|
||||||
|
requests.flush_waiters.non_empty().await;
|
||||||
|
while let Some(entry) = requests.flush_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,
|
||||||
|
}
|
||||||
|
|
|
||||||
77
src/ifs/wl_surface/wp_fifo_v1.rs
Normal file
77
src/ifs/wl_surface/wp_fifo_v1.rs
Normal file
|
|
@ -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<Client>,
|
||||||
|
pub surface: Rc<WlSurface>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpFifoV1 {
|
||||||
|
pub fn new(id: WpFifoV1Id, version: Version, surface: &Rc<WlSurface>) -> Self {
|
||||||
|
Self {
|
||||||
|
id,
|
||||||
|
client: surface.client.clone(),
|
||||||
|
surface: surface.clone(),
|
||||||
|
tracker: Default::default(),
|
||||||
|
version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn install(self: &Rc<Self>) -> 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<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.surface.pending.borrow_mut().fifo_barrier_set = true;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait_barrier(&self, _req: WaitBarrier, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.surface.pending.borrow_mut().fifo_barrier_wait = true;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy(&self, _req: Destroy, _slf: &Rc<Self>) -> 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<ClientError>),
|
||||||
|
#[error("The surface already has a fifo extension attached")]
|
||||||
|
Exists,
|
||||||
|
}
|
||||||
|
efrom!(WpFifoV1Error, ClientError);
|
||||||
96
src/ifs/wp_fifo_manager_v1.rs
Normal file
96
src/ifs/wp_fifo_manager_v1.rs
Normal file
|
|
@ -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<Client>,
|
||||||
|
pub tracker: Tracker<Self>,
|
||||||
|
pub version: Version,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WpFifoManagerV1Global {
|
||||||
|
pub fn new(name: GlobalName) -> Self {
|
||||||
|
Self { name }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bind_(
|
||||||
|
self: Rc<Self>,
|
||||||
|
id: WpFifoManagerV1Id,
|
||||||
|
client: &Rc<Client>,
|
||||||
|
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<Self>) -> Result<(), Self::Error> {
|
||||||
|
self.client.remove_obj(self)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_fifo(&self, req: GetFifo, _slf: &Rc<Self>) -> 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<ClientError>),
|
||||||
|
#[error(transparent)]
|
||||||
|
WpFifoV1Error(#[from] WpFifoV1Error),
|
||||||
|
}
|
||||||
|
efrom!(WpFifoManagerV1Error, ClientError);
|
||||||
15
src/state.rs
15
src/state.rs
|
|
@ -69,16 +69,16 @@ use {
|
||||||
theme::{Color, Theme},
|
theme::{Color, Theme},
|
||||||
time::Time,
|
time::Time,
|
||||||
tree::{
|
tree::{
|
||||||
ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, Node, NodeIds,
|
ContainerNode, ContainerSplit, Direction, DisplayNode, FloatNode, LatchListener, Node,
|
||||||
NodeVisitorBase, OutputNode, PlaceholderNode, TearingMode, ToplevelNode,
|
NodeIds, NodeVisitorBase, OutputNode, PlaceholderNode, TearingMode, ToplevelNode,
|
||||||
ToplevelNodeBase, VrrMode, WorkspaceNode,
|
ToplevelNodeBase, VrrMode, WorkspaceNode,
|
||||||
},
|
},
|
||||||
utils::{
|
utils::{
|
||||||
activation_token::ActivationToken, asyncevent::AsyncEvent, bindings::Bindings,
|
activation_token::ActivationToken, asyncevent::AsyncEvent, bindings::Bindings,
|
||||||
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt, fdcloser::FdCloser,
|
clonecell::CloneCell, copyhashmap::CopyHashMap, errorfmt::ErrorFmt,
|
||||||
hash_map_ext::HashMapExt, linkedlist::LinkedList, numcell::NumCell, queue::AsyncQueue,
|
event_listener::EventSource, fdcloser::FdCloser, hash_map_ext::HashMapExt,
|
||||||
refcounted::RefCounted, run_toplevel::RunToplevel,
|
linkedlist::LinkedList, numcell::NumCell, queue::AsyncQueue, refcounted::RefCounted,
|
||||||
toplevel_identifier::ToplevelIdentifier,
|
run_toplevel::RunToplevel, toplevel_identifier::ToplevelIdentifier,
|
||||||
},
|
},
|
||||||
video::{
|
video::{
|
||||||
dmabuf::DmaBufIds,
|
dmabuf::DmaBufIds,
|
||||||
|
|
@ -222,6 +222,7 @@ pub struct State {
|
||||||
pub ui_drag_enabled: Cell<bool>,
|
pub ui_drag_enabled: Cell<bool>,
|
||||||
pub ui_drag_threshold_squared: Cell<i32>,
|
pub ui_drag_threshold_squared: Cell<i32>,
|
||||||
pub toplevels: CopyHashMap<ToplevelIdentifier, Weak<dyn ToplevelNode>>,
|
pub toplevels: CopyHashMap<ToplevelIdentifier, Weak<dyn ToplevelNode>>,
|
||||||
|
pub const_40hz_latch: EventSource<dyn LatchListener>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Drop for State {
|
// impl Drop for State {
|
||||||
|
|
@ -938,7 +939,7 @@ impl State {
|
||||||
output.global.persistent.scale.get(),
|
output.global.persistent.scale.get(),
|
||||||
render_hw_cursor,
|
render_hw_cursor,
|
||||||
)?;
|
)?;
|
||||||
output.latched();
|
output.latched(false);
|
||||||
output.perform_screencopies(
|
output.perform_screencopies(
|
||||||
tex,
|
tex,
|
||||||
None,
|
None,
|
||||||
|
|
|
||||||
13
src/tasks.rs
13
src/tasks.rs
|
|
@ -1,5 +1,6 @@
|
||||||
mod backend;
|
mod backend;
|
||||||
mod connector;
|
mod connector;
|
||||||
|
mod const_clock;
|
||||||
mod drmdev;
|
mod drmdev;
|
||||||
mod hardware_cursor;
|
mod hardware_cursor;
|
||||||
mod idle;
|
mod idle;
|
||||||
|
|
@ -12,10 +13,11 @@ use {
|
||||||
state::State,
|
state::State,
|
||||||
tasks::{
|
tasks::{
|
||||||
backend::BackendEventHandler,
|
backend::BackendEventHandler,
|
||||||
|
const_clock::run_const_clock,
|
||||||
slow_clients::{SlowClientHandler, SlowEiClientHandler},
|
slow_clients::{SlowClientHandler, SlowEiClientHandler},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
std::rc::Rc,
|
std::{rc::Rc, time::Duration},
|
||||||
};
|
};
|
||||||
pub use {hardware_cursor::handle_hardware_cursor_tick, idle::idle};
|
pub use {hardware_cursor::handle_hardware_cursor_tick, idle::idle};
|
||||||
|
|
||||||
|
|
@ -33,3 +35,12 @@ pub async fn handle_slow_ei_clients(state: Rc<State>) {
|
||||||
let mut sch = SlowEiClientHandler { state };
|
let mut sch = SlowEiClientHandler { state };
|
||||||
sch.handle_events().await;
|
sch.handle_events().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn handle_const_40hz_latch(state: Rc<State>) {
|
||||||
|
let output = state.dummy_output.get().unwrap();
|
||||||
|
let duration = Duration::from_nanos(1_000_000_000 / 40);
|
||||||
|
run_const_clock(duration, &state.ring, &state.const_40hz_latch, |l| {
|
||||||
|
l.after_latch(&output, false)
|
||||||
|
})
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
|
||||||
49
src/tasks/const_clock.rs
Normal file
49
src/tasks/const_clock.rs
Normal file
|
|
@ -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<T, F>(
|
||||||
|
duration: Duration,
|
||||||
|
ring: &Rc<IoUring>,
|
||||||
|
source: &EventSource<T>,
|
||||||
|
mut f: F,
|
||||||
|
) where
|
||||||
|
T: ?Sized,
|
||||||
|
F: FnMut(Rc<T>),
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -95,7 +95,7 @@ pub struct OutputNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait LatchListener {
|
pub trait LatchListener {
|
||||||
fn after_latch(self: Rc<Self>, on: &OutputNode);
|
fn after_latch(self: Rc<Self>, on: &OutputNode, tearing: bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait VblankListener {
|
pub trait VblankListener {
|
||||||
|
|
@ -135,10 +135,10 @@ pub async fn output_render_data(state: Rc<State>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OutputNode {
|
impl OutputNode {
|
||||||
pub fn latched(&self) {
|
pub fn latched(&self, tearing: bool) {
|
||||||
self.schedule.latched();
|
self.schedule.latched();
|
||||||
for listener in self.latch_event.iter() {
|
for listener in self.latch_event.iter() {
|
||||||
listener.after_latch(self);
|
listener.after_latch(self, tearing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
8
wire/wp_fifo_manager_v1.txt
Normal file
8
wire/wp_fifo_manager_v1.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
request destroy {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request get_fifo {
|
||||||
|
id: id(wp_fifo_v1),
|
||||||
|
surface: id(wl_surface),
|
||||||
|
}
|
||||||
11
wire/wp_fifo_v1.txt
Normal file
11
wire/wp_fifo_v1.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
request set_barrier {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request wait_barrier {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
request destroy {
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue