// Copyright (c) 2017 The vulkano developers // Licensed under the Apache License, Version 2.0 // or the MIT // license , // at your option. All files in the project carrying such // notice may not be copied, modified, or distributed except // according to those terms. use crate::{ buffer::Buffer, descriptor_set::layout::DescriptorType, device::{Device, QueueFlags}, image::{sys::Image, ImageAspects, ImageLayout, ImageSubresourceRange}, macros::{vulkan_bitflags, vulkan_bitflags_enum}, shader::ShaderStages, DeviceSize, RequirementNotMet, Version, }; use ahash::HashMap; use once_cell::sync::Lazy; use smallvec::SmallVec; use std::{ops::Range, sync::Arc}; vulkan_bitflags_enum! { #[non_exhaustive] /// A set of [`PipelineStage`] values. PipelineStages impl { /// Returns whether `self` contains stages that are only available in /// `VkPipelineStageFlagBits2`. pub(crate) fn is_2(self) -> bool { !(self - (PipelineStages::TOP_OF_PIPE | PipelineStages::DRAW_INDIRECT | PipelineStages::VERTEX_INPUT | PipelineStages::VERTEX_SHADER | PipelineStages::TESSELLATION_CONTROL_SHADER | PipelineStages::TESSELLATION_EVALUATION_SHADER | PipelineStages::GEOMETRY_SHADER | PipelineStages::FRAGMENT_SHADER | PipelineStages::EARLY_FRAGMENT_TESTS | PipelineStages::LATE_FRAGMENT_TESTS | PipelineStages::COLOR_ATTACHMENT_OUTPUT | PipelineStages::COMPUTE_SHADER | PipelineStages::ALL_TRANSFER | PipelineStages::BOTTOM_OF_PIPE | PipelineStages::HOST | PipelineStages::ALL_GRAPHICS | PipelineStages::ALL_COMMANDS | PipelineStages::TRANSFORM_FEEDBACK | PipelineStages::CONDITIONAL_RENDERING | PipelineStages::ACCELERATION_STRUCTURE_BUILD | PipelineStages::RAY_TRACING_SHADER | PipelineStages::FRAGMENT_DENSITY_PROCESS | PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT | PipelineStages::COMMAND_PREPROCESS | PipelineStages::TASK_SHADER | PipelineStages::MESH_SHADER)) .is_empty() } /// Replaces and unsets flags that are equivalent to multiple other flags. /// /// This may set flags that are not supported by the device, so this is for internal use only /// and should not be passed on to Vulkan. pub(crate) fn expand(mut self, queue_flags: QueueFlags) -> Self { if self.intersects(PipelineStages::ALL_COMMANDS) { self -= PipelineStages::ALL_COMMANDS; self |= queue_flags.into(); } if self.intersects(PipelineStages::ALL_GRAPHICS) { self -= PipelineStages::ALL_GRAPHICS; self |= QueueFlags::GRAPHICS.into(); } if self.intersects(PipelineStages::VERTEX_INPUT) { self -= PipelineStages::VERTEX_INPUT; self |= PipelineStages::INDEX_INPUT | PipelineStages::VERTEX_ATTRIBUTE_INPUT; } if self.intersects(PipelineStages::PRE_RASTERIZATION_SHADERS) { self -= PipelineStages::PRE_RASTERIZATION_SHADERS; self |= PipelineStages::VERTEX_SHADER | PipelineStages::TESSELLATION_CONTROL_SHADER | PipelineStages::TESSELLATION_EVALUATION_SHADER | PipelineStages::GEOMETRY_SHADER | PipelineStages::TASK_SHADER | PipelineStages::MESH_SHADER; } if self.intersects(PipelineStages::ALL_TRANSFER) { self -= PipelineStages::ALL_TRANSFER; self |= PipelineStages::COPY | PipelineStages::RESOLVE | PipelineStages::BLIT | PipelineStages::CLEAR | PipelineStages::ACCELERATION_STRUCTURE_COPY; } self } pub(crate) fn with_earlier(self) -> Self { STAGE_ORDER.iter().rev().fold( self, |stages, &(before, after)| if stages.intersects(after) { stages.union(before) } else { stages } ) } pub(crate) fn with_later(self) -> Self { STAGE_ORDER.iter().fold( self, |stages, &(before, after)| if stages.intersects(before) { stages.union(after) } else { stages } ) } }, /// A single stage in the device's processing pipeline. PipelineStage, = PipelineStageFlags2(u64); /// A pseudo-stage representing the start of the pipeline. TOP_OF_PIPE, TopOfPipe = TOP_OF_PIPE, /// Indirect buffers are read. DRAW_INDIRECT, DrawIndirect = DRAW_INDIRECT, /// Vertex and index buffers are read. /// /// It is currently equivalent to setting all of the following flags, but automatically /// omitting any that are not supported in a given context. It also implicitly includes future /// flags that are added to Vulkan, if they are not yet supported by Vulkano. /// - `index_input` /// - `vertex_attribute_input` VERTEX_INPUT, VertexInput = VERTEX_INPUT, /// Vertex shaders are executed. VERTEX_SHADER, VertexShader = VERTEX_SHADER, /// Tessellation control shaders are executed. TESSELLATION_CONTROL_SHADER, TessellationControlShader = TESSELLATION_CONTROL_SHADER, /// Tessellation evaluation shaders are executed. TESSELLATION_EVALUATION_SHADER, TessellationEvaluationShader = TESSELLATION_EVALUATION_SHADER, /// Geometry shaders are executed. GEOMETRY_SHADER, GeometryShader = GEOMETRY_SHADER, /// Fragment shaders are executed. FRAGMENT_SHADER, FragmentShader = FRAGMENT_SHADER, /// Early fragment tests (depth and stencil tests before fragment shading) are performed. /// Subpass load operations for framebuffer attachments with a depth/stencil format are /// performed. EARLY_FRAGMENT_TESTS, EarlyFragmentTests = EARLY_FRAGMENT_TESTS, /// Late fragment tests (depth and stencil tests after fragment shading) are performed. /// Subpass store operations for framebuffer attachments with a depth/stencil format are /// performed. LATE_FRAGMENT_TESTS, LateFragmentTests = LATE_FRAGMENT_TESTS, /// The final color values are output from the pipeline after blending. /// Subpass load and store operations, multisample resolve operations for framebuffer /// attachments with a color or depth/stencil format, and `clear_attachments` are performed. COLOR_ATTACHMENT_OUTPUT, ColorAttachmentOutput = COLOR_ATTACHMENT_OUTPUT, /// Compute shaders are executed. COMPUTE_SHADER, ComputeShader = COMPUTE_SHADER, /// The set of all current and future transfer pipeline stages. /// /// It is currently equivalent to setting all of the following flags, but automatically /// omitting any that are not supported in a given context. It also implicitly includes future /// flags that are added to Vulkan, if they are not yet supported by Vulkano. /// - `copy` /// - `blit` /// - `resolve` /// - `clear` /// - `acceleration_structure_copy` ALL_TRANSFER, AllTransfer = ALL_TRANSFER, /// A pseudo-stage representing the end of the pipeline. BOTTOM_OF_PIPE, BottomOfPipe = BOTTOM_OF_PIPE, /// A pseudo-stage representing reads and writes to device memory on the host. HOST, Host = HOST, /// The set of all current and future graphics pipeline stages. /// /// It is currently equivalent to setting all of the following flags, but automatically /// omitting any that are not supported in a given context. It also implicitly includes future /// flags that are added to Vulkan, if they are not yet supported by Vulkano. /// - `draw_indirect` /// - `task_shader` /// - `mesh_shader` /// - `vertex_input` /// - `vertex_shader` /// - `tessellation_control_shader` /// - `tessellation_evaluation_shader` /// - `geometry_shader` /// - `fragment_shader` /// - `early_fragment_tests` /// - `late_fragment_tests` /// - `color_attachment_output` /// - `conditional_rendering` /// - `transform_feedback` /// - `fragment_shading_rate_attachment` /// - `fragment_density_process` /// - `invocation_mask` ALL_GRAPHICS, AllGraphics = ALL_GRAPHICS, /// The set of all current and future pipeline stages of all types. /// /// It is currently equivalent to setting all flags in `PipelineStages`, but automatically /// omitting any that are not supported in a given context. It also implicitly includes future /// flags that are added to Vulkan, if they are not yet supported by Vulkano. ALL_COMMANDS, AllCommands = ALL_COMMANDS, /// The `copy_buffer`, `copy_image`, `copy_buffer_to_image`, `copy_image_to_buffer` and /// `copy_query_pool_results` commands are executed. COPY, Copy = COPY { api_version: V1_3, device_extensions: [khr_synchronization2], }, /// The `resolve_image` command is executed. RESOLVE, Resolve = RESOLVE { api_version: V1_3, device_extensions: [khr_synchronization2], }, /// The `blit_image` command is executed. BLIT, Blit = BLIT { api_version: V1_3, device_extensions: [khr_synchronization2], }, /// The `clear_color_image`, `clear_depth_stencil_image`, `fill_buffer` and `update_buffer` /// commands are executed. CLEAR, Clear = CLEAR { api_version: V1_3, device_extensions: [khr_synchronization2], }, /// Index buffers are read. INDEX_INPUT, IndexInput = INDEX_INPUT { api_version: V1_3, device_extensions: [khr_synchronization2], }, /// Vertex buffers are read. VERTEX_ATTRIBUTE_INPUT, VertexAttributeInput = VERTEX_ATTRIBUTE_INPUT { api_version: V1_3, device_extensions: [khr_synchronization2], }, /// The various pre-rasterization shader types are executed. /// /// It is currently equivalent to setting all of the following flags, but automatically /// omitting any that are not supported in a given context. It also implicitly includes future /// flags that are added to Vulkan, if they are not yet supported by Vulkano. /// - `vertex_shader` /// - `tessellation_control_shader` /// - `tessellation_evaluation_shader` /// - `geometry_shader` /// - `task_shader` /// - `mesh_shader` PRE_RASTERIZATION_SHADERS, PreRasterizationShaders = PRE_RASTERIZATION_SHADERS { api_version: V1_3, device_extensions: [khr_synchronization2], }, /// Video decode operations are performed. VIDEO_DECODE, VideoDecode = VIDEO_DECODE_KHR { device_extensions: [khr_video_decode_queue], }, /// Video encode operations are performed. VIDEO_ENCODE, VideoEncode = VIDEO_ENCODE_KHR { device_extensions: [khr_video_encode_queue], }, /// Vertex attribute output values are written to the transform feedback buffers. TRANSFORM_FEEDBACK, TransformFeedback = TRANSFORM_FEEDBACK_EXT { device_extensions: [ext_transform_feedback], }, /// The predicate of conditional rendering is read. CONDITIONAL_RENDERING, ConditionalRendering = CONDITIONAL_RENDERING_EXT { device_extensions: [ext_conditional_rendering], }, /// Acceleration_structure commands are executed. ACCELERATION_STRUCTURE_BUILD, AccelerationStructureBuild = ACCELERATION_STRUCTURE_BUILD_KHR { device_extensions: [khr_acceleration_structure, nv_ray_tracing], }, /// The various ray tracing shader types are executed. RAY_TRACING_SHADER, RayTracingShader = RAY_TRACING_SHADER_KHR { device_extensions: [khr_ray_tracing_pipeline, nv_ray_tracing], }, /// The fragment density map is read to generate the fragment areas. FRAGMENT_DENSITY_PROCESS, FragmentDensityProcess = FRAGMENT_DENSITY_PROCESS_EXT { device_extensions: [ext_fragment_density_map], }, /// The fragment shading rate attachment or shading rate image is read to determine the /// fragment shading rate for portions of a rasterized primitive. FRAGMENT_SHADING_RATE_ATTACHMENT, FragmentShadingRateAttachment = FRAGMENT_SHADING_RATE_ATTACHMENT_KHR { device_extensions: [khr_fragment_shading_rate], }, /// Device-side preprocessing for generated commands via the `preprocess_generated_commands` /// command is handled. COMMAND_PREPROCESS, CommandPreprocess = COMMAND_PREPROCESS_NV { device_extensions: [nv_device_generated_commands], }, /// Task shaders are executed. TASK_SHADER, TaskShader = TASK_SHADER_EXT { device_extensions: [ext_mesh_shader, nv_mesh_shader], }, /// Mesh shaders are executed. MESH_SHADER, MeshShader = MESH_SHADER_EXT { device_extensions: [ext_mesh_shader, nv_mesh_shader], }, /// Subpass shading shaders are executed. SUBPASS_SHADING, SubpassShading = SUBPASS_SHADING_HUAWEI { device_extensions: [huawei_subpass_shading], }, /// The invocation mask image is read to optimize ray dispatch. INVOCATION_MASK, InvocationMask = INVOCATION_MASK_HUAWEI { device_extensions: [huawei_invocation_mask], }, /// The `copy_acceleration_structure` command is executed. ACCELERATION_STRUCTURE_COPY, AccelerationStructureCopy = ACCELERATION_STRUCTURE_COPY_KHR { device_extensions: [khr_ray_tracing_maintenance1], }, /// Micromap commands are executed. MICROMAP_BUILD, MicromapBuild = MICROMAP_BUILD_EXT { device_extensions: [ext_opacity_micromap], }, /// Optical flow operations are performed. OPTICAL_FLOW, OpticalFlow = OPTICAL_FLOW_NV { device_extensions: [nv_optical_flow], }, } macro_rules! stage_order { { $(( $($before:ident)|+, $($after:ident)|+, ),)+ } => { static STAGE_ORDER: [(PipelineStages, PipelineStages); 15] = [ $( ( PipelineStages::empty() $(.union(PipelineStages::$before))+ , PipelineStages::empty() $(.union(PipelineStages::$after))+ ), )+ ]; }; } // Per // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-pipeline-stages-types stage_order! { ( TOP_OF_PIPE, DRAW_INDIRECT | COPY | RESOLVE | BLIT | CLEAR | VIDEO_DECODE | VIDEO_ENCODE | CONDITIONAL_RENDERING | COMMAND_PREPROCESS | ACCELERATION_STRUCTURE_BUILD | SUBPASS_SHADING | ACCELERATION_STRUCTURE_COPY | MICROMAP_BUILD | OPTICAL_FLOW, ), ( DRAW_INDIRECT, COMPUTE_SHADER | INDEX_INPUT | RAY_TRACING_SHADER | TASK_SHADER, ), ( INDEX_INPUT, VERTEX_ATTRIBUTE_INPUT, ), ( VERTEX_ATTRIBUTE_INPUT, VERTEX_SHADER, ), ( VERTEX_SHADER, TESSELLATION_CONTROL_SHADER, ), ( TESSELLATION_CONTROL_SHADER, TESSELLATION_EVALUATION_SHADER, ), ( TESSELLATION_EVALUATION_SHADER, GEOMETRY_SHADER, ), ( GEOMETRY_SHADER, TRANSFORM_FEEDBACK, ), ( TASK_SHADER, MESH_SHADER, ), ( TRANSFORM_FEEDBACK | MESH_SHADER, FRAGMENT_SHADING_RATE_ATTACHMENT, ), ( FRAGMENT_DENSITY_PROCESS | FRAGMENT_SHADING_RATE_ATTACHMENT, EARLY_FRAGMENT_TESTS, ), ( EARLY_FRAGMENT_TESTS, FRAGMENT_SHADER, ), ( FRAGMENT_SHADER, LATE_FRAGMENT_TESTS, ), ( LATE_FRAGMENT_TESTS, COLOR_ATTACHMENT_OUTPUT, ), ( COLOR_ATTACHMENT_OUTPUT | COMPUTE_SHADER | COPY | RESOLVE | BLIT | CLEAR | VIDEO_DECODE | VIDEO_ENCODE | CONDITIONAL_RENDERING | COMMAND_PREPROCESS | ACCELERATION_STRUCTURE_BUILD | RAY_TRACING_SHADER | SUBPASS_SHADING | ACCELERATION_STRUCTURE_COPY | MICROMAP_BUILD | OPTICAL_FLOW, BOTTOM_OF_PIPE, ), } impl From for PipelineStages { /// Corresponds to the table "[Supported pipeline stage flags]" in the Vulkan specification. /// /// [Supported pipeline stage flags]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-pipeline-stages-supported #[inline] fn from(val: QueueFlags) -> Self { let mut result = PipelineStages::TOP_OF_PIPE | PipelineStages::BOTTOM_OF_PIPE | PipelineStages::HOST | PipelineStages::ALL_COMMANDS; if val.intersects(QueueFlags::GRAPHICS | QueueFlags::COMPUTE | QueueFlags::TRANSFER) { result |= PipelineStages::ALL_TRANSFER | PipelineStages::COPY | PipelineStages::RESOLVE | PipelineStages::BLIT | PipelineStages::CLEAR | PipelineStages::ACCELERATION_STRUCTURE_COPY; } if val.intersects(QueueFlags::GRAPHICS) { result |= PipelineStages::DRAW_INDIRECT | PipelineStages::VERTEX_INPUT | PipelineStages::VERTEX_SHADER | PipelineStages::TESSELLATION_CONTROL_SHADER | PipelineStages::TESSELLATION_EVALUATION_SHADER | PipelineStages::GEOMETRY_SHADER | PipelineStages::FRAGMENT_SHADER | PipelineStages::EARLY_FRAGMENT_TESTS | PipelineStages::LATE_FRAGMENT_TESTS | PipelineStages::COLOR_ATTACHMENT_OUTPUT | PipelineStages::ALL_GRAPHICS | PipelineStages::INDEX_INPUT | PipelineStages::VERTEX_ATTRIBUTE_INPUT | PipelineStages::PRE_RASTERIZATION_SHADERS | PipelineStages::CONDITIONAL_RENDERING | PipelineStages::TRANSFORM_FEEDBACK | PipelineStages::COMMAND_PREPROCESS | PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT | PipelineStages::TASK_SHADER | PipelineStages::MESH_SHADER | PipelineStages::FRAGMENT_DENSITY_PROCESS | PipelineStages::SUBPASS_SHADING | PipelineStages::INVOCATION_MASK; } if val.intersects(QueueFlags::COMPUTE) { result |= PipelineStages::DRAW_INDIRECT | PipelineStages::COMPUTE_SHADER | PipelineStages::CONDITIONAL_RENDERING | PipelineStages::COMMAND_PREPROCESS | PipelineStages::ACCELERATION_STRUCTURE_BUILD | PipelineStages::RAY_TRACING_SHADER | PipelineStages::MICROMAP_BUILD; } if val.intersects(QueueFlags::VIDEO_DECODE) { result |= PipelineStages::VIDEO_DECODE; } if val.intersects(QueueFlags::VIDEO_ENCODE) { result |= PipelineStages::VIDEO_ENCODE; } if val.intersects(QueueFlags::OPTICAL_FLOW) { result |= PipelineStages::OPTICAL_FLOW; } result } } impl From for ash::vk::PipelineStageFlags { #[inline] fn from(val: PipelineStage) -> Self { Self::from_raw(val as u32) } } impl From for ash::vk::PipelineStageFlags { #[inline] fn from(val: PipelineStages) -> Self { Self::from_raw(ash::vk::PipelineStageFlags2::from(val).as_raw() as u32) } } vulkan_bitflags! { #[non_exhaustive] /// A set of memory access types that are included in a memory dependency. AccessFlags impl { /// Returns whether `self` contains stages that are only available in /// `VkAccessFlagBits2`. pub(crate) fn is_2(self) -> bool { !(self - (AccessFlags::INDIRECT_COMMAND_READ | AccessFlags::INDEX_READ | AccessFlags::VERTEX_ATTRIBUTE_READ | AccessFlags::UNIFORM_READ | AccessFlags::INPUT_ATTACHMENT_READ | AccessFlags::SHADER_READ | AccessFlags::SHADER_WRITE | AccessFlags::COLOR_ATTACHMENT_READ | AccessFlags::COLOR_ATTACHMENT_WRITE | AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE | AccessFlags::TRANSFER_READ | AccessFlags::TRANSFER_WRITE | AccessFlags::HOST_READ | AccessFlags::HOST_WRITE | AccessFlags::MEMORY_READ | AccessFlags::MEMORY_WRITE | AccessFlags::SHADER_SAMPLED_READ | AccessFlags::SHADER_STORAGE_READ | AccessFlags::SHADER_STORAGE_WRITE | AccessFlags::VIDEO_DECODE_READ | AccessFlags::VIDEO_DECODE_WRITE | AccessFlags::VIDEO_ENCODE_READ | AccessFlags::VIDEO_ENCODE_WRITE | AccessFlags::TRANSFORM_FEEDBACK_WRITE | AccessFlags::TRANSFORM_FEEDBACK_COUNTER_READ | AccessFlags::TRANSFORM_FEEDBACK_COUNTER_WRITE | AccessFlags::CONDITIONAL_RENDERING_READ | AccessFlags::COMMAND_PREPROCESS_READ | AccessFlags::COMMAND_PREPROCESS_WRITE | AccessFlags::FRAGMENT_SHADING_RATE_ATTACHMENT_READ | AccessFlags::ACCELERATION_STRUCTURE_READ | AccessFlags::ACCELERATION_STRUCTURE_WRITE | AccessFlags::FRAGMENT_DENSITY_MAP_READ | AccessFlags::COLOR_ATTACHMENT_READ_NONCOHERENT | AccessFlags::INVOCATION_MASK_READ)) .is_empty() } /// Replaces and unsets flags that are equivalent to multiple other flags. /// /// This may set flags that are not supported by the device, so this is for internal use /// only and should not be passed on to Vulkan. #[allow(dead_code)] // TODO: use this function pub(crate) fn expand(mut self) -> Self { if self.intersects(AccessFlags::SHADER_READ) { self -= AccessFlags::SHADER_READ; self |= AccessFlags::UNIFORM_READ | AccessFlags::SHADER_SAMPLED_READ | AccessFlags::SHADER_STORAGE_READ | AccessFlags::SHADER_BINDING_TABLE_READ; } if self.intersects(AccessFlags::SHADER_WRITE) { self -= AccessFlags::SHADER_WRITE; self |= AccessFlags::SHADER_STORAGE_WRITE; } self } } = AccessFlags2(u64); /// Read access to an indirect buffer. INDIRECT_COMMAND_READ = INDIRECT_COMMAND_READ, /// Read access to an index buffer. INDEX_READ = INDEX_READ, /// Read access to a vertex buffer. VERTEX_ATTRIBUTE_READ = VERTEX_ATTRIBUTE_READ, /// Read access to a uniform buffer in a shader. UNIFORM_READ = UNIFORM_READ, /// Read access to an input attachment in a fragment shader, within a render pass. INPUT_ATTACHMENT_READ = INPUT_ATTACHMENT_READ, /// Read access to a buffer or image in a shader. /// /// It is currently equivalent to setting all of the following flags, but automatically /// omitting any that are not supported in a given context. It also implicitly includes future /// flags that are added to Vulkan, if they are not yet supported by Vulkano. /// - `uniform_read` /// - `shader_sampled_read` /// - `shader_storage_read` /// - `shader_binding_table_read` SHADER_READ = SHADER_READ, /// Write access to a buffer or image in a shader. /// /// It is currently equivalent to `shader_storage_write`. It also implicitly includes future /// flags that are added to Vulkan, if they are not yet supported by Vulkano. SHADER_WRITE = SHADER_WRITE, /// Read access to a color attachment during blending, logic operations or /// subpass load operations. COLOR_ATTACHMENT_READ = COLOR_ATTACHMENT_READ, /// Write access to a color, resolve or depth/stencil resolve attachment during a render pass /// or subpass store operations. COLOR_ATTACHMENT_WRITE = COLOR_ATTACHMENT_WRITE, /// Read access to a depth/stencil attachment during depth/stencil operations or /// subpass load operations. DEPTH_STENCIL_ATTACHMENT_READ = DEPTH_STENCIL_ATTACHMENT_READ, /// Write access to a depth/stencil attachment during depth/stencil operations or /// subpass store operations. DEPTH_STENCIL_ATTACHMENT_WRITE = DEPTH_STENCIL_ATTACHMENT_WRITE, /// Read access to a buffer or image during a copy, blit or resolve command. TRANSFER_READ = TRANSFER_READ, /// Write access to a buffer or image during a copy, blit, resolve or clear command. TRANSFER_WRITE = TRANSFER_WRITE, /// Read access performed by the host. HOST_READ = HOST_READ, /// Write access performed by the host. HOST_WRITE = HOST_WRITE, /// Any type of read access. /// /// This is equivalent to setting all `_read` flags that are allowed in the given context. MEMORY_READ = MEMORY_READ, /// Any type of write access. /// /// This is equivalent to setting all `_write` flags that are allowed in the given context. MEMORY_WRITE = MEMORY_WRITE, /// Read access to a uniform texel buffer or sampled image in a shader. SHADER_SAMPLED_READ = SHADER_SAMPLED_READ { api_version: V1_3, device_extensions: [khr_synchronization2], }, /// Read access to a storage buffer, storage texel buffer or storage image in a shader. SHADER_STORAGE_READ = SHADER_STORAGE_READ { api_version: V1_3, device_extensions: [khr_synchronization2], }, /// Write access to a storage buffer, storage texel buffer or storage image in a shader. SHADER_STORAGE_WRITE = SHADER_STORAGE_WRITE { api_version: V1_3, device_extensions: [khr_synchronization2], }, /// Read access to an image or buffer as part of a video decode operation. VIDEO_DECODE_READ = VIDEO_DECODE_READ_KHR { device_extensions: [khr_video_decode_queue], }, /// Write access to an image or buffer as part of a video decode operation. VIDEO_DECODE_WRITE = VIDEO_DECODE_WRITE_KHR { device_extensions: [khr_video_decode_queue], }, /// Read access to an image or buffer as part of a video encode operation. VIDEO_ENCODE_READ = VIDEO_ENCODE_READ_KHR { device_extensions: [khr_video_encode_queue], }, /// Write access to an image or buffer as part of a video encode operation. VIDEO_ENCODE_WRITE = VIDEO_ENCODE_WRITE_KHR { device_extensions: [khr_video_encode_queue], }, /// Write access to a transform feedback buffer during transform feedback operations. TRANSFORM_FEEDBACK_WRITE = TRANSFORM_FEEDBACK_WRITE_EXT { device_extensions: [ext_transform_feedback], }, /// Read access to a transform feedback counter buffer during transform feedback operations. TRANSFORM_FEEDBACK_COUNTER_READ = TRANSFORM_FEEDBACK_COUNTER_READ_EXT { device_extensions: [ext_transform_feedback], }, /// Write access to a transform feedback counter buffer during transform feedback operations. TRANSFORM_FEEDBACK_COUNTER_WRITE = TRANSFORM_FEEDBACK_COUNTER_WRITE_EXT { device_extensions: [ext_transform_feedback], }, /// Read access to a predicate during conditional rendering. CONDITIONAL_RENDERING_READ = CONDITIONAL_RENDERING_READ_EXT { device_extensions: [ext_conditional_rendering], }, /// Read access to preprocess buffers input to `preprocess_generated_commands`. COMMAND_PREPROCESS_READ = COMMAND_PREPROCESS_READ_NV { device_extensions: [nv_device_generated_commands], }, /// Read access to sequences buffers output by `preprocess_generated_commands`. COMMAND_PREPROCESS_WRITE = COMMAND_PREPROCESS_WRITE_NV { device_extensions: [nv_device_generated_commands], }, /// Read access to a fragment shading rate attachment during rasterization. FRAGMENT_SHADING_RATE_ATTACHMENT_READ = FRAGMENT_SHADING_RATE_ATTACHMENT_READ_KHR { device_extensions: [khr_fragment_shading_rate], }, /// Read access to an acceleration structure or acceleration structure scratch buffer during /// trace, build or copy commands. ACCELERATION_STRUCTURE_READ = ACCELERATION_STRUCTURE_READ_KHR { device_extensions: [khr_acceleration_structure, nv_ray_tracing], }, /// Write access to an acceleration structure or acceleration structure scratch buffer during /// trace, build or copy commands. ACCELERATION_STRUCTURE_WRITE = ACCELERATION_STRUCTURE_WRITE_KHR { device_extensions: [khr_acceleration_structure, nv_ray_tracing], }, /// Read access to a fragment density map attachment during dynamic fragment density map /// operations. FRAGMENT_DENSITY_MAP_READ = FRAGMENT_DENSITY_MAP_READ_EXT { device_extensions: [ext_fragment_density_map], }, /// Read access to color attachments when performing advanced blend operations. COLOR_ATTACHMENT_READ_NONCOHERENT = COLOR_ATTACHMENT_READ_NONCOHERENT_EXT { device_extensions: [ext_blend_operation_advanced], }, /// Read access to an invocation mask image. INVOCATION_MASK_READ = INVOCATION_MASK_READ_HUAWEI { device_extensions: [huawei_invocation_mask], }, /// Read access to a shader binding table. SHADER_BINDING_TABLE_READ = SHADER_BINDING_TABLE_READ_KHR { device_extensions: [khr_ray_tracing_maintenance1], }, /// Read access to a micromap object. MICROMAP_READ = MICROMAP_READ_EXT { device_extensions: [ext_opacity_micromap], }, /// Write access to a micromap object. MICROMAP_WRITE = MICROMAP_WRITE_EXT { device_extensions: [ext_opacity_micromap], }, /// Read access to a buffer or image during optical flow operations. OPTICAL_FLOW_READ = OPTICAL_FLOW_READ_NV { device_extensions: [nv_optical_flow], }, /// Write access to a buffer or image during optical flow operations. OPTICAL_FLOW_WRITE = OPTICAL_FLOW_WRITE_NV { device_extensions: [nv_optical_flow], }, } impl From for AccessFlags { /// Corresponds to the table "[Supported access types]" in the Vulkan specification. /// /// [Supported access types]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-access-types-supported #[inline] fn from(mut val: PipelineStages) -> Self { if val.is_empty() { return AccessFlags::empty(); } val = val.expand(QueueFlags::GRAPHICS | QueueFlags::COMPUTE | QueueFlags::TRANSFER); let mut result = AccessFlags::MEMORY_READ | AccessFlags::MEMORY_WRITE; if val.intersects(PipelineStages::DRAW_INDIRECT) { result |= AccessFlags::INDIRECT_COMMAND_READ | AccessFlags::TRANSFORM_FEEDBACK_COUNTER_READ; } if val.intersects( PipelineStages::VERTEX_SHADER | PipelineStages::TESSELLATION_CONTROL_SHADER | PipelineStages::TESSELLATION_EVALUATION_SHADER | PipelineStages::GEOMETRY_SHADER | PipelineStages::FRAGMENT_SHADER | PipelineStages::COMPUTE_SHADER | PipelineStages::RAY_TRACING_SHADER | PipelineStages::TASK_SHADER | PipelineStages::MESH_SHADER, ) { result |= AccessFlags::SHADER_READ | AccessFlags::UNIFORM_READ | AccessFlags::SHADER_SAMPLED_READ | AccessFlags::SHADER_STORAGE_READ | AccessFlags::SHADER_WRITE | AccessFlags::SHADER_STORAGE_WRITE | AccessFlags::ACCELERATION_STRUCTURE_READ; } if val.intersects(PipelineStages::FRAGMENT_SHADER | PipelineStages::SUBPASS_SHADING) { result |= AccessFlags::INPUT_ATTACHMENT_READ; } if val .intersects(PipelineStages::EARLY_FRAGMENT_TESTS | PipelineStages::LATE_FRAGMENT_TESTS) { result |= AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ | AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE; } if val.intersects(PipelineStages::COLOR_ATTACHMENT_OUTPUT) { result |= AccessFlags::COLOR_ATTACHMENT_READ | AccessFlags::COLOR_ATTACHMENT_WRITE | AccessFlags::COLOR_ATTACHMENT_READ_NONCOHERENT; } if val.intersects(PipelineStages::HOST) { result |= AccessFlags::HOST_READ | AccessFlags::HOST_WRITE; } if val.intersects( PipelineStages::COPY | PipelineStages::RESOLVE | PipelineStages::BLIT | PipelineStages::ACCELERATION_STRUCTURE_COPY, ) { result |= AccessFlags::TRANSFER_READ | AccessFlags::TRANSFER_WRITE; } if val.intersects(PipelineStages::CLEAR) { result |= AccessFlags::TRANSFER_WRITE; } if val.intersects(PipelineStages::INDEX_INPUT) { result |= AccessFlags::INDEX_READ; } if val.intersects(PipelineStages::VERTEX_ATTRIBUTE_INPUT) { result |= AccessFlags::VERTEX_ATTRIBUTE_READ; } if val.intersects(PipelineStages::VIDEO_DECODE) { result |= AccessFlags::VIDEO_DECODE_READ | AccessFlags::VIDEO_DECODE_WRITE; } if val.intersects(PipelineStages::VIDEO_ENCODE) { result |= AccessFlags::VIDEO_ENCODE_READ | AccessFlags::VIDEO_ENCODE_WRITE; } if val.intersects(PipelineStages::TRANSFORM_FEEDBACK) { result |= AccessFlags::TRANSFORM_FEEDBACK_WRITE | AccessFlags::TRANSFORM_FEEDBACK_COUNTER_WRITE | AccessFlags::TRANSFORM_FEEDBACK_COUNTER_READ; } if val.intersects(PipelineStages::CONDITIONAL_RENDERING) { result |= AccessFlags::CONDITIONAL_RENDERING_READ; } if val.intersects(PipelineStages::ACCELERATION_STRUCTURE_BUILD) { result |= AccessFlags::INDIRECT_COMMAND_READ | AccessFlags::SHADER_READ | AccessFlags::SHADER_SAMPLED_READ | AccessFlags::SHADER_STORAGE_READ | AccessFlags::SHADER_STORAGE_WRITE | AccessFlags::TRANSFER_READ | AccessFlags::TRANSFER_WRITE | AccessFlags::ACCELERATION_STRUCTURE_READ | AccessFlags::ACCELERATION_STRUCTURE_WRITE | AccessFlags::MICROMAP_READ; } if val.intersects(PipelineStages::RAY_TRACING_SHADER) { result |= AccessFlags::SHADER_BINDING_TABLE_READ; } if val.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS) { result |= AccessFlags::FRAGMENT_DENSITY_MAP_READ; } if val.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT) { result |= AccessFlags::FRAGMENT_SHADING_RATE_ATTACHMENT_READ; } if val.intersects(PipelineStages::COMMAND_PREPROCESS) { result |= AccessFlags::COMMAND_PREPROCESS_READ | AccessFlags::COMMAND_PREPROCESS_WRITE; } if val.intersects(PipelineStages::INVOCATION_MASK) { result |= AccessFlags::INVOCATION_MASK_READ; } if val.intersects(PipelineStages::MICROMAP_BUILD) { result |= AccessFlags::MICROMAP_READ | AccessFlags::MICROMAP_WRITE; } if val.intersects(PipelineStages::OPTICAL_FLOW) { result |= AccessFlags::OPTICAL_FLOW_READ | AccessFlags::OPTICAL_FLOW_WRITE; } result } } impl From for ash::vk::AccessFlags { #[inline] fn from(val: AccessFlags) -> Self { Self::from_raw(ash::vk::AccessFlags2::from(val).as_raw() as u32) } } /// The full specification of memory access by the pipeline for a particular resource. #[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] pub struct PipelineMemoryAccess { /// The pipeline stages the resource will be accessed in. pub stages: PipelineStages, /// The type of memory access that will be performed. pub access: AccessFlags, /// Whether the resource needs exclusive (mutable) access or can be shared. pub exclusive: bool, } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[allow(non_camel_case_types, dead_code)] #[repr(u8)] pub(crate) enum PipelineStageAccess { // There is no stage/access for this, but it is a memory write operation nonetheless. ImageLayoutTransition, DrawIndirect_IndirectCommandRead, DrawIndirect_TransformFeedbackCounterRead, VertexShader_UniformRead, VertexShader_ShaderSampledRead, VertexShader_ShaderStorageRead, VertexShader_ShaderStorageWrite, VertexShader_AccelerationStructureRead, TessellationControlShader_UniformRead, TessellationControlShader_ShaderSampledRead, TessellationControlShader_ShaderStorageRead, TessellationControlShader_ShaderStorageWrite, TessellationControlShader_AccelerationStructureRead, TessellationEvaluationShader_UniformRead, TessellationEvaluationShader_ShaderSampledRead, TessellationEvaluationShader_ShaderStorageRead, TessellationEvaluationShader_ShaderStorageWrite, TessellationEvaluationShader_AccelerationStructureRead, GeometryShader_UniformRead, GeometryShader_ShaderSampledRead, GeometryShader_ShaderStorageRead, GeometryShader_ShaderStorageWrite, GeometryShader_AccelerationStructureRead, FragmentShader_UniformRead, FragmentShader_InputAttachmentRead, FragmentShader_ShaderSampledRead, FragmentShader_ShaderStorageRead, FragmentShader_ShaderStorageWrite, FragmentShader_AccelerationStructureRead, EarlyFragmentTests_DepthStencilAttachmentRead, EarlyFragmentTests_DepthStencilAttachmentWrite, LateFragmentTests_DepthStencilAttachmentRead, LateFragmentTests_DepthStencilAttachmentWrite, ColorAttachmentOutput_ColorAttachmentRead, ColorAttachmentOutput_ColorAttachmentWrite, ColorAttachmentOutput_ColorAttachmentReadNoncoherent, ComputeShader_UniformRead, ComputeShader_ShaderSampledRead, ComputeShader_ShaderStorageRead, ComputeShader_ShaderStorageWrite, ComputeShader_AccelerationStructureRead, Host_HostRead, Host_HostWrite, Copy_TransferRead, Copy_TransferWrite, Resolve_TransferRead, Resolve_TransferWrite, Blit_TransferRead, Blit_TransferWrite, Clear_TransferWrite, IndexInput_IndexRead, VertexAttributeInput_VertexAttributeRead, VideoDecode_VideoDecodeRead, VideoDecode_VideoDecodeWrite, VideoEncode_VideoEncodeRead, VideoEncode_VideoEncodeWrite, TransformFeedback_TransformFeedbackWrite, TransformFeedback_TransformFeedbackCounterRead, TransformFeedback_TransformFeedbackCounterWrite, ConditionalRendering_ConditionalRenderingRead, AccelerationStructureBuild_IndirectCommandRead, AccelerationStructureBuild_UniformRead, AccelerationStructureBuild_TransferRead, AccelerationStructureBuild_TransferWrite, AccelerationStructureBuild_ShaderSampledRead, AccelerationStructureBuild_ShaderStorageRead, AccelerationStructureBuild_AccelerationStructureRead, AccelerationStructureBuild_AccelerationStructureWrite, AccelerationStructureBuild_MicromapRead, RayTracingShader_UniformRead, RayTracingShader_ShaderSampledRead, RayTracingShader_ShaderStorageRead, RayTracingShader_ShaderStorageWrite, RayTracingShader_AccelerationStructureRead, RayTracingShader_ShaderBindingTableRead, FragmentDensityProcess_FragmentDensityMapRead, FragmentShadingRateAttachment_FragmentShadingRateAttachmentRead, CommandPreprocess_CommandPreprocessRead, CommandPreprocess_CommandPreprocessWrite, TaskShader_UniformRead, TaskShader_ShaderSampledRead, TaskShader_ShaderStorageRead, TaskShader_ShaderStorageWrite, TaskShader_AccelerationStructureRead, MeshShader_UniformRead, MeshShader_ShaderSampledRead, MeshShader_ShaderStorageRead, MeshShader_ShaderStorageWrite, MeshShader_AccelerationStructureRead, SubpassShading_InputAttachmentRead, InvocationMask_InvocationMaskRead, AccelerationStructureCopy_TransferRead, AccelerationStructureCopy_TransferWrite, OpticalFlow_OpticalFlowRead, OpticalFlow_OpticalFlowWrite, MicromapBuild_MicromapRead, MicromapBuild_MicromapWrite, // If there are ever more than 128 preceding values, then there will be a compile error: // "discriminant value `128` assigned more than once" __MAX_VALUE__ = 128, } impl PipelineStageAccess { #[inline] pub(crate) const fn is_write(self) -> bool { matches!( self, PipelineStageAccess::ImageLayoutTransition | PipelineStageAccess::VertexShader_ShaderStorageWrite | PipelineStageAccess::TessellationControlShader_ShaderStorageWrite | PipelineStageAccess::TessellationEvaluationShader_ShaderStorageWrite | PipelineStageAccess::GeometryShader_ShaderStorageWrite | PipelineStageAccess::FragmentShader_ShaderStorageWrite | PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite | PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite | PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite | PipelineStageAccess::ComputeShader_ShaderStorageWrite | PipelineStageAccess::Host_HostWrite | PipelineStageAccess::Copy_TransferWrite | PipelineStageAccess::Resolve_TransferWrite | PipelineStageAccess::Blit_TransferWrite | PipelineStageAccess::Clear_TransferWrite | PipelineStageAccess::VideoDecode_VideoDecodeWrite | PipelineStageAccess::VideoEncode_VideoEncodeWrite | PipelineStageAccess::TransformFeedback_TransformFeedbackWrite | PipelineStageAccess::TransformFeedback_TransformFeedbackCounterWrite | PipelineStageAccess::AccelerationStructureBuild_TransferWrite | PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureWrite | PipelineStageAccess::RayTracingShader_ShaderStorageWrite | PipelineStageAccess::CommandPreprocess_CommandPreprocessWrite | PipelineStageAccess::TaskShader_ShaderStorageWrite | PipelineStageAccess::MeshShader_ShaderStorageWrite | PipelineStageAccess::AccelerationStructureCopy_TransferWrite | PipelineStageAccess::OpticalFlow_OpticalFlowWrite | PipelineStageAccess::MicromapBuild_MicromapWrite ) } pub(crate) fn iter_descriptor_stages( descriptor_type: DescriptorType, stages_read: ShaderStages, stages_write: ShaderStages, ) -> impl Iterator + 'static { static MAP_READ: Lazy< HashMap>, > = Lazy::new(|| { let uniform_read = [ DescriptorType::UniformBuffer, DescriptorType::UniformBufferDynamic, ] .into_iter() .map(|descriptor_type| { ( descriptor_type, [ ( PipelineStage::VertexShader, PipelineStageAccess::VertexShader_UniformRead, ), ( PipelineStage::TessellationControlShader, PipelineStageAccess::TessellationControlShader_UniformRead, ), ( PipelineStage::TessellationEvaluationShader, PipelineStageAccess::TessellationControlShader_UniformRead, ), ( PipelineStage::GeometryShader, PipelineStageAccess::GeometryShader_UniformRead, ), ( PipelineStage::FragmentShader, PipelineStageAccess::FragmentShader_UniformRead, ), ( PipelineStage::ComputeShader, PipelineStageAccess::ComputeShader_UniformRead, ), ( PipelineStage::RayTracingShader, PipelineStageAccess::RayTracingShader_UniformRead, ), ( PipelineStage::TaskShader, PipelineStageAccess::TaskShader_UniformRead, ), ( PipelineStage::MeshShader, PipelineStageAccess::MeshShader_UniformRead, ), ] .into_iter() .collect(), ) }); let shader_sampled_read = [ DescriptorType::CombinedImageSampler, DescriptorType::SampledImage, DescriptorType::UniformTexelBuffer, ] .into_iter() .map(|descriptor_type| { ( descriptor_type, [ ( PipelineStage::VertexShader, PipelineStageAccess::VertexShader_ShaderSampledRead, ), ( PipelineStage::TessellationControlShader, PipelineStageAccess::TessellationControlShader_ShaderSampledRead, ), ( PipelineStage::TessellationEvaluationShader, PipelineStageAccess::TessellationControlShader_ShaderSampledRead, ), ( PipelineStage::GeometryShader, PipelineStageAccess::GeometryShader_ShaderSampledRead, ), ( PipelineStage::FragmentShader, PipelineStageAccess::FragmentShader_ShaderSampledRead, ), ( PipelineStage::ComputeShader, PipelineStageAccess::ComputeShader_ShaderSampledRead, ), ( PipelineStage::RayTracingShader, PipelineStageAccess::RayTracingShader_ShaderSampledRead, ), ( PipelineStage::TaskShader, PipelineStageAccess::TaskShader_ShaderSampledRead, ), ( PipelineStage::MeshShader, PipelineStageAccess::MeshShader_ShaderSampledRead, ), ] .into_iter() .collect(), ) }); let shader_storage_read = [ DescriptorType::StorageImage, DescriptorType::StorageTexelBuffer, DescriptorType::StorageBuffer, DescriptorType::StorageBufferDynamic, ] .into_iter() .map(|descriptor_type| { ( descriptor_type, [ ( PipelineStage::VertexShader, PipelineStageAccess::VertexShader_ShaderStorageRead, ), ( PipelineStage::TessellationControlShader, PipelineStageAccess::TessellationControlShader_ShaderStorageRead, ), ( PipelineStage::TessellationEvaluationShader, PipelineStageAccess::TessellationControlShader_ShaderStorageRead, ), ( PipelineStage::GeometryShader, PipelineStageAccess::GeometryShader_ShaderStorageRead, ), ( PipelineStage::FragmentShader, PipelineStageAccess::FragmentShader_ShaderStorageRead, ), ( PipelineStage::ComputeShader, PipelineStageAccess::ComputeShader_ShaderStorageRead, ), ( PipelineStage::RayTracingShader, PipelineStageAccess::RayTracingShader_ShaderStorageRead, ), ( PipelineStage::TaskShader, PipelineStageAccess::TaskShader_ShaderStorageRead, ), ( PipelineStage::MeshShader, PipelineStageAccess::MeshShader_ShaderStorageRead, ), ] .into_iter() .collect(), ) }); let input_attachment_read = [DescriptorType::InputAttachment] .into_iter() .map(|descriptor_type| { ( descriptor_type, [( PipelineStage::FragmentShader, PipelineStageAccess::FragmentShader_InputAttachmentRead, )] .into_iter() .collect(), ) }); uniform_read .chain(shader_sampled_read) .chain(shader_storage_read) .chain(input_attachment_read) .collect() }); static MAP_WRITE: Lazy< HashMap>, > = Lazy::new(|| { let shader_storage_write = [ DescriptorType::StorageImage, DescriptorType::StorageTexelBuffer, DescriptorType::StorageBuffer, DescriptorType::StorageBufferDynamic, ] .into_iter() .map(|descriptor_type| { ( descriptor_type, [ ( PipelineStage::VertexShader, PipelineStageAccess::VertexShader_ShaderStorageWrite, ), ( PipelineStage::TessellationControlShader, PipelineStageAccess::TessellationControlShader_ShaderStorageWrite, ), ( PipelineStage::TessellationEvaluationShader, PipelineStageAccess::TessellationControlShader_ShaderStorageWrite, ), ( PipelineStage::GeometryShader, PipelineStageAccess::GeometryShader_ShaderStorageWrite, ), ( PipelineStage::FragmentShader, PipelineStageAccess::FragmentShader_ShaderStorageWrite, ), ( PipelineStage::ComputeShader, PipelineStageAccess::ComputeShader_ShaderStorageWrite, ), ( PipelineStage::RayTracingShader, PipelineStageAccess::RayTracingShader_ShaderStorageWrite, ), ( PipelineStage::TaskShader, PipelineStageAccess::TaskShader_ShaderStorageWrite, ), ( PipelineStage::MeshShader, PipelineStageAccess::MeshShader_ShaderStorageWrite, ), ] .into_iter() .collect(), ) }); shader_storage_write.collect() }); [ (stages_read, &*MAP_READ, "read"), (stages_write, &*MAP_WRITE, "write"), ] .into_iter() .filter(|(stages, _, _)| !stages.is_empty()) .flat_map(move |(stages, descriptor_map, access)| { let stages_map = descriptor_map.get(&descriptor_type).unwrap_or_else(|| { panic!( "DescriptorType::{:?} does not {} memory", descriptor_type, access, ) }); PipelineStages::from(stages).into_iter().map(move |stage| { *stages_map.get(&stage).unwrap_or_else(|| { panic!( "DescriptorType::{:?} does not {} memory in PipelineStage::{:?}", descriptor_type, access, stage, ) }) }) }) } } impl TryFrom for PipelineStage { type Error = (); #[inline] fn try_from(val: PipelineStageAccess) -> Result { Ok(match val { PipelineStageAccess::ImageLayoutTransition => return Err(()), PipelineStageAccess::DrawIndirect_IndirectCommandRead | PipelineStageAccess::DrawIndirect_TransformFeedbackCounterRead => PipelineStage::DrawIndirect, PipelineStageAccess::VertexShader_UniformRead | PipelineStageAccess::VertexShader_ShaderSampledRead | PipelineStageAccess::VertexShader_ShaderStorageRead | PipelineStageAccess::VertexShader_ShaderStorageWrite | PipelineStageAccess::VertexShader_AccelerationStructureRead => PipelineStage::VertexShader, PipelineStageAccess::TessellationControlShader_UniformRead | PipelineStageAccess::TessellationControlShader_ShaderSampledRead | PipelineStageAccess::TessellationControlShader_ShaderStorageRead | PipelineStageAccess::TessellationControlShader_ShaderStorageWrite | PipelineStageAccess::TessellationControlShader_AccelerationStructureRead => PipelineStage::TessellationControlShader, PipelineStageAccess::TessellationEvaluationShader_UniformRead | PipelineStageAccess::TessellationEvaluationShader_ShaderSampledRead | PipelineStageAccess::TessellationEvaluationShader_ShaderStorageRead | PipelineStageAccess::TessellationEvaluationShader_ShaderStorageWrite | PipelineStageAccess::TessellationEvaluationShader_AccelerationStructureRead => PipelineStage::TessellationEvaluationShader, PipelineStageAccess::GeometryShader_UniformRead | PipelineStageAccess::GeometryShader_ShaderSampledRead | PipelineStageAccess::GeometryShader_ShaderStorageRead | PipelineStageAccess::GeometryShader_ShaderStorageWrite | PipelineStageAccess::GeometryShader_AccelerationStructureRead => PipelineStage::GeometryShader, PipelineStageAccess::FragmentShader_UniformRead | PipelineStageAccess::FragmentShader_InputAttachmentRead | PipelineStageAccess::FragmentShader_ShaderSampledRead | PipelineStageAccess::FragmentShader_ShaderStorageRead | PipelineStageAccess::FragmentShader_ShaderStorageWrite | PipelineStageAccess::FragmentShader_AccelerationStructureRead => PipelineStage::FragmentShader, PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentRead | PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite => PipelineStage::EarlyFragmentTests, PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentRead | PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite => PipelineStage::LateFragmentTests, PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead | PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite | PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentReadNoncoherent => PipelineStage::ColorAttachmentOutput, PipelineStageAccess::ComputeShader_UniformRead | PipelineStageAccess::ComputeShader_ShaderSampledRead | PipelineStageAccess::ComputeShader_ShaderStorageRead | PipelineStageAccess::ComputeShader_ShaderStorageWrite | PipelineStageAccess::ComputeShader_AccelerationStructureRead => PipelineStage::ComputeShader, PipelineStageAccess::Host_HostRead | PipelineStageAccess::Host_HostWrite => PipelineStage::Host, PipelineStageAccess::Copy_TransferRead | PipelineStageAccess::Copy_TransferWrite => PipelineStage::Copy, PipelineStageAccess::Resolve_TransferRead | PipelineStageAccess::Resolve_TransferWrite => PipelineStage::Resolve, PipelineStageAccess::Blit_TransferRead | PipelineStageAccess::Blit_TransferWrite => PipelineStage::Blit, PipelineStageAccess::Clear_TransferWrite => PipelineStage::Clear, PipelineStageAccess::IndexInput_IndexRead => PipelineStage::IndexInput, PipelineStageAccess::VertexAttributeInput_VertexAttributeRead => PipelineStage::VertexAttributeInput, PipelineStageAccess::VideoDecode_VideoDecodeRead | PipelineStageAccess::VideoDecode_VideoDecodeWrite => PipelineStage::VideoDecode, PipelineStageAccess::VideoEncode_VideoEncodeRead | PipelineStageAccess::VideoEncode_VideoEncodeWrite => PipelineStage::VideoEncode, PipelineStageAccess::TransformFeedback_TransformFeedbackWrite | PipelineStageAccess::TransformFeedback_TransformFeedbackCounterRead | PipelineStageAccess::TransformFeedback_TransformFeedbackCounterWrite => PipelineStage::TransformFeedback, PipelineStageAccess::ConditionalRendering_ConditionalRenderingRead => PipelineStage::ConditionalRendering, PipelineStageAccess::AccelerationStructureBuild_IndirectCommandRead | PipelineStageAccess::AccelerationStructureBuild_UniformRead | PipelineStageAccess::AccelerationStructureBuild_TransferRead | PipelineStageAccess::AccelerationStructureBuild_TransferWrite | PipelineStageAccess::AccelerationStructureBuild_ShaderSampledRead | PipelineStageAccess::AccelerationStructureBuild_ShaderStorageRead | PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureRead | PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureWrite | PipelineStageAccess::AccelerationStructureBuild_MicromapRead => PipelineStage::AccelerationStructureBuild, PipelineStageAccess::RayTracingShader_UniformRead | PipelineStageAccess::RayTracingShader_ShaderSampledRead | PipelineStageAccess::RayTracingShader_ShaderStorageRead | PipelineStageAccess::RayTracingShader_ShaderStorageWrite | PipelineStageAccess::RayTracingShader_AccelerationStructureRead => PipelineStage::RayTracingShader, | PipelineStageAccess::RayTracingShader_ShaderBindingTableRead => PipelineStage::RayTracingShader, PipelineStageAccess::FragmentDensityProcess_FragmentDensityMapRead => PipelineStage::FragmentDensityProcess, PipelineStageAccess::FragmentShadingRateAttachment_FragmentShadingRateAttachmentRead => PipelineStage::FragmentShadingRateAttachment, PipelineStageAccess::CommandPreprocess_CommandPreprocessRead | PipelineStageAccess::CommandPreprocess_CommandPreprocessWrite => PipelineStage::CommandPreprocess, PipelineStageAccess::TaskShader_UniformRead | PipelineStageAccess::TaskShader_ShaderSampledRead | PipelineStageAccess::TaskShader_ShaderStorageRead | PipelineStageAccess::TaskShader_ShaderStorageWrite | PipelineStageAccess::TaskShader_AccelerationStructureRead => PipelineStage::TaskShader, PipelineStageAccess::MeshShader_UniformRead | PipelineStageAccess::MeshShader_ShaderSampledRead | PipelineStageAccess::MeshShader_ShaderStorageRead | PipelineStageAccess::MeshShader_ShaderStorageWrite | PipelineStageAccess::MeshShader_AccelerationStructureRead => PipelineStage::MeshShader, PipelineStageAccess::SubpassShading_InputAttachmentRead => PipelineStage::SubpassShading, PipelineStageAccess::InvocationMask_InvocationMaskRead => PipelineStage::InvocationMask, PipelineStageAccess::AccelerationStructureCopy_TransferRead | PipelineStageAccess::AccelerationStructureCopy_TransferWrite => PipelineStage::AccelerationStructureCopy, PipelineStageAccess::OpticalFlow_OpticalFlowRead | PipelineStageAccess::OpticalFlow_OpticalFlowWrite => PipelineStage::OpticalFlow, PipelineStageAccess::MicromapBuild_MicromapRead | PipelineStageAccess::MicromapBuild_MicromapWrite => PipelineStage::MicromapBuild, PipelineStageAccess::__MAX_VALUE__ => unreachable!(), }) } } impl From for AccessFlags { #[inline] fn from(val: PipelineStageAccess) -> Self { match val { PipelineStageAccess::ImageLayoutTransition => AccessFlags::empty(), PipelineStageAccess::DrawIndirect_IndirectCommandRead | PipelineStageAccess::AccelerationStructureBuild_IndirectCommandRead => AccessFlags::INDIRECT_COMMAND_READ, PipelineStageAccess::IndexInput_IndexRead => AccessFlags::INDEX_READ, PipelineStageAccess::VertexAttributeInput_VertexAttributeRead => AccessFlags::VERTEX_ATTRIBUTE_READ, PipelineStageAccess::VertexShader_UniformRead | PipelineStageAccess::TessellationControlShader_UniformRead | PipelineStageAccess::TessellationEvaluationShader_UniformRead | PipelineStageAccess::GeometryShader_UniformRead | PipelineStageAccess::FragmentShader_UniformRead | PipelineStageAccess::ComputeShader_UniformRead | PipelineStageAccess::AccelerationStructureBuild_UniformRead | PipelineStageAccess::RayTracingShader_UniformRead | PipelineStageAccess::TaskShader_UniformRead | PipelineStageAccess::MeshShader_UniformRead => AccessFlags::UNIFORM_READ, PipelineStageAccess::FragmentShader_InputAttachmentRead | PipelineStageAccess::SubpassShading_InputAttachmentRead => AccessFlags::INPUT_ATTACHMENT_READ, PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead => AccessFlags::COLOR_ATTACHMENT_READ, PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite => AccessFlags::COLOR_ATTACHMENT_WRITE, PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentRead | PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentRead => AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ, PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite | PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite => AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE, PipelineStageAccess::Copy_TransferRead | PipelineStageAccess::Resolve_TransferRead | PipelineStageAccess::Blit_TransferRead | PipelineStageAccess::AccelerationStructureBuild_TransferRead | PipelineStageAccess::AccelerationStructureCopy_TransferRead => AccessFlags::TRANSFER_READ, PipelineStageAccess::Copy_TransferWrite | PipelineStageAccess::Resolve_TransferWrite | PipelineStageAccess::Blit_TransferWrite | PipelineStageAccess::Clear_TransferWrite | PipelineStageAccess::AccelerationStructureBuild_TransferWrite | PipelineStageAccess::AccelerationStructureCopy_TransferWrite => AccessFlags::TRANSFER_WRITE, PipelineStageAccess::Host_HostRead => AccessFlags::HOST_READ, PipelineStageAccess::Host_HostWrite => AccessFlags::HOST_WRITE, PipelineStageAccess::VertexShader_ShaderSampledRead | PipelineStageAccess::TessellationControlShader_ShaderSampledRead | PipelineStageAccess::TessellationEvaluationShader_ShaderSampledRead | PipelineStageAccess::GeometryShader_ShaderSampledRead | PipelineStageAccess::FragmentShader_ShaderSampledRead | PipelineStageAccess::ComputeShader_ShaderSampledRead | PipelineStageAccess::AccelerationStructureBuild_ShaderSampledRead | PipelineStageAccess::RayTracingShader_ShaderSampledRead | PipelineStageAccess::TaskShader_ShaderSampledRead | PipelineStageAccess::MeshShader_ShaderSampledRead => AccessFlags::SHADER_SAMPLED_READ, PipelineStageAccess::VertexShader_ShaderStorageRead | PipelineStageAccess::TessellationControlShader_ShaderStorageRead | PipelineStageAccess::TessellationEvaluationShader_ShaderStorageRead | PipelineStageAccess::GeometryShader_ShaderStorageRead | PipelineStageAccess::FragmentShader_ShaderStorageRead | PipelineStageAccess::ComputeShader_ShaderStorageRead | PipelineStageAccess::AccelerationStructureBuild_ShaderStorageRead | PipelineStageAccess::RayTracingShader_ShaderStorageRead | PipelineStageAccess::TaskShader_ShaderStorageRead | PipelineStageAccess::MeshShader_ShaderStorageRead => AccessFlags::SHADER_STORAGE_READ, PipelineStageAccess::VertexShader_ShaderStorageWrite | PipelineStageAccess::TessellationControlShader_ShaderStorageWrite | PipelineStageAccess::TessellationEvaluationShader_ShaderStorageWrite | PipelineStageAccess::GeometryShader_ShaderStorageWrite | PipelineStageAccess::FragmentShader_ShaderStorageWrite | PipelineStageAccess::ComputeShader_ShaderStorageWrite | PipelineStageAccess::RayTracingShader_ShaderStorageWrite | PipelineStageAccess::TaskShader_ShaderStorageWrite | PipelineStageAccess::MeshShader_ShaderStorageWrite => AccessFlags::SHADER_STORAGE_WRITE, PipelineStageAccess::VideoDecode_VideoDecodeRead => AccessFlags::VIDEO_DECODE_READ, PipelineStageAccess::VideoDecode_VideoDecodeWrite => AccessFlags::VIDEO_DECODE_WRITE, PipelineStageAccess::VideoEncode_VideoEncodeRead => AccessFlags::VIDEO_ENCODE_READ, PipelineStageAccess::VideoEncode_VideoEncodeWrite => AccessFlags::VIDEO_ENCODE_WRITE, PipelineStageAccess::TransformFeedback_TransformFeedbackWrite => AccessFlags::TRANSFORM_FEEDBACK_WRITE, PipelineStageAccess::DrawIndirect_TransformFeedbackCounterRead | PipelineStageAccess::TransformFeedback_TransformFeedbackCounterRead => AccessFlags::TRANSFORM_FEEDBACK_COUNTER_READ, PipelineStageAccess::TransformFeedback_TransformFeedbackCounterWrite => AccessFlags::TRANSFORM_FEEDBACK_COUNTER_WRITE, PipelineStageAccess::ConditionalRendering_ConditionalRenderingRead => AccessFlags::CONDITIONAL_RENDERING_READ, PipelineStageAccess::CommandPreprocess_CommandPreprocessRead => AccessFlags::COMMAND_PREPROCESS_READ, PipelineStageAccess::CommandPreprocess_CommandPreprocessWrite => AccessFlags::COMMAND_PREPROCESS_WRITE, PipelineStageAccess::FragmentShadingRateAttachment_FragmentShadingRateAttachmentRead => AccessFlags::FRAGMENT_SHADING_RATE_ATTACHMENT_READ, PipelineStageAccess::VertexShader_AccelerationStructureRead | PipelineStageAccess::TessellationControlShader_AccelerationStructureRead | PipelineStageAccess::TessellationEvaluationShader_AccelerationStructureRead | PipelineStageAccess::GeometryShader_AccelerationStructureRead | PipelineStageAccess::FragmentShader_AccelerationStructureRead | PipelineStageAccess::ComputeShader_AccelerationStructureRead | PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureRead | PipelineStageAccess::RayTracingShader_AccelerationStructureRead | PipelineStageAccess::TaskShader_AccelerationStructureRead | PipelineStageAccess::MeshShader_AccelerationStructureRead => AccessFlags::ACCELERATION_STRUCTURE_READ, PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureWrite => AccessFlags::ACCELERATION_STRUCTURE_WRITE, PipelineStageAccess::FragmentDensityProcess_FragmentDensityMapRead => AccessFlags::FRAGMENT_DENSITY_MAP_READ, PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentReadNoncoherent => AccessFlags::COLOR_ATTACHMENT_READ_NONCOHERENT, PipelineStageAccess::InvocationMask_InvocationMaskRead => AccessFlags::INVOCATION_MASK_READ, PipelineStageAccess::RayTracingShader_ShaderBindingTableRead => AccessFlags::SHADER_BINDING_TABLE_READ, PipelineStageAccess::AccelerationStructureBuild_MicromapRead | PipelineStageAccess::MicromapBuild_MicromapRead => AccessFlags::MICROMAP_READ, PipelineStageAccess::MicromapBuild_MicromapWrite => AccessFlags::MICROMAP_WRITE, PipelineStageAccess::OpticalFlow_OpticalFlowRead => AccessFlags::OPTICAL_FLOW_READ, PipelineStageAccess::OpticalFlow_OpticalFlowWrite => AccessFlags::OPTICAL_FLOW_WRITE, PipelineStageAccess::__MAX_VALUE__ => unreachable!(), } } } #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] pub(crate) struct PipelineStageAccessSet(u128); #[allow(dead_code)] impl PipelineStageAccessSet { #[inline] pub(crate) const fn empty() -> Self { Self(0) } #[inline] pub(crate) const fn count(self) -> u32 { self.0.count_ones() } #[inline] pub(crate) const fn is_empty(self) -> bool { self.0 == 0 } #[inline] pub(crate) const fn intersects(self, other: Self) -> bool { self.0 & other.0 != 0 } #[inline] pub(crate) const fn contains(self, other: Self) -> bool { self.0 & other.0 == other.0 } #[inline] pub(crate) const fn union(self, other: Self) -> Self { Self(self.0 | other.0) } #[inline] pub(crate) const fn intersection(self, other: Self) -> Self { Self(self.0 & other.0) } #[inline] pub(crate) const fn difference(self, other: Self) -> Self { Self(self.0 & !other.0) } #[inline] pub(crate) const fn symmetric_difference(self, other: Self) -> Self { Self(self.0 ^ other.0) } #[inline] pub(crate) fn contains_enum(self, val: PipelineStageAccess) -> bool { self.intersects(val.into()) } } impl std::ops::BitAnd for PipelineStageAccessSet { type Output = Self; #[inline] fn bitand(self, rhs: Self) -> Self { self.intersection(rhs) } } impl std::ops::BitAndAssign for PipelineStageAccessSet { #[inline] fn bitand_assign(&mut self, rhs: Self) { *self = self.intersection(rhs); } } impl std::ops::BitOr for PipelineStageAccessSet { type Output = Self; #[inline] fn bitor(self, rhs: Self) -> Self { self.union(rhs) } } impl std::ops::BitOrAssign for PipelineStageAccessSet { #[inline] fn bitor_assign(&mut self, rhs: Self) { *self = self.union(rhs); } } impl std::ops::BitXor for PipelineStageAccessSet { type Output = Self; #[inline] fn bitxor(self, rhs: Self) -> Self { self.symmetric_difference(rhs) } } impl std::ops::BitXorAssign for PipelineStageAccessSet { #[inline] fn bitxor_assign(&mut self, rhs: Self) { *self = self.symmetric_difference(rhs); } } impl std::ops::Sub for PipelineStageAccessSet { type Output = Self; #[inline] fn sub(self, rhs: Self) -> Self { self.difference(rhs) } } impl std::ops::SubAssign for PipelineStageAccessSet { #[inline] fn sub_assign(&mut self, rhs: Self) { *self = self.difference(rhs); } } impl From for PipelineStageAccessSet { #[inline] fn from(val: PipelineStageAccess) -> Self { debug_assert!(val != PipelineStageAccess::__MAX_VALUE__); // You did something very dumb... Self(1u128 << val as u8) } } impl From for PipelineStageAccessSet { #[inline] fn from(stages: PipelineStages) -> Self { let mut result = Self::empty(); if stages.intersects(PipelineStages::DRAW_INDIRECT) { result |= Self::from(PipelineStageAccess::DrawIndirect_IndirectCommandRead) | Self::from(PipelineStageAccess::DrawIndirect_TransformFeedbackCounterRead) } if stages.intersects(PipelineStages::VERTEX_SHADER) { result |= Self::from(PipelineStageAccess::VertexShader_UniformRead) | Self::from(PipelineStageAccess::VertexShader_ShaderSampledRead) | Self::from(PipelineStageAccess::VertexShader_ShaderStorageRead) | Self::from(PipelineStageAccess::VertexShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::VertexShader_AccelerationStructureRead) } if stages.intersects(PipelineStages::TESSELLATION_CONTROL_SHADER) { result |= Self::from(PipelineStageAccess::TessellationControlShader_UniformRead) | Self::from(PipelineStageAccess::TessellationControlShader_ShaderSampledRead) | Self::from(PipelineStageAccess::TessellationControlShader_ShaderStorageRead) | Self::from(PipelineStageAccess::TessellationControlShader_ShaderStorageWrite) | Self::from( PipelineStageAccess::TessellationControlShader_AccelerationStructureRead, ) } if stages.intersects(PipelineStages::TESSELLATION_EVALUATION_SHADER) { result |= Self::from(PipelineStageAccess::TessellationEvaluationShader_UniformRead) | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderSampledRead) | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderStorageRead) | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderStorageWrite) | Self::from( PipelineStageAccess::TessellationEvaluationShader_AccelerationStructureRead, ) } if stages.intersects(PipelineStages::GEOMETRY_SHADER) { result |= Self::from(PipelineStageAccess::GeometryShader_UniformRead) | Self::from(PipelineStageAccess::GeometryShader_ShaderSampledRead) | Self::from(PipelineStageAccess::GeometryShader_ShaderStorageRead) | Self::from(PipelineStageAccess::GeometryShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::GeometryShader_AccelerationStructureRead) } if stages.intersects(PipelineStages::FRAGMENT_SHADER) { result |= Self::from(PipelineStageAccess::FragmentShader_UniformRead) | Self::from(PipelineStageAccess::FragmentShader_InputAttachmentRead) | Self::from(PipelineStageAccess::FragmentShader_ShaderSampledRead) | Self::from(PipelineStageAccess::FragmentShader_ShaderStorageRead) | Self::from(PipelineStageAccess::FragmentShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::FragmentShader_AccelerationStructureRead) } if stages.intersects(PipelineStages::EARLY_FRAGMENT_TESTS) { result |= Self::from(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentRead) | Self::from(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite) } if stages.intersects(PipelineStages::LATE_FRAGMENT_TESTS) { result |= Self::from(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentRead) | Self::from(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite) } if stages.intersects(PipelineStages::COLOR_ATTACHMENT_OUTPUT) { result |= Self::from(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead) | Self::from(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite) | Self::from( PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentReadNoncoherent, ) } if stages.intersects(PipelineStages::COMPUTE_SHADER) { result |= Self::from(PipelineStageAccess::ComputeShader_UniformRead) | Self::from(PipelineStageAccess::ComputeShader_ShaderSampledRead) | Self::from(PipelineStageAccess::ComputeShader_ShaderStorageRead) | Self::from(PipelineStageAccess::ComputeShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::ComputeShader_AccelerationStructureRead) } if stages.intersects(PipelineStages::HOST) { result |= Self::from(PipelineStageAccess::Host_HostRead) | Self::from(PipelineStageAccess::Host_HostWrite) } if stages.intersects(PipelineStages::COPY) { result |= Self::from(PipelineStageAccess::Copy_TransferRead) | Self::from(PipelineStageAccess::Copy_TransferWrite) } if stages.intersects(PipelineStages::RESOLVE) { result |= Self::from(PipelineStageAccess::Resolve_TransferRead) | Self::from(PipelineStageAccess::Resolve_TransferWrite) } if stages.intersects(PipelineStages::BLIT) { result |= Self::from(PipelineStageAccess::Blit_TransferRead) | Self::from(PipelineStageAccess::Blit_TransferWrite) } if stages.intersects(PipelineStages::CLEAR) { result |= Self::from(PipelineStageAccess::Clear_TransferWrite) } if stages.intersects(PipelineStages::INDEX_INPUT) { result |= Self::from(PipelineStageAccess::IndexInput_IndexRead) } if stages.intersects(PipelineStages::VERTEX_ATTRIBUTE_INPUT) { result |= Self::from(PipelineStageAccess::VertexAttributeInput_VertexAttributeRead) } if stages.intersects(PipelineStages::VIDEO_DECODE) { result |= Self::from(PipelineStageAccess::VideoDecode_VideoDecodeRead) | Self::from(PipelineStageAccess::VideoDecode_VideoDecodeWrite) } if stages.intersects(PipelineStages::VIDEO_ENCODE) { result |= Self::from(PipelineStageAccess::VideoEncode_VideoEncodeRead) | Self::from(PipelineStageAccess::VideoEncode_VideoEncodeWrite) } if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK) { result |= Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackWrite) | Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackCounterRead) | Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackCounterWrite) } if stages.intersects(PipelineStages::CONDITIONAL_RENDERING) { result |= Self::from(PipelineStageAccess::ConditionalRendering_ConditionalRenderingRead) } if stages.intersects(PipelineStages::ACCELERATION_STRUCTURE_BUILD) { result |= Self::from(PipelineStageAccess::AccelerationStructureBuild_IndirectCommandRead) | Self::from(PipelineStageAccess::AccelerationStructureBuild_UniformRead) | Self::from(PipelineStageAccess::AccelerationStructureBuild_TransferRead) | Self::from(PipelineStageAccess::AccelerationStructureBuild_TransferWrite) | Self::from(PipelineStageAccess::AccelerationStructureBuild_ShaderSampledRead) | Self::from(PipelineStageAccess::AccelerationStructureBuild_ShaderStorageRead) | Self::from( PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureRead, ) | Self::from( PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureWrite, ) // | Self::from(PipelineStageAccess::AccelerationStructureBuild_MicromapRead) } if stages.intersects(PipelineStages::RAY_TRACING_SHADER) { result |= Self::from(PipelineStageAccess::RayTracingShader_UniformRead) | Self::from(PipelineStageAccess::RayTracingShader_ShaderSampledRead) | Self::from(PipelineStageAccess::RayTracingShader_ShaderStorageRead) | Self::from(PipelineStageAccess::RayTracingShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::RayTracingShader_AccelerationStructureRead) // | Self::from(PipelineStageAccess::RayTracingShader_ShaderBindingTableRead) } if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS) { result |= Self::from(PipelineStageAccess::FragmentDensityProcess_FragmentDensityMapRead) } if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT) { result |= PipelineStageAccess::FragmentShadingRateAttachment_FragmentShadingRateAttachmentRead .into() } if stages.intersects(PipelineStages::COMMAND_PREPROCESS) { result |= Self::from(PipelineStageAccess::CommandPreprocess_CommandPreprocessRead) | Self::from(PipelineStageAccess::CommandPreprocess_CommandPreprocessWrite) } if stages.intersects(PipelineStages::TASK_SHADER) { result |= Self::from(PipelineStageAccess::TaskShader_UniformRead) | Self::from(PipelineStageAccess::TaskShader_ShaderSampledRead) | Self::from(PipelineStageAccess::TaskShader_ShaderStorageRead) | Self::from(PipelineStageAccess::TaskShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::TaskShader_AccelerationStructureRead) } if stages.intersects(PipelineStages::MESH_SHADER) { result |= Self::from(PipelineStageAccess::MeshShader_UniformRead) | Self::from(PipelineStageAccess::MeshShader_ShaderSampledRead) | Self::from(PipelineStageAccess::MeshShader_ShaderStorageRead) | Self::from(PipelineStageAccess::MeshShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::MeshShader_AccelerationStructureRead) } if stages.intersects(PipelineStages::SUBPASS_SHADING) { result |= Self::from(PipelineStageAccess::SubpassShading_InputAttachmentRead) } if stages.intersects(PipelineStages::INVOCATION_MASK) { result |= Self::from(PipelineStageAccess::InvocationMask_InvocationMaskRead) } /* if stages.intersects(PipelineStages::OPTICAL_FLOW) { result |= Self::from(PipelineStageAccess::OpticalFlow_OpticalFlowRead) | Self::from(PipelineStageAccess::OpticalFlow_OpticalFlowWrite) } if stages.intersects(PipelineStages::MICROMAP_BUILD) { result |= Self::from(PipelineStageAccess::MicromapBuild_MicromapWrite) | Self::from(PipelineStageAccess::MicromapBuild_MicromapRead) } */ result } } impl From for PipelineStageAccessSet { #[inline] fn from(access: AccessFlags) -> Self { let mut result = Self::empty(); if access.intersects(AccessFlags::INDIRECT_COMMAND_READ) { result |= Self::from(PipelineStageAccess::DrawIndirect_IndirectCommandRead) | Self::from(PipelineStageAccess::AccelerationStructureBuild_IndirectCommandRead) } if access.intersects(AccessFlags::INDEX_READ) { result |= Self::from(PipelineStageAccess::IndexInput_IndexRead) } if access.intersects(AccessFlags::VERTEX_ATTRIBUTE_READ) { result |= Self::from(PipelineStageAccess::VertexAttributeInput_VertexAttributeRead) } if access.intersects(AccessFlags::UNIFORM_READ) { result |= Self::from(PipelineStageAccess::VertexShader_UniformRead) | Self::from(PipelineStageAccess::TessellationControlShader_UniformRead) | Self::from(PipelineStageAccess::TessellationEvaluationShader_UniformRead) | Self::from(PipelineStageAccess::GeometryShader_UniformRead) | Self::from(PipelineStageAccess::FragmentShader_UniformRead) | Self::from(PipelineStageAccess::ComputeShader_UniformRead) | Self::from(PipelineStageAccess::AccelerationStructureBuild_UniformRead) | Self::from(PipelineStageAccess::RayTracingShader_UniformRead) | Self::from(PipelineStageAccess::TaskShader_UniformRead) | Self::from(PipelineStageAccess::MeshShader_UniformRead) } if access.intersects(AccessFlags::INPUT_ATTACHMENT_READ) { result |= Self::from(PipelineStageAccess::FragmentShader_InputAttachmentRead) | Self::from(PipelineStageAccess::SubpassShading_InputAttachmentRead) } if access.intersects(AccessFlags::COLOR_ATTACHMENT_READ) { result |= Self::from(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentRead) } if access.intersects(AccessFlags::COLOR_ATTACHMENT_WRITE) { result |= Self::from(PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentWrite) } if access.intersects(AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ) { result |= Self::from(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentRead) | Self::from(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentRead) } if access.intersects(AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE) { result |= Self::from(PipelineStageAccess::EarlyFragmentTests_DepthStencilAttachmentWrite) | Self::from(PipelineStageAccess::LateFragmentTests_DepthStencilAttachmentWrite) } if access.intersects(AccessFlags::TRANSFER_READ) { result |= Self::from(PipelineStageAccess::Copy_TransferRead) | Self::from(PipelineStageAccess::Resolve_TransferRead) | Self::from(PipelineStageAccess::Blit_TransferRead) | Self::from(PipelineStageAccess::AccelerationStructureBuild_TransferRead) } if access.intersects(AccessFlags::TRANSFER_WRITE) { result |= Self::from(PipelineStageAccess::Copy_TransferWrite) | Self::from(PipelineStageAccess::Resolve_TransferWrite) | Self::from(PipelineStageAccess::Blit_TransferWrite) | Self::from(PipelineStageAccess::Clear_TransferWrite) | Self::from(PipelineStageAccess::AccelerationStructureBuild_TransferWrite) } if access.intersects(AccessFlags::HOST_READ) { result |= Self::from(PipelineStageAccess::Host_HostRead) } if access.intersects(AccessFlags::HOST_WRITE) { result |= Self::from(PipelineStageAccess::Host_HostWrite) } if access.intersects(AccessFlags::SHADER_SAMPLED_READ) { result |= Self::from(PipelineStageAccess::VertexShader_ShaderSampledRead) | Self::from(PipelineStageAccess::TessellationControlShader_ShaderSampledRead) | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderSampledRead) | Self::from(PipelineStageAccess::GeometryShader_ShaderSampledRead) | Self::from(PipelineStageAccess::FragmentShader_ShaderSampledRead) | Self::from(PipelineStageAccess::ComputeShader_ShaderSampledRead) | Self::from(PipelineStageAccess::AccelerationStructureBuild_ShaderSampledRead) | Self::from(PipelineStageAccess::RayTracingShader_ShaderSampledRead) | Self::from(PipelineStageAccess::TaskShader_ShaderSampledRead) | Self::from(PipelineStageAccess::MeshShader_ShaderSampledRead) } if access.intersects(AccessFlags::SHADER_STORAGE_READ) { result |= Self::from(PipelineStageAccess::VertexShader_ShaderStorageRead) | Self::from(PipelineStageAccess::TessellationControlShader_ShaderStorageRead) | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderStorageRead) | Self::from(PipelineStageAccess::GeometryShader_ShaderStorageRead) | Self::from(PipelineStageAccess::FragmentShader_ShaderStorageRead) | Self::from(PipelineStageAccess::ComputeShader_ShaderStorageRead) | Self::from(PipelineStageAccess::AccelerationStructureBuild_ShaderStorageRead) | Self::from(PipelineStageAccess::RayTracingShader_ShaderStorageRead) | Self::from(PipelineStageAccess::TaskShader_ShaderStorageRead) | Self::from(PipelineStageAccess::MeshShader_ShaderStorageRead) } if access.intersects(AccessFlags::SHADER_STORAGE_WRITE) { result |= Self::from(PipelineStageAccess::VertexShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::TessellationControlShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::TessellationEvaluationShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::GeometryShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::FragmentShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::ComputeShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::RayTracingShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::TaskShader_ShaderStorageWrite) | Self::from(PipelineStageAccess::MeshShader_ShaderStorageWrite) } if access.intersects(AccessFlags::VIDEO_DECODE_READ) { result |= Self::from(PipelineStageAccess::VideoDecode_VideoDecodeRead) } if access.intersects(AccessFlags::VIDEO_DECODE_WRITE) { result |= Self::from(PipelineStageAccess::VideoDecode_VideoDecodeWrite) } if access.intersects(AccessFlags::VIDEO_ENCODE_READ) { result |= Self::from(PipelineStageAccess::VideoEncode_VideoEncodeRead) } if access.intersects(AccessFlags::VIDEO_ENCODE_WRITE) { result |= Self::from(PipelineStageAccess::VideoEncode_VideoEncodeWrite) } if access.intersects(AccessFlags::TRANSFORM_FEEDBACK_WRITE) { result |= Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackWrite) } if access.intersects(AccessFlags::TRANSFORM_FEEDBACK_COUNTER_READ) { result |= Self::from(PipelineStageAccess::DrawIndirect_TransformFeedbackCounterRead) | Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackCounterRead) } if access.intersects(AccessFlags::TRANSFORM_FEEDBACK_COUNTER_WRITE) { result |= Self::from(PipelineStageAccess::TransformFeedback_TransformFeedbackCounterWrite) } if access.intersects(AccessFlags::CONDITIONAL_RENDERING_READ) { result |= Self::from(PipelineStageAccess::ConditionalRendering_ConditionalRenderingRead) } if access.intersects(AccessFlags::COMMAND_PREPROCESS_READ) { result |= Self::from(PipelineStageAccess::CommandPreprocess_CommandPreprocessRead) } if access.intersects(AccessFlags::COMMAND_PREPROCESS_WRITE) { result |= Self::from(PipelineStageAccess::CommandPreprocess_CommandPreprocessWrite) } if access.intersects(AccessFlags::FRAGMENT_SHADING_RATE_ATTACHMENT_READ) { result |= Self::from(PipelineStageAccess::FragmentShadingRateAttachment_FragmentShadingRateAttachmentRead) } if access.intersects(AccessFlags::ACCELERATION_STRUCTURE_READ) { result |= Self::from(PipelineStageAccess::VertexShader_AccelerationStructureRead) | Self::from( PipelineStageAccess::TessellationControlShader_AccelerationStructureRead, ) | Self::from( PipelineStageAccess::TessellationEvaluationShader_AccelerationStructureRead, ) | Self::from(PipelineStageAccess::GeometryShader_AccelerationStructureRead) | Self::from(PipelineStageAccess::FragmentShader_AccelerationStructureRead) | Self::from(PipelineStageAccess::ComputeShader_AccelerationStructureRead) | Self::from( PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureRead, ) | Self::from(PipelineStageAccess::RayTracingShader_AccelerationStructureRead) | Self::from(PipelineStageAccess::TaskShader_AccelerationStructureRead) | Self::from(PipelineStageAccess::MeshShader_AccelerationStructureRead) } if access.intersects(AccessFlags::ACCELERATION_STRUCTURE_WRITE) { result |= Self::from( PipelineStageAccess::AccelerationStructureBuild_AccelerationStructureWrite, ) } if access.intersects(AccessFlags::FRAGMENT_DENSITY_MAP_READ) { result |= Self::from(PipelineStageAccess::FragmentDensityProcess_FragmentDensityMapRead) } if access.intersects(AccessFlags::COLOR_ATTACHMENT_READ_NONCOHERENT) { result |= Self::from( PipelineStageAccess::ColorAttachmentOutput_ColorAttachmentReadNoncoherent, ) } if access.intersects(AccessFlags::INVOCATION_MASK_READ) { result |= Self::from(PipelineStageAccess::InvocationMask_InvocationMaskRead) } /* if access.intersects(AccessFlags::SHADER_BINDING_TABLE_READ) { result |= Self::from(PipelineStageAccess::RayTracingShader_ShaderBindingTableRead) } if access.intersects(AccessFlags::MICROMAP_READ) { result |= Self::from(PipelineStageAccess::AccelerationStructureBuild_MicromapRead) | Self::from(PipelineStageAccess::MicromapBuild_MicromapRead) } if access.intersects(AccessFlags::MICROMAP_WRITE) { result |= Self::from(PipelineStageAccess::MicromapBuild_MicromapWrite) } if access.intersects(AccessFlags::OPTICAL_FLOW_READ) { result |= Self::from(PipelineStageAccess::OpticalFlow_OpticalFlowRead) } if access.intersects(AccessFlags::OPTICAL_FLOW_WRITE) { result |= Self::from(PipelineStageAccess::OpticalFlow_OpticalFlowWrite) } */ result } } /// Dependency info for barriers in a pipeline barrier or event command. /// /// A pipeline barrier creates a dependency between commands submitted before the barrier (the /// source scope) and commands submitted after it (the destination scope). An event command acts /// like a split pipeline barrier: the source scope and destination scope are defined /// relative to different commands. Each `DependencyInfo` consists of multiple individual barriers /// that concern a either single resource or operate globally. /// /// Each barrier has a set of source/destination pipeline stages and source/destination memory /// access types. The pipeline stages create an *execution dependency*: the `src_stages` of /// commands submitted before the barrier must be completely finished before before any of the /// `dst_stages` of commands after the barrier are allowed to start. The memory access types /// create a *memory dependency*: in addition to the execution dependency, any `src_access` /// performed before the barrier must be made available and visible before any `dst_access` /// are made after the barrier. #[derive(Clone, Debug)] pub struct DependencyInfo { /// Flags to modify how the execution and memory dependencies are formed. /// /// The default value is empty. pub dependency_flags: DependencyFlags, /// Memory barriers for global operations and accesses, not limited to a single resource. /// /// The default value is empty. pub memory_barriers: SmallVec<[MemoryBarrier; 2]>, /// Memory barriers for individual buffers. /// /// The default value is empty. pub buffer_memory_barriers: SmallVec<[BufferMemoryBarrier; 8]>, /// Memory barriers for individual images. /// /// The default value is empty. pub image_memory_barriers: SmallVec<[ImageMemoryBarrier; 8]>, pub _ne: crate::NonExhaustive, } impl DependencyInfo { /// Returns whether `self` contains any barriers. #[inline] pub fn is_empty(&self) -> bool { self.memory_barriers.is_empty() && self.buffer_memory_barriers.is_empty() && self.image_memory_barriers.is_empty() } /// Clears all barriers. #[inline] pub fn clear(&mut self) { self.memory_barriers.clear(); self.buffer_memory_barriers.clear(); self.image_memory_barriers.clear(); } } impl Default for DependencyInfo { #[inline] fn default() -> Self { Self { dependency_flags: DependencyFlags::empty(), memory_barriers: SmallVec::new(), buffer_memory_barriers: SmallVec::new(), image_memory_barriers: SmallVec::new(), _ne: crate::NonExhaustive(()), } } } vulkan_bitflags! { #[non_exhaustive] /// Flags that modify how execution and memory dependencies are formed. DependencyFlags = DependencyFlags(u32); /// For framebuffer-space pipeline stages, specifies that the dependency is framebuffer-local. /// The implementation can start the destination operation for some given pixels as long as the /// source operation is finished for these given pixels. /// /// Framebuffer-local dependencies are usually more efficient, especially on tile-based /// architectures. BY_REGION = BY_REGION, /// For devices that consist of multiple physical devices, specifies that the dependency is /// device-local. The dependency will only apply to the operations on each physical device /// individually, rather than applying to all physical devices as a whole. This allows each /// physical device to operate independently of the others. /// /// The device API version must be at least 1.1, or the [`khr_device_group`] extension must be /// enabled on the device. /// /// [`khr_device_group`]: crate::device::DeviceExtensions::khr_device_group DEVICE_GROUP = DEVICE_GROUP { api_version: V1_1, device_extensions: [khr_device_group], }, /// For subpass dependencies, and pipeline barriers executing within a render pass instance, /// if the render pass uses multiview rendering, specifies that the dependency is view-local. /// Each view in the destination subpass will only depend on a single view in the destination /// subpass, instead of all views. /// /// The device API version must be at least 1.1, or the [`khr_multiview`] extension must be /// enabled on the device. /// /// [`khr_multiview`]: crate::device::DeviceExtensions::khr_multiview VIEW_LOCAL = VIEW_LOCAL { api_version: V1_1, device_extensions: [khr_multiview], }, } /// A memory barrier that is applied globally. #[derive(Clone, Debug)] pub struct MemoryBarrier { /// The pipeline stages in the source scope to wait for. /// /// The default value is [`PipelineStages::empty()`]. pub src_stages: PipelineStages, /// The memory accesses in the source scope to make available and visible. /// /// The default value is [`AccessFlags::empty()`]. pub src_access: AccessFlags, /// The pipeline stages in the destination scope that must wait for `src_stages`. /// /// The default value is [`PipelineStages::empty()`]. pub dst_stages: PipelineStages, /// The memory accesses in the destination scope that must wait for `src_access` to be made /// available and visible. pub dst_access: AccessFlags, pub _ne: crate::NonExhaustive, } impl Default for MemoryBarrier { #[inline] fn default() -> Self { Self { src_stages: PipelineStages::empty(), src_access: AccessFlags::empty(), dst_stages: PipelineStages::empty(), dst_access: AccessFlags::empty(), _ne: crate::NonExhaustive(()), } } } /// A memory barrier that is applied to a single buffer. #[derive(Clone, Debug)] pub struct BufferMemoryBarrier { /// The pipeline stages in the source scope to wait for. /// /// The default value is [`PipelineStages::empty()`]. pub src_stages: PipelineStages, /// The memory accesses in the source scope to make available and visible. /// /// The default value is [`AccessFlags::empty()`]. pub src_access: AccessFlags, /// The pipeline stages in the destination scope that must wait for `src_stages`. /// /// The default value is [`PipelineStages::empty()`]. pub dst_stages: PipelineStages, /// The memory accesses in the destination scope that must wait for `src_access` to be made /// available and visible. pub dst_access: AccessFlags, /// For resources created with [`Sharing::Exclusive`](crate::sync::Sharing), transfers /// ownership of a resource from one queue family to another. pub queue_family_ownership_transfer: Option, /// The buffer to apply the barrier to. pub buffer: Arc, /// The byte range of `buffer` to apply the barrier to. pub range: Range, pub _ne: crate::NonExhaustive, } impl BufferMemoryBarrier { #[inline] pub fn buffer(buffer: Arc) -> Self { Self { src_stages: PipelineStages::empty(), src_access: AccessFlags::empty(), dst_stages: PipelineStages::empty(), dst_access: AccessFlags::empty(), queue_family_ownership_transfer: None, buffer, range: 0..0, _ne: crate::NonExhaustive(()), } } } /// A memory barrier that is applied to a single image. #[derive(Clone, Debug)] pub struct ImageMemoryBarrier { /// The pipeline stages in the source scope to wait for. /// /// The default value is [`PipelineStages::empty()`]. pub src_stages: PipelineStages, /// The memory accesses in the source scope to make available and visible. /// /// The default value is [`AccessFlags::empty()`]. pub src_access: AccessFlags, /// The pipeline stages in the destination scope that must wait for `src_stages`. /// /// The default value is [`PipelineStages::empty()`]. pub dst_stages: PipelineStages, /// The memory accesses in the destination scope that must wait for `src_access` to be made /// available and visible. pub dst_access: AccessFlags, /// The layout that the specified `subresource_range` of `image` is expected to be in when the /// source scope completes. pub old_layout: ImageLayout, /// The layout that the specified `subresource_range` of `image` will be transitioned to before /// the destination scope begins. pub new_layout: ImageLayout, /// For resources created with [`Sharing::Exclusive`](crate::sync::Sharing), transfers /// ownership of a resource from one queue family to another. pub queue_family_ownership_transfer: Option, /// The image to apply the barrier to. pub image: Arc, /// The subresource range of `image` to apply the barrier to. pub subresource_range: ImageSubresourceRange, pub _ne: crate::NonExhaustive, } impl ImageMemoryBarrier { #[inline] pub fn image(image: Arc) -> Self { Self { src_stages: PipelineStages::empty(), src_access: AccessFlags::empty(), dst_stages: PipelineStages::empty(), dst_access: AccessFlags::empty(), old_layout: ImageLayout::Undefined, new_layout: ImageLayout::Undefined, queue_family_ownership_transfer: None, image, subresource_range: ImageSubresourceRange { aspects: ImageAspects::empty(), // Can't use image format aspects because `color` can't be specified with `planeN`. mip_levels: 0..0, array_layers: 0..0, }, _ne: crate::NonExhaustive(()), } } } /// Specifies a queue family ownership transfer for a resource. /// /// There are three classes of queues that can be used in an ownership transfer: /// - A **local** queue exists on the current [`Instance`] and [`Device`]. /// - An **external** queue does not exist on the current [`Instance`], but has the same /// [`device_uuid`] and [`driver_uuid`] as the current [`Device`]. /// - A **foreign** queue can be an external queue, or any queue on another device for which the /// mentioned parameters do not match. /// /// [`Instance`]: crate::instance::Instance /// [`Device`]: crate::device::Device /// [`device_uuid`]: crate::device::Properties::device_uuid /// [`driver_uuid`]: crate::device::Properties::driver_uuid #[derive(Clone, Copy, Debug)] pub enum QueueFamilyOwnershipTransfer { /// For a resource with [`Sharing::Exclusive`], transfers ownership between two local queues. /// /// [`Sharing::Exclusive`]: crate::sync::Sharing::Exclusive ExclusiveBetweenLocal { /// The queue family that currently owns the resource. src_index: u32, /// The queue family to transfer ownership to. dst_index: u32, }, /// For a resource with [`Sharing::Exclusive`], transfers ownership from a local queue to an /// external queue. /// /// The device API version must be at least 1.1, or the [`khr_external_memory`] extension must /// be enabled on the device. /// /// [`Sharing::Exclusive`]: crate::sync::Sharing::Exclusive /// [`khr_external_memory`]: crate::device::DeviceExtensions::khr_external_memory ExclusiveToExternal { /// The queue family that currently owns the resource. src_index: u32, }, /// For a resource with [`Sharing::Exclusive`], transfers ownership from an external queue to a /// local queue. /// /// The device API version must be at least 1.1, or the [`khr_external_memory`] extension must /// be enabled on the device. /// /// [`Sharing::Exclusive`]: crate::sync::Sharing::Exclusive /// [`khr_external_memory`]: crate::device::DeviceExtensions::khr_external_memory ExclusiveFromExternal { /// The queue family to transfer ownership to. dst_index: u32, }, /// For a resource with [`Sharing::Exclusive`], transfers ownership from a local queue to a /// foreign queue. /// /// The [`ext_queue_family_foreign`] extension must be enabled on the device. /// /// [`Sharing::Exclusive`]: crate::sync::Sharing::Exclusive /// [`ext_queue_family_foreign`]: crate::device::DeviceExtensions::ext_queue_family_foreign ExclusiveToForeign { /// The queue family that currently owns the resource. src_index: u32, }, /// For a resource with [`Sharing::Exclusive`], transfers ownership from a foreign queue to a /// local queue. /// /// The [`ext_queue_family_foreign`] extension must be enabled on the device. /// /// [`Sharing::Exclusive`]: crate::sync::Sharing::Exclusive /// [`ext_queue_family_foreign`]: crate::device::DeviceExtensions::ext_queue_family_foreign ExclusiveFromForeign { /// The queue family to transfer ownership to. dst_index: u32, }, /// For a resource with [`Sharing::Concurrent`], transfers ownership from its local queues to /// an external queue. /// /// The device API version must be at least 1.1, or the [`khr_external_memory`] extension must /// be enabled on the device. /// /// [`Sharing::Concurrent`]: crate::sync::Sharing::Concurrent /// [`khr_external_memory`]: crate::device::DeviceExtensions::khr_external_memory ConcurrentToExternal, /// For a resource with [`Sharing::Concurrent`], transfers ownership from an external queue to /// its local queues. /// /// The device API version must be at least 1.1, or the [`khr_external_memory`] extension must /// be enabled on the device. /// /// [`Sharing::Concurrent`]: crate::sync::Sharing::Concurrent /// [`khr_external_memory`]: crate::device::DeviceExtensions::khr_external_memory ConcurrentFromExternal, /// For a resource with [`Sharing::Concurrent`], transfers ownership from its local queues to /// a foreign queue. /// /// The [`ext_queue_family_foreign`] extension must be enabled on the device. /// /// [`Sharing::Concurrent`]: crate::sync::Sharing::Concurrent /// [`ext_queue_family_foreign`]: crate::device::DeviceExtensions::ext_queue_family_foreign ConcurrentToForeign, /// For a resource with [`Sharing::Concurrent`], transfers ownership from a foreign queue to /// its local queues. /// /// The [`ext_queue_family_foreign`] extension must be enabled on the device. /// /// [`Sharing::Concurrent`]: crate::sync::Sharing::Concurrent /// [`ext_queue_family_foreign`]: crate::device::DeviceExtensions::ext_queue_family_foreign ConcurrentFromForeign, } impl QueueFamilyOwnershipTransfer { pub(crate) fn validate_device(self, device: &Device) -> Result<(), RequirementNotMet> { match self { QueueFamilyOwnershipTransfer::ExclusiveToExternal { .. } => { if !(device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_external_memory) { return Err(crate::RequirementNotMet { required_for: "`QueueFamilyOwnershipTransfer::ExclusiveToExternal", requires_one_of: crate::RequiresOneOf { api_version: Some(Version::V1_1), device_extensions: &["khr_external_memory"], ..Default::default() }, }); } } QueueFamilyOwnershipTransfer::ExclusiveFromExternal { .. } => { if !(device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_external_memory) { return Err(crate::RequirementNotMet { required_for: "`QueueFamilyOwnershipTransfer::ExclusiveFromExternal", requires_one_of: crate::RequiresOneOf { api_version: Some(Version::V1_1), device_extensions: &["khr_external_memory"], ..Default::default() }, }); } } QueueFamilyOwnershipTransfer::ExclusiveToForeign { .. } => { if !device.enabled_extensions().ext_queue_family_foreign { return Err(crate::RequirementNotMet { required_for: "`QueueFamilyOwnershipTransfer::ExclusiveToForeign", requires_one_of: crate::RequiresOneOf { device_extensions: &["ext_queue_family_foreign"], ..Default::default() }, }); } } QueueFamilyOwnershipTransfer::ExclusiveFromForeign { .. } => { if !device.enabled_extensions().ext_queue_family_foreign { return Err(crate::RequirementNotMet { required_for: "`QueueFamilyOwnershipTransfer::ExclusiveFromForeign", requires_one_of: crate::RequiresOneOf { device_extensions: &["ext_queue_family_foreign"], ..Default::default() }, }); } } QueueFamilyOwnershipTransfer::ConcurrentToExternal => { if !(device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_external_memory) { return Err(crate::RequirementNotMet { required_for: "`QueueFamilyOwnershipTransfer::ConcurrentToExternal", requires_one_of: crate::RequiresOneOf { api_version: Some(Version::V1_1), device_extensions: &["khr_external_memory"], ..Default::default() }, }); } } QueueFamilyOwnershipTransfer::ConcurrentFromExternal => { if !(device.api_version() >= Version::V1_1 || device.enabled_extensions().khr_external_memory) { return Err(crate::RequirementNotMet { required_for: "`QueueFamilyOwnershipTransfer::ConcurrentFromExternal", requires_one_of: crate::RequiresOneOf { api_version: Some(Version::V1_1), device_extensions: &["khr_external_memory"], ..Default::default() }, }); } } QueueFamilyOwnershipTransfer::ConcurrentToForeign => { if !device.enabled_extensions().ext_queue_family_foreign { return Err(crate::RequirementNotMet { required_for: "`QueueFamilyOwnershipTransfer::ConcurrentToForeign", requires_one_of: crate::RequiresOneOf { device_extensions: &["ext_queue_family_foreign"], ..Default::default() }, }); } } QueueFamilyOwnershipTransfer::ConcurrentFromForeign => { if !device.enabled_extensions().ext_queue_family_foreign { return Err(crate::RequirementNotMet { required_for: "`QueueFamilyOwnershipTransfer::ConcurrentFromForeign", requires_one_of: crate::RequiresOneOf { device_extensions: &["ext_queue_family_foreign"], ..Default::default() }, }); } } _ => (), } Ok(()) } } impl From for (u32, u32) { fn from(val: QueueFamilyOwnershipTransfer) -> Self { match val { QueueFamilyOwnershipTransfer::ExclusiveBetweenLocal { src_index, dst_index, } => (src_index, dst_index), QueueFamilyOwnershipTransfer::ExclusiveToExternal { src_index } => { (src_index, ash::vk::QUEUE_FAMILY_EXTERNAL) } QueueFamilyOwnershipTransfer::ExclusiveFromExternal { dst_index } => { (ash::vk::QUEUE_FAMILY_EXTERNAL, dst_index) } QueueFamilyOwnershipTransfer::ExclusiveToForeign { src_index } => { (src_index, ash::vk::QUEUE_FAMILY_FOREIGN_EXT) } QueueFamilyOwnershipTransfer::ExclusiveFromForeign { dst_index } => { (ash::vk::QUEUE_FAMILY_FOREIGN_EXT, dst_index) } QueueFamilyOwnershipTransfer::ConcurrentToExternal => ( ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_EXTERNAL, ), QueueFamilyOwnershipTransfer::ConcurrentFromExternal => ( ash::vk::QUEUE_FAMILY_EXTERNAL, ash::vk::QUEUE_FAMILY_IGNORED, ), QueueFamilyOwnershipTransfer::ConcurrentToForeign => ( ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_FOREIGN_EXT, ), QueueFamilyOwnershipTransfer::ConcurrentFromForeign => ( ash::vk::QUEUE_FAMILY_FOREIGN_EXT, ash::vk::QUEUE_FAMILY_IGNORED, ), } } }