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}