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 pub use super::commands::{ 11 bind_push::UnsafeCommandBufferBuilderBindVertexBuffer, 12 secondary::UnsafeCommandBufferBuilderExecuteCommands, 13 }; 14 use super::{ 15 pool::CommandPoolAlloc, CommandBufferInheritanceInfo, CommandBufferLevel, CommandBufferUsage, 16 }; 17 use crate::{ 18 command_buffer::{ 19 CommandBufferInheritanceRenderPassInfo, CommandBufferInheritanceRenderPassType, 20 CommandBufferInheritanceRenderingInfo, 21 }, 22 device::{Device, DeviceOwned}, 23 query::QueryControlFlags, 24 OomError, VulkanError, VulkanObject, 25 }; 26 use smallvec::SmallVec; 27 use std::{ptr, sync::Arc}; 28 29 /// Command buffer being built. 30 /// 31 /// # Safety 32 /// 33 /// - All submitted commands must be valid and follow the requirements of the Vulkan specification. 34 /// - Any resources used by submitted commands must outlive the returned builder and its created 35 /// command buffer. They must be protected against data races through manual synchronization. 36 /// 37 /// > **Note**: Some checks are still made with `debug_assert!`. Do not expect to be able to 38 /// > submit invalid commands. 39 #[derive(Debug)] 40 pub struct UnsafeCommandBufferBuilder { 41 pub(super) handle: ash::vk::CommandBuffer, 42 pub(super) device: Arc<Device>, 43 usage: CommandBufferUsage, 44 } 45 46 impl UnsafeCommandBufferBuilder { 47 /// Creates a new builder, for recording commands. 48 /// 49 /// # Safety 50 /// 51 /// - `pool_alloc` must outlive the returned builder and its created command buffer. 52 /// - `kind` must match how `pool_alloc` was created. 53 #[inline] new( pool_alloc: &CommandPoolAlloc, begin_info: CommandBufferBeginInfo, ) -> Result<UnsafeCommandBufferBuilder, OomError>54 pub unsafe fn new( 55 pool_alloc: &CommandPoolAlloc, 56 begin_info: CommandBufferBeginInfo, 57 ) -> Result<UnsafeCommandBufferBuilder, OomError> { 58 let CommandBufferBeginInfo { 59 usage, 60 inheritance_info, 61 _ne: _, 62 } = begin_info; 63 64 // VUID-vkBeginCommandBuffer-commandBuffer-00049 65 // Can't validate 66 67 // VUID-vkBeginCommandBuffer-commandBuffer-00050 68 // Can't validate 69 70 let device = pool_alloc.device().clone(); 71 72 // VUID-vkBeginCommandBuffer-commandBuffer-00051 73 debug_assert_eq!( 74 pool_alloc.level() == CommandBufferLevel::Secondary, 75 inheritance_info.is_some() 76 ); 77 78 { 79 // VUID-vkBeginCommandBuffer-commandBuffer-02840 80 // Guaranteed by use of enum 81 let mut flags = ash::vk::CommandBufferUsageFlags::from(usage); 82 let mut inheritance_info_vk = None; 83 let mut inheritance_rendering_info_vk = None; 84 let mut color_attachment_formats_vk: SmallVec<[_; 4]> = SmallVec::new(); 85 86 if let Some(inheritance_info) = &inheritance_info { 87 let &CommandBufferInheritanceInfo { 88 ref render_pass, 89 occlusion_query, 90 query_statistics_flags, 91 _ne: _, 92 } = inheritance_info; 93 94 let inheritance_info_vk = 95 inheritance_info_vk.insert(ash::vk::CommandBufferInheritanceInfo { 96 render_pass: ash::vk::RenderPass::null(), 97 subpass: 0, 98 framebuffer: ash::vk::Framebuffer::null(), 99 occlusion_query_enable: ash::vk::FALSE, 100 query_flags: ash::vk::QueryControlFlags::empty(), 101 pipeline_statistics: query_statistics_flags.into(), 102 ..Default::default() 103 }); 104 105 if let Some(flags) = occlusion_query { 106 inheritance_info_vk.occlusion_query_enable = ash::vk::TRUE; 107 108 if flags.intersects(QueryControlFlags::PRECISE) { 109 inheritance_info_vk.query_flags = ash::vk::QueryControlFlags::PRECISE; 110 } 111 } 112 113 if let Some(render_pass) = render_pass { 114 flags |= ash::vk::CommandBufferUsageFlags::RENDER_PASS_CONTINUE; 115 116 match render_pass { 117 CommandBufferInheritanceRenderPassType::BeginRenderPass( 118 render_pass_info, 119 ) => { 120 let &CommandBufferInheritanceRenderPassInfo { 121 ref subpass, 122 ref framebuffer, 123 } = render_pass_info; 124 125 inheritance_info_vk.render_pass = subpass.render_pass().handle(); 126 inheritance_info_vk.subpass = subpass.index(); 127 inheritance_info_vk.framebuffer = framebuffer 128 .as_ref() 129 .map(|fb| fb.handle()) 130 .unwrap_or_default(); 131 } 132 CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => { 133 let &CommandBufferInheritanceRenderingInfo { 134 view_mask, 135 ref color_attachment_formats, 136 depth_attachment_format, 137 stencil_attachment_format, 138 rasterization_samples, 139 } = rendering_info; 140 141 color_attachment_formats_vk.extend( 142 color_attachment_formats.iter().map(|format| { 143 format.map_or(ash::vk::Format::UNDEFINED, Into::into) 144 }), 145 ); 146 147 let inheritance_rendering_info_vk = inheritance_rendering_info_vk 148 .insert(ash::vk::CommandBufferInheritanceRenderingInfo { 149 flags: ash::vk::RenderingFlags::empty(), 150 view_mask, 151 color_attachment_count: color_attachment_formats_vk.len() 152 as u32, 153 p_color_attachment_formats: color_attachment_formats_vk 154 .as_ptr(), 155 depth_attachment_format: depth_attachment_format 156 .map_or(ash::vk::Format::UNDEFINED, Into::into), 157 stencil_attachment_format: stencil_attachment_format 158 .map_or(ash::vk::Format::UNDEFINED, Into::into), 159 rasterization_samples: rasterization_samples.into(), 160 ..Default::default() 161 }); 162 163 inheritance_info_vk.p_next = 164 inheritance_rendering_info_vk as *const _ as *const _; 165 } 166 } 167 } 168 } 169 170 let begin_info_vk = ash::vk::CommandBufferBeginInfo { 171 flags, 172 p_inheritance_info: inheritance_info_vk 173 .as_ref() 174 .map_or(ptr::null(), |info| info), 175 ..Default::default() 176 }; 177 178 let fns = device.fns(); 179 180 (fns.v1_0.begin_command_buffer)(pool_alloc.handle(), &begin_info_vk) 181 .result() 182 .map_err(VulkanError::from)?; 183 } 184 185 Ok(UnsafeCommandBufferBuilder { 186 handle: pool_alloc.handle(), 187 device, 188 usage, 189 }) 190 } 191 192 /// Turns the builder into an actual command buffer. 193 #[inline] build(self) -> Result<UnsafeCommandBuffer, OomError>194 pub fn build(self) -> Result<UnsafeCommandBuffer, OomError> { 195 unsafe { 196 let fns = self.device.fns(); 197 (fns.v1_0.end_command_buffer)(self.handle) 198 .result() 199 .map_err(VulkanError::from)?; 200 201 Ok(UnsafeCommandBuffer { 202 command_buffer: self.handle, 203 device: self.device.clone(), 204 usage: self.usage, 205 }) 206 } 207 } 208 } 209 210 unsafe impl VulkanObject for UnsafeCommandBufferBuilder { 211 type Handle = ash::vk::CommandBuffer; 212 213 #[inline] handle(&self) -> Self::Handle214 fn handle(&self) -> Self::Handle { 215 self.handle 216 } 217 } 218 219 unsafe impl DeviceOwned for UnsafeCommandBufferBuilder { 220 #[inline] device(&self) -> &Arc<Device>221 fn device(&self) -> &Arc<Device> { 222 &self.device 223 } 224 } 225 226 /// Parameters to begin recording a command buffer. 227 #[derive(Clone, Debug)] 228 pub struct CommandBufferBeginInfo { 229 /// How the command buffer will be used. 230 /// 231 /// The default value is [`CommandBufferUsage::MultipleSubmit`]. 232 pub usage: CommandBufferUsage, 233 234 /// For a secondary command buffer, this must be `Some`, containing the context that will be 235 /// inherited from the primary command buffer. For a primary command buffer, this must be 236 /// `None`. 237 /// 238 /// The default value is `None`. 239 pub inheritance_info: Option<CommandBufferInheritanceInfo>, 240 241 pub _ne: crate::NonExhaustive, 242 } 243 244 impl Default for CommandBufferBeginInfo { 245 #[inline] default() -> Self246 fn default() -> Self { 247 Self { 248 usage: CommandBufferUsage::MultipleSubmit, 249 inheritance_info: None, 250 _ne: crate::NonExhaustive(()), 251 } 252 } 253 } 254 255 /// Command buffer that has been built. 256 /// 257 /// # Safety 258 /// 259 /// The command buffer must not outlive the command pool that it was created from, 260 /// nor the resources used by the recorded commands. 261 #[derive(Debug)] 262 pub struct UnsafeCommandBuffer { 263 command_buffer: ash::vk::CommandBuffer, 264 device: Arc<Device>, 265 usage: CommandBufferUsage, 266 } 267 268 impl UnsafeCommandBuffer { 269 #[inline] usage(&self) -> CommandBufferUsage270 pub fn usage(&self) -> CommandBufferUsage { 271 self.usage 272 } 273 } 274 275 unsafe impl DeviceOwned for UnsafeCommandBuffer { 276 #[inline] device(&self) -> &Arc<Device>277 fn device(&self) -> &Arc<Device> { 278 &self.device 279 } 280 } 281 282 unsafe impl VulkanObject for UnsafeCommandBuffer { 283 type Handle = ash::vk::CommandBuffer; 284 285 #[inline] handle(&self) -> Self::Handle286 fn handle(&self) -> Self::Handle { 287 self.command_buffer 288 } 289 } 290