1use {
2 crate::{
3 core::{device_owned, Device, DeviceId},
4 family::QueueId,
5 },
6 rendy_core::hal::{device::Device as _, Backend},
7};
8
9#[derive(Clone, Copy, Debug)]
11pub struct FenceEpoch {
12 pub queue: QueueId,
14
15 pub epoch: u64,
17}
18
19#[derive(Clone, Copy, Debug)]
20enum FenceState {
21 Unsignaled,
22 Signaled,
23 Submitted(FenceEpoch),
24}
25
26#[derive(Debug)]
28pub struct Fence<B: Backend> {
29 device: DeviceId,
30 raw: B::Fence,
31 state: FenceState,
32}
33
34device_owned!(Fence<B>);
35
36impl<B> Fence<B>
37where
38 B: Backend,
39{
40 pub fn new(
42 device: &Device<B>,
43 signaled: bool,
44 ) -> Result<Self, rendy_core::hal::device::OutOfMemory> {
45 let raw = device.raw().create_fence(false)?;
46 Ok(Fence {
47 device: device.id(),
48 raw,
49 state: if signaled {
50 FenceState::Signaled
51 } else {
52 FenceState::Unsignaled
53 },
54 })
55 }
56
57 pub fn is_submitted(&self) -> bool {
59 match self.state {
60 FenceState::Submitted(_) => true,
61 _ => false,
62 }
63 }
64
65 pub fn is_signaled(&self) -> bool {
67 match self.state {
68 FenceState::Signaled => true,
69 _ => false,
70 }
71 }
72
73 pub fn is_unsignaled(&self) -> bool {
76 !self.is_signaled()
77 }
78
79 pub(crate) fn mark_submitted(&mut self, epoch: FenceEpoch) {
82 match self.state {
83 FenceState::Unsignaled => {
84 self.state = FenceState::Submitted(epoch);
85 }
86 _ => panic!("Must be Unsignaled"),
87 }
88 }
89
90 pub fn reset(
94 &mut self,
95 device: &Device<B>,
96 ) -> Result<(), rendy_core::hal::device::OutOfMemory> {
97 self.assert_device_owner(device);
98 match self.state {
99 FenceState::Signaled => {
100 unsafe { device.reset_fence(&self.raw) }?;
101 self.state = FenceState::Unsignaled;
102 Ok(())
103 }
104 _ => panic!("Must be signaled"),
105 }
106 }
107
108 pub unsafe fn mark_reset(&mut self) {
113 match self.state {
114 FenceState::Signaled => {
115 self.state = FenceState::Unsignaled;
116 }
117 _ => panic!("Must be signaled"),
118 }
119 }
120
121 pub unsafe fn mark_signaled(&mut self) -> FenceEpoch {
125 match self.state {
126 FenceState::Submitted(epoch) => {
127 self.state = FenceState::Signaled;
128 epoch
129 }
130 _ => panic!("Must be submitted"),
131 }
132 }
133
134 pub fn wait_signaled(
138 &mut self,
139 device: &Device<B>,
140 timeout_ns: u64,
141 ) -> Result<Option<FenceEpoch>, rendy_core::hal::device::OomOrDeviceLost> {
142 self.assert_device_owner(device);
143
144 match self.state {
145 FenceState::Submitted(epoch) => {
146 if unsafe { device.wait_for_fence(&self.raw, timeout_ns) }? {
147 self.state = FenceState::Signaled;
148 Ok(Some(epoch))
149 } else {
150 Ok(None)
151 }
152 }
153 _ => panic!("Must be submitted"),
154 }
155 }
156
157 pub fn check_signaled(
161 &mut self,
162 device: &Device<B>,
163 ) -> Result<Option<FenceEpoch>, rendy_core::hal::device::DeviceLost> {
164 self.assert_device_owner(device);
165
166 match self.state {
167 FenceState::Submitted(epoch) => {
168 if unsafe { device.get_fence_status(&self.raw) }? {
169 self.state = FenceState::Signaled;
170 Ok(Some(epoch))
171 } else {
172 Ok(None)
173 }
174 }
175 _ => panic!("Must be submitted"),
176 }
177 }
178
179 pub fn raw(&self) -> &B::Fence {
182 &self.raw
183 }
184
185 pub fn epoch(&self) -> FenceEpoch {
188 match self.state {
189 FenceState::Submitted(epoch) => epoch,
190 _ => panic!("Must be submitted"),
191 }
192 }
193
194 pub fn into_inner(self) -> B::Fence {
197 match self.state {
198 FenceState::Signaled | FenceState::Unsignaled => self.raw,
199 _ => panic!("Submitted fence must be waited upon before destroying"),
200 }
201 }
202}