1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
//! Command buffers. //! //! A command buffer collects a list of commands to be submitted to the device. //! Each command buffer has specific capabilities for graphics, compute or transfer operations, //! and can be either a "primary" command buffer or a "secondary" command buffer. Operations //! always start from a primary command buffer, but a primary command buffer can contain calls //! to secondary command buffers that contain snippets of commands that do specific things, similar //! to function calls. //! //! All the possible commands are implemented in the `RawCommandBuffer` trait, and then the `CommandBuffer` //! and related types make a generic, strongly-typed wrapper around it that only expose the methods that //! are valid for the capabilities it provides. // TODO: Document pipelines and subpasses better. use crate::queue::capability::{Capability, Supports}; use crate::Backend; use std::borrow::Borrow; use std::marker::PhantomData; mod compute; mod graphics; mod raw; mod render_pass; mod transfer; pub use self::graphics::*; pub use self::raw::{ ClearColorRaw, ClearDepthStencilRaw, ClearValueRaw, CommandBufferFlags, CommandBufferInheritanceInfo, DescriptorSetOffset, IntoRawCommandBuffer, Level as RawLevel, RawCommandBuffer, }; pub use self::render_pass::*; pub use self::transfer::*; /// Trait indicating how many times a Submit object can be submitted to a command buffer. pub trait Shot {} /// Indicates a Submit that can only be submitted once. #[derive(Debug)] pub enum OneShot {} impl Shot for OneShot {} /// Indicates a Submit that can be submitted multiple times. #[derive(Debug)] pub enum MultiShot {} impl Shot for MultiShot {} /// A trait indicating the level of a command buffer. pub trait Level {} /// Indicates a primary command buffer. /// Vulkan describes a primary command buffer as one which can be directly submitted /// to a queue, and can execute `Secondary` command buffers. #[derive(Debug)] pub enum Primary {} impl Level for Primary {} /// Indicates a secondary command buffer. /// /// Vulkan describes a secondary command buffer as one which cannot be directly submitted /// to a queue, but can be executed by a primary command buffer. This allows /// multiple secondary command buffers to be constructed which do specific /// things and can then be composed together into primary command buffers. #[derive(Debug)] pub enum Secondary {} impl Level for Secondary {} /// A property of a command buffer to be submitted to a queue with specific capability. pub trait Submittable<B: Backend, C: Capability, L: Level>: Borrow<B::CommandBuffer> {} /// A convenience alias for not typing out the full signature of a secondary command buffer. pub type SecondaryCommandBuffer<B, C, S = OneShot> = CommandBuffer<B, C, S, Secondary>; /// A strongly-typed command buffer that will only implement methods that are valid for the operations /// it supports. #[derive(Debug)] pub struct CommandBuffer<B: Backend, C, S = OneShot, L = Primary, R = <B as Backend>::CommandBuffer> { pub(crate) raw: R, pub(crate) _marker: PhantomData<(B, C, S, L)>, } impl<B, C, S, L, R> Borrow<R> for CommandBuffer<B, C, S, L, R> where R: RawCommandBuffer<B>, B: Backend<CommandBuffer = R>, { fn borrow(&self) -> &B::CommandBuffer { &self.raw } } impl<B: Backend, C, K: Capability + Supports<C>, S, L: Level> Submittable<B, K, L> for CommandBuffer<B, C, S, L> { } impl<B: Backend, C, S, L> IntoRawCommandBuffer<B, C> for CommandBuffer<B, C, S, L> { fn into_raw(self) -> B::CommandBuffer { self.raw } } impl<B: Backend, C> CommandBuffer<B, C, OneShot, Primary> { /// Begin recording a one-shot primary command buffer. pub unsafe fn begin(&mut self) { let flags = CommandBufferFlags::ONE_TIME_SUBMIT; self.raw .begin(flags, CommandBufferInheritanceInfo::default()); } } impl<B: Backend, C> CommandBuffer<B, C, MultiShot, Primary> { /// Begin recording a multi-shot primary command buffer. pub unsafe fn begin(&mut self, allow_pending_resubmit: bool) { let flags = if allow_pending_resubmit { CommandBufferFlags::SIMULTANEOUS_USE } else { CommandBufferFlags::empty() }; self.raw .begin(flags, CommandBufferInheritanceInfo::default()); } } impl<B: Backend, C> CommandBuffer<B, C, OneShot, Secondary> { /// Begin recording a one-shot secondary command buffer. pub unsafe fn begin(&mut self, inheritance: CommandBufferInheritanceInfo<B>) { let flags = CommandBufferFlags::ONE_TIME_SUBMIT; self.raw.begin(flags, inheritance); } } impl<B: Backend, C> CommandBuffer<B, C, MultiShot, Secondary> { /// Begin recording a multi-shot secondary command buffer. pub unsafe fn begin( &mut self, allow_pending_resubmit: bool, inheritance: CommandBufferInheritanceInfo<B>, ) { let flags = if allow_pending_resubmit { CommandBufferFlags::SIMULTANEOUS_USE } else { CommandBufferFlags::empty() }; self.raw.begin(flags, inheritance); } } impl<B: Backend, C, S: Shot, L: Level> CommandBuffer<B, C, S, L> { /// Create a new typed command buffer from a raw command pool. pub unsafe fn new(raw: B::CommandBuffer) -> Self { CommandBuffer { raw, _marker: PhantomData, } } /// Finish recording commands to the command buffers. /// /// The command buffer must be reset to able to re-record commands. pub unsafe fn finish(&mut self) { self.raw.finish(); } /// Empties the command buffer, optionally releasing all resources from the /// commands that have been submitted. The command buffer is moved back to /// the "initial" state. /// /// The command buffer must not be in the "pending" state. Additionally, the /// command pool must have been created with the RESET_INDIVIDUAL flag to be /// able to reset individual buffers. pub unsafe fn reset(&mut self, release_resources: bool) { self.raw.reset(release_resources); } /* /// Get a reference to the raw command buffer pub fn as_raw(&self) -> &B::CommandBuffer { &self.raw } /// Get a mutable reference to the raw command buffer pub fn as_raw_mut(&mut self) -> &mut B::CommandBuffer { &mut self.raw }*/ /// Downgrade a command buffer to a lesser capability type. pub unsafe fn downgrade<D>(&mut self) -> &mut CommandBuffer<B, D, S> where C: Supports<D>, { ::std::mem::transmute(self) } } impl<B: Backend, C, S: Shot> CommandBuffer<B, C, S, Primary> { /// Identical to the `RawCommandBuffer` method of the same name. pub unsafe fn execute_commands<'a, I, T, K>(&mut self, cmd_buffers: I) where K: Capability, T: 'a + Submittable<B, K, Secondary>, I: IntoIterator<Item = &'a T>, C: Supports<K>, { self.raw .execute_commands(cmd_buffers.into_iter().map(|cmb| cmb.borrow())); } }