atagen

monolith

public
Star0
Watch0
272bdf93aeadc79daea64d4765ba1f31e693d592
1
ssh://brewery@pls.lobotomise.me:33/atagen/monolith.git

Blame: crates/render-vk/src/sync.rs

824bf02b6e55atagen2026-10-16 09:15 UTC1
use crate::device::Shared;
824bf02b6e55atagen2026-10-16 09:15 UTC2
use ash::vk;
7de49c2aa70batagen2026-10-16 09:27 UTC3
use rustix::event::{PollFd, PollFlags, poll};
824bf02b6e55atagen2026-10-16 09:15 UTC4
use smithay::backend::renderer::sync::{Fence, Interrupted};
824bf02b6e55atagen2026-10-16 09:15 UTC5
use std::fmt;
7de49c2aa70batagen2026-10-16 09:27 UTC6
use std::os::fd::{FromRawFd, OwnedFd};
7de49c2aa70batagen2026-10-16 09:27 UTC7
use std::sync::{Arc, Mutex};
7de49c2aa70batagen2026-10-16 09:27 UTC8
7de49c2aa70batagen2026-10-16 09:27 UTC9
enum State {
7de49c2aa70batagen2026-10-16 09:27 UTC10
    Pending,
7de49c2aa70batagen2026-10-16 09:27 UTC11
    /// Exporting a sync_file resets the Vulkan fence, so from then on the
7de49c2aa70batagen2026-10-16 09:27 UTC12
    /// file is the only record of completion. `None` means it had already
7de49c2aa70batagen2026-10-16 09:27 UTC13
    /// signalled when exported.
7de49c2aa70batagen2026-10-16 09:27 UTC14
    Exported(Option<OwnedFd>),
7de49c2aa70batagen2026-10-16 09:27 UTC15
}
824bf02b6e55atagen2026-10-16 09:15 UTC16
824bf02b6e55atagen2026-10-16 09:15 UTC17
pub(crate) struct FenceInner {
7de49c2aa70batagen2026-10-16 09:27 UTC18
    shared: Arc<Shared>,
7de49c2aa70batagen2026-10-16 09:27 UTC19
    fence: vk::Fence,
7de49c2aa70batagen2026-10-16 09:27 UTC20
    exportable: bool,
7de49c2aa70batagen2026-10-16 09:27 UTC21
    state: Mutex<State>,
824bf02b6e55atagen2026-10-16 09:15 UTC22
}
824bf02b6e55atagen2026-10-16 09:15 UTC23
824bf02b6e55atagen2026-10-16 09:15 UTC24
impl FenceInner {
824bf02b6e55atagen2026-10-16 09:15 UTC25
    pub fn new(shared: &Arc<Shared>) -> Result<Arc<Self>, vk::Result> {
7de49c2aa70batagen2026-10-16 09:27 UTC26
        let exportable = shared.device.dmabuf.is_some();
7de49c2aa70batagen2026-10-16 09:27 UTC27
        let mut export = vk::ExportFenceCreateInfo::default()
7de49c2aa70batagen2026-10-16 09:27 UTC28
            .handle_types(vk::ExternalFenceHandleTypeFlags::SYNC_FD);
7de49c2aa70batagen2026-10-16 09:27 UTC29
        let mut info = vk::FenceCreateInfo::default();
7de49c2aa70batagen2026-10-16 09:27 UTC30
        if exportable {
7de49c2aa70batagen2026-10-16 09:27 UTC31
            info = info.push_next(&mut export);
7de49c2aa70batagen2026-10-16 09:27 UTC32
        }
d5eca1c82213atagen2026-10-16 13:56 UTC33
        let spare = shared
d5eca1c82213atagen2026-10-16 13:56 UTC34
            .device
d5eca1c82213atagen2026-10-16 13:56 UTC35
            .spare_fences
d5eca1c82213atagen2026-10-16 13:56 UTC36
            .lock()
d5eca1c82213atagen2026-10-16 13:56 UTC37
            .unwrap_or_else(|e| e.into_inner())
d5eca1c82213atagen2026-10-16 13:56 UTC38
            .pop();
d5eca1c82213atagen2026-10-16 13:56 UTC39
        let fence = match spare {
d5eca1c82213atagen2026-10-16 13:56 UTC40
            Some(f) => {
d5eca1c82213atagen2026-10-16 13:56 UTC41
                unsafe { shared.device.device.reset_fences(&[f])? };
d5eca1c82213atagen2026-10-16 13:56 UTC42
                f
d5eca1c82213atagen2026-10-16 13:56 UTC43
            }
d5eca1c82213atagen2026-10-16 13:56 UTC44
            None => unsafe { shared.device.device.create_fence(&info, None)? },
d5eca1c82213atagen2026-10-16 13:56 UTC45
        };
824bf02b6e55atagen2026-10-16 09:15 UTC46
        Ok(Arc::new(Self {
824bf02b6e55atagen2026-10-16 09:15 UTC47
            shared: shared.clone(),
824bf02b6e55atagen2026-10-16 09:15 UTC48
            fence,
7de49c2aa70batagen2026-10-16 09:27 UTC49
            exportable,
7de49c2aa70batagen2026-10-16 09:27 UTC50
            state: Mutex::new(State::Pending),
824bf02b6e55atagen2026-10-16 09:15 UTC51
        }))
824bf02b6e55atagen2026-10-16 09:15 UTC52
    }
824bf02b6e55atagen2026-10-16 09:15 UTC53
7de49c2aa70batagen2026-10-16 09:27 UTC54
    pub fn fence(&self) -> vk::Fence {
7de49c2aa70batagen2026-10-16 09:27 UTC55
        self.fence
7de49c2aa70batagen2026-10-16 09:27 UTC56
    }
7de49c2aa70batagen2026-10-16 09:27 UTC57
824bf02b6e55atagen2026-10-16 09:15 UTC58
    pub fn signaled(&self) -> bool {
7de49c2aa70batagen2026-10-16 09:27 UTC59
        match &*self.state.lock().unwrap_or_else(|e| e.into_inner()) {
7de49c2aa70batagen2026-10-16 09:27 UTC60
            State::Pending => {
7de49c2aa70batagen2026-10-16 09:27 UTC61
                unsafe { self.shared.device.device.get_fence_status(self.fence) }.unwrap_or(true)
7de49c2aa70batagen2026-10-16 09:27 UTC62
            }
7de49c2aa70batagen2026-10-16 09:27 UTC63
            State::Exported(None) => true,
7de49c2aa70batagen2026-10-16 09:27 UTC64
            State::Exported(Some(fd)) => readable(fd, Some(&Default::default())),
7de49c2aa70batagen2026-10-16 09:27 UTC65
        }
824bf02b6e55atagen2026-10-16 09:15 UTC66
    }
824bf02b6e55atagen2026-10-16 09:15 UTC67
cabbef6c998aatagen2026-10-16 13:42 UTC68
    /// Blocks until the GPU signals. A pending fence is first turned into its
cabbef6c998aatagen2026-10-16 13:42 UTC69
    /// sync_file and polled, because waiting on the Vulkan fence itself sleeps
cabbef6c998aatagen2026-10-16 13:42 UTC70
    /// in 10 ms steps on NVIDIA even when the work is done in microseconds.
824bf02b6e55atagen2026-10-16 09:15 UTC71
    pub fn wait(&self) -> Result<(), vk::Result> {
cabbef6c998aatagen2026-10-16 13:42 UTC72
        if self.exportable {
cabbef6c998aatagen2026-10-16 13:42 UTC73
            drop(self.export());
cabbef6c998aatagen2026-10-16 13:42 UTC74
        }
7de49c2aa70batagen2026-10-16 09:27 UTC75
        match &*self.state.lock().unwrap_or_else(|e| e.into_inner()) {
7de49c2aa70batagen2026-10-16 09:27 UTC76
            State::Pending => unsafe {
7de49c2aa70batagen2026-10-16 09:27 UTC77
                self.shared
7de49c2aa70batagen2026-10-16 09:27 UTC78
                    .device
7de49c2aa70batagen2026-10-16 09:27 UTC79
                    .device
7de49c2aa70batagen2026-10-16 09:27 UTC80
                    .wait_for_fences(&[self.fence], true, u64::MAX)
7de49c2aa70batagen2026-10-16 09:27 UTC81
            },
7de49c2aa70batagen2026-10-16 09:27 UTC82
            State::Exported(None) => Ok(()),
7de49c2aa70batagen2026-10-16 09:27 UTC83
            State::Exported(Some(fd)) => {
7de49c2aa70batagen2026-10-16 09:27 UTC84
                readable(fd, None);
7de49c2aa70batagen2026-10-16 09:27 UTC85
                Ok(())
7de49c2aa70batagen2026-10-16 09:27 UTC86
            }
7de49c2aa70batagen2026-10-16 09:27 UTC87
        }
7de49c2aa70batagen2026-10-16 09:27 UTC88
    }
7de49c2aa70batagen2026-10-16 09:27 UTC89
cabbef6c998aatagen2026-10-16 13:42 UTC90
    #[profiling::function]
7de49c2aa70batagen2026-10-16 09:27 UTC91
    fn export(&self) -> Option<OwnedFd> {
7de49c2aa70batagen2026-10-16 09:27 UTC92
        if !self.exportable {
7de49c2aa70batagen2026-10-16 09:27 UTC93
            return None;
7de49c2aa70batagen2026-10-16 09:27 UTC94
        }
7de49c2aa70batagen2026-10-16 09:27 UTC95
        let ext = self.shared.device.dmabuf.as_ref()?;
7de49c2aa70batagen2026-10-16 09:27 UTC96
        let mut state = self.state.lock().unwrap_or_else(|e| e.into_inner());
7de49c2aa70batagen2026-10-16 09:27 UTC97
        if let State::Pending = *state {
7de49c2aa70batagen2026-10-16 09:27 UTC98
            let info = vk::FenceGetFdInfoKHR::default()
7de49c2aa70batagen2026-10-16 09:27 UTC99
                .fence(self.fence)
7de49c2aa70batagen2026-10-16 09:27 UTC100
                .handle_type(vk::ExternalFenceHandleTypeFlags::SYNC_FD);
7de49c2aa70batagen2026-10-16 09:27 UTC101
            let raw = unsafe { ext.fence_fd.get_fence_fd(&info) }.ok()?;
7de49c2aa70batagen2026-10-16 09:27 UTC102
            *state = State::Exported((raw >= 0).then(|| unsafe { OwnedFd::from_raw_fd(raw) }));
7de49c2aa70batagen2026-10-16 09:27 UTC103
        }
7de49c2aa70batagen2026-10-16 09:27 UTC104
        match &*state {
7de49c2aa70batagen2026-10-16 09:27 UTC105
            State::Exported(Some(fd)) => fd.try_clone().ok(),
7de49c2aa70batagen2026-10-16 09:27 UTC106
            _ => None,
7de49c2aa70batagen2026-10-16 09:27 UTC107
        }
7de49c2aa70batagen2026-10-16 09:27 UTC108
    }
7de49c2aa70batagen2026-10-16 09:27 UTC109
}
7de49c2aa70batagen2026-10-16 09:27 UTC110
7de49c2aa70batagen2026-10-16 09:27 UTC111
fn readable(fd: &OwnedFd, timeout: Option<&rustix::event::Timespec>) -> bool {
7de49c2aa70batagen2026-10-16 09:27 UTC112
    let mut fds = [PollFd::new(fd, PollFlags::IN)];
7de49c2aa70batagen2026-10-16 09:27 UTC113
    loop {
7de49c2aa70batagen2026-10-16 09:27 UTC114
        match poll(&mut fds, timeout) {
7de49c2aa70batagen2026-10-16 09:27 UTC115
            Ok(n) => return n > 0,
7de49c2aa70batagen2026-10-16 09:27 UTC116
            Err(rustix::io::Errno::INTR) => continue,
7de49c2aa70batagen2026-10-16 09:27 UTC117
            Err(_) => return true,
824bf02b6e55atagen2026-10-16 09:15 UTC118
        }
824bf02b6e55atagen2026-10-16 09:15 UTC119
    }
824bf02b6e55atagen2026-10-16 09:15 UTC120
}
824bf02b6e55atagen2026-10-16 09:15 UTC121
d5eca1c82213atagen2026-10-16 13:56 UTC122
/// Fences go back to a pool instead of being destroyed, which cut the median
d5eca1c82213atagen2026-10-16 13:56 UTC123
/// queue submit on NVIDIA from 87 to 52 us. One still pending is destroyed.
824bf02b6e55atagen2026-10-16 09:15 UTC124
impl Drop for FenceInner {
824bf02b6e55atagen2026-10-16 09:15 UTC125
    fn drop(&mut self) {
d5eca1c82213atagen2026-10-16 13:56 UTC126
        let d = &self.shared.device.device;
d5eca1c82213atagen2026-10-16 13:56 UTC127
        let state = self.state.get_mut().unwrap_or_else(|e| e.into_inner());
d5eca1c82213atagen2026-10-16 13:56 UTC128
        let idle = match state {
d5eca1c82213atagen2026-10-16 13:56 UTC129
            State::Pending => unsafe { d.get_fence_status(self.fence) }.unwrap_or(false),
d5eca1c82213atagen2026-10-16 13:56 UTC130
            State::Exported(_) => true,
d5eca1c82213atagen2026-10-16 13:56 UTC131
        };
d5eca1c82213atagen2026-10-16 13:56 UTC132
        if idle {
d5eca1c82213atagen2026-10-16 13:56 UTC133
            self.shared
d5eca1c82213atagen2026-10-16 13:56 UTC134
                .device
d5eca1c82213atagen2026-10-16 13:56 UTC135
                .spare_fences
d5eca1c82213atagen2026-10-16 13:56 UTC136
                .lock()
d5eca1c82213atagen2026-10-16 13:56 UTC137
                .unwrap_or_else(|e| e.into_inner())
d5eca1c82213atagen2026-10-16 13:56 UTC138
                .push(self.fence);
d5eca1c82213atagen2026-10-16 13:56 UTC139
        } else {
d5eca1c82213atagen2026-10-16 13:56 UTC140
            unsafe { d.destroy_fence(self.fence, None) };
d5eca1c82213atagen2026-10-16 13:56 UTC141
        }
824bf02b6e55atagen2026-10-16 09:15 UTC142
    }
824bf02b6e55atagen2026-10-16 09:15 UTC143
}
824bf02b6e55atagen2026-10-16 09:15 UTC144
824bf02b6e55atagen2026-10-16 09:15 UTC145
impl fmt::Debug for FenceInner {
824bf02b6e55atagen2026-10-16 09:15 UTC146
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
824bf02b6e55atagen2026-10-16 09:15 UTC147
        f.debug_tuple("FenceInner").field(&self.fence).finish()
824bf02b6e55atagen2026-10-16 09:15 UTC148
    }
