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 //! Recording commands to execute on the device.
11 //!
12 //! With Vulkan, to get the device to perform work, even relatively simple tasks, you must create a
13 //! command buffer. A command buffer is a list of commands that will executed by the device.
14 //! You must first record commands to a command buffer builder, then build it into an actual
15 //! command buffer, and then it can be used. Depending on how a command buffer is created, it can
16 //! be used only once, or reused many times.
17 //!
18 //! # Command pools and allocators
19 //!
20 //! Command buffers are allocated from *command pools*. A command pool holds memory that is used to
21 //! record the sequence of commands in a command buffer. Command pools are not thread-safe, and
22 //! therefore commands cannot be recorded to a single command buffer from multiple threads at a
23 //! time.
24 //!
25 //! Raw command pools are unsafe to use, so Vulkano uses [command buffer allocators] to manage
26 //! command buffers and pools, to ensure their memory is used efficiently, and to protect against
27 //! invalid usage. Vulkano provides the [`StandardCommandBufferAllocator`] for this purpose, but
28 //! you can also create your own by implementing the [`CommandBufferAllocator`] trait.
29 //!
30 //! # Primary and secondary command buffers
31 //!
32 //! There are two levels of command buffers:
33 //!
34 //! - [`PrimaryCommandBufferAbstract`] can be executed on a queue, and is the main command buffer
35 //!   type. It cannot be executed within another command buffer.
36 //! - [`SecondaryCommandBufferAbstract`] can only be executed within a primary command buffer,
37 //!   not directly on a queue.
38 //!
39 //! Using secondary command buffers, there is slightly more overhead than using primary command
40 //! buffers alone, but there are also advantages. A single command buffer cannot be recorded
41 //! from multiple threads at a time, so if you want to divide the recording work among several
42 //! threads, each thread must record its own command buffer. While it is possible for these to be
43 //! all primary command buffers, there are limitations: a render pass or query cannot span multiple
44 //! primary command buffers, while secondary command buffers can [inherit] this state from their
45 //! parent primary command buffer. Therefore, to have a single render pass or query that is shared
46 //! across all the command buffers, you must record secondary command buffers.
47 //!
48 //! # Recording a command buffer
49 //!
50 //! To record a new command buffer, the most direct way is to create a new
51 //! [`AutoCommandBufferBuilder`]. You can then call methods on this object to record new commands to
52 //! the command buffer. When you are done recording, you call [`build`] to finalise the command
53 //! buffer and turn it into either a [`PrimaryCommandBufferAbstract`] or a
54 //! [`SecondaryCommandBufferAbstract`].
55 //!
56 // //! Using the standard `CommandBufferBuilder`, you must enter synchronization commands such as
57 // //! [pipeline barriers], to ensure that there are no races and memory access hazards. This can be
58 // //! difficult to do manually, so Vulkano also provides an alternative builder,
59 // //! [`AutoCommandBufferBuilder`]. Using this builder, you do not have to worry about managing
60 // //! synchronization, but the end result may not be quite as efficient.
61 //!
62 //! # Submitting a primary command buffer
63 //!
64 //! Once primary a command buffer is recorded and built, you can use the
65 //! [`PrimaryCommandBufferAbstract`] trait to submit the command buffer to a queue. Submitting a
66 //! command buffer returns an object that implements the [`GpuFuture`] trait and that represents
67 //! the moment when the execution will end on the GPU.
68 //!
69 //! ```
70 //! use vulkano::command_buffer::AutoCommandBufferBuilder;
71 //! use vulkano::command_buffer::CommandBufferUsage;
72 //! use vulkano::command_buffer::PrimaryCommandBufferAbstract;
73 //! use vulkano::command_buffer::SubpassContents;
74 //!
75 //! # use vulkano::{buffer::BufferContents, pipeline::graphics::vertex_input::Vertex};
76 //!
77 //! # #[derive(BufferContents, Vertex)]
78 //! # #[repr(C)]
79 //! # struct PosVertex {
80 //! #     #[format(R32G32B32_SFLOAT)]
81 //! #     position: [f32; 3]
82 //! # };
83 //! # let device: std::sync::Arc<vulkano::device::Device> = return;
84 //! # let queue: std::sync::Arc<vulkano::device::Queue> = return;
85 //! # let vertex_buffer: vulkano::buffer::Subbuffer<[PosVertex]> = return;
86 //! # let render_pass_begin_info: vulkano::command_buffer::RenderPassBeginInfo = return;
87 //! # let graphics_pipeline: std::sync::Arc<vulkano::pipeline::graphics::GraphicsPipeline> = return;
88 //! # let command_buffer_allocator: vulkano::command_buffer::allocator::StandardCommandBufferAllocator = return;
89 //! let cb = AutoCommandBufferBuilder::primary(
90 //!     &command_buffer_allocator,
91 //!     queue.queue_family_index(),
92 //!     CommandBufferUsage::MultipleSubmit
93 //! ).unwrap()
94 //! .begin_render_pass(render_pass_begin_info, SubpassContents::Inline).unwrap()
95 //! .bind_pipeline_graphics(graphics_pipeline.clone())
96 //! .bind_vertex_buffers(0, vertex_buffer.clone())
97 //! .draw(vertex_buffer.len() as u32, 1, 0, 0).unwrap()
98 //! .end_render_pass().unwrap()
99 //! .build().unwrap();
100 //!
101 //! let _future = cb.execute(queue.clone());
102 //! ```
103 //!
104 //! [`StandardCommandBufferAllocator`]: self::allocator::StandardCommandBufferAllocator
105 //! [`CommandBufferAllocator`]: self::allocator::CommandBufferAllocator
106 //! [inherit]: CommandBufferInheritanceInfo
107 //! [`build`]: CommandBufferBuilder::build
108 //! [pipeline barriers]: CommandBufferBuilder::pipeline_barrier
109 //! [`GpuFuture`]: crate::sync::GpuFuture
110 
111 #[doc(no_inline)]
112 pub(crate) use self::standard::{PrimaryCommandBuffer, SecondaryCommandBuffer};
113 pub use self::{
114     auto::{
115         AutoCommandBufferBuilder, BuildError, CommandBufferBeginError, PrimaryAutoCommandBuffer,
116         SecondaryAutoCommandBuffer,
117     },
118     commands::{
119         clear::{ClearColorImageInfo, ClearDepthStencilImageInfo, ClearError},
120         copy::{
121             BlitImageInfo, BufferCopy, BufferImageCopy, CopyBufferInfo, CopyBufferInfoTyped,
122             CopyBufferToImageInfo, CopyError, CopyErrorResource, CopyImageInfo,
123             CopyImageToBufferInfo, ImageBlit, ImageCopy, ImageResolve, ResolveImageInfo,
124         },
125         debug::DebugUtilsError,
126         pipeline::PipelineExecutionError,
127         query::QueryError,
128         render_pass::{
129             ClearAttachment, ClearRect, RenderPassBeginInfo, RenderPassError,
130             RenderingAttachmentInfo, RenderingAttachmentResolveInfo, RenderingInfo,
131         },
132         secondary::ExecuteCommandsError,
133     },
134     traits::{
135         CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract,
136         SecondaryCommandBufferAbstract,
137     },
138 };
139 use crate::{
140     buffer::{Buffer, Subbuffer},
141     format::Format,
142     image::{sys::Image, ImageAccess, ImageLayout, ImageSubresourceRange, SampleCount},
143     macros::vulkan_enum,
144     query::{QueryControlFlags, QueryPipelineStatisticFlags},
145     range_map::RangeMap,
146     render_pass::{Framebuffer, Subpass},
147     sync::{semaphore::Semaphore, PipelineMemoryAccess, PipelineStages},
148     DeviceSize,
149 };
150 use ahash::HashMap;
151 use bytemuck::{Pod, Zeroable};
152 use std::{ops::Range, sync::Arc};
153 
154 pub mod allocator;
155 mod auto;
156 mod commands;
157 pub mod pool;
158 pub(crate) mod standard;
159 pub mod synced;
160 pub mod sys;
161 mod traits;
162 
163 #[repr(C)]
164 #[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
165 pub struct DrawIndirectCommand {
166     pub vertex_count: u32,
167     pub instance_count: u32,
168     pub first_vertex: u32,
169     pub first_instance: u32,
170 }
171 
172 #[repr(C)]
173 #[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
174 pub struct DrawIndexedIndirectCommand {
175     pub index_count: u32,
176     pub instance_count: u32,
177     pub first_index: u32,
178     pub vertex_offset: u32,
179     pub first_instance: u32,
180 }
181 
182 #[repr(C)]
183 #[derive(Clone, Copy, Debug, Default, Zeroable, Pod, PartialEq, Eq)]
184 pub struct DispatchIndirectCommand {
185     pub x: u32,
186     pub y: u32,
187     pub z: u32,
188 }
189 
190 vulkan_enum! {
191     #[non_exhaustive]
192 
193     /// Describes what a subpass in a command buffer will contain.
194     SubpassContents = SubpassContents(i32);
195 
196     /// The subpass will only directly contain commands.
197     Inline = INLINE,
198 
199     /// The subpass will only contain secondary command buffers invocations.
200     SecondaryCommandBuffers = SECONDARY_COMMAND_BUFFERS,
201 }
202 
203 impl From<SubpassContents> for ash::vk::RenderingFlags {
204     #[inline]
from(val: SubpassContents) -> Self205     fn from(val: SubpassContents) -> Self {
206         match val {
207             SubpassContents::Inline => Self::empty(),
208             SubpassContents::SecondaryCommandBuffers => Self::CONTENTS_SECONDARY_COMMAND_BUFFERS,
209         }
210     }
211 }
212 
213 vulkan_enum! {
214     /// Determines the kind of command buffer to create.
215     CommandBufferLevel = CommandBufferLevel(i32);
216 
217     /// Primary command buffers can be executed on a queue, and can call secondary command buffers.
218     /// Render passes must begin and end within the same primary command buffer.
219     Primary = PRIMARY,
220 
221     /// Secondary command buffers cannot be executed on a queue, but can be executed by a primary
222     /// command buffer. If created for a render pass, they must fit within a single render subpass.
223     Secondary = SECONDARY,
224 }
225 
226 /// The context that a secondary command buffer can inherit from the primary command
227 /// buffer it's executed in.
228 #[derive(Clone, Debug)]
229 pub struct CommandBufferInheritanceInfo {
230     /// If `Some`, the secondary command buffer is required to be executed within a render pass
231     /// instance, and can only call draw operations.
232     /// If `None`, it must be executed outside a render pass instance, and can execute dispatch and
233     /// transfer operations, but not drawing operations.
234     ///
235     /// The default value is `None`.
236     pub render_pass: Option<CommandBufferInheritanceRenderPassType>,
237 
238     /// If `Some`, the secondary command buffer is allowed to be executed within a primary that has
239     /// an occlusion query active. The inner `QueryControlFlags` specifies which flags the
240     /// active occlusion is allowed to have enabled.
241     /// If `None`, the primary command buffer cannot have an occlusion query active when this
242     /// secondary command buffer is executed.
243     ///
244     /// The `inherited_queries` feature must be enabled if this is `Some`.
245     ///
246     /// The default value is `None`.
247     pub occlusion_query: Option<QueryControlFlags>,
248 
249     /// Which pipeline statistics queries are allowed to be active on the primary command buffer
250     /// when this secondary command buffer is executed.
251     ///
252     /// If this value is not empty, the [`pipeline_statistics_query`] feature must be enabled on
253     /// the device.
254     ///
255     /// The default value is [`QueryPipelineStatisticFlags::empty()`].
256     ///
257     /// [`pipeline_statistics_query`]: crate::device::Features::pipeline_statistics_query
258     pub query_statistics_flags: QueryPipelineStatisticFlags,
259 
260     pub _ne: crate::NonExhaustive,
261 }
262 
263 impl Default for CommandBufferInheritanceInfo {
264     #[inline]
default() -> Self265     fn default() -> Self {
266         Self {
267             render_pass: None,
268             occlusion_query: None,
269             query_statistics_flags: QueryPipelineStatisticFlags::empty(),
270             _ne: crate::NonExhaustive(()),
271         }
272     }
273 }
274 
275 /// Selects the type of render pass for command buffer inheritance.
276 #[derive(Clone, Debug)]
277 pub enum CommandBufferInheritanceRenderPassType {
278     /// The secondary command buffer will be executed within a render pass begun with
279     /// `begin_render_pass`, using a `RenderPass` object and `Framebuffer`.
280     BeginRenderPass(CommandBufferInheritanceRenderPassInfo),
281 
282     /// The secondary command buffer will be executed within a render pass begun with
283     /// `begin_rendering`, using dynamic rendering.
284     BeginRendering(CommandBufferInheritanceRenderingInfo),
285 }
286 
287 impl From<Subpass> for CommandBufferInheritanceRenderPassType {
288     #[inline]
from(val: Subpass) -> Self289     fn from(val: Subpass) -> Self {
290         Self::BeginRenderPass(val.into())
291     }
292 }
293 
294 impl From<CommandBufferInheritanceRenderPassInfo> for CommandBufferInheritanceRenderPassType {
295     #[inline]
from(val: CommandBufferInheritanceRenderPassInfo) -> Self296     fn from(val: CommandBufferInheritanceRenderPassInfo) -> Self {
297         Self::BeginRenderPass(val)
298     }
299 }
300 
301 impl From<CommandBufferInheritanceRenderingInfo> for CommandBufferInheritanceRenderPassType {
302     #[inline]
from(val: CommandBufferInheritanceRenderingInfo) -> Self303     fn from(val: CommandBufferInheritanceRenderingInfo) -> Self {
304         Self::BeginRendering(val)
305     }
306 }
307 
308 /// The render pass context that a secondary command buffer is created for.
309 #[derive(Clone, Debug)]
310 pub struct CommandBufferInheritanceRenderPassInfo {
311     /// The render subpass that this secondary command buffer must be executed within.
312     ///
313     /// There is no default value.
314     pub subpass: Subpass,
315 
316     /// The framebuffer object that will be used when calling the command buffer.
317     /// This parameter is optional and is an optimization hint for the implementation.
318     ///
319     /// The default value is `None`.
320     pub framebuffer: Option<Arc<Framebuffer>>,
321 }
322 
323 impl CommandBufferInheritanceRenderPassInfo {
324     /// Returns a `CommandBufferInheritanceRenderPassInfo` with the specified `subpass`.
325     #[inline]
subpass(subpass: Subpass) -> Self326     pub fn subpass(subpass: Subpass) -> Self {
327         Self {
328             subpass,
329             framebuffer: None,
330         }
331     }
332 }
333 
334 impl From<Subpass> for CommandBufferInheritanceRenderPassInfo {
335     #[inline]
from(subpass: Subpass) -> Self336     fn from(subpass: Subpass) -> Self {
337         Self {
338             subpass,
339             framebuffer: None,
340         }
341     }
342 }
343 
344 /// The dynamic rendering context that a secondary command buffer is created for.
345 #[derive(Clone, Debug)]
346 pub struct CommandBufferInheritanceRenderingInfo {
347     /// If not `0`, indicates that multiview rendering will be enabled, and specifies the view
348     /// indices that are rendered to. The value is a bitmask, so that that for example `0b11` will
349     /// draw to the first two views and `0b101` will draw to the first and third view.
350     ///
351     /// If set to a nonzero value, then the [`multiview`] feature must be enabled on the device.
352     ///
353     /// The default value is `0`.
354     ///
355     /// [`multiview`]: crate::device::Features::multiview
356     pub view_mask: u32,
357 
358     /// The formats of the color attachments that will be used during rendering.
359     ///
360     /// If an element is `None`, it indicates that the attachment will not be used.
361     ///
362     /// The default value is empty.
363     pub color_attachment_formats: Vec<Option<Format>>,
364 
365     /// The format of the depth attachment that will be used during rendering.
366     ///
367     /// If set to `None`, it indicates that no depth attachment will be used.
368     ///
369     /// The default value is `None`.
370     pub depth_attachment_format: Option<Format>,
371 
372     /// The format of the stencil attachment that will be used during rendering.
373     ///
374     /// If set to `None`, it indicates that no stencil attachment will be used.
375     ///
376     /// The default value is `None`.
377     pub stencil_attachment_format: Option<Format>,
378 
379     /// The number of samples that the color, depth and stencil attachments will have.
380     ///
381     /// The default value is [`SampleCount::Sample1`]
382     pub rasterization_samples: SampleCount,
383 }
384 
385 impl Default for CommandBufferInheritanceRenderingInfo {
386     #[inline]
default() -> Self387     fn default() -> Self {
388         Self {
389             view_mask: 0,
390             color_attachment_formats: Vec::new(),
391             depth_attachment_format: None,
392             stencil_attachment_format: None,
393             rasterization_samples: SampleCount::Sample1,
394         }
395     }
396 }
397 
398 /// Usage flags to pass when creating a command buffer.
399 ///
400 /// The safest option is `SimultaneousUse`, but it may be slower than the other two.
401 // NOTE: The ordering is important: the variants are listed from least to most permissive!
402 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
403 #[repr(u32)]
404 pub enum CommandBufferUsage {
405     /// The command buffer can only be submitted once before being destroyed. Any further submit is
406     /// forbidden. This makes it possible for the implementation to perform additional
407     /// optimizations.
408     OneTimeSubmit = ash::vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT.as_raw(),
409 
410     /// The command buffer can be used multiple times, but must not execute or record more than once
411     /// simultaneously. In other words, it is as if executing the command buffer borrows it mutably.
412     MultipleSubmit = 0,
413 
414     /// The command buffer can be executed multiple times in parallel on different queues.
415     /// If it's a secondary command buffer, it can be recorded to multiple primary command buffers
416     /// at once.
417     SimultaneousUse = ash::vk::CommandBufferUsageFlags::SIMULTANEOUS_USE.as_raw(),
418 }
419 
420 impl From<CommandBufferUsage> for ash::vk::CommandBufferUsageFlags {
421     #[inline]
from(val: CommandBufferUsage) -> Self422     fn from(val: CommandBufferUsage) -> Self {
423         Self::from_raw(val as u32)
424     }
425 }
426 
427 /// Parameters to submit command buffers to a queue.
428 #[derive(Clone, Debug)]
429 pub struct SubmitInfo {
430     /// The semaphores to wait for before beginning the execution of this batch of
431     /// command buffer operations.
432     ///
433     /// The default value is empty.
434     pub wait_semaphores: Vec<SemaphoreSubmitInfo>,
435 
436     /// The command buffers to execute.
437     ///
438     /// The default value is empty.
439     pub command_buffers: Vec<Arc<dyn PrimaryCommandBufferAbstract>>,
440 
441     /// The semaphores to signal after the execution of this batch of command buffer operations
442     /// has completed.
443     ///
444     /// The default value is empty.
445     pub signal_semaphores: Vec<SemaphoreSubmitInfo>,
446 
447     pub _ne: crate::NonExhaustive,
448 }
449 
450 impl Default for SubmitInfo {
451     #[inline]
default() -> Self452     fn default() -> Self {
453         Self {
454             wait_semaphores: Vec::new(),
455             command_buffers: Vec::new(),
456             signal_semaphores: Vec::new(),
457             _ne: crate::NonExhaustive(()),
458         }
459     }
460 }
461 
462 /// Parameters for a semaphore signal or wait operation in a command buffer submission.
463 #[derive(Clone, Debug)]
464 pub struct SemaphoreSubmitInfo {
465     /// The semaphore to signal or wait for.
466     pub semaphore: Arc<Semaphore>,
467 
468     /// For a semaphore wait operation, specifies the pipeline stages in the second synchronization
469     /// scope: stages of queue operations following the wait operation that can start executing
470     /// after the semaphore is signalled.
471     ///
472     /// For a semaphore signal operation, specifies the pipeline stages in the first synchronization
473     /// scope: stages of queue operations preceding the signal operation that must complete before
474     /// the semaphore is signalled.
475     /// If this value does not equal [`ALL_COMMANDS`], then the [`synchronization2`] feature must
476     /// be enabled on the device.
477     ///
478     /// The default value is [`ALL_COMMANDS`].
479     ///
480     /// [`ALL_COMMANDS`]: PipelineStages::ALL_COMMANDS
481     /// [`synchronization2`]: crate::device::Features::synchronization2
482     pub stages: PipelineStages,
483 
484     pub _ne: crate::NonExhaustive,
485 }
486 
487 impl SemaphoreSubmitInfo {
488     /// Returns a `SemaphoreSubmitInfo` with the specified `semaphore`.
489     #[inline]
semaphore(semaphore: Arc<Semaphore>) -> Self490     pub fn semaphore(semaphore: Arc<Semaphore>) -> Self {
491         Self {
492             semaphore,
493             stages: PipelineStages::ALL_COMMANDS,
494             _ne: crate::NonExhaustive(()),
495         }
496     }
497 }
498 
499 #[derive(Debug, Default)]
500 pub struct CommandBufferState {
501     has_been_submitted: bool,
502     pending_submits: u32,
503 }
504 
505 impl CommandBufferState {
has_been_submitted(&self) -> bool506     pub(crate) fn has_been_submitted(&self) -> bool {
507         self.has_been_submitted
508     }
509 
is_submit_pending(&self) -> bool510     pub(crate) fn is_submit_pending(&self) -> bool {
511         self.pending_submits != 0
512     }
513 
add_queue_submit(&mut self)514     pub(crate) unsafe fn add_queue_submit(&mut self) {
515         self.has_been_submitted = true;
516         self.pending_submits += 1;
517     }
518 
set_submit_finished(&mut self)519     pub(crate) unsafe fn set_submit_finished(&mut self) {
520         self.pending_submits -= 1;
521     }
522 }
523 
524 #[doc(hidden)]
525 #[derive(Debug)]
526 pub struct CommandBufferResourcesUsage {
527     pub(crate) buffers: Vec<CommandBufferBufferUsage>,
528     pub(crate) images: Vec<CommandBufferImageUsage>,
529     pub(crate) buffer_indices: HashMap<Arc<Buffer>, usize>,
530     pub(crate) image_indices: HashMap<Arc<Image>, usize>,
531 }
532 
533 #[derive(Debug)]
534 pub(crate) struct CommandBufferBufferUsage {
535     pub(crate) buffer: Arc<Buffer>,
536     pub(crate) ranges: RangeMap<DeviceSize, CommandBufferBufferRangeUsage>,
537 }
538 
539 #[derive(Clone, Debug, PartialEq, Eq)]
540 pub(crate) struct CommandBufferBufferRangeUsage {
541     pub(crate) first_use: Option<ResourceUseRef>,
542     pub(crate) mutable: bool,
543 }
544 
545 #[derive(Debug)]
546 pub(crate) struct CommandBufferImageUsage {
547     pub(crate) image: Arc<Image>,
548     pub(crate) ranges: RangeMap<DeviceSize, CommandBufferImageRangeUsage>,
549 }
550 
551 #[derive(Clone, Debug, PartialEq, Eq)]
552 pub(crate) struct CommandBufferImageRangeUsage {
553     pub(crate) first_use: Option<ResourceUseRef>,
554     pub(crate) mutable: bool,
555     pub(crate) expected_layout: ImageLayout,
556     pub(crate) final_layout: ImageLayout,
557 }
558 
559 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
560 pub struct ResourceUseRef {
561     pub command_index: usize,
562     pub command_name: &'static str,
563     pub resource_in_command: ResourceInCommand,
564     pub secondary_use_ref: Option<SecondaryResourceUseRef>,
565 }
566 
567 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
568 pub struct SecondaryResourceUseRef {
569     pub command_index: usize,
570     pub command_name: &'static str,
571     pub resource_in_command: ResourceInCommand,
572 }
573 
574 impl From<ResourceUseRef> for SecondaryResourceUseRef {
575     #[inline]
from(val: ResourceUseRef) -> Self576     fn from(val: ResourceUseRef) -> Self {
577         let ResourceUseRef {
578             command_index,
579             command_name,
580             resource_in_command,
581             secondary_use_ref,
582         } = val;
583 
584         debug_assert!(secondary_use_ref.is_none());
585 
586         SecondaryResourceUseRef {
587             command_index,
588             command_name,
589             resource_in_command,
590         }
591     }
592 }
593 
594 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
595 #[non_exhaustive]
596 pub enum ResourceInCommand {
597     ColorAttachment { index: u32 },
598     ColorResolveAttachment { index: u32 },
599     DepthStencilAttachment,
600     DepthStencilResolveAttachment,
601     DescriptorSet { set: u32, binding: u32, index: u32 },
602     Destination,
603     FramebufferAttachment { index: u32 },
604     ImageMemoryBarrier { index: u32 },
605     IndexBuffer,
606     IndirectBuffer,
607     SecondaryCommandBuffer { index: u32 },
608     Source,
609     VertexBuffer { binding: u32 },
610 }
611 
612 #[doc(hidden)]
613 #[derive(Debug, Default)]
614 pub struct SecondaryCommandBufferResourcesUsage {
615     pub(crate) buffers: Vec<SecondaryCommandBufferBufferUsage>,
616     pub(crate) images: Vec<SecondaryCommandBufferImageUsage>,
617 }
618 
619 #[derive(Debug)]
620 pub(crate) struct SecondaryCommandBufferBufferUsage {
621     pub(crate) use_ref: ResourceUseRef,
622     pub(crate) buffer: Subbuffer<[u8]>,
623     pub(crate) range: Range<DeviceSize>,
624     pub(crate) memory: PipelineMemoryAccess,
625 }
626 
627 #[derive(Debug)]
628 pub(crate) struct SecondaryCommandBufferImageUsage {
629     pub(crate) use_ref: ResourceUseRef,
630     pub(crate) image: Arc<dyn ImageAccess>,
631     pub(crate) subresource_range: ImageSubresourceRange,
632     pub(crate) memory: PipelineMemoryAccess,
633     pub(crate) start_layout: ImageLayout,
634     pub(crate) end_layout: ImageLayout,
635 }
636