• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016 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 crate::buffer::BufferAccess;
11 use crate::command_buffer::submit::SubmitAnyBuilder;
12 use crate::command_buffer::submit::SubmitCommandBufferBuilder;
13 use crate::command_buffer::sys::UnsafeCommandBuffer;
14 use crate::command_buffer::CommandBufferInheritance;
15 use crate::command_buffer::ImageUninitializedSafe;
16 use crate::device::Device;
17 use crate::device::DeviceOwned;
18 use crate::device::Queue;
19 use crate::image::ImageAccess;
20 use crate::image::ImageLayout;
21 use crate::render_pass::FramebufferAbstract;
22 use crate::sync::now;
23 use crate::sync::AccessCheckError;
24 use crate::sync::AccessError;
25 use crate::sync::AccessFlags;
26 use crate::sync::FlushError;
27 use crate::sync::GpuFuture;
28 use crate::sync::NowFuture;
29 use crate::sync::PipelineMemoryAccess;
30 use crate::sync::PipelineStages;
31 use crate::SafeDeref;
32 use crate::VulkanObject;
33 use std::borrow::Cow;
34 use std::error;
35 use std::fmt;
36 use std::sync::atomic::AtomicBool;
37 use std::sync::atomic::Ordering;
38 use std::sync::Arc;
39 use std::sync::Mutex;
40 
41 pub unsafe trait PrimaryCommandBuffer: DeviceOwned {
42     /// Returns the underlying `UnsafeCommandBuffer` of this command buffer.
inner(&self) -> &UnsafeCommandBuffer43     fn inner(&self) -> &UnsafeCommandBuffer;
44 
45     /// Checks whether this command buffer is allowed to be submitted after the `future` and on
46     /// the given queue, and if so locks it.
47     ///
48     /// If you call this function, then you should call `unlock` afterwards.
lock_submit( &self, future: &dyn GpuFuture, queue: &Queue, ) -> Result<(), CommandBufferExecError>49     fn lock_submit(
50         &self,
51         future: &dyn GpuFuture,
52         queue: &Queue,
53     ) -> Result<(), CommandBufferExecError>;
54 
55     /// Unlocks the command buffer. Should be called once for each call to `lock_submit`.
56     ///
57     /// # Safety
58     ///
59     /// Must not be called if you haven't called `lock_submit` before.
unlock(&self)60     unsafe fn unlock(&self);
61 
62     /// Executes this command buffer on a queue.
63     ///
64     /// This function returns an object that implements the `GpuFuture` trait. See the
65     /// documentation of the `sync` module for more information.
66     ///
67     /// The command buffer is not actually executed until you call `flush()` on the object.
68     /// You are encouraged to chain together as many futures as possible before calling `flush()`,
69     /// and call `.then_signal_future()` before doing so. Note however that once you called
70     /// `execute()` there is no way to cancel the execution, even if you didn't flush yet.
71     ///
72     /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
73     /// > concrete type.
74     ///
75     /// > **Note**: This is just a shortcut for `execute_after(vulkano::sync::now(), queue)`.
76     ///
77     /// # Panic
78     ///
79     /// Panics if the device of the command buffer is not the same as the device of the future.
80     #[inline]
execute( self, queue: Arc<Queue>, ) -> Result<CommandBufferExecFuture<NowFuture, Self>, CommandBufferExecError> where Self: Sized + 'static,81     fn execute(
82         self,
83         queue: Arc<Queue>,
84     ) -> Result<CommandBufferExecFuture<NowFuture, Self>, CommandBufferExecError>
85     where
86         Self: Sized + 'static,
87     {
88         let device = queue.device().clone();
89         self.execute_after(now(device), queue)
90     }
91 
92     /// Executes the command buffer after an existing future.
93     ///
94     /// This function returns an object that implements the `GpuFuture` trait. See the
95     /// documentation of the `sync` module for more information.
96     ///
97     /// The command buffer is not actually executed until you call `flush()` on the object.
98     /// You are encouraged to chain together as many futures as possible before calling `flush()`,
99     /// and call `.then_signal_future()` before doing so. Note however that once you called
100     /// `execute()` there is no way to cancel the execution, even if you didn't flush yet.
101     ///
102     /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
103     /// > concrete type.
104     ///
105     /// This function requires the `'static` lifetime to be on the command buffer. This is because
106     /// this function returns a `CommandBufferExecFuture` whose job is to lock resources and keep
107     /// them alive while they are in use by the GPU. If `'static` wasn't required, you could call
108     /// `std::mem::forget` on that object and "unlock" these resources. For more information about
109     /// this problem, search the web for "rust thread scoped leakpocalypse".
110     ///
111     /// # Panic
112     ///
113     /// Panics if the device of the command buffer is not the same as the device of the future.
114     #[inline]
execute_after<F>( self, future: F, queue: Arc<Queue>, ) -> Result<CommandBufferExecFuture<F, Self>, CommandBufferExecError> where Self: Sized + 'static, F: GpuFuture,115     fn execute_after<F>(
116         self,
117         future: F,
118         queue: Arc<Queue>,
119     ) -> Result<CommandBufferExecFuture<F, Self>, CommandBufferExecError>
120     where
121         Self: Sized + 'static,
122         F: GpuFuture,
123     {
124         assert_eq!(
125             self.device().internal_object(),
126             future.device().internal_object()
127         );
128 
129         if !future.queue_change_allowed() {
130             assert!(future.queue().unwrap().is_same(&queue));
131         }
132 
133         self.lock_submit(&future, &queue)?;
134 
135         Ok(CommandBufferExecFuture {
136             previous: future,
137             command_buffer: self,
138             queue,
139             submitted: Mutex::new(false),
140             finished: AtomicBool::new(false),
141         })
142     }
143 
check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>144     fn check_buffer_access(
145         &self,
146         buffer: &dyn BufferAccess,
147         exclusive: bool,
148         queue: &Queue,
149     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>;
150 
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>151     fn check_image_access(
152         &self,
153         image: &dyn ImageAccess,
154         layout: ImageLayout,
155         exclusive: bool,
156         queue: &Queue,
157     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>;
158 }
159 
160 unsafe impl<T> PrimaryCommandBuffer for T
161 where
162     T: SafeDeref,
163     T::Target: PrimaryCommandBuffer,
164 {
165     #[inline]
inner(&self) -> &UnsafeCommandBuffer166     fn inner(&self) -> &UnsafeCommandBuffer {
167         (**self).inner()
168     }
169 
170     #[inline]
lock_submit( &self, future: &dyn GpuFuture, queue: &Queue, ) -> Result<(), CommandBufferExecError>171     fn lock_submit(
172         &self,
173         future: &dyn GpuFuture,
174         queue: &Queue,
175     ) -> Result<(), CommandBufferExecError> {
176         (**self).lock_submit(future, queue)
177     }
178 
179     #[inline]
unlock(&self)180     unsafe fn unlock(&self) {
181         (**self).unlock();
182     }
183 
184     #[inline]
check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>185     fn check_buffer_access(
186         &self,
187         buffer: &dyn BufferAccess,
188         exclusive: bool,
189         queue: &Queue,
190     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
191         (**self).check_buffer_access(buffer, exclusive, queue)
192     }
193 
194     #[inline]
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>195     fn check_image_access(
196         &self,
197         image: &dyn ImageAccess,
198         layout: ImageLayout,
199         exclusive: bool,
200         queue: &Queue,
201     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
202         (**self).check_image_access(image, layout, exclusive, queue)
203     }
204 }
205 
206 pub unsafe trait SecondaryCommandBuffer: DeviceOwned {
207     /// Returns the underlying `UnsafeCommandBuffer` of this command buffer.
inner(&self) -> &UnsafeCommandBuffer208     fn inner(&self) -> &UnsafeCommandBuffer;
209 
210     /// Checks whether this command buffer is allowed to be recorded to a command buffer,
211     /// and if so locks it.
212     ///
213     /// If you call this function, then you should call `unlock` afterwards.
lock_record(&self) -> Result<(), CommandBufferExecError>214     fn lock_record(&self) -> Result<(), CommandBufferExecError>;
215 
216     /// Unlocks the command buffer. Should be called once for each call to `lock_record`.
217     ///
218     /// # Safety
219     ///
220     /// Must not be called if you haven't called `lock_record` before.
unlock(&self)221     unsafe fn unlock(&self);
222 
223     /// Returns a `CommandBufferInheritance` value describing the properties that the command
224     /// buffer inherits from its parent primary command buffer.
inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract>225     fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract>;
226 
227     /// Returns the number of buffers accessed by this command buffer.
num_buffers(&self) -> usize228     fn num_buffers(&self) -> usize;
229 
230     /// Returns the `index`th buffer of this command buffer, or `None` if out of range.
231     ///
232     /// The valid range is between 0 and `num_buffers()`.
buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)>233     fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)>;
234 
235     /// Returns the number of images accessed by this command buffer.
num_images(&self) -> usize236     fn num_images(&self) -> usize;
237 
238     /// Returns the `index`th image of this command buffer, or `None` if out of range.
239     ///
240     /// The valid range is between 0 and `num_images()`.
image( &self, index: usize, ) -> Option<( &dyn ImageAccess, PipelineMemoryAccess, ImageLayout, ImageLayout, ImageUninitializedSafe, )>241     fn image(
242         &self,
243         index: usize,
244     ) -> Option<(
245         &dyn ImageAccess,
246         PipelineMemoryAccess,
247         ImageLayout,
248         ImageLayout,
249         ImageUninitializedSafe,
250     )>;
251 }
252 
253 unsafe impl<T> SecondaryCommandBuffer for T
254 where
255     T: SafeDeref,
256     T::Target: SecondaryCommandBuffer,
257 {
258     #[inline]
inner(&self) -> &UnsafeCommandBuffer259     fn inner(&self) -> &UnsafeCommandBuffer {
260         (**self).inner()
261     }
262 
263     #[inline]
lock_record(&self) -> Result<(), CommandBufferExecError>264     fn lock_record(&self) -> Result<(), CommandBufferExecError> {
265         (**self).lock_record()
266     }
267 
268     #[inline]
unlock(&self)269     unsafe fn unlock(&self) {
270         (**self).unlock();
271     }
272 
273     #[inline]
inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract>274     fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract> {
275         (**self).inheritance()
276     }
277 
278     #[inline]
num_buffers(&self) -> usize279     fn num_buffers(&self) -> usize {
280         (**self).num_buffers()
281     }
282 
283     #[inline]
buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)>284     fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)> {
285         (**self).buffer(index)
286     }
287 
288     #[inline]
num_images(&self) -> usize289     fn num_images(&self) -> usize {
290         (**self).num_images()
291     }
292 
293     #[inline]
image( &self, index: usize, ) -> Option<( &dyn ImageAccess, PipelineMemoryAccess, ImageLayout, ImageLayout, ImageUninitializedSafe, )>294     fn image(
295         &self,
296         index: usize,
297     ) -> Option<(
298         &dyn ImageAccess,
299         PipelineMemoryAccess,
300         ImageLayout,
301         ImageLayout,
302         ImageUninitializedSafe,
303     )> {
304         (**self).image(index)
305     }
306 }
307 
308 /// Represents a command buffer being executed by the GPU and the moment when the execution
309 /// finishes.
310 #[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
311 pub struct CommandBufferExecFuture<F, Cb>
312 where
313     F: GpuFuture,
314     Cb: PrimaryCommandBuffer,
315 {
316     previous: F,
317     command_buffer: Cb,
318     queue: Arc<Queue>,
319     // True if the command buffer has already been submitted.
320     // If flush is called multiple times, we want to block so that only one flushing is executed.
321     // Therefore we use a `Mutex<bool>` and not an `AtomicBool`.
322     submitted: Mutex<bool>,
323     finished: AtomicBool,
324 }
325 
326 unsafe impl<F, Cb> GpuFuture for CommandBufferExecFuture<F, Cb>
327 where
328     F: GpuFuture,
329     Cb: PrimaryCommandBuffer,
330 {
331     #[inline]
cleanup_finished(&mut self)332     fn cleanup_finished(&mut self) {
333         self.previous.cleanup_finished();
334     }
335 
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>336     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
337         Ok(match self.previous.build_submission()? {
338             SubmitAnyBuilder::Empty => {
339                 let mut builder = SubmitCommandBufferBuilder::new();
340                 builder.add_command_buffer(self.command_buffer.inner());
341                 SubmitAnyBuilder::CommandBuffer(builder)
342             }
343             SubmitAnyBuilder::SemaphoresWait(sem) => {
344                 let mut builder: SubmitCommandBufferBuilder = sem.into();
345                 builder.add_command_buffer(self.command_buffer.inner());
346                 SubmitAnyBuilder::CommandBuffer(builder)
347             }
348             SubmitAnyBuilder::CommandBuffer(mut builder) => {
349                 // FIXME: add pipeline barrier
350                 builder.add_command_buffer(self.command_buffer.inner());
351                 SubmitAnyBuilder::CommandBuffer(builder)
352             }
353             SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_) => {
354                 unimplemented!() // TODO:
355                                  /*present.submit();     // TODO: wrong
356                                  let mut builder = SubmitCommandBufferBuilder::new();
357                                  builder.add_command_buffer(self.command_buffer.inner());
358                                  SubmitAnyBuilder::CommandBuffer(builder)*/
359             }
360         })
361     }
362 
363     #[inline]
flush(&self) -> Result<(), FlushError>364     fn flush(&self) -> Result<(), FlushError> {
365         unsafe {
366             let mut submitted = self.submitted.lock().unwrap();
367             if *submitted {
368                 return Ok(());
369             }
370 
371             let queue = self.queue.clone();
372 
373             match self.build_submission()? {
374                 SubmitAnyBuilder::Empty => {}
375                 SubmitAnyBuilder::CommandBuffer(builder) => {
376                     builder.submit(&queue)?;
377                 }
378                 _ => unreachable!(),
379             };
380 
381             // Only write `true` here in order to try again next time if we failed to submit.
382             *submitted = true;
383             Ok(())
384         }
385     }
386 
387     #[inline]
signal_finished(&self)388     unsafe fn signal_finished(&self) {
389         if self.finished.swap(true, Ordering::SeqCst) == false {
390             self.command_buffer.unlock();
391         }
392 
393         self.previous.signal_finished();
394     }
395 
396     #[inline]
queue_change_allowed(&self) -> bool397     fn queue_change_allowed(&self) -> bool {
398         false
399     }
400 
401     #[inline]
queue(&self) -> Option<Arc<Queue>>402     fn queue(&self) -> Option<Arc<Queue>> {
403         Some(self.queue.clone())
404     }
405 
406     #[inline]
check_buffer_access( &self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>407     fn check_buffer_access(
408         &self,
409         buffer: &dyn BufferAccess,
410         exclusive: bool,
411         queue: &Queue,
412     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
413         match self
414             .command_buffer
415             .check_buffer_access(buffer, exclusive, queue)
416         {
417             Ok(v) => Ok(v),
418             Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
419             Err(AccessCheckError::Unknown) => {
420                 self.previous.check_buffer_access(buffer, exclusive, queue)
421             }
422         }
423     }
424 
425     #[inline]
check_image_access( &self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool, queue: &Queue, ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>426     fn check_image_access(
427         &self,
428         image: &dyn ImageAccess,
429         layout: ImageLayout,
430         exclusive: bool,
431         queue: &Queue,
432     ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
433         match self
434             .command_buffer
435             .check_image_access(image, layout, exclusive, queue)
436         {
437             Ok(v) => Ok(v),
438             Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
439             Err(AccessCheckError::Unknown) => self
440                 .previous
441                 .check_image_access(image, layout, exclusive, queue),
442         }
443     }
444 }
445 
446 unsafe impl<F, Cb> DeviceOwned for CommandBufferExecFuture<F, Cb>
447 where
448     F: GpuFuture,
449     Cb: PrimaryCommandBuffer,
450 {
451     #[inline]
device(&self) -> &Arc<Device>452     fn device(&self) -> &Arc<Device> {
453         self.command_buffer.device()
454     }
455 }
456 
457 impl<F, Cb> Drop for CommandBufferExecFuture<F, Cb>
458 where
459     F: GpuFuture,
460     Cb: PrimaryCommandBuffer,
461 {
drop(&mut self)462     fn drop(&mut self) {
463         unsafe {
464             if !*self.finished.get_mut() {
465                 // TODO: handle errors?
466                 self.flush().unwrap();
467                 // Block until the queue finished.
468                 self.queue.wait().unwrap();
469                 self.command_buffer.unlock();
470                 self.previous.signal_finished();
471             }
472         }
473     }
474 }
475 
476 /// Error that can happen when attempting to execute a command buffer.
477 #[derive(Clone, Debug, PartialEq, Eq)]
478 pub enum CommandBufferExecError {
479     /// Access to a resource has been denied.
480     AccessError {
481         error: AccessError,
482         command_name: Cow<'static, str>,
483         command_param: Cow<'static, str>,
484         command_offset: usize,
485     },
486 
487     /// The command buffer or one of the secondary command buffers it executes was created with the
488     /// "one time submit" flag, but has already been submitted it the past.
489     OneTimeSubmitAlreadySubmitted,
490 
491     /// The command buffer or one of the secondary command buffers it executes is already in use by
492     /// the GPU and was not created with the "concurrent" flag.
493     ExclusiveAlreadyInUse,
494     // TODO: missing entries (eg. wrong queue family, secondary command buffer)
495 }
496 
497 impl error::Error for CommandBufferExecError {
498     #[inline]
source(&self) -> Option<&(dyn error::Error + 'static)>499     fn source(&self) -> Option<&(dyn error::Error + 'static)> {
500         match *self {
501             CommandBufferExecError::AccessError { ref error, .. } => Some(error),
502             _ => None,
503         }
504     }
505 }
506 
507 impl fmt::Display for CommandBufferExecError {
508     #[inline]
fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error>509     fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
510         write!(
511             fmt,
512             "{}",
513             match *self {
514                 CommandBufferExecError::AccessError { .. } =>
515                     "access to a resource has been denied",
516                 CommandBufferExecError::OneTimeSubmitAlreadySubmitted => {
517                     "the command buffer or one of the secondary command buffers it executes was \
518                  created with the \"one time submit\" flag, but has already been submitted in \
519                  the past"
520                 }
521                 CommandBufferExecError::ExclusiveAlreadyInUse => {
522                     "the command buffer or one of the secondary command buffers it executes is \
523                  already in use was not created with the \"concurrent\" flag"
524                 }
525             }
526         )
527     }
528 }
529