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