• 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 //! Commands that the GPU will execute (includes draw commands).
11 //!
12 //! With Vulkan, before the GPU can do anything you must create a `CommandBuffer`. A command buffer
13 //! is a list of commands that will executed by the GPU. Once a command buffer is created, you can
14 //! execute it. A command buffer must always be created even for the most simple tasks.
15 //!
16 //! # Primary and secondary command buffers.
17 //!
18 //! There are three types of command buffers:
19 //!
20 //! - **Primary command buffers**. They can contain any command. They are the only type of command
21 //!   buffer that can be submitted to a queue.
22 //! - **Secondary "graphics" command buffers**. They can only contain draw and clear commands.
23 //!   They can only be called from a primary command buffer when inside a render pass.
24 //! - **Secondary "compute" command buffers**. They can only contain non-render-pass-related
25 //!   commands (ie. everything but drawing, clearing, etc.) and cannot enter a render pass. They
26 //!   can only be called from a primary command buffer outside of a render pass.
27 //!
28 //! Using secondary command buffers leads to slightly lower performance on the GPU, but they have
29 //! two advantages on the CPU side:
30 //!
31 //! - Building a command buffer is a single-threaded operation, but by using secondary command
32 //!   buffers you can build multiple secondary command buffers in multiple threads simultaneously.
33 //! - Secondary command buffers can be kept alive between frames. When you always repeat the same
34 //!   operations, it might be a good idea to build a secondary command buffer once at
35 //!   initialization and then reuse it afterwards.
36 //!
37 //! # The `AutoCommandBufferBuilder`
38 //!
39 //! The most basic (and recommended) way to create a command buffer is to create a
40 //! [`AutoCommandBufferBuilder`](struct.AutoCommandBufferBuilder.html), then record commands to it.
41 //! When you are done adding commands, build it to obtain either a `PrimaryAutoCommandBuffer` or
42 //! `SecondAutoCommandBuffer`.
43 //!
44 //! Once built, use [the `PrimaryCommandBuffer` trait](trait.PrimaryCommandBuffer.html) to submit the
45 //! command buffer. Submitting a command buffer returns an object that implements the `GpuFuture` trait
46 //! and that represents the moment when the execution will end on the GPU.
47 //!
48 //! ```
49 //! use vulkano::command_buffer::AutoCommandBufferBuilder;
50 //! use vulkano::command_buffer::CommandBufferUsage;
51 //! use vulkano::command_buffer::PrimaryCommandBuffer;
52 //!
53 //! # let device: std::sync::Arc<vulkano::device::Device> = return;
54 //! # let queue: std::sync::Arc<vulkano::device::Queue> = return;
55 //! let cb = AutoCommandBufferBuilder::primary(
56 //!     device.clone(),
57 //!     queue.family(),
58 //!     CommandBufferUsage::MultipleSubmit
59 //! ).unwrap()
60 //! // TODO: add an actual command to this example
61 //! .build().unwrap();
62 //!
63 //! let _future = cb.execute(queue.clone());
64 //! ```
65 //!
66 //! # Internal architecture of vulkano
67 //!
68 //! The `commands_raw` and `commands_extra` modules contain structs that correspond to various
69 //! commands that can be added to command buffer builders. A command can be added to a command
70 //! buffer builder by using the `AddCommand<C>` trait, where `C` is the command struct.
71 //!
72 //! The `AutoCommandBufferBuilder` internally uses a `UnsafeCommandBufferBuilder` wrapped around
73 //! multiple layers. See the `cb` module for more information.
74 //!
75 //! Command pools are automatically handled by default, but vulkano also allows you to use
76 //! alternative command pool implementations and use them. See the `pool` module for more
77 //! information.
78 
79 pub use self::auto::AutoCommandBufferBuilder;
80 pub use self::auto::AutoCommandBufferBuilderContextError;
81 pub use self::auto::BeginError;
82 pub use self::auto::BeginQueryError;
83 pub use self::auto::BeginRenderPassError;
84 pub use self::auto::BlitImageError;
85 pub use self::auto::BuildError;
86 pub use self::auto::ClearColorImageError;
87 pub use self::auto::CopyBufferError;
88 pub use self::auto::CopyBufferImageError;
89 pub use self::auto::CopyImageError;
90 pub use self::auto::CopyQueryPoolResultsError;
91 pub use self::auto::DebugMarkerError;
92 pub use self::auto::DispatchError;
93 pub use self::auto::DispatchIndirectError;
94 pub use self::auto::DrawError;
95 pub use self::auto::DrawIndexedError;
96 pub use self::auto::DrawIndexedIndirectError;
97 pub use self::auto::DrawIndirectError;
98 pub use self::auto::EndQueryError;
99 pub use self::auto::ExecuteCommandsError;
100 pub use self::auto::FillBufferError;
101 pub use self::auto::PrimaryAutoCommandBuffer;
102 pub use self::auto::ResetQueryPoolError;
103 pub use self::auto::SecondaryAutoCommandBuffer;
104 pub use self::auto::UpdateBufferError;
105 pub use self::auto::WriteTimestampError;
106 pub use self::state_cacher::StateCacher;
107 pub use self::state_cacher::StateCacherOutcome;
108 pub use self::traits::CommandBufferExecError;
109 pub use self::traits::CommandBufferExecFuture;
110 pub use self::traits::PrimaryCommandBuffer;
111 pub use self::traits::SecondaryCommandBuffer;
112 use crate::pipeline::depth_stencil::DynamicStencilValue;
113 use crate::pipeline::viewport::{Scissor, Viewport};
114 use crate::query::QueryControlFlags;
115 use crate::query::QueryPipelineStatisticFlags;
116 use crate::render_pass::{Framebuffer, Subpass};
117 use std::sync::Arc;
118 
119 mod auto;
120 pub mod pool;
121 mod state_cacher;
122 pub mod submit;
123 pub mod synced;
124 pub mod sys;
125 mod traits;
126 pub mod validity;
127 
128 #[derive(Debug, Clone, Copy)]
129 pub enum ImageUninitializedSafe {
130     Safe,
131     Unsafe,
132 }
133 
134 impl ImageUninitializedSafe {
is_safe(&self) -> bool135     pub fn is_safe(&self) -> bool {
136         match self {
137             Self::Safe => true,
138             Self::Unsafe => false,
139         }
140     }
141 }
142 
143 #[repr(C)]
144 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
145 pub struct DrawIndirectCommand {
146     pub vertex_count: u32,
147     pub instance_count: u32,
148     pub first_vertex: u32,
149     pub first_instance: u32,
150 }
151 
152 #[repr(C)]
153 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
154 pub struct DrawIndexedIndirectCommand {
155     pub index_count: u32,
156     pub instance_count: u32,
157     pub first_index: u32,
158     pub vertex_offset: u32,
159     pub first_instance: u32,
160 }
161 
162 #[repr(C)]
163 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
164 pub struct DispatchIndirectCommand {
165     pub x: u32,
166     pub y: u32,
167     pub z: u32,
168 }
169 
170 /// The dynamic state to use for a draw command.
171 // TODO: probably not the right location
172 #[derive(Debug, Clone)]
173 pub struct DynamicState {
174     pub line_width: Option<f32>,
175     pub viewports: Option<Vec<Viewport>>,
176     pub scissors: Option<Vec<Scissor>>,
177     pub compare_mask: Option<DynamicStencilValue>,
178     pub write_mask: Option<DynamicStencilValue>,
179     pub reference: Option<DynamicStencilValue>,
180 }
181 
182 impl DynamicState {
183     #[inline]
none() -> DynamicState184     pub fn none() -> DynamicState {
185         DynamicState {
186             line_width: None,
187             viewports: None,
188             scissors: None,
189             compare_mask: None,
190             write_mask: None,
191             reference: None,
192         }
193     }
194 }
195 
196 impl Default for DynamicState {
197     #[inline]
default() -> DynamicState198     fn default() -> DynamicState {
199         DynamicState::none()
200     }
201 }
202 
203 /// Describes what a subpass in a command buffer will contain.
204 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
205 #[repr(i32)]
206 pub enum SubpassContents {
207     /// The subpass will only directly contain commands.
208     Inline = ash::vk::SubpassContents::INLINE.as_raw(),
209     /// The subpass will only contain secondary command buffers invocations.
210     SecondaryCommandBuffers = ash::vk::SubpassContents::SECONDARY_COMMAND_BUFFERS.as_raw(),
211 }
212 
213 impl From<SubpassContents> for ash::vk::SubpassContents {
214     #[inline]
from(val: SubpassContents) -> Self215     fn from(val: SubpassContents) -> Self {
216         Self::from_raw(val as i32)
217     }
218 }
219 
220 /// Determines the kind of command buffer to create.
221 #[derive(Debug, Clone)]
222 pub enum CommandBufferLevel<F> {
223     /// Primary command buffers can be executed on a queue, and can call secondary command buffers.
224     /// Render passes must begin and end within the same primary command buffer.
225     Primary,
226 
227     /// Secondary command buffers cannot be executed on a queue, but can be executed by a primary
228     /// command buffer. If created for a render pass, they must fit within a single render subpass.
229     Secondary(CommandBufferInheritance<F>),
230 }
231 
232 /// The context that a secondary command buffer can inherit from the primary command
233 /// buffer it's executed in.
234 #[derive(Clone, Debug, Default)]
235 pub struct CommandBufferInheritance<F> {
236     /// If `Some`, the secondary command buffer is required to be executed within a specific
237     /// render subpass, and can only call draw operations.
238     /// If `None`, it must be executed outside a render pass, and can execute dispatch and transfer
239     /// operations, but not drawing operations.
240     render_pass: Option<CommandBufferInheritanceRenderPass<F>>,
241 
242     /// If `Some`, the secondary command buffer is allowed to be executed within a primary that has
243     /// an occlusion query active. The inner `QueryControlFlags` specifies which flags the
244     /// active occlusion is allowed to have enabled.
245     /// If `None`, the primary command buffer cannot have an occlusion query active when this
246     /// secondary command buffer is executed.
247     ///
248     /// The `inherited_queries` feature must be enabled if this is `Some`.
249     occlusion_query: Option<QueryControlFlags>,
250 
251     /// Which pipeline statistics queries are allowed to be active on the primary command buffer
252     /// when this secondary command buffer is executed.
253     ///
254     /// The `pipeline_statistics_query` feature must be enabled if any of the flags of this value
255     /// are set.
256     query_statistics_flags: QueryPipelineStatisticFlags,
257 }
258 
259 /// The render pass context that a secondary command buffer is created for.
260 #[derive(Debug, Clone)]
261 pub struct CommandBufferInheritanceRenderPass<F> {
262     /// The render subpass that this secondary command buffer must be executed within.
263     pub subpass: Subpass,
264 
265     /// The framebuffer object that will be used when calling the command buffer.
266     /// This parameter is optional and is an optimization hint for the implementation.
267     pub framebuffer: Option<F>,
268 }
269 
270 impl CommandBufferLevel<Framebuffer<()>> {
271     /// Equivalent to `Kind::Primary`.
272     ///
273     /// > **Note**: If you use `let kind = Kind::Primary;` in your code, you will probably get a
274     /// > compilation error because the Rust compiler couldn't determine the template parameters
275     /// > of `Kind`. To solve that problem in an easy way you can use this function instead.
276     #[inline]
primary() -> CommandBufferLevel<Arc<Framebuffer<()>>>277     pub fn primary() -> CommandBufferLevel<Arc<Framebuffer<()>>> {
278         CommandBufferLevel::Primary
279     }
280 
281     /// Equivalent to `Kind::Secondary`.
282     ///
283     /// > **Note**: If you use `let kind = Kind::Secondary;` in your code, you will probably get a
284     /// > compilation error because the Rust compiler couldn't determine the template parameters
285     /// > of `Kind`. To solve that problem in an easy way you can use this function instead.
286     #[inline]
secondary( occlusion_query: Option<QueryControlFlags>, query_statistics_flags: QueryPipelineStatisticFlags, ) -> CommandBufferLevel<Arc<Framebuffer<()>>>287     pub fn secondary(
288         occlusion_query: Option<QueryControlFlags>,
289         query_statistics_flags: QueryPipelineStatisticFlags,
290     ) -> CommandBufferLevel<Arc<Framebuffer<()>>> {
291         CommandBufferLevel::Secondary(CommandBufferInheritance {
292             render_pass: None,
293             occlusion_query,
294             query_statistics_flags,
295         })
296     }
297 }
298 
299 /// Usage flags to pass when creating a command buffer.
300 ///
301 /// The safest option is `SimultaneousUse`, but it may be slower than the other two.
302 // NOTE: The ordering is important: the variants are listed from least to most permissive!
303 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
304 #[repr(u32)]
305 pub enum CommandBufferUsage {
306     /// The command buffer can only be submitted once before being destroyed. Any further submit is
307     /// forbidden. This makes it possible for the implementation to perform additional
308     /// optimizations.
309     OneTimeSubmit = ash::vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT.as_raw(),
310 
311     /// The command buffer can be used multiple times, but must not execute or record more than once
312     /// simultaneously. In other words, it is as if executing the command buffer borrows it mutably.
313     MultipleSubmit = 0,
314 
315     /// The command buffer can be executed multiple times in parallel on different queues.
316     /// If it's a secondary command buffer, it can be recorded to multiple primary command buffers
317     /// at once.
318     SimultaneousUse = ash::vk::CommandBufferUsageFlags::SIMULTANEOUS_USE.as_raw(),
319 }
320 
321 impl From<CommandBufferUsage> for ash::vk::CommandBufferUsageFlags {
322     #[inline]
from(val: CommandBufferUsage) -> Self323     fn from(val: CommandBufferUsage) -> Self {
324         Self::from_raw(val as u32)
325     }
326 }
327