• 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 std::sync::atomic::AtomicBool;
11 use std::sync::atomic::Ordering;
12 use std::sync::Arc;
13 use std::sync::Mutex;
14 
15 use crate::buffer::BufferAccess;
16 use crate::command_buffer::submit::SubmitAnyBuilder;
17 use crate::command_buffer::submit::SubmitCommandBufferBuilder;
18 use crate::command_buffer::submit::SubmitSemaphoresWaitBuilder;
19 use crate::device::Device;
20 use crate::device::DeviceOwned;
21 use crate::device::Queue;
22 use crate::image::ImageAccess;
23 use crate::image::ImageLayout;
24 use crate::sync::AccessCheckError;
25 use crate::sync::AccessFlags;
26 use crate::sync::FlushError;
27 use crate::sync::GpuFuture;
28 use crate::sync::PipelineStages;
29 use crate::sync::Semaphore;
30 
31 /// Builds a new semaphore signal future.
32 #[inline]
then_signal_semaphore<F>(future: F) -> SemaphoreSignalFuture<F> where F: GpuFuture,33 pub fn then_signal_semaphore<F>(future: F) -> SemaphoreSignalFuture<F>
34 where
35     F: GpuFuture,
36 {
37     let device = future.device().clone();
38 
39     assert!(future.queue().is_some()); // TODO: document
40 
41     SemaphoreSignalFuture {
42         previous: future,
43         semaphore: Semaphore::from_pool(device).unwrap(),
44         wait_submitted: Mutex::new(false),
45         finished: AtomicBool::new(false),
46     }
47 }
48 
49 /// Represents a semaphore being signaled after a previous event.
50 #[must_use = "Dropping this object will immediately block the thread until the GPU has finished \
51               processing the submission"]
52 pub struct SemaphoreSignalFuture<F>
53 where
54     F: GpuFuture,
55 {
56     previous: F,
57     semaphore: Semaphore,
58     // True if the signaling command has already been submitted.
59     // If flush is called multiple times, we want to block so that only one flushing is executed.
60     // Therefore we use a `Mutex<bool>` and not an `AtomicBool`.
61     wait_submitted: Mutex<bool>,
62     finished: AtomicBool,
63 }
64 
65 unsafe impl<F> GpuFuture for SemaphoreSignalFuture<F>
66 where
67     F: GpuFuture,
68 {
69     #[inline]
cleanup_finished(&mut self)70     fn cleanup_finished(&mut self) {
71         self.previous.cleanup_finished();
72     }
73 
74     #[inline]
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>75     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
76         // Flushing the signaling part, since it must always be submitted before the waiting part.
77         self.flush()?;
78 
79         let mut sem = SubmitSemaphoresWaitBuilder::new();
80         sem.add_wait_semaphore(&self.semaphore);
81         Ok(SubmitAnyBuilder::SemaphoresWait(sem))
82     }
83 
flush(&self) -> Result<(), FlushError>84     fn flush(&self) -> Result<(), FlushError> {
85         unsafe {
86             let mut wait_submitted = self.wait_submitted.lock().unwrap();
87 
88             if *wait_submitted {
89                 return Ok(());
90             }
91 
92             let queue = self.previous.queue().unwrap().clone();
93 
94             match self.previous.build_submission()? {
95                 SubmitAnyBuilder::Empty => {
96                     let mut builder = SubmitCommandBufferBuilder::new();
97                     builder.add_signal_semaphore(&self.semaphore);
98                     builder.submit(&queue)?;
99                 }
100                 SubmitAnyBuilder::SemaphoresWait(sem) => {
101                     let mut builder: SubmitCommandBufferBuilder = sem.into();
102                     builder.add_signal_semaphore(&self.semaphore);
103                     builder.submit(&queue)?;
104                 }
105                 SubmitAnyBuilder::CommandBuffer(mut builder) => {
106                     debug_assert_eq!(builder.num_signal_semaphores(), 0);
107                     builder.add_signal_semaphore(&self.semaphore);
108                     builder.submit(&queue)?;
109                 }
110                 SubmitAnyBuilder::BindSparse(_) => {
111                     unimplemented!() // TODO: how to do that?
112                                      /*debug_assert_eq!(builder.num_signal_semaphores(), 0);
113                                      builder.add_signal_semaphore(&self.semaphore);
114                                      builder.submit(&queue)?;*/
115                 }
116                 SubmitAnyBuilder::QueuePresent(present) => {
117                     present.submit(&queue)?;
118                     let mut builder = SubmitCommandBufferBuilder::new();
119                     builder.add_signal_semaphore(&self.semaphore);
120                     builder.submit(&queue)?; // FIXME: problematic because if we return an error and flush() is called again, then we'll submit the present twice
121                 }
122             };
123 
124             // Only write `true` here in order to try again next time if an error occurs.
125             *wait_submitted = true;
126             Ok(())
127         }
128     }
129 
130     #[inline]
signal_finished(&self)131     unsafe fn signal_finished(&self) {
132         debug_assert!(*self.wait_submitted.lock().unwrap());
133         self.finished.store(true, Ordering::SeqCst);
134         self.previous.signal_finished();
135     }
136 
137     #[inline]
queue_change_allowed(&self) -> bool138     fn queue_change_allowed(&self) -> bool {
139         true
140     }
141 
142     #[inline]
queue(&self) -> Option<Arc<Queue>>143     fn queue(&self) -> Option<Arc<Queue>> {
144         self.previous.queue()
145     }
146 
147     #[inline]
check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>148     fn check_buffer_access(
149         &self,
150         buffer: &dyn BufferAccess,
151         exclusive: bool,
152         queue: &Queue,
153     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
154         self.previous
155             .check_buffer_access(buffer, exclusive, queue)
156             .map(|_| None)
157     }
158 
159     #[inline]
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>160     fn check_image_access(
161         &self,
162         image: &dyn ImageAccess,
163         layout: ImageLayout,
164         exclusive: bool,
165         queue: &Queue,
166     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
167         self.previous
168             .check_image_access(image, layout, exclusive, queue)
169             .map(|_| None)
170     }
171 }
172 
173 unsafe impl<F> DeviceOwned for SemaphoreSignalFuture<F>
174 where
175     F: GpuFuture,
176 {
177     #[inline]
device(&self) -> &Arc<Device>178     fn device(&self) -> &Arc<Device> {
179         self.semaphore.device()
180     }
181 }
182 
183 impl<F> Drop for SemaphoreSignalFuture<F>
184 where
185     F: GpuFuture,
186 {
drop(&mut self)187     fn drop(&mut self) {
188         unsafe {
189             if !*self.finished.get_mut() {
190                 // TODO: handle errors?
191                 self.flush().unwrap();
192                 // Block until the queue finished.
193                 self.queue().unwrap().wait().unwrap();
194                 self.previous.signal_finished();
195             }
196         }
197     }
198 }
199