wgpu_hal/vulkan/
semaphore_list.rs

1//! Definition of the [`SemaphoreList`] type.
2
3use alloc::vec::Vec;
4use ash::vk;
5use core::mem::MaybeUninit;
6
7/// A list of Vulkan semaphores to signal.
8///
9/// This represents a list of binary or timeline semaphores, together
10/// with values for the timeline semaphores.
11///
12/// This type ensures that the array of semaphores to be signaled
13/// stays aligned with the array of values for timeline semaphores
14/// appearing in that list. The [`add_to_submit`] method prepares the
15/// `vkQueueSubmit` arguments appropriately for whatever semaphores we
16/// actually have.
17///
18/// [`add_to_submit`]: SemaphoreList::add_to_submit
19#[derive(Debug, Default)]
20pub struct SemaphoreList {
21    /// Semaphores to signal.
22    ///
23    /// This can be a mix of binary and timeline semaphores.
24    semaphores: Vec<vk::Semaphore>,
25
26    /// Values for timeline semaphores.
27    ///
28    /// If no timeline semaphores are present in [`semaphores`], this
29    /// is empty. If any timeline semaphores are present, then this
30    /// has the same length as [`semaphores`], with dummy !0 values
31    /// in the elements corresponding to binary semaphores, since
32    /// Vulkan ignores these.
33    ///
34    /// [`semaphores`]: Self::semaphores
35    values: Vec<u64>,
36}
37
38impl SemaphoreList {
39    pub fn is_empty(&self) -> bool {
40        self.semaphores.is_empty()
41    }
42
43    /// Add this list to the semaphores to be signalled by a `vkQueueSubmit` call.
44    ///
45    /// - Set `submit_info`'s `pSignalSemaphores` list to this list's
46    ///   semaphores.
47    ///
48    /// - If this list contains any timeline semaphores, then initialize
49    ///   `timeline_info`, set its `pSignalSemaphoreValues` to this
50    ///   list's values, and add it to `submit_info`s extension chain.
51    ///
52    /// Return the revised `submit_info` value.
53    pub fn add_to_submit<'i, 's: 'i>(
54        &'s self,
55        submit_info: vk::SubmitInfo<'i>,
56        timeline_info: &'i mut MaybeUninit<vk::TimelineSemaphoreSubmitInfo<'i>>,
57    ) -> vk::SubmitInfo<'i> {
58        self.check();
59        let mut submit_info = submit_info.signal_semaphores(&self.semaphores);
60        if !self.values.is_empty() {
61            let timeline_info = timeline_info.write(
62                vk::TimelineSemaphoreSubmitInfo::default().signal_semaphore_values(&self.values),
63            );
64            submit_info = submit_info.push_next(timeline_info);
65        }
66        submit_info
67    }
68
69    /// Add a binary semaphore to this list.
70    pub fn push_binary(&mut self, semaphore: vk::Semaphore) {
71        self.semaphores.push(semaphore);
72        // Push a dummy value if necessary.
73        if !self.values.is_empty() {
74            self.values.push(!0);
75        }
76        self.check();
77    }
78
79    /// Add a timeline semaphore to this list, to be signalled with
80    /// `value`.
81    pub fn push_timeline(&mut self, semaphore: vk::Semaphore, value: u64) {
82        self.pad_values();
83        self.semaphores.push(semaphore);
84        self.values.push(value);
85        self.check();
86    }
87
88    /// Append `other` to `self`, leaving `other` empty.
89    pub fn append(&mut self, other: &mut Self) {
90        // If we're about to receive values, ensure we're aligned first.
91        if !other.values.is_empty() {
92            self.pad_values();
93        }
94        self.semaphores.append(&mut other.semaphores);
95        self.values.append(&mut other.values);
96        // If we had values, but `other` did not, re-align.
97        if !self.values.is_empty() {
98            self.pad_values();
99        }
100        self.check();
101    }
102
103    /// Pad `self.values` with dummy values for binary semaphores,
104    /// in preparation for adding a timeline semaphore value.
105    ///
106    /// This is a no-op if we already have values.
107    fn pad_values(&mut self) {
108        self.values.resize(self.semaphores.len(), !0);
109    }
110
111    #[track_caller]
112    fn check(&self) {
113        debug_assert!(self.values.is_empty() || self.values.len() == self.semaphores.len());
114    }
115}