oximedia_gpu/
sync_primitive.rs1#![allow(dead_code)]
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum SyncType {
7 Semaphore,
9 Fence,
11 Barrier,
13}
14
15impl SyncType {
16 #[must_use]
22 pub fn wait_type(&self) -> &'static str {
23 match self {
24 Self::Semaphore => "gpu_wait",
25 Self::Fence => "cpu_wait",
26 Self::Barrier => "pipeline_stall",
27 }
28 }
29
30 #[must_use]
32 pub fn is_cpu_visible(&self) -> bool {
33 matches!(self, Self::Fence)
34 }
35}
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39pub enum SyncState {
40 Unsignaled,
42 Pending,
44 Signaled,
46}
47
48impl SyncState {
49 #[must_use]
51 pub fn is_signaled(&self) -> bool {
52 matches!(self, Self::Signaled)
53 }
54
55 #[must_use]
57 pub fn is_pending(&self) -> bool {
58 matches!(self, Self::Pending)
59 }
60}
61
62pub struct GpuSync {
68 sync_type: SyncType,
69 state: SyncState,
70 label: String,
71 signal_count: u64,
73}
74
75impl GpuSync {
76 #[must_use]
78 pub fn new(sync_type: SyncType, label: impl Into<String>) -> Self {
79 Self {
80 sync_type,
81 state: SyncState::Unsignaled,
82 label: label.into(),
83 signal_count: 0,
84 }
85 }
86
87 pub fn signal(&mut self) {
92 self.state = SyncState::Signaled;
93 self.signal_count += 1;
94 }
95
96 pub fn enqueue(&mut self) {
98 if self.state == SyncState::Unsignaled {
99 self.state = SyncState::Pending;
100 }
101 }
102
103 #[must_use]
109 pub fn wait(&self) -> bool {
110 self.state == SyncState::Signaled
111 }
112
113 pub fn reset(&mut self) -> bool {
118 if self.state == SyncState::Pending {
119 return false;
120 }
121 self.state = SyncState::Unsignaled;
122 true
123 }
124
125 #[must_use]
127 pub fn state(&self) -> SyncState {
128 self.state
129 }
130
131 #[must_use]
133 pub fn sync_type(&self) -> SyncType {
134 self.sync_type
135 }
136
137 #[must_use]
139 pub fn label(&self) -> &str {
140 &self.label
141 }
142
143 #[must_use]
145 pub fn signal_count(&self) -> u64 {
146 self.signal_count
147 }
148}
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153
154 #[test]
157 fn test_semaphore_wait_type() {
158 assert_eq!(SyncType::Semaphore.wait_type(), "gpu_wait");
159 }
160
161 #[test]
162 fn test_fence_wait_type() {
163 assert_eq!(SyncType::Fence.wait_type(), "cpu_wait");
164 }
165
166 #[test]
167 fn test_barrier_wait_type() {
168 assert_eq!(SyncType::Barrier.wait_type(), "pipeline_stall");
169 }
170
171 #[test]
172 fn test_fence_is_cpu_visible() {
173 assert!(SyncType::Fence.is_cpu_visible());
174 }
175
176 #[test]
177 fn test_semaphore_not_cpu_visible() {
178 assert!(!SyncType::Semaphore.is_cpu_visible());
179 }
180
181 #[test]
184 fn test_signaled_is_signaled() {
185 assert!(SyncState::Signaled.is_signaled());
186 }
187
188 #[test]
189 fn test_unsignaled_not_signaled() {
190 assert!(!SyncState::Unsignaled.is_signaled());
191 }
192
193 #[test]
194 fn test_pending_is_pending() {
195 assert!(SyncState::Pending.is_pending());
196 }
197
198 #[test]
199 fn test_signaled_not_pending() {
200 assert!(!SyncState::Signaled.is_pending());
201 }
202
203 #[test]
206 fn test_new_sync_is_unsignaled() {
207 let s = GpuSync::new(SyncType::Fence, "f");
208 assert_eq!(s.state(), SyncState::Unsignaled);
209 }
210
211 #[test]
212 fn test_signal_transitions_to_signaled() {
213 let mut s = GpuSync::new(SyncType::Semaphore, "s");
214 s.signal();
215 assert_eq!(s.state(), SyncState::Signaled);
216 }
217
218 #[test]
219 fn test_wait_returns_true_when_signaled() {
220 let mut s = GpuSync::new(SyncType::Fence, "f");
221 s.signal();
222 assert!(s.wait());
223 }
224
225 #[test]
226 fn test_wait_returns_false_when_unsignaled() {
227 let s = GpuSync::new(SyncType::Fence, "f");
228 assert!(!s.wait());
229 }
230
231 #[test]
232 fn test_reset_from_signaled_succeeds() {
233 let mut s = GpuSync::new(SyncType::Fence, "f");
234 s.signal();
235 assert!(s.reset());
236 assert_eq!(s.state(), SyncState::Unsignaled);
237 }
238
239 #[test]
240 fn test_reset_from_pending_fails() {
241 let mut s = GpuSync::new(SyncType::Semaphore, "s");
242 s.enqueue();
243 assert!(!s.reset());
244 assert_eq!(s.state(), SyncState::Pending);
245 }
246
247 #[test]
248 fn test_enqueue_transitions_to_pending() {
249 let mut s = GpuSync::new(SyncType::Barrier, "b");
250 s.enqueue();
251 assert_eq!(s.state(), SyncState::Pending);
252 }
253
254 #[test]
255 fn test_signal_count_increments() {
256 let mut s = GpuSync::new(SyncType::Fence, "f");
257 s.signal();
258 s.reset();
259 s.signal();
260 assert_eq!(s.signal_count(), 2);
261 }
262
263 #[test]
264 fn test_label_stored() {
265 let s = GpuSync::new(SyncType::Fence, "my_fence");
266 assert_eq!(s.label(), "my_fence");
267 }
268
269 #[test]
270 fn test_sync_type_stored() {
271 let s = GpuSync::new(SyncType::Barrier, "b");
272 assert_eq!(s.sync_type(), SyncType::Barrier);
273 }
274
275 #[test]
276 fn test_full_lifecycle() {
277 let mut s = GpuSync::new(SyncType::Fence, "lifecycle");
278 assert_eq!(s.state(), SyncState::Unsignaled);
279 s.enqueue();
280 assert_eq!(s.state(), SyncState::Pending);
281 s.signal();
282 assert!(s.wait());
283 assert!(s.reset());
284 assert_eq!(s.state(), SyncState::Unsignaled);
285 }
286}