1//! Helper for synchronizing rendering operations
2use std::{error::Error, fmt, os::unix::io::OwnedFd, sync::Arc};
34use downcast_rs::{impl_downcast, Downcast};
56#[cfg(feature = "backend_egl")]
7mod egl;
89/// Waiting for the fence was interrupted for an unknown reason.
10///
11/// This does not mean that the fence is signalled or not, neither that
12/// any timeout was reached. Waiting should be attempted again.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub struct Interrupted;
1516impl fmt::Display for Interrupted {
17fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
18 f.write_str("Wait for Fence was interrupted")
19 }
20}
21impl Error for Interrupted {}
2223/// A fence that will be signaled in finite time
24pub trait Fence: std::fmt::Debug + Send + Sync + Downcast {
25/// Queries the state of the fence
26fn is_signaled(&self) -> bool;
2728/// Blocks the current thread until the fence is signaled
29fn wait(&self) -> Result<(), Interrupted>;
3031/// Returns whether this fence can be exported
32 /// as a native fence fd
33fn is_exportable(&self) -> bool;
3435/// Export this fence as a native fence fd
36fn export(&self) -> Option<OwnedFd>;
37}
38impl_downcast!(Fence);
3940/// A sync point the will be signaled in finite time
41#[derive(Debug, Clone)]
42#[must_use = "this `SyncPoint` may contain a fence that should be awaited, failing to do so may result in unexpected rendering artifacts"]
43pub struct SyncPoint {
44 fence: Option<Arc<dyn Fence>>,
45}
4647impl Default for SyncPoint {
48fn default() -> Self {
49Self::signaled()
50 }
51}
5253impl SyncPoint {
54/// Create an already signaled sync point
55pub fn signaled() -> Self {
56Self {
57 fence: Default::default(),
58 }
59 }
6061/// Returns `true` if `SyncPoint` contains a [`Fence`]
62pub fn contains_fence(&self) -> bool {
63self.fence.is_some()
64 }
6566/// Get a reference to the underlying [`Fence`] if any
67 ///
68 /// Returns `None` if the sync point does not contain a fence
69 /// or contains a different type of fence
70pub fn get<F: Fence + 'static>(&self) -> Option<&F> {
71self.fence.as_ref().and_then(|f| f.downcast_ref())
72 }
7374/// Queries the state of the sync point
75 ///
76 /// Will always return `true` in case the sync point does not contain a fence
77pub fn is_reached(&self) -> bool {
78self.fence.as_ref().map(|f| f.is_signaled()).unwrap_or(true)
79 }
8081/// Blocks the current thread until the sync point is signaled
82 ///
83 /// If the sync point does not contain a fence this will never block.
84#[profiling::function]
85pub fn wait(&self) -> Result<(), Interrupted> {
86if let Some(fence) = self.fence.as_ref() {
87 fence.wait()
88 } else {
89Ok(())
90 }
91 }
9293/// Returns whether this sync point can be exported as a native fence fd
94 ///
95 /// Will always return `false` in case the sync point does not contain a fence
96pub fn is_exportable(&self) -> bool {
97self.fence.as_ref().map(|f| f.is_exportable()).unwrap_or(false)
98 }
99100/// Export this [`SyncPoint`] as a native fence fd
101 ///
102 /// Will always return `None` in case the sync point does not contain a fence
103#[profiling::function]
104pub fn export(&self) -> Option<OwnedFd> {
105self.fence.as_ref().and_then(|f| f.export())
106 }
107}
108109impl<T: Fence + 'static> From<T> for SyncPoint {
110#[inline]
111fn from(value: T) -> Self {
112 SyncPoint {
113 fence: Some(Arc::new(value)),
114 }
115 }
116}