Skip to main content

vulkano/command_buffer/
mod.rs

1//! Recording commands to execute on the device.
2//!
3//! With Vulkan, to get the device to perform work, even relatively simple tasks, you must create a
4//! command buffer. A command buffer is a list of commands that will executed by the device.
5//! You must first record commands to a recording command buffer, then end the recording to turn it
6//! into an actual command buffer, and then it can be used. Depending on how a command buffer is
7//! created, it can be used only once, or reused many times.
8//!
9//! # Command pools and allocators
10//!
11//! Command buffers are allocated from *command pools*. A command pool holds memory that is used to
12//! record the sequence of commands in a command buffer. Command pools are not thread-safe, and
13//! therefore commands cannot be recorded to a single command buffer from multiple threads at a
14//! time.
15//!
16//! Raw command pools are unsafe to use, so Vulkano uses [command buffer allocators] to manage
17//! command buffers and pools, to ensure their memory is used efficiently, and to protect against
18//! invalid usage. Vulkano provides the [`StandardCommandBufferAllocator`] for this purpose, but
19//! you can also create your own by implementing the [`CommandBufferAllocator`] trait.
20//!
21//! # Primary and secondary command buffers
22//!
23//! There are two levels of command buffers:
24//!
25//! - A primary command buffer can be executed on a queue, and is the main command buffer level. It
26//!   cannot be executed within another command buffer.
27//! - A secondary command buffer can only be executed within a primary command buffer, not directly
28//!   on a queue.
29//!
30//! Using secondary command buffers, there is slightly more overhead than using primary command
31//! buffers alone, but there are also advantages. A single command buffer cannot be recorded
32//! from multiple threads at a time, so if you want to divide the recording work among several
33//! threads, each thread must record its own command buffer. While it is possible for these to be
34//! all primary command buffers, there are limitations: a render pass or query cannot span multiple
35//! primary command buffers, while secondary command buffers can [inherit] this state from their
36//! parent primary command buffer. Therefore, to have a single render pass or query that is shared
37//! across all the command buffers, you must record secondary command buffers.
38//!
39//! # Recording a command buffer
40//!
41//! To record a new command buffer, the most direct way is to create a new
42//! [`AutoCommandBufferBuilder`]. You can then call methods on this object to record new commands
43//! to the command buffer. When you are done recording, you call [`build`] to finalise the command
44//! buffer and turn it into either a [`PrimaryAutoCommandBuffer`] or a
45//! [`SecondaryAutoCommandBuffer`].
46//!
47//! # Submitting a primary command buffer
48//!
49//! Once a primary command buffer is recorded and built, you can submit the
50//! [`PrimaryAutoCommandBuffer`] to a queue. Submitting a command buffer returns an object that
51//! implements the [`GpuFuture`] trait and that represents the moment when the execution will end
52//! on the GPU.
53//!
54//! ```
55//! use vulkano::command_buffer::{
56//!     AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBufferAbstract,
57//!     SubpassContents,
58//! };
59//!
60//! # let device: std::sync::Arc<vulkano::device::Device> = return;
61//! # let queue: std::sync::Arc<vulkano::device::Queue> = return;
62//! # let vertex_buffer: vulkano::buffer::Subbuffer<[u32]> = return;
63//! # let render_pass_begin_info: vulkano::command_buffer::RenderPassBeginInfo = return;
64//! # let graphics_pipeline: std::sync::Arc<vulkano::pipeline::graphics::GraphicsPipeline> = return;
65//! # let command_buffer_allocator: std::sync::Arc<vulkano::command_buffer::allocator::StandardCommandBufferAllocator> = return;
66//! #
67//! let mut cb = AutoCommandBufferBuilder::primary(
68//!     command_buffer_allocator.clone(),
69//!     queue.queue_family_index(),
70//!     CommandBufferUsage::OneTimeSubmit,
71//! )
72//! .unwrap();
73//!
74//! cb.begin_render_pass(render_pass_begin_info, Default::default())
75//!     .unwrap()
76//!     .bind_pipeline_graphics(graphics_pipeline.clone())
77//!     .unwrap()
78//!     .bind_vertex_buffers(0, vertex_buffer.clone())
79//!     .unwrap();
80//! unsafe { cb.draw(vertex_buffer.len() as u32, 1, 0, 0) }.unwrap();
81//!
82//! cb.end_render_pass(Default::default()).unwrap();
83//!
84//! let cb = cb.build().unwrap();
85//!
86//! let future = cb.execute(queue.clone());
87//! ```
88//!
89//! [`StandardCommandBufferAllocator`]: allocator::StandardCommandBufferAllocator
90//! [`CommandBufferAllocator`]: allocator::CommandBufferAllocator
91//! [inherit]: CommandBufferInheritanceInfo
92//! [`build`]: AutoCommandBufferBuilder::build
93//! [`GpuFuture`]: crate::sync::GpuFuture
94
95#[allow(unused_imports)] // everything is exported for future-proofing
96pub use self::commands::{
97    acceleration_structure::*, clear::*, copy::*, debug::*, dynamic_state::*, pipeline::*,
98    query::*, render_pass::*, secondary::*, sync::*,
99};
100pub use self::{
101    auto::{AutoCommandBufferBuilder, PrimaryAutoCommandBuffer, SecondaryAutoCommandBuffer},
102    sys::{CommandBuffer, CommandBufferBeginInfo, RecordingCommandBuffer},
103    traits::{
104        CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract,
105        SecondaryCommandBufferAbstract,
106    },
107};
108use crate::{
109    buffer::{Buffer, Subbuffer},
110    device::{Device, DeviceOwned},
111    format::{Format, FormatFeatures},
112    image::{Image, ImageAspects, ImageLayout, ImageSubresourceRange, SampleCount},
113    macros::vulkan_enum,
114    query::{QueryControlFlags, QueryPipelineStatisticFlags},
115    range_map::RangeMap,
116    render_pass::{Framebuffer, Subpass},
117    sync::{
118        semaphore::{Semaphore, SemaphoreType},
119        PipelineStageAccessFlags, PipelineStages,
120    },
121    DeviceSize, Requires, RequiresAllOf, RequiresOneOf, ValidationError, VulkanObject,
122};
123#[cfg(doc)]
124use crate::{
125    device::{DeviceFeatures, DeviceProperties},
126    pipeline::graphics::vertex_input::VertexInputRate,
127};
128use bytemuck::{Pod, Zeroable};
129use foldhash::HashMap;
130use smallvec::SmallVec;
131use std::{ops::Range, sync::Arc};
132
133pub mod allocator;
134pub mod auto;
135mod commands;
136pub mod pool;
137mod sys;
138mod traits;
139
140/// Used as buffer contents to provide input for the
141/// [`AutoCommandBufferBuilder::dispatch_indirect`] command.
142///
143/// # Safety
144///
145/// - The `x`, `y` and `z` values must not be greater than the respective elements of the
146///   [`max_compute_work_group_count`](DeviceProperties::max_compute_work_group_count) device
147///   limit.
148#[repr(C)]
149#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
150pub struct DispatchIndirectCommand {
151    pub x: u32,
152    pub y: u32,
153    pub z: u32,
154}
155
156/// Used as buffer contents to provide input for the
157/// [`AutoCommandBufferBuilder::draw_indirect`] command.
158///
159/// # Safety
160///
161/// - Every vertex number within the specified range must fall within the range of the bound
162///   vertex-rate vertex buffers.
163/// - Every instance number within the specified range must fall within the range of the bound
164///   instance-rate vertex buffers.
165/// - If the [`draw_indirect_first_instance`](DeviceFeatures::draw_indirect_first_instance) feature
166///   is not enabled, then `first_instance` must be `0`.
167/// - If an [instance divisor](VertexInputRate::Instance) other than 1 is used, and the
168///   [`supports_non_zero_first_instance`](DeviceProperties::supports_non_zero_first_instance)
169///   device property is `false`, then `first_instance` must be `0`.
170#[repr(C)]
171#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
172pub struct DrawIndirectCommand {
173    pub vertex_count: u32,
174    pub instance_count: u32,
175    pub first_vertex: u32,
176    pub first_instance: u32,
177}
178
179/// Used as buffer contents to provide input for the
180/// [`AutoCommandBufferBuilder::draw_mesh_tasks_indirect`] command.
181///
182/// # Safety
183///
184/// - If the graphics pipeline **does not** include a task shader, then the `group_count_x`,
185///   `group_count_y` and `group_count_z` values must not be greater than the respective elements
186///   of the [`max_mesh_work_group_count`](DeviceProperties::max_mesh_work_group_count) device
187///   limit, and the product of these three values must not be greater than the
188///   [`max_mesh_work_group_total_count`](DeviceProperties::max_mesh_work_group_total_count) device
189///   limit.
190/// - If the graphics pipeline **does** include a task shader, then the `group_count_x`,
191///   `group_count_y` and `group_count_z` values must not be greater than the respective elements
192///   of the [`max_task_work_group_count`](DeviceProperties::max_task_work_group_count) device
193///   limit, and the product of these three values must not be greater than the
194///   [`max_task_work_group_total_count`](DeviceProperties::max_task_work_group_total_count) device
195///   limit.
196#[repr(C)]
197#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
198pub struct DrawMeshTasksIndirectCommand {
199    pub group_count_x: u32,
200    pub group_count_y: u32,
201    pub group_count_z: u32,
202}
203
204/// Used as buffer contents to provide input for the
205/// [`AutoCommandBufferBuilder::draw_indexed_indirect`] command.
206///
207/// # Safety
208///
209/// - Every index within the specified range must fall within the range of the bound index buffer.
210/// - Every vertex number that is retrieved from the index buffer must fall within the range of the
211///   bound vertex-rate vertex buffers.
212/// - Every vertex number that is retrieved from the index buffer, if it is not the special
213///   primitive restart value, must be no greater than the
214///   [`max_draw_indexed_index_value`](DeviceProperties::max_draw_indexed_index_value) device
215///   limit.
216/// - Every instance number within the specified range must fall within the range of the bound
217///   instance-rate vertex buffers.
218/// - If the [`draw_indirect_first_instance`](DeviceFeatures::draw_indirect_first_instance) feature
219///   is not enabled, then `first_instance` must be `0`.
220/// - If an [instance divisor](VertexInputRate::Instance) other than 1 is used, and the
221///   [`supports_non_zero_first_instance`](DeviceProperties::supports_non_zero_first_instance)
222///   device property is `false`, then `first_instance` must be `0`.
223#[repr(C)]
224#[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
225pub struct DrawIndexedIndirectCommand {
226    pub index_count: u32,
227    pub instance_count: u32,
228    pub first_index: u32,
229    pub vertex_offset: u32,
230    pub first_instance: u32,
231}
232
233vulkan_enum! {
234    #[non_exhaustive]
235
236    /// Describes what a subpass in a command buffer will contain.
237    SubpassContents = SubpassContents(i32);
238
239    /// The subpass will only directly contain commands.
240    Inline = INLINE,
241
242    /// The subpass will only contain secondary command buffers invocations.
243    SecondaryCommandBuffers = SECONDARY_COMMAND_BUFFERS,
244}
245
246impl From<SubpassContents> for ash::vk::RenderingFlags {
247    #[inline]
248    fn from(val: SubpassContents) -> Self {
249        match val {
250            SubpassContents::Inline => Self::empty(),
251            SubpassContents::SecondaryCommandBuffers => Self::CONTENTS_SECONDARY_COMMAND_BUFFERS,
252        }
253    }
254}
255
256vulkan_enum! {
257    /// Determines the kind of command buffer to create.
258    CommandBufferLevel = CommandBufferLevel(i32);
259
260    /// Primary command buffers can be executed on a queue, and can call secondary command buffers.
261    /// Render passes must begin and end within the same primary command buffer.
262    Primary = PRIMARY,
263
264    /// Secondary command buffers cannot be executed on a queue, but can be executed by a primary
265    /// command buffer. If created for a render pass, they must fit within a single render subpass.
266    Secondary = SECONDARY,
267}
268
269/// The context that a secondary command buffer can inherit from the primary command
270/// buffer it's executed in.
271#[derive(Clone, Debug)]
272pub struct CommandBufferInheritanceInfo {
273    /// If `Some`, the secondary command buffer is required to be executed within a render pass
274    /// instance, and can only call draw operations.
275    /// If `None`, it must be executed outside a render pass instance, and can execute dispatch and
276    /// transfer operations, but not drawing operations.
277    ///
278    /// The default value is `None`.
279    pub render_pass: Option<CommandBufferInheritanceRenderPassType>,
280
281    /// If `Some`, the secondary command buffer is allowed to be executed within a primary that has
282    /// an occlusion query active. The inner `QueryControlFlags` specifies which flags the
283    /// active occlusion is allowed to have enabled.
284    /// If `None`, the primary command buffer cannot have an occlusion query active when this
285    /// secondary command buffer is executed.
286    ///
287    /// The `inherited_queries` feature must be enabled if this is `Some`.
288    ///
289    /// The default value is `None`.
290    pub occlusion_query: Option<QueryControlFlags>,
291
292    /// Which `PipelineStatistics` queries are allowed to be active on the primary command buffer
293    /// when this secondary command buffer is executed.
294    ///
295    /// If this value is not empty, the [`pipeline_statistics_query`] feature must be enabled on
296    /// the device.
297    ///
298    /// The default value is [`QueryPipelineStatisticFlags::empty()`].
299    ///
300    /// [`pipeline_statistics_query`]: crate::device::DeviceFeatures::pipeline_statistics_query
301    pub pipeline_statistics: QueryPipelineStatisticFlags,
302
303    pub _ne: crate::NonExhaustive,
304}
305
306impl Default for CommandBufferInheritanceInfo {
307    #[inline]
308    fn default() -> Self {
309        Self {
310            render_pass: None,
311            occlusion_query: None,
312            pipeline_statistics: QueryPipelineStatisticFlags::empty(),
313            _ne: crate::NonExhaustive(()),
314        }
315    }
316}
317
318impl CommandBufferInheritanceInfo {
319    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
320        let &Self {
321            ref render_pass,
322            occlusion_query,
323            pipeline_statistics,
324            _ne: _,
325        } = self;
326
327        if let Some(render_pass) = render_pass {
328            // VUID-VkCommandBufferBeginInfo-flags-06000
329            // VUID-VkCommandBufferBeginInfo-flags-06002
330            // Ensured by the definition of the `CommandBufferInheritanceRenderPassType` enum.
331
332            match render_pass {
333                CommandBufferInheritanceRenderPassType::BeginRenderPass(render_pass_info) => {
334                    render_pass_info
335                        .validate(device)
336                        .map_err(|err| err.add_context("render_pass"))?;
337                }
338                CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
339                    rendering_info
340                        .validate(device)
341                        .map_err(|err| err.add_context("render_pass"))?;
342                }
343            }
344        }
345
346        if let Some(control_flags) = occlusion_query {
347            control_flags.validate_device(device).map_err(|err| {
348                err.add_context("occlusion_query")
349                    .set_vuids(&["VUID-VkCommandBufferInheritanceInfo-queryFlags-00057"])
350            })?;
351
352            if !device.enabled_features().inherited_queries {
353                return Err(Box::new(ValidationError {
354                    context: "occlusion_query".into(),
355                    problem: "is `Some`".into(),
356                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
357                        "inherited_queries",
358                    )])]),
359                    vuids: &["VUID-VkCommandBufferInheritanceInfo-occlusionQueryEnable-00056"],
360                }));
361            }
362
363            if control_flags.intersects(QueryControlFlags::PRECISE)
364                && !device.enabled_features().occlusion_query_precise
365            {
366                return Err(Box::new(ValidationError {
367                    context: "occlusion_query".into(),
368                    problem: "contains `QueryControlFlags::PRECISE`".into(),
369                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
370                        "occlusion_query_precise",
371                    )])]),
372                    vuids: &["VUID-vkBeginCommandBuffer-commandBuffer-00052"],
373                }));
374            }
375        }
376
377        pipeline_statistics.validate_device(device).map_err(|err| {
378            err.add_context("pipeline_statistics")
379                .set_vuids(&["VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-02789"])
380        })?;
381
382        if pipeline_statistics.count() > 0 && !device.enabled_features().pipeline_statistics_query {
383            return Err(Box::new(ValidationError {
384                context: "pipeline_statistics".into(),
385                problem: "is not empty".into(),
386                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
387                    "pipeline_statistics_query",
388                )])]),
389                vuids: &["VUID-VkCommandBufferInheritanceInfo-pipelineStatistics-00058"],
390            }));
391        }
392
393        Ok(())
394    }
395
396    pub(crate) fn to_vk<'a>(
397        &self,
398        extensions_vk: &'a mut CommandBufferInheritanceInfoExtensionsVk<'_>,
399    ) -> ash::vk::CommandBufferInheritanceInfo<'a> {
400        let &Self {
401            ref render_pass,
402            occlusion_query,
403            pipeline_statistics,
404            _ne: _,
405        } = self;
406
407        let (render_pass_vk, subpass_vk, framebuffer_vk) = render_pass
408            .as_ref()
409            .and_then(|render_pass| match render_pass {
410                CommandBufferInheritanceRenderPassType::BeginRenderPass(render_pass_info) => {
411                    let &CommandBufferInheritanceRenderPassInfo {
412                        ref subpass,
413                        ref framebuffer,
414                    } = render_pass_info;
415
416                    Some((
417                        subpass.render_pass().handle(),
418                        subpass.index(),
419                        framebuffer
420                            .as_ref()
421                            .map(|fb| fb.handle())
422                            .unwrap_or_default(),
423                    ))
424                }
425                CommandBufferInheritanceRenderPassType::BeginRendering(_) => None,
426            })
427            .unwrap_or_default();
428
429        let (occlusion_query_enable, query_flags_vk) = occlusion_query
430            .map(|flags| (true, flags.into()))
431            .unwrap_or_default();
432
433        let mut val_vk = ash::vk::CommandBufferInheritanceInfo::default()
434            .render_pass(render_pass_vk)
435            .subpass(subpass_vk)
436            .framebuffer(framebuffer_vk)
437            .occlusion_query_enable(occlusion_query_enable)
438            .query_flags(query_flags_vk)
439            .pipeline_statistics(pipeline_statistics.into());
440
441        let CommandBufferInheritanceInfoExtensionsVk {
442            rendering_info_vk: rendering_vk,
443        } = extensions_vk;
444
445        if let Some(next) = rendering_vk {
446            val_vk = val_vk.push_next(next);
447        }
448
449        val_vk
450    }
451
452    pub(crate) fn to_vk_extensions<'a>(
453        &self,
454        fields1_vk: &'a CommandBufferInheritanceInfoFields1Vk,
455    ) -> CommandBufferInheritanceInfoExtensionsVk<'a> {
456        let CommandBufferInheritanceInfoFields1Vk {
457            rendering_info_fields1_vk,
458        } = fields1_vk;
459
460        let rendering_info_vk = self
461            .render_pass
462            .as_ref()
463            .zip(rendering_info_fields1_vk.as_ref())
464            .and_then(
465                |(render_pass, rendering_info_fields1_vk)| match render_pass {
466                    CommandBufferInheritanceRenderPassType::BeginRenderPass(_) => None,
467                    CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
468                        Some(rendering_info.to_vk(rendering_info_fields1_vk))
469                    }
470                },
471            );
472
473        CommandBufferInheritanceInfoExtensionsVk { rendering_info_vk }
474    }
475
476    pub(crate) fn to_vk_fields1(&self) -> CommandBufferInheritanceInfoFields1Vk {
477        let rendering_info_fields1_vk =
478            self.render_pass
479                .as_ref()
480                .and_then(|render_pass| match render_pass {
481                    CommandBufferInheritanceRenderPassType::BeginRenderPass(_) => None,
482                    CommandBufferInheritanceRenderPassType::BeginRendering(rendering_info) => {
483                        Some(rendering_info.to_vk_fields1())
484                    }
485                });
486
487        CommandBufferInheritanceInfoFields1Vk {
488            rendering_info_fields1_vk,
489        }
490    }
491}
492
493pub(crate) struct CommandBufferInheritanceInfoExtensionsVk<'a> {
494    pub(crate) rendering_info_vk: Option<ash::vk::CommandBufferInheritanceRenderingInfo<'a>>,
495}
496
497pub(crate) struct CommandBufferInheritanceInfoFields1Vk {
498    pub(crate) rendering_info_fields1_vk: Option<CommandBufferInheritanceRenderingInfoFields1Vk>,
499}
500
501/// Selects the type of render pass for command buffer inheritance.
502#[derive(Clone, Debug)]
503pub enum CommandBufferInheritanceRenderPassType {
504    /// The secondary command buffer will be executed within a render pass begun with
505    /// `begin_render_pass`, using a `RenderPass` object and `Framebuffer`.
506    BeginRenderPass(CommandBufferInheritanceRenderPassInfo),
507
508    /// The secondary command buffer will be executed within a render pass begun with
509    /// `begin_rendering`, using dynamic rendering.
510    BeginRendering(CommandBufferInheritanceRenderingInfo),
511}
512
513impl From<Subpass> for CommandBufferInheritanceRenderPassType {
514    #[inline]
515    fn from(val: Subpass) -> Self {
516        Self::BeginRenderPass(val.into())
517    }
518}
519
520impl From<CommandBufferInheritanceRenderPassInfo> for CommandBufferInheritanceRenderPassType {
521    #[inline]
522    fn from(val: CommandBufferInheritanceRenderPassInfo) -> Self {
523        Self::BeginRenderPass(val)
524    }
525}
526
527impl From<CommandBufferInheritanceRenderingInfo> for CommandBufferInheritanceRenderPassType {
528    #[inline]
529    fn from(val: CommandBufferInheritanceRenderingInfo) -> Self {
530        Self::BeginRendering(val)
531    }
532}
533
534/// The render pass context that a secondary command buffer is created for.
535#[derive(Clone, Debug)]
536pub struct CommandBufferInheritanceRenderPassInfo {
537    /// The render subpass that this secondary command buffer must be executed within.
538    ///
539    /// There is no default value.
540    pub subpass: Subpass,
541
542    /// The framebuffer object that will be used when calling the command buffer.
543    /// This parameter is optional and is an optimization hint for the implementation.
544    ///
545    /// The default value is `None`.
546    pub framebuffer: Option<Arc<Framebuffer>>,
547}
548
549impl CommandBufferInheritanceRenderPassInfo {
550    /// Returns a `CommandBufferInheritanceRenderPassInfo` with the specified `subpass`.
551    #[inline]
552    pub fn subpass(subpass: Subpass) -> Self {
553        Self {
554            subpass,
555            framebuffer: None,
556        }
557    }
558
559    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
560        let &Self {
561            ref subpass,
562            ref framebuffer,
563        } = self;
564
565        // VUID-VkCommandBufferInheritanceInfo-commonparent
566        assert_eq!(device, subpass.render_pass().device().as_ref());
567
568        // VUID-VkCommandBufferBeginInfo-flags-06001
569        // Ensured by how the `Subpass` type is constructed.
570
571        if let Some(framebuffer) = framebuffer {
572            // VUID-VkCommandBufferInheritanceInfo-commonparent
573            assert_eq!(device, framebuffer.device().as_ref());
574
575            if !framebuffer
576                .render_pass()
577                .is_compatible_with(subpass.render_pass())
578            {
579                return Err(Box::new(ValidationError {
580                    problem: "`framebuffer` is not compatible with `subpass.render_pass()`".into(),
581                    vuids: &["VUID-VkCommandBufferBeginInfo-flags-00055"],
582                    ..Default::default()
583                }));
584            }
585        }
586
587        Ok(())
588    }
589}
590
591impl From<Subpass> for CommandBufferInheritanceRenderPassInfo {
592    #[inline]
593    fn from(subpass: Subpass) -> Self {
594        Self {
595            subpass,
596            framebuffer: None,
597        }
598    }
599}
600
601/// The dynamic rendering context that a secondary command buffer is created for.
602#[derive(Clone, Debug)]
603pub struct CommandBufferInheritanceRenderingInfo {
604    /// If not `0`, indicates that multiview rendering will be enabled, and specifies the view
605    /// indices that are rendered to. The value is a bitmask, so that that for example `0b11` will
606    /// draw to the first two views and `0b101` will draw to the first and third view.
607    ///
608    /// If set to a nonzero value, then the [`multiview`] feature must be enabled on the device.
609    ///
610    /// The default value is `0`.
611    ///
612    /// [`multiview`]: crate::device::DeviceFeatures::multiview
613    pub view_mask: u32,
614
615    /// The formats of the color attachments that will be used during rendering.
616    ///
617    /// If an element is `None`, it indicates that the attachment will not be used.
618    ///
619    /// The default value is empty.
620    pub color_attachment_formats: Vec<Option<Format>>,
621
622    /// The format of the depth attachment that will be used during rendering.
623    ///
624    /// If set to `None`, it indicates that no depth attachment will be used.
625    ///
626    /// The default value is `None`.
627    pub depth_attachment_format: Option<Format>,
628
629    /// The format of the stencil attachment that will be used during rendering.
630    ///
631    /// If set to `None`, it indicates that no stencil attachment will be used.
632    ///
633    /// The default value is `None`.
634    pub stencil_attachment_format: Option<Format>,
635
636    /// The number of samples that the color, depth and stencil attachments will have.
637    ///
638    /// The default value is [`SampleCount::Sample1`]
639    pub rasterization_samples: SampleCount,
640}
641
642impl Default for CommandBufferInheritanceRenderingInfo {
643    #[inline]
644    fn default() -> Self {
645        Self {
646            view_mask: 0,
647            color_attachment_formats: Vec::new(),
648            depth_attachment_format: None,
649            stencil_attachment_format: None,
650            rasterization_samples: SampleCount::Sample1,
651        }
652    }
653}
654
655impl CommandBufferInheritanceRenderingInfo {
656    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
657        let &Self {
658            view_mask,
659            ref color_attachment_formats,
660            depth_attachment_format,
661            stencil_attachment_format,
662            rasterization_samples,
663        } = self;
664
665        let properties = device.physical_device().properties();
666
667        if view_mask != 0 && !device.enabled_features().multiview {
668            return Err(Box::new(ValidationError {
669                context: "view_mask".into(),
670                problem: "is not zero".into(),
671                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
672                    "multiview",
673                )])]),
674                vuids: &["VUID-VkCommandBufferInheritanceRenderingInfo-multiview-06008"],
675            }));
676        }
677
678        let view_count = u32::BITS - view_mask.leading_zeros();
679
680        if view_count > properties.max_multiview_view_count.unwrap_or(0) {
681            return Err(Box::new(ValidationError {
682                context: "view_mask".into(),
683                problem: "the number of views exceeds the \
684                    `max_multiview_view_count` limit"
685                    .into(),
686                vuids: &["VUID-VkCommandBufferInheritanceRenderingInfo-viewMask-06009"],
687                ..Default::default()
688            }));
689        }
690
691        for (index, format) in color_attachment_formats
692            .iter()
693            .enumerate()
694            .flat_map(|(i, f)| f.map(|f| (i, f)))
695        {
696            format.validate_device(device).map_err(|err| {
697                err.add_context(format!("color_attachment_formats[{}]", index)).set_vuids(
698                    &["VUID-VkCommandBufferInheritanceRenderingInfo-pColorAttachmentFormats-parameter"],
699                )
700            })?;
701
702            if format == Format::UNDEFINED {
703                return Err(Box::new(ValidationError {
704                    context: format!("color_attachment_formats[{}]", index).into(),
705                    problem: "is `Format::UNDEFINED`".into(),
706                    ..Default::default()
707                }));
708            }
709
710            let format_properties =
711                unsafe { device.physical_device().format_properties_unchecked(format) };
712            let potential_format_features = format_properties.potential_format_features();
713
714            if !potential_format_features.intersects(FormatFeatures::COLOR_ATTACHMENT) {
715                return Err(Box::new(ValidationError {
716                    context: format!("color_attachment_formats[{}]", index).into(),
717                    problem: "the potential format features do not contain \
718                        `FormatFeatures::COLOR_ATTACHMENT`".into(),
719                    vuids: &["VUID-VkCommandBufferInheritanceRenderingInfo-pColorAttachmentFormats-06006"],
720                    ..Default::default()
721                }));
722            }
723        }
724
725        if let Some(format) = depth_attachment_format {
726            format.validate_device(device).map_err(|err| {
727                err.add_context("depth_attachment_format").set_vuids(&[
728                    "VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-parameter",
729                ])
730            })?;
731
732            if format == Format::UNDEFINED {
733                return Err(Box::new(ValidationError {
734                    context: "depth_attachment_format".into(),
735                    problem: "is `Format::UNDEFINED`".into(),
736                    ..Default::default()
737                }));
738            }
739
740            if !format.aspects().intersects(ImageAspects::DEPTH) {
741                return Err(Box::new(ValidationError {
742                    context: "depth_attachment_format".into(),
743                    problem: "does not have a depth aspect".into(),
744                    vuids: &[
745                        "VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06540",
746                    ],
747                    ..Default::default()
748                }));
749            }
750
751            let format_properties =
752                unsafe { device.physical_device().format_properties_unchecked(format) };
753            let potential_format_features = format_properties.potential_format_features();
754
755            if !potential_format_features.intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) {
756                return Err(Box::new(ValidationError {
757                    context: "depth_attachment_format".into(),
758                    problem: "the potential format features do not contain \
759                        `FormatFeatures::DEPTH_STENCIL_ATTACHMENT`"
760                        .into(),
761                    vuids: &[
762                        "VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06007",
763                    ],
764                    ..Default::default()
765                }));
766            }
767        }
768
769        if let Some(format) = stencil_attachment_format {
770            format.validate_device(device).map_err(|err| {
771                err.add_context("stencil_attachment_format").set_vuids(&["VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-parameter"])
772            })?;
773
774            if format == Format::UNDEFINED {
775                return Err(Box::new(ValidationError {
776                    context: "stencil_attachment_format".into(),
777                    problem: "is `Format::UNDEFINED`".into(),
778                    ..Default::default()
779                }));
780            }
781
782            if !format.aspects().intersects(ImageAspects::STENCIL) {
783                return Err(Box::new(ValidationError {
784                    context: "stencil_attachment_format".into(),
785                    problem: "does not have a stencil aspect".into(),
786                    vuids: &[
787                        "VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-06541",
788                    ],
789                    ..Default::default()
790                }));
791            }
792
793            let format_properties =
794                unsafe { device.physical_device().format_properties_unchecked(format) };
795            let potential_format_features = format_properties.potential_format_features();
796
797            if !potential_format_features.intersects(FormatFeatures::DEPTH_STENCIL_ATTACHMENT) {
798                return Err(Box::new(ValidationError {
799                    context: "stencil_attachment_format".into(),
800                    problem: "the potential format features do not contain \
801                        `FormatFeatures::DEPTH_STENCIL_ATTACHMENT`"
802                        .into(),
803                    vuids: &[
804                        "VUID-VkCommandBufferInheritanceRenderingInfo-stencilAttachmentFormat-06199",
805                    ],
806                    ..Default::default()
807                }));
808            }
809        }
810
811        if let (Some(depth_format), Some(stencil_format)) =
812            (depth_attachment_format, stencil_attachment_format)
813        {
814            if depth_format != stencil_format {
815                return Err(Box::new(ValidationError {
816                    problem: "`depth_attachment_format` and `stencil_attachment_format` are both \
817                        `Some`, but are not equal"
818                        .into(),
819                    vuids: &[
820                        "VUID-VkCommandBufferInheritanceRenderingInfo-depthAttachmentFormat-06200",
821                    ],
822                    ..Default::default()
823                }));
824            }
825        }
826
827        rasterization_samples
828            .validate_device(device)
829            .map_err(|err| {
830                err.add_context("rasterization_samples").set_vuids(&[
831                    "VUID-VkCommandBufferInheritanceRenderingInfo-rasterizationSamples-parameter",
832                ])
833            })?;
834
835        Ok(())
836    }
837
838    pub(crate) fn to_vk<'a>(
839        &self,
840        fields1_vk: &'a CommandBufferInheritanceRenderingInfoFields1Vk,
841    ) -> ash::vk::CommandBufferInheritanceRenderingInfo<'a> {
842        let &Self {
843            view_mask,
844            color_attachment_formats: _,
845            depth_attachment_format,
846            stencil_attachment_format,
847            rasterization_samples,
848        } = self;
849        let CommandBufferInheritanceRenderingInfoFields1Vk {
850            color_attachment_formats_vk,
851        } = fields1_vk;
852
853        ash::vk::CommandBufferInheritanceRenderingInfo::default()
854            .flags(ash::vk::RenderingFlags::empty())
855            .view_mask(view_mask)
856            .color_attachment_formats(color_attachment_formats_vk)
857            .depth_attachment_format(
858                depth_attachment_format.map_or(ash::vk::Format::UNDEFINED, Into::into),
859            )
860            .stencil_attachment_format(
861                stencil_attachment_format.map_or(ash::vk::Format::UNDEFINED, Into::into),
862            )
863            .rasterization_samples(rasterization_samples.into())
864    }
865
866    pub(crate) fn to_vk_fields1(&self) -> CommandBufferInheritanceRenderingInfoFields1Vk {
867        let Self {
868            color_attachment_formats,
869            ..
870        } = self;
871
872        let color_attachment_formats_vk = color_attachment_formats
873            .iter()
874            .map(|format| format.map_or(ash::vk::Format::UNDEFINED, Into::into))
875            .collect();
876
877        CommandBufferInheritanceRenderingInfoFields1Vk {
878            color_attachment_formats_vk,
879        }
880    }
881}
882
883pub(crate) struct CommandBufferInheritanceRenderingInfoFields1Vk {
884    pub(crate) color_attachment_formats_vk: SmallVec<[ash::vk::Format; 4]>,
885}
886
887/// Usage flags to pass when creating a command buffer.
888///
889/// The safest option is `SimultaneousUse`, but it may be slower than the other two.
890// NOTE: The ordering is important: the variants are listed from least to most permissive!
891#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
892#[repr(u32)]
893pub enum CommandBufferUsage {
894    /// The command buffer can only be submitted once before being destroyed. Any further submit is
895    /// forbidden. This makes it possible for the implementation to perform additional
896    /// optimizations.
897    OneTimeSubmit = ash::vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT.as_raw(),
898
899    /// The command buffer can be used multiple times, but must not execute or record more than
900    /// once simultaneously. In other words, it is as if executing the command buffer borrows
901    /// it mutably.
902    MultipleSubmit = 0,
903
904    /// The command buffer can be executed multiple times in parallel on different queues.
905    /// If it's a secondary command buffer, it can be recorded to multiple primary command buffers
906    /// at once.
907    SimultaneousUse = ash::vk::CommandBufferUsageFlags::SIMULTANEOUS_USE.as_raw(),
908}
909
910impl From<CommandBufferUsage> for ash::vk::CommandBufferUsageFlags {
911    #[inline]
912    fn from(val: CommandBufferUsage) -> Self {
913        Self::from_raw(val as u32)
914    }
915}
916
917/// Parameters to submit command buffers to a queue.
918#[derive(Clone, Debug)]
919pub struct SubmitInfo {
920    /// The semaphores to wait for before beginning the execution of this batch of
921    /// command buffer operations.
922    ///
923    /// The default value is empty.
924    pub wait_semaphores: Vec<SemaphoreSubmitInfo>,
925
926    /// The command buffers to execute.
927    ///
928    /// The default value is empty.
929    pub command_buffers: Vec<CommandBufferSubmitInfo>,
930
931    /// The semaphores to signal after the execution of this batch of command buffer operations
932    /// has completed.
933    ///
934    /// The default value is empty.
935    pub signal_semaphores: Vec<SemaphoreSubmitInfo>,
936
937    pub _ne: crate::NonExhaustive,
938}
939
940impl Default for SubmitInfo {
941    #[inline]
942    fn default() -> Self {
943        Self {
944            wait_semaphores: Vec::new(),
945            command_buffers: Vec::new(),
946            signal_semaphores: Vec::new(),
947            _ne: crate::NonExhaustive(()),
948        }
949    }
950}
951
952impl SubmitInfo {
953    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
954        let &Self {
955            ref wait_semaphores,
956            ref command_buffers,
957            ref signal_semaphores,
958            _ne: _,
959        } = self;
960
961        for (index, semaphore_submit_info) in wait_semaphores.iter().enumerate() {
962            semaphore_submit_info
963                .validate(device)
964                .map_err(|err| err.add_context(format!("wait_semaphores[{}]", index)))?;
965        }
966
967        for (index, command_buffer_submit_info) in command_buffers.iter().enumerate() {
968            command_buffer_submit_info
969                .validate(device)
970                .map_err(|err| err.add_context(format!("command_buffers[{}]", index)))?;
971        }
972
973        for (index, semaphore_submit_info) in signal_semaphores.iter().enumerate() {
974            semaphore_submit_info
975                .validate(device)
976                .map_err(|err| err.add_context(format!("signal_semaphores[{}]", index)))?;
977
978            let &SemaphoreSubmitInfo {
979                semaphore: _,
980                value: _,
981                stages,
982                _ne: _,
983            } = semaphore_submit_info;
984
985            if stages != PipelineStages::ALL_COMMANDS && !device.enabled_features().synchronization2
986            {
987                return Err(Box::new(ValidationError {
988                    context: format!("signal_semaphores[{}].stages", index).into(),
989                    problem: "is not `PipelineStages::ALL_COMMANDS`".into(),
990                    requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
991                        "synchronization2",
992                    )])]),
993                    vuids: &["VUID-vkQueueSubmit2-synchronization2-03866"],
994                }));
995            }
996        }
997
998        // unsafe
999        // VUID-VkSubmitInfo2-semaphore-03882
1000        // VUID-VkSubmitInfo2-semaphore-03883
1001        // VUID-VkSubmitInfo2-semaphore-03884
1002
1003        Ok(())
1004    }
1005
1006    pub(crate) fn to_vk2<'a>(
1007        &self,
1008        fields1_vk: &'a SubmitInfo2Fields1Vk,
1009    ) -> ash::vk::SubmitInfo2<'a> {
1010        let SubmitInfo2Fields1Vk {
1011            wait_semaphore_infos_vk,
1012            command_buffer_infos_vk,
1013            signal_semaphore_infos_vk,
1014        } = fields1_vk;
1015
1016        ash::vk::SubmitInfo2::default()
1017            .flags(ash::vk::SubmitFlags::empty()) // TODO:
1018            .wait_semaphore_infos(wait_semaphore_infos_vk)
1019            .command_buffer_infos(command_buffer_infos_vk)
1020            .signal_semaphore_infos(signal_semaphore_infos_vk)
1021    }
1022
1023    pub(crate) fn to_vk2_fields1(&self) -> SubmitInfo2Fields1Vk {
1024        let &Self {
1025            ref wait_semaphores,
1026            ref command_buffers,
1027            ref signal_semaphores,
1028            _ne: _,
1029        } = self;
1030
1031        SubmitInfo2Fields1Vk {
1032            wait_semaphore_infos_vk: wait_semaphores
1033                .iter()
1034                .map(SemaphoreSubmitInfo::to_vk2)
1035                .collect(),
1036            command_buffer_infos_vk: command_buffers
1037                .iter()
1038                .map(CommandBufferSubmitInfo::to_vk2)
1039                .collect(),
1040            signal_semaphore_infos_vk: signal_semaphores
1041                .iter()
1042                .map(SemaphoreSubmitInfo::to_vk2)
1043                .collect(),
1044        }
1045    }
1046
1047    pub(crate) fn to_vk<'a>(
1048        &self,
1049        fields1_vk: &'a SubmitInfoFields1Vk,
1050        extensions_vk: &'a mut SubmitInfoExtensionsVk<'_>,
1051    ) -> ash::vk::SubmitInfo<'a> {
1052        let SubmitInfoFields1Vk {
1053            wait_semaphores_vk,
1054            wait_dst_stage_mask_vk,
1055            wait_semaphore_values_vk: _,
1056            command_buffers_vk,
1057            signal_semaphores_vk,
1058            signal_semaphore_values_vk: _,
1059        } = fields1_vk;
1060
1061        let mut val_vk = ash::vk::SubmitInfo::default()
1062            .wait_semaphores(wait_semaphores_vk)
1063            .wait_dst_stage_mask(wait_dst_stage_mask_vk)
1064            .command_buffers(command_buffers_vk)
1065            .signal_semaphores(signal_semaphores_vk);
1066
1067        let SubmitInfoExtensionsVk {
1068            timeline_semaphore_vk,
1069        } = extensions_vk;
1070
1071        if let Some(next) = timeline_semaphore_vk {
1072            val_vk = val_vk.push_next(next);
1073        }
1074
1075        val_vk
1076    }
1077
1078    pub(crate) fn to_vk_extensions<'a>(
1079        &self,
1080        fields1_vk: &'a SubmitInfoFields1Vk,
1081    ) -> SubmitInfoExtensionsVk<'a> {
1082        let Self {
1083            wait_semaphores,
1084            command_buffers: _,
1085            signal_semaphores,
1086            _ne: _,
1087        } = self;
1088        let SubmitInfoFields1Vk {
1089            wait_semaphores_vk: _,
1090            wait_dst_stage_mask_vk: _,
1091            command_buffers_vk: _,
1092            signal_semaphores_vk: _,
1093            wait_semaphore_values_vk,
1094            signal_semaphore_values_vk,
1095        } = fields1_vk;
1096
1097        let timeline_semaphore_vk = (wait_semaphores.iter())
1098            .chain(signal_semaphores.iter())
1099            .any(|semaphore_submit_info| {
1100                semaphore_submit_info.semaphore.semaphore_type() == SemaphoreType::Timeline
1101            })
1102            .then(|| {
1103                ash::vk::TimelineSemaphoreSubmitInfo::default()
1104                    .wait_semaphore_values(wait_semaphore_values_vk)
1105                    .signal_semaphore_values(signal_semaphore_values_vk)
1106            });
1107
1108        SubmitInfoExtensionsVk {
1109            timeline_semaphore_vk,
1110        }
1111    }
1112
1113    pub(crate) fn to_vk_fields1(&self) -> SubmitInfoFields1Vk {
1114        let Self {
1115            wait_semaphores,
1116            command_buffers,
1117            signal_semaphores,
1118            _ne: _,
1119        } = self;
1120
1121        let mut wait_semaphores_vk = SmallVec::with_capacity(wait_semaphores.len());
1122        let mut wait_dst_stage_mask_vk = SmallVec::with_capacity(wait_semaphores.len());
1123        let mut wait_semaphore_values_vk = SmallVec::with_capacity(wait_semaphores.len());
1124
1125        for semaphore_submit_info in wait_semaphores {
1126            let &SemaphoreSubmitInfo {
1127                ref semaphore,
1128                value,
1129                stages,
1130                _ne: _,
1131            } = semaphore_submit_info;
1132
1133            wait_semaphores_vk.push(semaphore.handle());
1134            wait_dst_stage_mask_vk.push(stages.into());
1135            wait_semaphore_values_vk.push(value);
1136        }
1137
1138        let command_buffers_vk = command_buffers
1139            .iter()
1140            .map(CommandBufferSubmitInfo::to_vk)
1141            .collect();
1142
1143        let mut signal_semaphores_vk = SmallVec::with_capacity(signal_semaphores.len());
1144        let mut signal_semaphore_values_vk = SmallVec::with_capacity(signal_semaphores.len());
1145
1146        for semaphore_submit_info in signal_semaphores {
1147            let &SemaphoreSubmitInfo {
1148                ref semaphore,
1149                value,
1150                stages: _,
1151                _ne: _,
1152            } = semaphore_submit_info;
1153
1154            signal_semaphores_vk.push(semaphore.handle());
1155            signal_semaphore_values_vk.push(value);
1156        }
1157
1158        SubmitInfoFields1Vk {
1159            wait_semaphores_vk,
1160            wait_dst_stage_mask_vk,
1161            wait_semaphore_values_vk,
1162            command_buffers_vk,
1163            signal_semaphores_vk,
1164            signal_semaphore_values_vk,
1165        }
1166    }
1167}
1168
1169pub(crate) struct SubmitInfo2Fields1Vk {
1170    pub(crate) wait_semaphore_infos_vk: SmallVec<[ash::vk::SemaphoreSubmitInfo<'static>; 4]>,
1171    pub(crate) command_buffer_infos_vk: SmallVec<[ash::vk::CommandBufferSubmitInfo<'static>; 4]>,
1172    pub(crate) signal_semaphore_infos_vk: SmallVec<[ash::vk::SemaphoreSubmitInfo<'static>; 4]>,
1173}
1174
1175pub(crate) struct SubmitInfoExtensionsVk<'a> {
1176    pub(crate) timeline_semaphore_vk: Option<ash::vk::TimelineSemaphoreSubmitInfo<'a>>,
1177}
1178
1179pub(crate) struct SubmitInfoFields1Vk {
1180    pub(crate) wait_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
1181    pub(crate) wait_dst_stage_mask_vk: SmallVec<[ash::vk::PipelineStageFlags; 4]>,
1182    pub(crate) wait_semaphore_values_vk: SmallVec<[u64; 4]>,
1183    pub(crate) command_buffers_vk: SmallVec<[ash::vk::CommandBuffer; 4]>,
1184    pub(crate) signal_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
1185    pub(crate) signal_semaphore_values_vk: SmallVec<[u64; 4]>,
1186}
1187
1188/// Parameters for a command buffer in a queue submit operation.
1189#[derive(Clone, Debug)]
1190pub struct CommandBufferSubmitInfo {
1191    /// The command buffer to execute.
1192    ///
1193    /// There is no default value.
1194    pub command_buffer: Arc<dyn PrimaryCommandBufferAbstract>,
1195
1196    pub _ne: crate::NonExhaustive,
1197}
1198
1199impl CommandBufferSubmitInfo {
1200    /// Returns a `CommandBufferSubmitInfo` with the specified `command_buffer`.
1201    #[inline]
1202    pub fn new(command_buffer: Arc<dyn PrimaryCommandBufferAbstract>) -> Self {
1203        Self {
1204            command_buffer,
1205            _ne: crate::NonExhaustive(()),
1206        }
1207    }
1208
1209    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1210        let &Self {
1211            ref command_buffer,
1212            _ne: _,
1213        } = self;
1214
1215        // VUID?
1216        assert_eq!(device, command_buffer.device().as_ref());
1217
1218        Ok(())
1219    }
1220
1221    pub(crate) fn to_vk2(&self) -> ash::vk::CommandBufferSubmitInfo<'static> {
1222        let &Self {
1223            ref command_buffer,
1224            _ne: _,
1225        } = self;
1226
1227        ash::vk::CommandBufferSubmitInfo::default()
1228            .command_buffer(command_buffer.handle())
1229            .device_mask(0) // TODO:
1230    }
1231
1232    pub(crate) fn to_vk(&self) -> ash::vk::CommandBuffer {
1233        let &Self {
1234            ref command_buffer,
1235            _ne: _,
1236        } = self;
1237
1238        command_buffer.handle()
1239    }
1240}
1241
1242/// Parameters for a semaphore signal or wait operation in a queue submit operation.
1243#[derive(Clone, Debug)]
1244pub struct SemaphoreSubmitInfo {
1245    /// The semaphore to signal or wait for.
1246    ///
1247    /// There is no default value.
1248    pub semaphore: Arc<Semaphore>,
1249
1250    /// If `semaphore.semaphore_type()` is [`SemaphoreType::Timeline`], specifies the value that
1251    /// will be used for the semaphore operation:
1252    /// - If it's a signal operation, then the semaphore's value will be set to this value when it
1253    ///   is signaled.
1254    /// - If it's a wait operation, then the semaphore will wait until its value is greater than or
1255    ///   equal to this value.
1256    ///
1257    /// If `semaphore.semaphore_type()` is [`SemaphoreType::Binary`], then this must be `0`.
1258    ///
1259    /// The default value is `0`.
1260    pub value: u64,
1261
1262    /// For a semaphore wait operation, specifies the pipeline stages in the second synchronization
1263    /// scope: stages of queue operations following the wait operation that can start executing
1264    /// after the semaphore is signalled.
1265    ///
1266    /// For a semaphore signal operation, specifies the pipeline stages in the first
1267    /// synchronization scope: stages of queue operations preceding the signal operation that
1268    /// must complete before the semaphore is signalled.
1269    /// If this value does not equal [`ALL_COMMANDS`], then the [`synchronization2`] feature must
1270    /// be enabled on the device.
1271    ///
1272    /// The default value is [`ALL_COMMANDS`].
1273    ///
1274    /// [`ALL_COMMANDS`]: PipelineStages::ALL_COMMANDS
1275    /// [`synchronization2`]: crate::device::DeviceFeatures::synchronization2
1276    pub stages: PipelineStages,
1277
1278    pub _ne: crate::NonExhaustive,
1279}
1280
1281impl SemaphoreSubmitInfo {
1282    /// Returns a `SemaphoreSubmitInfo` with the specified `semaphore`.
1283    #[inline]
1284    pub fn new(semaphore: Arc<Semaphore>) -> Self {
1285        Self {
1286            semaphore,
1287            value: 0,
1288            stages: PipelineStages::ALL_COMMANDS,
1289            _ne: crate::NonExhaustive(()),
1290        }
1291    }
1292
1293    pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
1294        let &Self {
1295            ref semaphore,
1296            value,
1297            stages,
1298            _ne: _,
1299        } = self;
1300
1301        // VUID?
1302        assert_eq!(device, semaphore.device().as_ref());
1303
1304        match semaphore.semaphore_type() {
1305            SemaphoreType::Binary => {
1306                if value != 0 {
1307                    return Err(Box::new(ValidationError {
1308                        problem: "`semaphore.semaphore_type()` is `SemaphoreType::Binary`, but \
1309                            `value` is not `0`"
1310                            .into(),
1311                        ..Default::default()
1312                    }));
1313                }
1314            }
1315            SemaphoreType::Timeline => {}
1316        }
1317
1318        stages.validate_device(device).map_err(|err| {
1319            err.add_context("stages")
1320                .set_vuids(&["VUID-VkSemaphoreSubmitInfo-stageMask-parameter"])
1321        })?;
1322
1323        if !device.enabled_features().synchronization2 && stages.contains_flags2() {
1324            return Err(Box::new(ValidationError {
1325                context: "stages".into(),
1326                problem: "contains flags from `VkPipelineStageFlagBits2`".into(),
1327                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1328                    "synchronization2",
1329                )])]),
1330                ..Default::default()
1331            }));
1332        }
1333
1334        if !device.enabled_features().geometry_shader
1335            && stages.intersects(PipelineStages::GEOMETRY_SHADER)
1336        {
1337            return Err(Box::new(ValidationError {
1338                context: "stages".into(),
1339                problem: "contains `PipelineStages::GEOMETRY_SHADER`".into(),
1340                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1341                    "geometry_shader",
1342                )])]),
1343                vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03929"],
1344            }));
1345        }
1346
1347        if !device.enabled_features().tessellation_shader
1348            && stages.intersects(
1349                PipelineStages::TESSELLATION_CONTROL_SHADER
1350                    | PipelineStages::TESSELLATION_EVALUATION_SHADER,
1351            )
1352        {
1353            return Err(Box::new(ValidationError {
1354                context: "stages".into(),
1355                problem: "contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
1356                    `PipelineStages::TESSELLATION_EVALUATION_SHADER`"
1357                    .into(),
1358                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1359                    "tessellation_shader",
1360                )])]),
1361                vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03930"],
1362            }));
1363        }
1364
1365        if !device.enabled_features().conditional_rendering
1366            && stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
1367        {
1368            return Err(Box::new(ValidationError {
1369                context: "stages".into(),
1370                problem: "contains `PipelineStages::CONDITIONAL_RENDERING`".into(),
1371                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1372                    "conditional_rendering",
1373                )])]),
1374                vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03931"],
1375            }));
1376        }
1377
1378        if !device.enabled_features().fragment_density_map
1379            && stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
1380        {
1381            return Err(Box::new(ValidationError {
1382                context: "stages".into(),
1383                problem: "contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`".into(),
1384                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1385                    "fragment_density_map",
1386                )])]),
1387                vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03932"],
1388            }));
1389        }
1390
1391        if !device.enabled_features().transform_feedback
1392            && stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
1393        {
1394            return Err(Box::new(ValidationError {
1395                context: "stages".into(),
1396                problem: "contains `PipelineStages::TRANSFORM_FEEDBACK`".into(),
1397                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1398                    "transform_feedback",
1399                )])]),
1400                vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03933"],
1401            }));
1402        }
1403
1404        if !device.enabled_features().mesh_shader && stages.intersects(PipelineStages::MESH_SHADER)
1405        {
1406            return Err(Box::new(ValidationError {
1407                context: "stages".into(),
1408                problem: "contains `PipelineStages::MESH_SHADER`".into(),
1409                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1410                    "mesh_shader",
1411                )])]),
1412                vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03934"],
1413            }));
1414        }
1415
1416        if !device.enabled_features().task_shader && stages.intersects(PipelineStages::TASK_SHADER)
1417        {
1418            return Err(Box::new(ValidationError {
1419                context: "stages".into(),
1420                problem: "contains `PipelineStages::TASK_SHADER`".into(),
1421                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1422                    "task_shader",
1423                )])]),
1424                vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-03935"],
1425            }));
1426        }
1427
1428        if !(device.enabled_features().attachment_fragment_shading_rate
1429            || device.enabled_features().shading_rate_image)
1430            && stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
1431        {
1432            return Err(Box::new(ValidationError {
1433                context: "stages".into(),
1434                problem: "contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`".into(),
1435                requires_one_of: RequiresOneOf(&[
1436                    RequiresAllOf(&[Requires::DeviceFeature("attachment_fragment_shading_rate")]),
1437                    RequiresAllOf(&[Requires::DeviceFeature("shading_rate_image")]),
1438                ]),
1439                vuids: &["VUID-VkMemoryBarrier2-shadingRateImage-07316"],
1440            }));
1441        }
1442
1443        if !device.enabled_features().subpass_shading
1444            && stages.intersects(PipelineStages::SUBPASS_SHADER)
1445        {
1446            return Err(Box::new(ValidationError {
1447                context: "stages".into(),
1448                problem: "contains `PipelineStages::SUBPASS_SHADER`".into(),
1449                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1450                    "subpass_shading",
1451                )])]),
1452                vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-04957"],
1453            }));
1454        }
1455
1456        if !device.enabled_features().invocation_mask
1457            && stages.intersects(PipelineStages::INVOCATION_MASK)
1458        {
1459            return Err(Box::new(ValidationError {
1460                context: "stages".into(),
1461                problem: "contains `PipelineStages::INVOCATION_MASK`".into(),
1462                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1463                    "invocation_mask",
1464                )])]),
1465                vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-04995"],
1466            }));
1467        }
1468
1469        if !(device.enabled_extensions().nv_ray_tracing
1470            || device.enabled_features().ray_tracing_pipeline)
1471            && stages.intersects(PipelineStages::RAY_TRACING_SHADER)
1472        {
1473            return Err(Box::new(ValidationError {
1474                context: "stages".into(),
1475                problem: "contains `PipelineStages::RAY_TRACING_SHADER`".into(),
1476                requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
1477                    "ray_tracing_pipeline",
1478                )])]),
1479                vuids: &["VUID-VkSemaphoreSubmitInfo-stageMask-07946"],
1480            }));
1481        }
1482
1483        Ok(())
1484    }
1485
1486    pub(crate) fn to_vk2(&self) -> ash::vk::SemaphoreSubmitInfo<'static> {
1487        let &Self {
1488            ref semaphore,
1489            value,
1490            stages,
1491            _ne: _,
1492        } = self;
1493
1494        ash::vk::SemaphoreSubmitInfo::default()
1495            .semaphore(semaphore.handle())
1496            .value(value)
1497            .stage_mask(stages.into())
1498            .device_index(0) // TODO:
1499    }
1500}
1501
1502#[derive(Debug, Default)]
1503pub struct CommandBufferState {
1504    has_been_submitted: bool,
1505    pending_submits: u32,
1506}
1507
1508impl CommandBufferState {
1509    pub(crate) fn has_been_submitted(&self) -> bool {
1510        self.has_been_submitted
1511    }
1512
1513    pub(crate) fn is_submit_pending(&self) -> bool {
1514        self.pending_submits != 0
1515    }
1516
1517    pub(crate) unsafe fn add_queue_submit(&mut self) {
1518        self.has_been_submitted = true;
1519        self.pending_submits += 1;
1520    }
1521
1522    pub(crate) unsafe fn set_submit_finished(&mut self) {
1523        self.pending_submits -= 1;
1524    }
1525}
1526
1527#[doc(hidden)]
1528#[derive(Debug)]
1529pub struct CommandBufferResourcesUsage {
1530    pub(crate) buffers: Vec<CommandBufferBufferUsage>,
1531    pub(crate) images: Vec<CommandBufferImageUsage>,
1532    pub(crate) buffer_indices: HashMap<Arc<Buffer>, usize>,
1533    pub(crate) image_indices: HashMap<Arc<Image>, usize>,
1534}
1535
1536#[derive(Debug)]
1537pub(crate) struct CommandBufferBufferUsage {
1538    pub(crate) buffer: Arc<Buffer>,
1539    pub(crate) ranges: RangeMap<DeviceSize, CommandBufferBufferRangeUsage>,
1540}
1541
1542#[derive(Clone, Debug, PartialEq, Eq)]
1543pub(crate) struct CommandBufferBufferRangeUsage {
1544    pub(crate) first_use: Option<ResourceUseRef>,
1545    pub(crate) mutable: bool,
1546}
1547
1548#[derive(Debug)]
1549pub(crate) struct CommandBufferImageUsage {
1550    pub(crate) image: Arc<Image>,
1551    pub(crate) ranges: RangeMap<DeviceSize, CommandBufferImageRangeUsage>,
1552}
1553
1554#[derive(Clone, Debug, PartialEq, Eq)]
1555pub(crate) struct CommandBufferImageRangeUsage {
1556    pub(crate) first_use: Option<ResourceUseRef>,
1557    pub(crate) mutable: bool,
1558    pub(crate) expected_layout: ImageLayout,
1559    pub(crate) final_layout: ImageLayout,
1560}
1561
1562#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1563pub struct ResourceUseRef {
1564    pub command_index: usize,
1565    pub command_name: &'static str,
1566    pub resource_in_command: ResourceInCommand,
1567    pub secondary_use_ref: Option<SecondaryResourceUseRef>,
1568}
1569
1570#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1571pub struct SecondaryResourceUseRef {
1572    pub command_index: usize,
1573    pub command_name: &'static str,
1574    pub resource_in_command: ResourceInCommand,
1575}
1576
1577impl From<ResourceUseRef> for SecondaryResourceUseRef {
1578    #[inline]
1579    fn from(val: ResourceUseRef) -> Self {
1580        let ResourceUseRef {
1581            command_index,
1582            command_name,
1583            resource_in_command,
1584            secondary_use_ref,
1585        } = val;
1586
1587        debug_assert!(secondary_use_ref.is_none());
1588
1589        SecondaryResourceUseRef {
1590            command_index,
1591            command_name,
1592            resource_in_command,
1593        }
1594    }
1595}
1596
1597#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
1598#[non_exhaustive]
1599pub enum ResourceInCommand {
1600    AccelerationStructure { index: u32 },
1601    ColorAttachment { index: u32 },
1602    ColorResolveAttachment { index: u32 },
1603    DepthStencilAttachment,
1604    DepthStencilResolveAttachment,
1605    DescriptorSet { set: u32, binding: u32, index: u32 },
1606    Destination,
1607    FramebufferAttachment { index: u32 },
1608    GeometryAabbsData { index: u32 },
1609    GeometryInstancesData,
1610    GeometryTrianglesTransformData { index: u32 },
1611    GeometryTrianglesIndexData { index: u32 },
1612    GeometryTrianglesVertexData { index: u32 },
1613    ImageMemoryBarrier { index: u32 },
1614    IndexBuffer,
1615    IndirectBuffer,
1616    ScratchData,
1617    SecondaryCommandBuffer { index: u32 },
1618    Source,
1619    VertexBuffer { binding: u32 },
1620    ShaderBindingTableBuffer,
1621}
1622
1623#[doc(hidden)]
1624#[derive(Debug, Default)]
1625pub struct SecondaryCommandBufferResourcesUsage {
1626    pub(crate) buffers: Vec<SecondaryCommandBufferBufferUsage>,
1627    pub(crate) images: Vec<SecondaryCommandBufferImageUsage>,
1628}
1629
1630#[derive(Debug)]
1631pub(crate) struct SecondaryCommandBufferBufferUsage {
1632    pub(crate) use_ref: ResourceUseRef,
1633    pub(crate) buffer: Subbuffer<[u8]>,
1634    pub(crate) range: Range<DeviceSize>,
1635    pub(crate) memory_access: PipelineStageAccessFlags,
1636}
1637
1638#[derive(Debug)]
1639pub(crate) struct SecondaryCommandBufferImageUsage {
1640    pub(crate) use_ref: ResourceUseRef,
1641    pub(crate) image: Arc<Image>,
1642    pub(crate) subresource_range: ImageSubresourceRange,
1643    pub(crate) memory_access: PipelineStageAccessFlags,
1644    pub(crate) start_layout: ImageLayout,
1645    pub(crate) end_layout: ImageLayout,
1646}