1#[allow(unused_imports)] pub 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#[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#[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#[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#[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 SubpassContents = SubpassContents(i32);
238
239 Inline = INLINE,
241
242 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 CommandBufferLevel = CommandBufferLevel(i32);
259
260 Primary = PRIMARY,
263
264 Secondary = SECONDARY,
267}
268
269#[derive(Clone, Debug)]
272pub struct CommandBufferInheritanceInfo {
273 pub render_pass: Option<CommandBufferInheritanceRenderPassType>,
280
281 pub occlusion_query: Option<QueryControlFlags>,
291
292 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 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#[derive(Clone, Debug)]
503pub enum CommandBufferInheritanceRenderPassType {
504 BeginRenderPass(CommandBufferInheritanceRenderPassInfo),
507
508 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#[derive(Clone, Debug)]
536pub struct CommandBufferInheritanceRenderPassInfo {
537 pub subpass: Subpass,
541
542 pub framebuffer: Option<Arc<Framebuffer>>,
547}
548
549impl CommandBufferInheritanceRenderPassInfo {
550 #[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 assert_eq!(device, subpass.render_pass().device().as_ref());
567
568 if let Some(framebuffer) = framebuffer {
572 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#[derive(Clone, Debug)]
603pub struct CommandBufferInheritanceRenderingInfo {
604 pub view_mask: u32,
614
615 pub color_attachment_formats: Vec<Option<Format>>,
621
622 pub depth_attachment_format: Option<Format>,
628
629 pub stencil_attachment_format: Option<Format>,
635
636 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#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
892#[repr(u32)]
893pub enum CommandBufferUsage {
894 OneTimeSubmit = ash::vk::CommandBufferUsageFlags::ONE_TIME_SUBMIT.as_raw(),
898
899 MultipleSubmit = 0,
903
904 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#[derive(Clone, Debug)]
919pub struct SubmitInfo {
920 pub wait_semaphores: Vec<SemaphoreSubmitInfo>,
925
926 pub command_buffers: Vec<CommandBufferSubmitInfo>,
930
931 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 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()) .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#[derive(Clone, Debug)]
1190pub struct CommandBufferSubmitInfo {
1191 pub command_buffer: Arc<dyn PrimaryCommandBufferAbstract>,
1195
1196 pub _ne: crate::NonExhaustive,
1197}
1198
1199impl CommandBufferSubmitInfo {
1200 #[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 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) }
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#[derive(Clone, Debug)]
1244pub struct SemaphoreSubmitInfo {
1245 pub semaphore: Arc<Semaphore>,
1249
1250 pub value: u64,
1261
1262 pub stages: PipelineStages,
1277
1278 pub _ne: crate::NonExhaustive,
1279}
1280
1281impl SemaphoreSubmitInfo {
1282 #[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 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) }
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}