824bf02b6e55atagen2026-10-16 09:15 UTC149
}
824bf02b6e55atagen2026-10-16 09:15 UTC150
824bf02b6e55atagen2026-10-16 09:15 UTC151
#[derive(Debug)]
824bf02b6e55atagen2026-10-16 09:15 UTC152
pub(crate) struct VkFence(pub Arc<FenceInner>);
824bf02b6e55atagen2026-10-16 09:15 UTC153
824bf02b6e55atagen2026-10-16 09:15 UTC154
impl Fence for VkFence {
824bf02b6e55atagen2026-10-16 09:15 UTC155
    fn is_signaled(&self) -> bool {
824bf02b6e55atagen2026-10-16 09:15 UTC156
        self.0.signaled()
824bf02b6e55atagen2026-10-16 09:15 UTC157
    }
824bf02b6e55atagen2026-10-16 09:15 UTC158
824bf02b6e55atagen2026-10-16 09:15 UTC159
    fn wait(&self) -> Result<(), Interrupted> {
824bf02b6e55atagen2026-10-16 09:15 UTC160
        self.0.wait().map_err(|_| Interrupted)
824bf02b6e55atagen2026-10-16 09:15 UTC161
    }
824bf02b6e55atagen2026-10-16 09:15 UTC162
824bf02b6e55atagen2026-10-16 09:15 UTC163
    fn is_exportable(&self) -> bool {
7de49c2aa70batagen2026-10-16 09:27 UTC164
        self.0.exportable
824bf02b6e55atagen2026-10-16 09:15 UTC165
    }
824bf02b6e55atagen2026-10-16 09:15 UTC166
7de49c2aa70batagen2026-10-16 09:27 UTC167
    fn export(&self) -> Option<OwnedFd> {
7de49c2aa70batagen2026-10-16 09:27 UTC168
        self.0.export()
824bf02b6e55atagen2026-10-16 09:15 UTC169
    }
824bf02b6e55atagen2026-10-16 09:15 UTC170
}