atagen

monolith

public
Star0
Watch0
f27fa4c2ade9c2a037543c421da5fcb19636e644
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git
crates/render-vk/src/sync.rsRust134 lines3.9 KB
1
use crate::device::Shared;
2
use ash::vk;
3
use rustix::event::{PollFd, PollFlags, poll};
4
use smithay::backend::renderer::sync::{Fence, Interrupted};
5
use std::fmt;
6
use std::os::fd::{FromRawFd, OwnedFd};
7
use std::sync::{Arc, Mutex};
8
9
enum State {
10
    Pending,
11
    /// Exporting a sync_file resets the Vulkan fence, so from then on the
12
    /// file is the only record of completion. `None` means it had already
13
    /// signalled when exported.
14
    Exported(Option<OwnedFd>),
15
}
16
17
pub(crate) struct FenceInner {
18
    shared: Arc<Shared>,
19
    fence: vk::Fence,
20
    exportable: bool,
21
    state: Mutex<State>,
22
}
23
24
impl FenceInner {
25
    pub fn new(shared: &Arc<Shared>) -> Result<Arc<Self>, vk::Result> {
26
        let exportable = shared.device.dmabuf.is_some();
27
        let mut export = vk::ExportFenceCreateInfo::default()
28
            .handle_types(vk::ExternalFenceHandleTypeFlags::SYNC_FD);
29
        let mut info = vk::FenceCreateInfo::default();
30
        if exportable {
31
            info = info.push_next(&mut export);
32
        }
33
        let fence = unsafe { shared.device.device.create_fence(&info, None)? };
34
        Ok(Arc::new(Self {
35
            shared: shared.clone(),
36
            fence,
37
            exportable,
38
            state: Mutex::new(State::Pending),
39
        }))
40
    }
41
42
    pub fn fence(&self) -> vk::Fence {
43
        self.fence
44
    }
45
46
    pub fn signaled(&self) -> bool {
47
        match &*self.state.lock().unwrap_or_else(|e| e.into_inner()) {
48
            State::Pending => {
49
                unsafe { self.shared.device.device.get_fence_status(self.fence) }.unwrap_or(true)
50
            }
51
            State::Exported(None) => true,
52
            State::Exported(Some(fd)) => readable(fd, Some(&Default::default())),
53
        }
54
    }
55
56
    pub fn wait(&self) -> Result<(), vk::Result> {
57
        match &*self.state.lock().unwrap_or_else(|e| e.into_inner()) {
58
            State::Pending => unsafe {
59
                self.shared
60
                    .device
61
                    .device
62
                    .wait_for_fences(&[self.fence], true, u64::MAX)
63
            },
64
            State::Exported(None) => Ok(()),
65
            State::Exported(Some(fd)) => {
66
                readable(fd, None);
67
                Ok(())
68
            }
69
        }
70
    }
71
72
    fn export(&self) -> Option<OwnedFd> {
73
        if !self.exportable {
74
            return None;
75
        }
76
        let ext = self.shared.device.dmabuf.as_ref()?;
77
        let mut state = self.state.lock().unwrap_or_else(|e| e.into_inner());
78
        if let State::Pending = *state {
79
            let info = vk::FenceGetFdInfoKHR::default()
80
                .fence(self.fence)
81
                .handle_type(vk::ExternalFenceHandleTypeFlags::SYNC_FD);
82
            let raw = unsafe { ext.fence_fd.get_fence_fd(&info) }.ok()?;
83
            *state = State::Exported((raw >= 0).then(|| unsafe { OwnedFd::from_raw_fd(raw) }));
84
        }
85
        match &*state {
86
            State::Exported(Some(fd)) => fd.try_clone().ok(),
87
            _ => None,
88
        }
89
    }
90
}
91
92
fn readable(fd: &OwnedFd, timeout: Option<&rustix::event::Timespec>) -> bool {
93
    let mut fds = [PollFd::new(fd, PollFlags::IN)];
94
    loop {
95
        match poll(&mut fds, timeout) {
96
            Ok(n) => return n > 0,
97
            Err(rustix::io::Errno::INTR) => continue,
98
            Err(_) => return true,
99
        }
100
    }
101
}
102
103
impl Drop for FenceInner {
104
    fn drop(&mut self) {
105
        unsafe { self.shared.device.device.destroy_fence(self.fence, None) };
106
    }
107
}
108
109
impl fmt::Debug for FenceInner {
110
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111
        f.debug_tuple("FenceInner").field(&self.fence).finish()
112
    }
113
}
114
115
#[derive(Debug)]
116
pub(crate) struct VkFence(pub Arc<FenceInner>);
117
118
impl Fence for VkFence {
119
    fn is_signaled(&self) -> bool {
120
        self.0.signaled()
121
    }
122
123
    fn wait(&self) -> Result<(), Interrupted> {
124
        self.0.wait().map_err(|_| Interrupted)
125
    }
126
127
    fn is_exportable(&self) -> bool {
128
        self.0.exportable
129
    }
130
131
    fn export(&self) -> Option<OwnedFd> {
132
        self.0.export()
133
    }
134
}