• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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