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 super::{
11     CommandBufferInheritanceInfo, CommandBufferResourcesUsage, CommandBufferState,
12     CommandBufferUsage, SecondaryCommandBufferResourcesUsage, SemaphoreSubmitInfo, SubmitInfo,
13 };
14 use crate::{
15     buffer::Buffer,
16     device::{Device, DeviceOwned, Queue},
17     image::{sys::Image, ImageLayout},
18     swapchain::Swapchain,
19     sync::{
20         future::{
21             now, AccessCheckError, AccessError, FlushError, GpuFuture, NowFuture, SubmitAnyBuilder,
22         },
23         PipelineStages,
24     },
25     DeviceSize, SafeDeref, VulkanObject,
26 };
27 use parking_lot::{Mutex, MutexGuard};
28 use std::{
29     borrow::Cow,
30     error::Error,
31     fmt::{Debug, Display, Error as FmtError, Formatter},
32     ops::Range,
33     sync::{
34         atomic::{AtomicBool, Ordering},
35         Arc,
36     },
37     thread,
38 };
39 
40 pub unsafe trait PrimaryCommandBufferAbstract:
41     VulkanObject<Handle = ash::vk::CommandBuffer> + DeviceOwned + Send + Sync
42 {
43     /// Returns the usage of this command buffer.
usage(&self) -> CommandBufferUsage44     fn usage(&self) -> CommandBufferUsage;
45 
46     /// Executes this command buffer on a queue.
47     ///
48     /// This function returns an object that implements the [`GpuFuture`] trait. See the
49     /// documentation of the [`future`][crate::sync::future] module for more information.
50     ///
51     /// The command buffer is not actually executed until you call [`flush()`][GpuFuture::flush] on
52     /// the future.  You are encouraged to chain together as many futures as possible prior to
53     /// calling [`flush()`][GpuFuture::flush]. In order to know when the future has completed, call
54     /// one of [`then_signal_fence()`][GpuFuture::then_signal_fence] or
55     /// [`then_signal_semaphore()`][GpuFuture::then_signal_semaphore]. You can do both together
56     /// with [`then_signal_fence_and_flush()`][GpuFuture::then_signal_fence_and_flush] or
57     /// [`then_signal_semaphore_and_flush()`][GpuFuture::then_signal_semaphore_and_flush],
58     /// respectively.
59     ///
60     /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
61     /// > concrete type.
62     ///
63     /// > **Note**: This is just a shortcut for `execute_after(vulkano::sync::now(), queue)`.
64     ///
65     /// # Panics
66     ///
67     /// - Panics if the device of the command buffer is not the same as the device of the future.
68     #[inline]
execute( self, queue: Arc<Queue>, ) -> Result<CommandBufferExecFuture<NowFuture>, CommandBufferExecError> where Self: Sized + 'static,69     fn execute(
70         self,
71         queue: Arc<Queue>,
72     ) -> Result<CommandBufferExecFuture<NowFuture>, CommandBufferExecError>
73     where
74         Self: Sized + 'static,
75     {
76         let device = queue.device().clone();
77         self.execute_after(now(device), queue)
78     }
79 
80     /// Executes the command buffer after an existing future.
81     ///
82     /// This function returns an object that implements the [`GpuFuture`] trait. See the
83     /// documentation of the [`future`][crate::sync::future] module for more information.
84     ///
85     /// The command buffer is not actually executed until you call [`flush()`][GpuFuture::flush] on
86     /// the future.  You are encouraged to chain together as many futures as possible prior to
87     /// calling [`flush()`][GpuFuture::flush]. In order to know when the future has completed, call
88     /// one of [`then_signal_fence()`][GpuFuture::then_signal_fence] or
89     /// [`then_signal_semaphore()`][GpuFuture::then_signal_semaphore]. You can do both together
90     /// with [`then_signal_fence_and_flush()`][GpuFuture::then_signal_fence_and_flush] or
91     /// [`then_signal_semaphore_and_flush()`][GpuFuture::then_signal_semaphore_and_flush],
92     /// respectively.
93     ///
94     /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a
95     /// > concrete type.
96     ///
97     /// This function requires the `'static` lifetime to be on the command buffer. This is because
98     /// this function returns a `CommandBufferExecFuture` whose job is to lock resources and keep
99     /// them alive while they are in use by the GPU. If `'static` wasn't required, you could call
100     /// `std::mem::forget` on that object and "unlock" these resources. For more information about
101     /// this problem, search the web for "rust thread scoped leakpocalypse".
102     ///
103     /// # Panics
104     ///
105     /// - Panics if the device of the command buffer is not the same as the device of the future.
execute_after<F>( self, future: F, queue: Arc<Queue>, ) -> Result<CommandBufferExecFuture<F>, CommandBufferExecError> where Self: Sized + 'static, F: GpuFuture,106     fn execute_after<F>(
107         self,
108         future: F,
109         queue: Arc<Queue>,
110     ) -> Result<CommandBufferExecFuture<F>, CommandBufferExecError>
111     where
112         Self: Sized + 'static,
113         F: GpuFuture,
114     {
115         assert_eq!(self.device().handle(), future.device().handle());
116 
117         if !future.queue_change_allowed() {
118             assert!(future.queue().unwrap() == queue);
119         }
120 
121         Ok(CommandBufferExecFuture {
122             previous: future,
123             command_buffer: Arc::new(self),
124             queue,
125             submitted: Mutex::new(false),
126             finished: AtomicBool::new(false),
127         })
128     }
129 
130     #[doc(hidden)]
state(&self) -> MutexGuard<'_, CommandBufferState>131     fn state(&self) -> MutexGuard<'_, CommandBufferState>;
132 
133     #[doc(hidden)]
resources_usage(&self) -> &CommandBufferResourcesUsage134     fn resources_usage(&self) -> &CommandBufferResourcesUsage;
135 }
136 
137 impl Debug for dyn PrimaryCommandBufferAbstract {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>138     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
139         Debug::fmt(&self.handle(), f)
140     }
141 }
142 
143 unsafe impl<T> PrimaryCommandBufferAbstract for T
144 where
145     T: VulkanObject<Handle = ash::vk::CommandBuffer> + SafeDeref + Send + Sync,
146     T::Target: PrimaryCommandBufferAbstract,
147 {
usage(&self) -> CommandBufferUsage148     fn usage(&self) -> CommandBufferUsage {
149         (**self).usage()
150     }
151 
state(&self) -> MutexGuard<'_, CommandBufferState>152     fn state(&self) -> MutexGuard<'_, CommandBufferState> {
153         (**self).state()
154     }
155 
resources_usage(&self) -> &CommandBufferResourcesUsage156     fn resources_usage(&self) -> &CommandBufferResourcesUsage {
157         (**self).resources_usage()
158     }
159 }
160 
161 pub unsafe trait SecondaryCommandBufferAbstract:
162     VulkanObject<Handle = ash::vk::CommandBuffer> + DeviceOwned + Send + Sync
163 {
164     /// Returns the usage of this command buffer.
usage(&self) -> CommandBufferUsage165     fn usage(&self) -> CommandBufferUsage;
166 
167     /// Returns a `CommandBufferInheritance` value describing the properties that the command
168     /// buffer inherits from its parent primary command buffer.
inheritance_info(&self) -> &CommandBufferInheritanceInfo169     fn inheritance_info(&self) -> &CommandBufferInheritanceInfo;
170 
171     /// Checks whether this command buffer is allowed to be recorded to a command buffer,
172     /// and if so locks it.
173     ///
174     /// If you call this function, then you should call `unlock` afterwards.
lock_record(&self) -> Result<(), CommandBufferExecError>175     fn lock_record(&self) -> Result<(), CommandBufferExecError>;
176 
177     /// Unlocks the command buffer. Should be called once for each call to `lock_record`.
178     ///
179     /// # Safety
180     ///
181     /// Must not be called if you haven't called `lock_record` before.
unlock(&self)182     unsafe fn unlock(&self);
183 
184     #[doc(hidden)]
resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage185     fn resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage;
186 }
187 
188 unsafe impl<T> SecondaryCommandBufferAbstract for T
189 where
190     T: VulkanObject<Handle = ash::vk::CommandBuffer> + SafeDeref + Send + Sync,
191     T::Target: SecondaryCommandBufferAbstract,
192 {
usage(&self) -> CommandBufferUsage193     fn usage(&self) -> CommandBufferUsage {
194         (**self).usage()
195     }
196 
inheritance_info(&self) -> &CommandBufferInheritanceInfo197     fn inheritance_info(&self) -> &CommandBufferInheritanceInfo {
198         (**self).inheritance_info()
199     }
200 
lock_record(&self) -> Result<(), CommandBufferExecError>201     fn lock_record(&self) -> Result<(), CommandBufferExecError> {
202         (**self).lock_record()
203     }
204 
unlock(&self)205     unsafe fn unlock(&self) {
206         (**self).unlock();
207     }
208 
resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage209     fn resources_usage(&self) -> &SecondaryCommandBufferResourcesUsage {
210         (**self).resources_usage()
211     }
212 }
213 
214 /// Represents a command buffer being executed by the GPU and the moment when the execution
215 /// finishes.
216 #[derive(Debug)]
217 #[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
218 pub struct CommandBufferExecFuture<F>
219 where
220     F: GpuFuture,
221 {
222     previous: F,
223     command_buffer: Arc<dyn PrimaryCommandBufferAbstract>,
224     queue: Arc<Queue>,
225     // True if the command buffer has already been submitted.
226     // If flush is called multiple times, we want to block so that only one flushing is executed.
227     // Therefore we use a `Mutex<bool>` and not an `AtomicBool`.
228     submitted: Mutex<bool>,
229     finished: AtomicBool,
230 }
231 
232 impl<F> CommandBufferExecFuture<F>
233 where
234     F: GpuFuture,
235 {
236     // Implementation of `build_submission`. Doesn't check whenever the future was already flushed.
237     // You must make sure to not submit same command buffer multiple times.
build_submission_impl(&self) -> Result<SubmitAnyBuilder, FlushError>238     unsafe fn build_submission_impl(&self) -> Result<SubmitAnyBuilder, FlushError> {
239         Ok(match self.previous.build_submission()? {
240             SubmitAnyBuilder::Empty => SubmitAnyBuilder::CommandBuffer(
241                 SubmitInfo {
242                     command_buffers: vec![self.command_buffer.clone()],
243                     ..Default::default()
244                 },
245                 None,
246             ),
247             SubmitAnyBuilder::SemaphoresWait(semaphores) => {
248                 SubmitAnyBuilder::CommandBuffer(
249                     SubmitInfo {
250                         wait_semaphores: semaphores
251                             .into_iter()
252                             .map(|semaphore| {
253                                 SemaphoreSubmitInfo {
254                                     // TODO: correct stages ; hard
255                                     stages: PipelineStages::ALL_COMMANDS,
256                                     ..SemaphoreSubmitInfo::semaphore(semaphore)
257                                 }
258                             })
259                             .collect(),
260                         command_buffers: vec![self.command_buffer.clone()],
261                         ..Default::default()
262                     },
263                     None,
264                 )
265             }
266             SubmitAnyBuilder::CommandBuffer(mut submit_info, fence) => {
267                 // FIXME: add pipeline barrier
268                 submit_info
269                     .command_buffers
270                     .push(self.command_buffer.clone());
271                 SubmitAnyBuilder::CommandBuffer(submit_info, fence)
272             }
273             SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_, _) => {
274                 unimplemented!() // TODO:
275                                  /*present.submit();     // TODO: wrong
276                                  let mut builder = SubmitCommandBufferBuilder::new();
277                                  builder.add_command_buffer(self.command_buffer.inner());
278                                  SubmitAnyBuilder::CommandBuffer(builder)*/
279             }
280         })
281     }
282 }
283 
284 unsafe impl<F> GpuFuture for CommandBufferExecFuture<F>
285 where
286     F: GpuFuture,
287 {
cleanup_finished(&mut self)288     fn cleanup_finished(&mut self) {
289         self.previous.cleanup_finished();
290     }
291 
build_submission(&self) -> Result<SubmitAnyBuilder, FlushError>292     unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
293         if *self.submitted.lock() {
294             return Ok(SubmitAnyBuilder::Empty);
295         }
296 
297         self.build_submission_impl()
298     }
299 
flush(&self) -> Result<(), FlushError>300     fn flush(&self) -> Result<(), FlushError> {
301         unsafe {
302             let mut submitted = self.submitted.lock();
303             if *submitted {
304                 return Ok(());
305             }
306 
307             match self.build_submission_impl()? {
308                 SubmitAnyBuilder::Empty => {}
309                 SubmitAnyBuilder::CommandBuffer(submit_info, fence) => {
310                     self.queue.with(|mut q| {
311                         q.submit_with_future(submit_info, fence, &self.previous, &self.queue)
312                     })?;
313                 }
314                 _ => unreachable!(),
315             };
316 
317             // Only write `true` here in order to try again next time if we failed to submit.
318             *submitted = true;
319             Ok(())
320         }
321     }
322 
signal_finished(&self)323     unsafe fn signal_finished(&self) {
324         self.finished.store(true, Ordering::SeqCst);
325         self.previous.signal_finished();
326     }
327 
queue_change_allowed(&self) -> bool328     fn queue_change_allowed(&self) -> bool {
329         false
330     }
331 
queue(&self) -> Option<Arc<Queue>>332     fn queue(&self) -> Option<Arc<Queue>> {
333         Some(self.queue.clone())
334     }
335 
check_buffer_access( &self, buffer: &Buffer, range: Range<DeviceSize>, exclusive: bool, queue: &Queue, ) -> Result<(), AccessCheckError>336     fn check_buffer_access(
337         &self,
338         buffer: &Buffer,
339         range: Range<DeviceSize>,
340         exclusive: bool,
341         queue: &Queue,
342     ) -> Result<(), AccessCheckError> {
343         let resources_usage = self.command_buffer.resources_usage();
344         let usage = match resources_usage.buffer_indices.get(buffer) {
345             Some(&index) => &resources_usage.buffers[index],
346             None => return Err(AccessCheckError::Unknown),
347         };
348 
349         // TODO: check the queue family
350 
351         let result = usage
352             .ranges
353             .range(&range)
354             .try_fold((), |_, (_range, range_usage)| {
355                 if !range_usage.mutable && exclusive {
356                     Err(AccessCheckError::Unknown)
357                 } else {
358                     Ok(())
359                 }
360             });
361 
362         match result {
363             Ok(()) => Ok(()),
364             Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
365             Err(AccessCheckError::Unknown) => self
366                 .previous
367                 .check_buffer_access(buffer, range, exclusive, queue),
368         }
369     }
370 
check_image_access( &self, image: &Image, range: Range<DeviceSize>, exclusive: bool, expected_layout: ImageLayout, queue: &Queue, ) -> Result<(), AccessCheckError>371     fn check_image_access(
372         &self,
373         image: &Image,
374         range: Range<DeviceSize>,
375         exclusive: bool,
376         expected_layout: ImageLayout,
377         queue: &Queue,
378     ) -> Result<(), AccessCheckError> {
379         let resources_usage = self.command_buffer.resources_usage();
380         let usage = match resources_usage.image_indices.get(image) {
381             Some(&index) => &resources_usage.images[index],
382             None => return Err(AccessCheckError::Unknown),
383         };
384 
385         // TODO: check the queue family
386 
387         let result = usage
388             .ranges
389             .range(&range)
390             .try_fold((), |_, (_range, range_usage)| {
391                 if expected_layout != ImageLayout::Undefined
392                     && range_usage.final_layout != expected_layout
393                 {
394                     return Err(AccessCheckError::Denied(
395                         AccessError::UnexpectedImageLayout {
396                             allowed: range_usage.final_layout,
397                             requested: expected_layout,
398                         },
399                     ));
400                 }
401 
402                 if !range_usage.mutable && exclusive {
403                     Err(AccessCheckError::Unknown)
404                 } else {
405                     Ok(())
406                 }
407             });
408 
409         match result {
410             Ok(()) => Ok(()),
411             Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)),
412             Err(AccessCheckError::Unknown) => {
413                 self.previous
414                     .check_image_access(image, range, exclusive, expected_layout, queue)
415             }
416         }
417     }
418 
419     #[inline]
check_swapchain_image_acquired( &self, swapchain: &Swapchain, image_index: u32, _before: bool, ) -> Result<(), AccessCheckError>420     fn check_swapchain_image_acquired(
421         &self,
422         swapchain: &Swapchain,
423         image_index: u32,
424         _before: bool,
425     ) -> Result<(), AccessCheckError> {
426         self.previous
427             .check_swapchain_image_acquired(swapchain, image_index, false)
428     }
429 }
430 
431 unsafe impl<F> DeviceOwned for CommandBufferExecFuture<F>
432 where
433     F: GpuFuture,
434 {
device(&self) -> &Arc<Device>435     fn device(&self) -> &Arc<Device> {
436         self.command_buffer.device()
437     }
438 }
439 
440 impl<F> Drop for CommandBufferExecFuture<F>
441 where
442     F: GpuFuture,
443 {
drop(&mut self)444     fn drop(&mut self) {
445         if !*self.finished.get_mut() && !thread::panicking() {
446             // TODO: handle errors?
447             self.flush().unwrap();
448             // Block until the queue finished.
449             self.queue.with(|mut q| q.wait_idle()).unwrap();
450             unsafe { self.previous.signal_finished() };
451         }
452     }
453 }
454 
455 /// Error that can happen when attempting to execute a command buffer.
456 #[derive(Clone, Debug, PartialEq, Eq)]
457 pub enum CommandBufferExecError {
458     /// Access to a resource has been denied.
459     AccessError {
460         error: AccessError,
461         command_name: Cow<'static, str>,
462         command_param: Cow<'static, str>,
463         command_offset: usize,
464     },
465 
466     /// The command buffer or one of the secondary command buffers it executes was created with the
467     /// "one time submit" flag, but has already been submitted it the past.
468     OneTimeSubmitAlreadySubmitted,
469 
470     /// The command buffer or one of the secondary command buffers it executes is already in use by
471     /// the GPU and was not created with the "concurrent" flag.
472     ExclusiveAlreadyInUse,
473     // TODO: missing entries (eg. wrong queue family, secondary command buffer)
474 }
475 
476 impl Error for CommandBufferExecError {
source(&self) -> Option<&(dyn Error + 'static)>477     fn source(&self) -> Option<&(dyn Error + 'static)> {
478         match self {
479             CommandBufferExecError::AccessError { error, .. } => Some(error),
480             _ => None,
481         }
482     }
483 }
484 
485 impl Display for CommandBufferExecError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>486     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
487         write!(
488             f,
489             "{}",
490             match self {
491                 CommandBufferExecError::AccessError { .. } =>
492                     "access to a resource has been denied",
493                 CommandBufferExecError::OneTimeSubmitAlreadySubmitted => {
494                     "the command buffer or one of the secondary command buffers it executes was \
495                     created with the \"one time submit\" flag, but has already been submitted in \
496                     the past"
497                 }
498                 CommandBufferExecError::ExclusiveAlreadyInUse => {
499                     "the command buffer or one of the secondary command buffers it executes is \
500                     already in use was not created with the \"concurrent\" flag"
501                 }
502             }
503         )
504     }
505 }
506