• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2022 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 //! The standard command buffer and builder.
11 //!
12 //! Using `CommandBufferBuilder`, you must manually record synchronization commands to ensure
13 //! correct operation.
14 
15 #![allow(dead_code)]
16 
17 pub use self::builder::*;
18 use super::{
19     allocator::{CommandBufferAlloc, StandardCommandBufferAlloc},
20     CommandBufferExecError, CommandBufferInheritanceInfo, CommandBufferState, CommandBufferUsage,
21 };
22 use crate::{
23     device::{Device, DeviceOwned},
24     VulkanObject,
25 };
26 use parking_lot::Mutex;
27 use std::{
28     any::Any,
29     sync::{
30         atomic::{AtomicBool, Ordering},
31         Arc,
32     },
33 };
34 
35 mod builder;
36 
37 /// A command buffer that is finished recording, and can be submitted to a queue.
38 pub struct PrimaryCommandBuffer<A = StandardCommandBufferAlloc>
39 where
40     A: CommandBufferAlloc,
41 {
42     alloc: A,
43     _usage: CommandBufferUsage,
44     _resources: Vec<Box<dyn Any + Send + Sync>>,
45 
46     _state: Mutex<CommandBufferState>,
47 }
48 
49 unsafe impl<A> VulkanObject for PrimaryCommandBuffer<A>
50 where
51     A: CommandBufferAlloc,
52 {
53     type Handle = ash::vk::CommandBuffer;
54 
55     #[inline]
handle(&self) -> Self::Handle56     fn handle(&self) -> Self::Handle {
57         self.alloc.inner().handle()
58     }
59 }
60 
61 unsafe impl<A> DeviceOwned for PrimaryCommandBuffer<A>
62 where
63     A: CommandBufferAlloc,
64 {
65     #[inline]
device(&self) -> &Arc<Device>66     fn device(&self) -> &Arc<Device> {
67         self.alloc.device()
68     }
69 }
70 
71 /// A command buffer that is finished recording, and can be executed within a primary command
72 /// buffer by calling [`execute_commands`].
73 ///
74 /// [`execute_commands`]: CommandBufferBuilder::execute_commands
75 pub struct SecondaryCommandBuffer<A = StandardCommandBufferAlloc>
76 where
77     A: CommandBufferAlloc,
78 {
79     alloc: A,
80     inheritance_info: CommandBufferInheritanceInfo,
81     usage: CommandBufferUsage,
82     _resources: Vec<Box<dyn Any + Send + Sync>>,
83 
84     submit_state: SubmitState,
85 }
86 
87 unsafe impl<A> VulkanObject for SecondaryCommandBuffer<A>
88 where
89     A: CommandBufferAlloc,
90 {
91     type Handle = ash::vk::CommandBuffer;
92 
93     #[inline]
handle(&self) -> Self::Handle94     fn handle(&self) -> Self::Handle {
95         self.alloc.inner().handle()
96     }
97 }
98 
99 unsafe impl<A> DeviceOwned for SecondaryCommandBuffer<A>
100 where
101     A: CommandBufferAlloc,
102 {
103     #[inline]
device(&self) -> &Arc<Device>104     fn device(&self) -> &Arc<Device> {
105         self.alloc.device()
106     }
107 }
108 
109 impl<A> SecondaryCommandBuffer<A>
110 where
111     A: CommandBufferAlloc,
112 {
113     #[inline]
inheritance_info(&self) -> &CommandBufferInheritanceInfo114     pub fn inheritance_info(&self) -> &CommandBufferInheritanceInfo {
115         &self.inheritance_info
116     }
117 
lock_record(&self) -> Result<(), CommandBufferExecError>118     pub fn lock_record(&self) -> Result<(), CommandBufferExecError> {
119         match self.submit_state {
120             SubmitState::OneTime {
121                 ref already_submitted,
122             } => {
123                 let was_already_submitted = already_submitted.swap(true, Ordering::Acquire);
124                 if was_already_submitted {
125                     return Err(CommandBufferExecError::OneTimeSubmitAlreadySubmitted);
126                 }
127             }
128             SubmitState::ExclusiveUse { ref in_use } => {
129                 let already_in_use = in_use.swap(true, Ordering::Acquire);
130                 if already_in_use {
131                     return Err(CommandBufferExecError::ExclusiveAlreadyInUse);
132                 }
133             }
134             SubmitState::Concurrent => (),
135         };
136 
137         Ok(())
138     }
139 
unlock(&self)140     pub unsafe fn unlock(&self) {
141         match self.submit_state {
142             SubmitState::OneTime {
143                 ref already_submitted,
144             } => {
145                 debug_assert!(already_submitted.load(Ordering::Relaxed));
146             }
147             SubmitState::ExclusiveUse { ref in_use } => {
148                 let old_val = in_use.swap(false, Ordering::Release);
149                 debug_assert!(old_val);
150             }
151             SubmitState::Concurrent => (),
152         };
153     }
154 }
155 
156 /// Whether the command buffer can be submitted.
157 #[derive(Debug)]
158 enum SubmitState {
159     /// The command buffer was created with the "SimultaneousUse" flag. Can always be submitted at
160     /// any time.
161     Concurrent,
162 
163     /// The command buffer can only be submitted once simultaneously.
164     ExclusiveUse {
165         /// True if the command buffer is current in use by the GPU.
166         in_use: AtomicBool,
167     },
168 
169     /// The command buffer can only ever be submitted once.
170     OneTime {
171         /// True if the command buffer has already been submitted once and can be no longer be
172         /// submitted.
173         already_submitted: AtomicBool,
174     },
175 }
176