1 // Copyright (c) 2017 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9
10 use super::{AccessCheckError, FlushError, GpuFuture, SubmitAnyBuilder};
11 use crate::{
12 buffer::Buffer,
13 command_buffer::{SemaphoreSubmitInfo, SubmitInfo},
14 device::{Device, DeviceOwned, Queue},
15 image::{sys::Image, ImageLayout},
16 swapchain::Swapchain,
17 sync::{future::AccessError, semaphore::Semaphore, PipelineStages},
18 DeviceSize,
19 };
20 use parking_lot::Mutex;
21 use smallvec::smallvec;
22 use std::{
23 ops::Range,
24 sync::{
25 atomic::{AtomicBool, Ordering},
26 Arc,
27 },
28 thread,
29 };
30
31 /// Builds a new semaphore signal future.
then_signal_semaphore<F>(future: F) -> SemaphoreSignalFuture<F> where F: GpuFuture,32 pub fn then_signal_semaphore<F>(future: F) -> SemaphoreSignalFuture<F>
33 where
34 F: GpuFuture,
35 {
36 let device = future.device().clone();
37
38 assert!(future.queue().is_some()); // TODO: document
39
40 SemaphoreSignalFuture {
41 previous: future,
42 semaphore: Arc::new(Semaphore::from_pool(device).unwrap()),
43 wait_submitted: Mutex::new(false),
44 finished: AtomicBool::new(false),
45 }
46 }
47
48 /// Represents a semaphore being signaled after a previous event.
49 #[must_use = "Dropping this object will immediately block the thread until the GPU has finished \
50 processing the submission"]
51 pub struct SemaphoreSignalFuture<F>
52 where
53 F: GpuFuture,
54 {
55 previous: F,
56 semaphore: Arc<Semaphore>,
57 // True if the signaling command has already been submitted.
58 // If flush is called multiple times, we want to block so that only one flushing is executed.
59 // Therefore we use a `Mutex<bool>` and not an `AtomicBool`.
60 wait_submitted: Mutex<bool>,
61 finished: AtomicBool,
62 }
63
64 unsafe impl<F> GpuFuture for SemaphoreSignalFuture<F>
65 where
66 F: GpuFuture,
67 {
cleanup_finished(&mut self)68 fn cleanup_finished(&mut self) {
69 self.previous.cleanup_finished();
70 }
71
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>72 unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
73 // Flushing the signaling part, since it must always be submitted before the waiting part.
74 self.flush()?;
75 let sem = smallvec![self.semaphore.clone()];
76
77 Ok(SubmitAnyBuilder::SemaphoresWait(sem))
78 }
79
flush(&self) -> Result<(), FlushError>80 fn flush(&self) -> Result<(), FlushError> {
81 unsafe {
82 let mut wait_submitted = self.wait_submitted.lock();
83
84 if *wait_submitted {
85 return Ok(());
86 }
87
88 let queue = self.previous.queue().unwrap();
89
90 match self.previous.build_submission()? {
91 SubmitAnyBuilder::Empty => {
92 queue.with(|mut q| {
93 q.submit_unchecked(
94 [SubmitInfo {
95 signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
96 self.semaphore.clone(),
97 )],
98 ..Default::default()
99 }],
100 None,
101 )
102 })?;
103 }
104 SubmitAnyBuilder::SemaphoresWait(semaphores) => {
105 queue.with(|mut q| {
106 q.submit_unchecked(
107 [SubmitInfo {
108 wait_semaphores: semaphores
109 .into_iter()
110 .map(|semaphore| {
111 SemaphoreSubmitInfo {
112 // TODO: correct stages ; hard
113 stages: PipelineStages::ALL_COMMANDS,
114 ..SemaphoreSubmitInfo::semaphore(semaphore)
115 }
116 })
117 .collect(),
118 signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
119 self.semaphore.clone(),
120 )],
121 ..Default::default()
122 }],
123 None,
124 )
125 })?;
126 }
127 SubmitAnyBuilder::CommandBuffer(mut submit_info, fence) => {
128 debug_assert!(submit_info.signal_semaphores.is_empty());
129
130 submit_info
131 .signal_semaphores
132 .push(SemaphoreSubmitInfo::semaphore(self.semaphore.clone()));
133
134 queue.with(|mut q| {
135 q.submit_with_future(submit_info, fence, &self.previous, &queue)
136 })?;
137 }
138 SubmitAnyBuilder::BindSparse(_, _) => {
139 unimplemented!() // TODO: how to do that?
140 /*debug_assert_eq!(builder.num_signal_semaphores(), 0);
141 builder.add_signal_semaphore(&self.semaphore);
142 builder.submit(&queue)?;*/
143 }
144 SubmitAnyBuilder::QueuePresent(present_info) => {
145 // VUID-VkPresentIdKHR-presentIds-04999
146 for swapchain_info in &present_info.swapchain_infos {
147 if swapchain_info.present_id.map_or(false, |present_id| {
148 !swapchain_info.swapchain.try_claim_present_id(present_id)
149 }) {
150 return Err(FlushError::PresentIdLessThanOrEqual);
151 }
152
153 match self.previous.check_swapchain_image_acquired(
154 &swapchain_info.swapchain,
155 swapchain_info.image_index,
156 true,
157 ) {
158 Ok(_) => (),
159 Err(AccessCheckError::Unknown) => {
160 return Err(AccessError::SwapchainImageNotAcquired.into())
161 }
162 Err(AccessCheckError::Denied(e)) => return Err(e.into()),
163 }
164 }
165
166 queue.with(|mut q| {
167 q.present_unchecked(present_info)?
168 .map(|r| r.map(|_| ()))
169 .fold(Ok(()), Result::and)?;
170 // FIXME: problematic because if we return an error and flush() is called again, then we'll submit the present twice
171 q.submit_unchecked(
172 [SubmitInfo {
173 signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
174 self.semaphore.clone(),
175 )],
176 ..Default::default()
177 }],
178 None,
179 )?;
180 Ok::<_, FlushError>(())
181 })?;
182 }
183 };
184
185 // Only write `true` here in order to try again next time if an error occurs.
186 *wait_submitted = true;
187 Ok(())
188 }
189 }
190
signal_finished(&self)191 unsafe fn signal_finished(&self) {
192 debug_assert!(*self.wait_submitted.lock());
193 self.finished.store(true, Ordering::SeqCst);
194 self.previous.signal_finished();
195 }
196
queue_change_allowed(&self) -> bool197 fn queue_change_allowed(&self) -> bool {
198 true
199 }
200
queue(&self) -> Option<Arc<Queue>>201 fn queue(&self) -> Option<Arc<Queue>> {
202 self.previous.queue()
203 }
204
check_buffer_access( &self, buffer: &Buffer, range: Range<DeviceSize>, exclusive: bool, queue: &Queue, ) -> Result<(), AccessCheckError>205 fn check_buffer_access(
206 &self,
207 buffer: &Buffer,
208 range: Range<DeviceSize>,
209 exclusive: bool,
210 queue: &Queue,
211 ) -> Result<(), AccessCheckError> {
212 self.previous
213 .check_buffer_access(buffer, range, exclusive, queue)
214 }
215
check_image_access( &self, image: &Image, range: Range<DeviceSize>, exclusive: bool, expected_layout: ImageLayout, queue: &Queue, ) -> Result<(), AccessCheckError>216 fn check_image_access(
217 &self,
218 image: &Image,
219 range: Range<DeviceSize>,
220 exclusive: bool,
221 expected_layout: ImageLayout,
222 queue: &Queue,
223 ) -> Result<(), AccessCheckError> {
224 self.previous
225 .check_image_access(image, range, exclusive, expected_layout, queue)
226 }
227
228 #[inline]
check_swapchain_image_acquired( &self, swapchain: &Swapchain, image_index: u32, _before: bool, ) -> Result<(), AccessCheckError>229 fn check_swapchain_image_acquired(
230 &self,
231 swapchain: &Swapchain,
232 image_index: u32,
233 _before: bool,
234 ) -> Result<(), AccessCheckError> {
235 self.previous
236 .check_swapchain_image_acquired(swapchain, image_index, false)
237 }
238 }
239
240 unsafe impl<F> DeviceOwned for SemaphoreSignalFuture<F>
241 where
242 F: GpuFuture,
243 {
device(&self) -> &Arc<Device>244 fn device(&self) -> &Arc<Device> {
245 self.semaphore.device()
246 }
247 }
248
249 impl<F> Drop for SemaphoreSignalFuture<F>
250 where
251 F: GpuFuture,
252 {
drop(&mut self)253 fn drop(&mut self) {
254 if !*self.finished.get_mut() && !thread::panicking() {
255 // TODO: handle errors?
256 self.flush().unwrap();
257 // Block until the queue finished.
258 self.queue().unwrap().with(|mut q| q.wait_idle()).unwrap();
259 unsafe { self.previous.signal_finished() };
260 }
261 }
262 }
263