• 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 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