aboutsummaryrefslogtreecommitdiff
path: root/src/command_buffer/standard/builder/sync.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/command_buffer/standard/builder/sync.rs')
-rw-r--r--src/command_buffer/standard/builder/sync.rs4459
1 files changed, 4459 insertions, 0 deletions
diff --git a/src/command_buffer/standard/builder/sync.rs b/src/command_buffer/standard/builder/sync.rs
new file mode 100644
index 0000000..c608194
--- /dev/null
+++ b/src/command_buffer/standard/builder/sync.rs
@@ -0,0 +1,4459 @@
+// Copyright (c) 2022 The vulkano developers
+// Licensed under the Apache License, Version 2.0
+// <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
+// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
+// at your option. All files in the project carrying such
+// notice may not be copied, modified, or distributed except
+// according to those terms.
+
+use super::{CommandBufferBuilder, RenderPassStateType};
+use crate::{
+ command_buffer::allocator::CommandBufferAllocator,
+ device::{DeviceOwned, QueueFlags},
+ image::{ImageAspects, ImageCreateFlags, ImageLayout, ImageUsage},
+ sync::{
+ event::Event, AccessFlags, BufferMemoryBarrier, DependencyFlags, DependencyInfo,
+ ImageMemoryBarrier, MemoryBarrier, PipelineStages, QueueFamilyOwnershipTransfer, Sharing,
+ },
+ DeviceSize, RequirementNotMet, RequiresOneOf, Version, VulkanObject,
+};
+use smallvec::SmallVec;
+use std::{
+ cmp::max,
+ error::Error,
+ fmt::{Display, Error as FmtError, Formatter},
+ ptr,
+ sync::Arc,
+};
+
+impl<L, A> CommandBufferBuilder<L, A>
+where
+ A: CommandBufferAllocator,
+{
+ /// Inserts a memory dependency into the queue.
+ ///
+ /// A pipeline barrier is the primary means of synchronizing work within a single queue.
+ /// Without a pipeline barrier, all commands in a queue could complete out of order, and there
+ /// would be no guarantee about the ordering of memory accesses. When a dependency is inserted,
+ /// a chosen subset of operations after the barrier (the destination synchronization scope)
+ /// depend on, and therefore must wait for the completion of, a chosen subset operations before
+ /// barrier (the source synchronization scope).
+ ///
+ /// When the queue has to wait, it may not be doing useful work, so barriers should be kept to
+ /// the minimum needed to ensure proper functioning. Overly broad barriers, specifying
+ /// a larger class of operations than needed (especially [`ALL_COMMANDS`]), can slow down the
+ /// queue and make it work less efficiently.
+ ///
+ /// In addition to ensuring correct operation, pipeline barriers are also used to transition
+ /// images (or parts of images) from one [image layout] to another.
+ ///
+ /// # Safety
+ ///
+ /// - All images that are accessed by the command must be in the expected image layout.
+ /// - For each element of `dependency_info.image_memory_barriers` that contains an image layout
+ /// transition, which is a write operation, the barrier must be defined appropriately to
+ /// ensure no memory access hazard occurs.
+ ///
+ /// [`ALL_COMMANDS`]: PipelineStages::ALL_COMMANDS
+ /// [image layout]: ImageLayout
+ #[inline]
+ pub unsafe fn pipeline_barrier(
+ &mut self,
+ dependency_info: DependencyInfo,
+ ) -> Result<&mut Self, SynchronizationError> {
+ self.validate_pipeline_barrier(&dependency_info)?;
+
+ unsafe { Ok(self.pipeline_barrier_unchecked(dependency_info)) }
+ }
+
+ fn validate_pipeline_barrier(
+ &self,
+ dependency_info: &DependencyInfo,
+ ) -> Result<(), SynchronizationError> {
+ let device = self.device();
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdPipelineBarrier2-commandBuffer-cmdpool
+ if !queue_family_properties.queue_flags.intersects(
+ QueueFlags::TRANSFER
+ | QueueFlags::GRAPHICS
+ | QueueFlags::COMPUTE
+ | QueueFlags::VIDEO_DECODE
+ | QueueFlags::VIDEO_ENCODE,
+ ) {
+ return Err(SynchronizationError::NotSupportedByQueueFamily);
+ }
+
+ let &DependencyInfo {
+ dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ // VUID-VkDependencyInfo-dependencyFlags-parameter
+ dependency_flags.validate_device(device)?;
+
+ let check_stages_access = |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ src_access: AccessFlags,
+ dst_stages: PipelineStages,
+ dst_access: AccessFlags|
+ -> Result<(), SynchronizationError> {
+ for (stages, access) in [(src_stages, src_access), (dst_stages, dst_access)] {
+ // VUID-vkCmdPipelineBarrier2-synchronization2-03848
+ if !device.enabled_features().synchronization2 {
+ if stages.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_stages` or `dst_stages` contains flags from \
+ `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if access.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` or `dst_access` contains flags from \
+ `VkAccessFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstStageMask-parameter
+ stages.validate_device(device)?;
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-parameter
+ access.validate_device(device)?;
+
+ // VUID-vkCmdPipelineBarrier2-srcStageMask-03849
+ // VUID-vkCmdPipelineBarrier2-dstStageMask-03850
+ if !PipelineStages::from(queue_family_properties.queue_flags).contains(stages) {
+ match ty {
+ 'm' => {
+ return Err(SynchronizationError::MemoryBarrierStageNotSupported {
+ barrier_index,
+ })
+ }
+ 'b' => {
+ return Err(
+ SynchronizationError::BufferMemoryBarrierStageNotSupported {
+ barrier_index,
+ },
+ )
+ }
+ 'i' => {
+ return Err(SynchronizationError::ImageMemoryBarrierStageNotSupported {
+ barrier_index,
+ })
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03929
+ // VUID-VkMemoryBarrier2-dstStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03929
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(PipelineStages::GEOMETRY_SHADER)
+ && !device.enabled_features().geometry_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::GEOMETRY_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03930
+ // VUID-VkMemoryBarrier2-dstStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03930
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(
+ PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER,
+ ) && !device.enabled_features().tessellation_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
+ `PipelineStages::TESSELLATION_EVALUATION_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03931
+ // VUID-VkMemoryBarrier2-dstStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03931
+ // VUID-VImagekMemoryBarrier2-srcStageMask-03931
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03931
+ if stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
+ && !device.enabled_features().conditional_rendering
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::CONDITIONAL_RENDERING`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03932
+ // VUID-VkMemoryBarrier2-dstStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03932
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03932
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03932
+ if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
+ && !device.enabled_features().fragment_density_map
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03933
+ // VUID-VkMemoryBarrier2-dstStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03933
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03933
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03933
+ if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
+ && !device.enabled_features().transform_feedback
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TRANSFORM_FEEDBACK`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03934
+ // VUID-VkMemoryBarrier2-dstStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03934
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03934
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03934
+ if stages.intersects(PipelineStages::MESH_SHADER)
+ && !device.enabled_features().mesh_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::MESH_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03935
+ // VUID-VkMemoryBarrier2-dstStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03935
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03935
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03935
+ if stages.intersects(PipelineStages::TASK_SHADER)
+ && !device.enabled_features().task_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TASK_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
+ && !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_fragment_shading_rate", "shading_rate_image"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04957
+ // VUID-VkMemoryBarrier2-dstStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04957
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04957
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04957
+ if stages.intersects(PipelineStages::SUBPASS_SHADING)
+ && !device.enabled_features().subpass_shading
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::SUBPASS_SHADING`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04995
+ // VUID-VkMemoryBarrier2-dstStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04995
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04995
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04995
+ if stages.intersects(PipelineStages::INVOCATION_MASK)
+ && !device.enabled_features().invocation_mask
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::INVOCATION_MASK`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdPipelineBarrier-srcStageMask-03937
+ // VUID-vkCmdPipelineBarrier-dstStageMask-03937
+ if stages.is_empty() && !device.enabled_features().synchronization2 {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ is empty",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // A bit of a ridiculous number of VUIDs...
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-07458
+
+ if !AccessFlags::from(stages).contains(access) {
+ match ty {
+ 'm' => {
+ return Err(
+ SynchronizationError::MemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ )
+ }
+ 'b' => return Err(
+ SynchronizationError::BufferMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ 'i' => return Err(
+ SynchronizationError::ImageMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-06256
+ if !device.enabled_features().ray_query
+ && src_access.intersects(AccessFlags::ACCELERATION_STRUCTURE_READ)
+ && src_stages.intersects(
+ PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::COMPUTE_SHADER
+ | PipelineStages::PRE_RASTERIZATION_SHADERS
+ | PipelineStages::TASK_SHADER
+ | PipelineStages::MESH_SHADER,
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` contains `ACCELERATION_STRUCTURE_READ`, and \
+ `src_stages` contains a shader stage other than `RAY_TRACING_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["ray_query"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ };
+
+ let check_queue_family_ownership_transfer = |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ dst_stages: PipelineStages,
+ queue_family_ownership_transfer: Option<
+ QueueFamilyOwnershipTransfer,
+ >,
+ sharing: &Sharing<_>|
+ -> Result<(), SynchronizationError> {
+ if let Some(transfer) = queue_family_ownership_transfer {
+ // VUID?
+ transfer.validate_device(device)?;
+
+ // VUID-VkBufferMemoryBarrier2-srcQueueFamilyIndex-04087
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04070
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04088
+ // VUID-VkImageMemoryBarrier2-image-04071
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ let queue_family_count =
+ device.physical_device().queue_family_properties().len() as u32;
+
+ let provided_queue_family_index = match (sharing, transfer) {
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveBetweenLocal {
+ src_index,
+ dst_index,
+ },
+ ) => Some(max(src_index, dst_index)),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveToExternal { src_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveToForeign { src_index },
+ ) => Some(src_index),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveFromExternal { dst_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveFromForeign { dst_index },
+ ) => Some(dst_index),
+ (
+ Sharing::Concurrent(_),
+ QueueFamilyOwnershipTransfer::ConcurrentToExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentFromExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentToForeign
+ | QueueFamilyOwnershipTransfer::ConcurrentFromForeign,
+ ) => None,
+ _ => match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ },
+ }.filter(|&index| index >= queue_family_count);
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04089
+ // VUID-VkImageMemoryBarrier2-image-04072
+
+ if let Some(provided_queue_family_index) = provided_queue_family_index {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03851
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03854
+ if src_stages.intersects(PipelineStages::HOST)
+ || dst_stages.intersects(PipelineStages::HOST)
+ {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferHostNotAllowed {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferHostForbidden {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ Ok(())
+ };
+
+ for (barrier_index, barrier) in memory_barriers.iter().enumerate() {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'm',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+ }
+
+ for (barrier_index, barrier) in buffer_memory_barriers.iter().enumerate() {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkBufferMemoryBarrier2-buffer-01931
+ // Ensured by Buffer type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'b',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check queue family transfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'b',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ buffer.sharing(),
+ )?;
+
+ /*
+ Check range
+ */
+
+ // VUID-VkBufferMemoryBarrier2-size-01188
+ assert!(!range.is_empty());
+
+ // VUID-VkBufferMemoryBarrier2-offset-01187
+ // VUID-VkBufferMemoryBarrier2-size-01189
+ if range.end > buffer.size() {
+ return Err(SynchronizationError::BufferMemoryBarrierOutOfRange {
+ barrier_index,
+ range_end: range.end,
+ buffer_size: buffer.size(),
+ });
+ }
+ }
+
+ for (barrier_index, barrier) in image_memory_barriers.iter().enumerate() {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkImageMemoryBarrier2-image-01932
+ // Ensured by Image type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'i',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check layouts
+ */
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-parameter
+ old_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-newLayout-parameter
+ new_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03855
+ if src_stages.intersects(PipelineStages::HOST)
+ && !matches!(
+ old_layout,
+ ImageLayout::Preinitialized | ImageLayout::Undefined | ImageLayout::General
+ )
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierOldLayoutFromHostInvalid {
+ barrier_index,
+ old_layout,
+ },
+ );
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01197
+ // Not checked yet, therefore unsafe.
+
+ // VUID-VkImageMemoryBarrier2-newLayout-01198
+ if matches!(
+ new_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ ) {
+ return Err(SynchronizationError::ImageMemoryBarrierNewLayoutInvalid {
+ barrier_index,
+ });
+ }
+
+ // VUID-VkImageMemoryBarrier2-attachmentFeedbackLoopLayout-07313
+ /*if !device.enabled_features().attachment_feedback_loop_layout
+ && matches!(new_layout, ImageLayout::AttachmentFeedbackLoopOptimal)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element where \
+ `new_layout` is `AttachmentFeedbackLoopOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_feedback_loop_layout"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ for layout in [old_layout, new_layout] {
+ // VUID-VkImageMemoryBarrier2-synchronization2-06911
+ /*if !device.enabled_features().synchronization2
+ && matches!(
+ layout,
+ ImageLayout::AttachmentOptimal | ImageLayout::ReadOnlyOptimal
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `old_layout` or `new_layout` is `AttachmentOptimal` or \
+ `ReadOnlyOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-07006
+ /*if layout == ImageLayout::AttachmentFeedbackLoopOptimal {
+ if !image.usage().intersects(
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ ) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::COLOR_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::INPUT_ATTACHMENT | ImageUsage::SAMPLED)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::INPUT_ATTACHMENT
+ | ImageUsage::SAMPLED,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::ATTACHMENT_FEEDBACK_LOOP)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::ATTACHMENT_FEEDBACK_LOOP,
+ },
+ );
+ }
+ }*/
+
+ let requires_one_of_usage = match layout {
+ // VUID-VkImageMemoryBarrier2-oldLayout-01208
+ ImageLayout::ColorAttachmentOptimal => ImageUsage::COLOR_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01209
+ ImageLayout::DepthStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01210
+ ImageLayout::DepthStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01211
+ ImageLayout::ShaderReadOnlyOptimal => {
+ ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01212
+ ImageLayout::TransferSrcOptimal => ImageUsage::TRANSFER_SRC,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01213
+ ImageLayout::TransferDstOptimal => ImageUsage::TRANSFER_DST,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01658
+ ImageLayout::DepthReadOnlyStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01659
+ ImageLayout::DepthAttachmentStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ /*
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04065
+ ImageLayout::DepthReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04066
+ ImageLayout::DepthAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04067
+ ImageLayout::StencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04068
+ ImageLayout::StencilAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03938
+ ImageLayout::AttachmentOptimal => {
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03939
+ ImageLayout::ReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-02088
+ ImageLayout::FragmentShadingRateAttachmentOptimal => {
+ ImageUsage::FRAGMENT_SHADING_RATE_ATTACHMENT
+ }
+ */
+ _ => continue,
+ };
+
+ if !image.usage().intersects(requires_one_of_usage) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage,
+ },
+ );
+ }
+ }
+
+ /*
+ Check queue family tansfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'i',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ image.sharing(),
+ )?;
+
+ /*
+ Check subresource range
+ */
+
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
+
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ let image_aspects = image.format().unwrap().aspects();
+
+ // VUID-VkImageMemoryBarrier2-image-01673
+ // VUID-VkImageMemoryBarrier2-image-03319
+ if image_aspects.contains(subresource_range.aspects) {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - image_aspects,
+ });
+ }
+
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ // VUID-VkImageMemoryBarrier2-image-03320
+ if !device.enabled_features().separate_depth_stencil_layouts
+ && image_aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ && !subresource_range
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `image` has both a depth and a stencil aspect, and \
+ `subresource_range.aspects` does not contain both aspects",
+ requires_one_of: RequiresOneOf {
+ features: &["separate_depth_stencil_layouts"],
+ ..Default::default()
+ },
+ });
+ }
+ } else {
+ // VUID-VkImageMemoryBarrier2-image-01671
+ if !image.flags().intersects(ImageCreateFlags::DISJOINT)
+ && subresource_range.aspects != ImageAspects::COLOR
+ {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - ImageAspects::COLOR,
+ });
+ }
+ }
+
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(!subresource_range.mip_levels.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01486
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01724
+ if subresource_range.mip_levels.end > image.mip_levels() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierMipLevelsOutOfRange {
+ barrier_index,
+ mip_levels_range_end: subresource_range.mip_levels.end,
+ image_mip_levels: image.mip_levels(),
+ },
+ );
+ }
+
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(!subresource_range.array_layers.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01488
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01725
+ if subresource_range.array_layers.end > image.dimensions().array_layers() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierArrayLayersOutOfRange {
+ barrier_index,
+ array_layers_range_end: subresource_range.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ },
+ );
+ }
+ }
+
+ /*
+ Checks for current render pass
+ */
+
+ if let Some(render_pass_state) = self.builder_state.render_pass.as_ref() {
+ // VUID-vkCmdPipelineBarrier2-None-06191
+ let begin_render_pass_state = match &render_pass_state.render_pass {
+ RenderPassStateType::BeginRenderPass(x) => x,
+ RenderPassStateType::BeginRendering(_) => {
+ return Err(SynchronizationError::ForbiddenWithBeginRendering)
+ }
+ };
+ let subpass_index = begin_render_pass_state.subpass.index();
+ let subpass_desc = begin_render_pass_state.subpass.subpass_desc();
+ let dependencies = begin_render_pass_state.subpass.render_pass().dependencies();
+
+ // VUID-vkCmdPipelineBarrier2-pDependencies-02285
+ // TODO: see https://github.com/KhronosGroup/Vulkan-Docs/issues/1982
+ if !dependencies.iter().any(|dependency| {
+ dependency.src_subpass == Some(subpass_index)
+ && dependency.dst_subpass == Some(subpass_index)
+ }) {
+ return Err(SynchronizationError::MemoryBarrierNoMatchingSubpassSelfDependency);
+ }
+
+ // VUID-vkCmdPipelineBarrier2-bufferMemoryBarrierCount-01178
+ if !buffer_memory_barriers.is_empty() {
+ return Err(SynchronizationError::BufferMemoryBarrierForbiddenInsideRenderPass);
+ }
+
+ for (barrier_index, barrier) in image_memory_barriers.iter().enumerate() {
+ // VUID-vkCmdPipelineBarrier2-image-04073
+ // TODO: How are you supposed to verify this in secondary command buffers,
+ // when there is no inherited framebuffer?
+ // The image is not known until you execute it in a primary command buffer.
+ if let Some(framebuffer) = &begin_render_pass_state.framebuffer {
+ let attachment_index = (framebuffer.attachments().iter())
+ .position(|attachment| attachment.image().inner().image == &barrier.image)
+ .ok_or(SynchronizationError::ImageMemoryBarrierNotInputAttachment {
+ barrier_index,
+ })? as u32;
+
+ if !(subpass_desc.input_attachments.iter().flatten())
+ .any(|atch_ref| atch_ref.attachment == attachment_index)
+ {
+ return Err(SynchronizationError::ImageMemoryBarrierNotInputAttachment {
+ barrier_index,
+ });
+ }
+
+ if !(subpass_desc.color_attachments.iter().flatten())
+ .chain(subpass_desc.depth_stencil_attachment.as_ref())
+ .any(|atch_ref| atch_ref.attachment == attachment_index)
+ {
+ return Err(SynchronizationError::ImageMemoryBarrierNotColorDepthStencilAttachment {
+ barrier_index,
+ });
+ }
+ }
+
+ // VUID-vkCmdPipelineBarrier2-oldLayout-01181
+ if barrier.old_layout != barrier.new_layout {
+ return Err(SynchronizationError::ImageMemoryBarrierLayoutTransitionForbiddenInsideRenderPass {
+ barrier_index,
+ });
+ }
+
+ // VUID-vkCmdPipelineBarrier2-srcQueueFamilyIndex-01182
+ if barrier.queue_family_ownership_transfer.is_some() {
+ return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferForbiddenInsideRenderPass {
+ barrier_index,
+ });
+ }
+ }
+ } else {
+ // VUID-vkCmdPipelineBarrier2-dependencyFlags-01186
+ if dependency_flags.intersects(DependencyFlags::VIEW_LOCAL) {
+ return Err(SynchronizationError::DependencyFlagsViewLocalNotAllowed);
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn pipeline_barrier_unchecked(
+ &mut self,
+ dependency_info: DependencyInfo,
+ ) -> &mut Self {
+ if dependency_info.is_empty() {
+ return self;
+ }
+
+ let &DependencyInfo {
+ dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = &dependency_info;
+
+ if self.device().enabled_features().synchronization2 {
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ ash::vk::MemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let dependency_info_vk = ash::vk::DependencyInfo {
+ dependency_flags: dependency_flags.into(),
+ memory_barrier_count: memory_barriers_vk.len() as u32,
+ p_memory_barriers: memory_barriers_vk.as_ptr(),
+ buffer_memory_barrier_count: buffer_memory_barriers_vk.len() as u32,
+ p_buffer_memory_barriers: buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barrier_count: image_memory_barriers_vk.len() as u32,
+ p_image_memory_barriers: image_memory_barriers_vk.as_ptr(),
+ ..Default::default()
+ };
+
+ let fns = self.device().fns();
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_pipeline_barrier2)(self.handle(), &dependency_info_vk);
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_pipeline_barrier2_khr)(
+ self.handle(),
+ &dependency_info_vk,
+ );
+ }
+ } else {
+ let mut src_stage_mask = ash::vk::PipelineStageFlags::empty();
+ let mut dst_stage_mask = ash::vk::PipelineStageFlags::empty();
+
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ ash::vk::MemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ if src_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the first scope."
+ src_stage_mask |= ash::vk::PipelineStageFlags::TOP_OF_PIPE;
+ }
+
+ if dst_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the second scope."
+ dst_stage_mask |= ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE;
+ }
+
+ let fns = self.device().fns();
+ (fns.v1_0.cmd_pipeline_barrier)(
+ self.handle(),
+ src_stage_mask,
+ dst_stage_mask,
+ dependency_flags.into(),
+ memory_barriers_vk.len() as u32,
+ memory_barriers_vk.as_ptr(),
+ buffer_memory_barriers_vk.len() as u32,
+ buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barriers_vk.len() as u32,
+ image_memory_barriers_vk.as_ptr(),
+ );
+ }
+
+ let command_index = self.next_command_index;
+ let command_name = "pipeline_barrier";
+ self.resources_usage_state.record_pipeline_barrier(
+ command_index,
+ command_name,
+ &dependency_info,
+ self.queue_family_properties().queue_flags,
+ );
+
+ self.resources
+ .reserve(buffer_memory_barriers.len() + image_memory_barriers.len());
+
+ for barrier in dependency_info.buffer_memory_barriers {
+ self.resources.push(Box::new(barrier.buffer));
+ }
+
+ for barrier in dependency_info.image_memory_barriers {
+ self.resources.push(Box::new(barrier.image));
+ }
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Signals an [`Event`] from the device.
+ ///
+ /// # Safety
+ ///
+ /// - All images that are accessed by the command must be in the expected image layout.
+ /// - For each element of `dependency_info.image_memory_barriers` that contains an image layout
+ /// transition, which is a write operation, the barrier must be defined appropriately to
+ /// ensure no memory access hazard occurs.
+ #[inline]
+ pub unsafe fn set_event(
+ &mut self,
+ event: Arc<Event>,
+ dependency_info: DependencyInfo,
+ ) -> Result<&mut Self, SynchronizationError> {
+ self.validate_set_event(&event, &dependency_info)?;
+
+ unsafe { Ok(self.set_event_unchecked(event, dependency_info)) }
+ }
+
+ fn validate_set_event(
+ &self,
+ event: &Event,
+ dependency_info: &DependencyInfo,
+ ) -> Result<(), SynchronizationError> {
+ // VUID-vkCmdSetEvent2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(SynchronizationError::ForbiddenInsideRenderPass);
+ }
+
+ // VUID-vkCmdSetEvent2-commandBuffer-03826
+ // TODO:
+
+ let device = self.device();
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdSetEvent2-commandBuffer-cmdpool
+ if !queue_family_properties.queue_flags.intersects(
+ QueueFlags::GRAPHICS
+ | QueueFlags::COMPUTE
+ | QueueFlags::VIDEO_DECODE
+ | QueueFlags::VIDEO_ENCODE,
+ ) {
+ return Err(SynchronizationError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdSetEvent2-commonparent
+ assert_eq!(device, event.device());
+
+ let &DependencyInfo {
+ dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ // VUID-VkDependencyInfo-dependencyFlags-parameter
+ dependency_flags.validate_device(device)?;
+
+ // VUID-vkCmdSetEvent2-dependencyFlags-03825
+ assert!(dependency_flags.is_empty());
+
+ let check_stages_access = |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ src_access: AccessFlags,
+ dst_stages: PipelineStages,
+ dst_access: AccessFlags|
+ -> Result<(), SynchronizationError> {
+ for (stages, access) in [(src_stages, src_access), (dst_stages, dst_access)] {
+ // VUID-vkCmdSetEvent2-synchronization2-03824
+ if !device.enabled_features().synchronization2 {
+ if stages.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_stages` or `dst_stages` contains flags from \
+ `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if access.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` or `dst_access` contains flags from \
+ `VkAccessFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstStageMask-parameter
+ stages.validate_device(device)?;
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-parameter
+ access.validate_device(device)?;
+
+ // VUID-vkCmdSetEvent2-srcStageMask-03827
+ // VUID-vkCmdSetEvent2-dstStageMask-03828
+ if !PipelineStages::from(queue_family_properties.queue_flags).contains(stages) {
+ match ty {
+ 'm' => {
+ return Err(SynchronizationError::MemoryBarrierStageNotSupported {
+ barrier_index,
+ })
+ }
+ 'b' => {
+ return Err(
+ SynchronizationError::BufferMemoryBarrierStageNotSupported {
+ barrier_index,
+ },
+ )
+ }
+ 'i' => {
+ return Err(SynchronizationError::ImageMemoryBarrierStageNotSupported {
+ barrier_index,
+ })
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03929
+ // VUID-VkMemoryBarrier2-dstStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03929
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(PipelineStages::GEOMETRY_SHADER)
+ && !device.enabled_features().geometry_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::GEOMETRY_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03930
+ // VUID-VkMemoryBarrier2-dstStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03930
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(
+ PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER,
+ ) && !device.enabled_features().tessellation_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
+ `PipelineStages::TESSELLATION_EVALUATION_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03931
+ // VUID-VkMemoryBarrier2-dstStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03931
+ // VUID-VImagekMemoryBarrier2-srcStageMask-03931
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03931
+ if stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
+ && !device.enabled_features().conditional_rendering
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::CONDITIONAL_RENDERING`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03932
+ // VUID-VkMemoryBarrier2-dstStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03932
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03932
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03932
+ if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
+ && !device.enabled_features().fragment_density_map
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03933
+ // VUID-VkMemoryBarrier2-dstStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03933
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03933
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03933
+ if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
+ && !device.enabled_features().transform_feedback
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TRANSFORM_FEEDBACK`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03934
+ // VUID-VkMemoryBarrier2-dstStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03934
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03934
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03934
+ if stages.intersects(PipelineStages::MESH_SHADER)
+ && !device.enabled_features().mesh_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::MESH_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03935
+ // VUID-VkMemoryBarrier2-dstStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03935
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03935
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03935
+ if stages.intersects(PipelineStages::TASK_SHADER)
+ && !device.enabled_features().task_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TASK_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
+ && !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_fragment_shading_rate", "shading_rate_image"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04957
+ // VUID-VkMemoryBarrier2-dstStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04957
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04957
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04957
+ if stages.intersects(PipelineStages::SUBPASS_SHADING)
+ && !device.enabled_features().subpass_shading
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::SUBPASS_SHADING`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04995
+ // VUID-VkMemoryBarrier2-dstStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04995
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04995
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04995
+ if stages.intersects(PipelineStages::INVOCATION_MASK)
+ && !device.enabled_features().invocation_mask
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::INVOCATION_MASK`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdSetEvent-stageMask-03937
+ if stages.is_empty() && !device.enabled_features().synchronization2 {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ is empty",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // A bit of a ridiculous number of VUIDs...
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-07458
+
+ if !AccessFlags::from(stages).contains(access) {
+ match ty {
+ 'm' => {
+ return Err(
+ SynchronizationError::MemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ )
+ }
+ 'b' => return Err(
+ SynchronizationError::BufferMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ 'i' => return Err(
+ SynchronizationError::ImageMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-06256
+ if !device.enabled_features().ray_query
+ && src_access.intersects(AccessFlags::ACCELERATION_STRUCTURE_READ)
+ && src_stages.intersects(
+ PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::COMPUTE_SHADER
+ | PipelineStages::PRE_RASTERIZATION_SHADERS
+ | PipelineStages::TASK_SHADER
+ | PipelineStages::MESH_SHADER,
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` contains `ACCELERATION_STRUCTURE_READ`, and \
+ `src_stages` contains a shader stage other than `RAY_TRACING_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["ray_query"],
+ ..Default::default()
+ },
+ });
+ }
+
+ Ok(())
+ };
+
+ let check_queue_family_ownership_transfer = |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ dst_stages: PipelineStages,
+ queue_family_ownership_transfer: Option<
+ QueueFamilyOwnershipTransfer,
+ >,
+ sharing: &Sharing<_>|
+ -> Result<(), SynchronizationError> {
+ if let Some(transfer) = queue_family_ownership_transfer {
+ // VUID?
+ transfer.validate_device(device)?;
+
+ // VUID-VkBufferMemoryBarrier2-srcQueueFamilyIndex-04087
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04070
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04088
+ // VUID-VkImageMemoryBarrier2-image-04071
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ let queue_family_count =
+ device.physical_device().queue_family_properties().len() as u32;
+
+ let provided_queue_family_index = match (sharing, transfer) {
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveBetweenLocal {
+ src_index,
+ dst_index,
+ },
+ ) => Some(max(src_index, dst_index)),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveToExternal { src_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveToForeign { src_index },
+ ) => Some(src_index),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveFromExternal { dst_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveFromForeign { dst_index },
+ ) => Some(dst_index),
+ (
+ Sharing::Concurrent(_),
+ QueueFamilyOwnershipTransfer::ConcurrentToExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentFromExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentToForeign
+ | QueueFamilyOwnershipTransfer::ConcurrentFromForeign,
+ ) => None,
+ _ => match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ },
+ }.filter(|&index| index >= queue_family_count);
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04089
+ // VUID-VkImageMemoryBarrier2-image-04072
+
+ if let Some(provided_queue_family_index) = provided_queue_family_index {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03851
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03854
+ if src_stages.intersects(PipelineStages::HOST)
+ || dst_stages.intersects(PipelineStages::HOST)
+ {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferHostNotAllowed {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferHostForbidden {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ Ok(())
+ };
+
+ for (barrier_index, barrier) in memory_barriers.iter().enumerate() {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'm',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+ }
+
+ for (barrier_index, barrier) in buffer_memory_barriers.iter().enumerate() {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkBufferMemoryBarrier2-buffer-01931
+ // Ensured by Buffer type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'b',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check queue family transfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'b',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ buffer.sharing(),
+ )?;
+
+ /*
+ Check range
+ */
+
+ // VUID-VkBufferMemoryBarrier2-size-01188
+ assert!(!range.is_empty());
+
+ // VUID-VkBufferMemoryBarrier2-offset-01187
+ // VUID-VkBufferMemoryBarrier2-size-01189
+ if range.end > buffer.size() {
+ return Err(SynchronizationError::BufferMemoryBarrierOutOfRange {
+ barrier_index,
+ range_end: range.end,
+ buffer_size: buffer.size(),
+ });
+ }
+ }
+
+ for (barrier_index, barrier) in image_memory_barriers.iter().enumerate() {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkImageMemoryBarrier2-image-01932
+ // Ensured by Image type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'i',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check layouts
+ */
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-parameter
+ old_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-newLayout-parameter
+ new_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03855
+ if src_stages.intersects(PipelineStages::HOST)
+ && !matches!(
+ old_layout,
+ ImageLayout::Preinitialized | ImageLayout::Undefined | ImageLayout::General
+ )
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierOldLayoutFromHostInvalid {
+ barrier_index,
+ old_layout,
+ },
+ );
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01197
+ // Not checked yet, therefore unsafe.
+
+ // VUID-VkImageMemoryBarrier2-newLayout-01198
+ if matches!(
+ new_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ ) {
+ return Err(SynchronizationError::ImageMemoryBarrierNewLayoutInvalid {
+ barrier_index,
+ });
+ }
+
+ // VUID-VkImageMemoryBarrier2-attachmentFeedbackLoopLayout-07313
+ /*if !device.enabled_features().attachment_feedback_loop_layout
+ && matches!(new_layout, ImageLayout::AttachmentFeedbackLoopOptimal)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element where \
+ `new_layout` is `AttachmentFeedbackLoopOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_feedback_loop_layout"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ for layout in [old_layout, new_layout] {
+ // VUID-VkImageMemoryBarrier2-synchronization2-06911
+ /*if !device.enabled_features().synchronization2
+ && matches!(
+ layout,
+ ImageLayout::AttachmentOptimal | ImageLayout::ReadOnlyOptimal
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `old_layout` or `new_layout` is `AttachmentOptimal` or \
+ `ReadOnlyOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-07006
+ /*if layout == ImageLayout::AttachmentFeedbackLoopOptimal {
+ if !image.usage().intersects(
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ ) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::COLOR_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::INPUT_ATTACHMENT | ImageUsage::SAMPLED)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::INPUT_ATTACHMENT
+ | ImageUsage::SAMPLED,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::ATTACHMENT_FEEDBACK_LOOP)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::ATTACHMENT_FEEDBACK_LOOP,
+ },
+ );
+ }
+ }*/
+
+ let requires_one_of_usage = match layout {
+ // VUID-VkImageMemoryBarrier2-oldLayout-01208
+ ImageLayout::ColorAttachmentOptimal => ImageUsage::COLOR_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01209
+ ImageLayout::DepthStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01210
+ ImageLayout::DepthStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01211
+ ImageLayout::ShaderReadOnlyOptimal => {
+ ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01212
+ ImageLayout::TransferSrcOptimal => ImageUsage::TRANSFER_SRC,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01213
+ ImageLayout::TransferDstOptimal => ImageUsage::TRANSFER_DST,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01658
+ ImageLayout::DepthReadOnlyStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01659
+ ImageLayout::DepthAttachmentStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ /*
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04065
+ ImageLayout::DepthReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04066
+ ImageLayout::DepthAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04067
+ ImageLayout::StencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04068
+ ImageLayout::StencilAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03938
+ ImageLayout::AttachmentOptimal => {
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03939
+ ImageLayout::ReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-02088
+ ImageLayout::FragmentShadingRateAttachmentOptimal => {
+ ImageUsage::FRAGMENT_SHADING_RATE_ATTACHMENT
+ }
+ */
+ _ => continue,
+ };
+
+ if !image.usage().intersects(requires_one_of_usage) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage,
+ },
+ );
+ }
+ }
+
+ /*
+ Check queue family tansfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'i',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ image.sharing(),
+ )?;
+
+ /*
+ Check subresource range
+ */
+
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
+
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ let image_aspects = image.format().unwrap().aspects();
+
+ // VUID-VkImageMemoryBarrier2-image-01673
+ // VUID-VkImageMemoryBarrier2-image-03319
+ if image_aspects.contains(subresource_range.aspects) {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - image_aspects,
+ });
+ }
+
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ // VUID-VkImageMemoryBarrier2-image-03320
+ if !device.enabled_features().separate_depth_stencil_layouts
+ && image_aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ && !subresource_range
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `image` has both a depth and a stencil aspect, and \
+ `subresource_range.aspects` does not contain both aspects",
+ requires_one_of: RequiresOneOf {
+ features: &["separate_depth_stencil_layouts"],
+ ..Default::default()
+ },
+ });
+ }
+ } else {
+ // VUID-VkImageMemoryBarrier2-image-01671
+ if !image.flags().intersects(ImageCreateFlags::DISJOINT)
+ && subresource_range.aspects != ImageAspects::COLOR
+ {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - ImageAspects::COLOR,
+ });
+ }
+ }
+
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(!subresource_range.mip_levels.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01486
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01724
+ if subresource_range.mip_levels.end > image.mip_levels() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierMipLevelsOutOfRange {
+ barrier_index,
+ mip_levels_range_end: subresource_range.mip_levels.end,
+ image_mip_levels: image.mip_levels(),
+ },
+ );
+ }
+
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(!subresource_range.array_layers.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01488
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01725
+ if subresource_range.array_layers.end > image.dimensions().array_layers() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierArrayLayersOutOfRange {
+ barrier_index,
+ array_layers_range_end: subresource_range.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ },
+ );
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn set_event_unchecked(
+ &mut self,
+ event: Arc<Event>,
+ dependency_info: DependencyInfo,
+ ) -> &mut Self {
+ let DependencyInfo {
+ dependency_flags,
+ memory_barriers,
+ buffer_memory_barriers,
+ image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ let fns = self.device().fns();
+
+ if self.device().enabled_features().synchronization2 {
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ ash::vk::MemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let dependency_info_vk = ash::vk::DependencyInfo {
+ dependency_flags: dependency_flags.into(),
+ memory_barrier_count: memory_barriers_vk.len() as u32,
+ p_memory_barriers: memory_barriers_vk.as_ptr(),
+ buffer_memory_barrier_count: buffer_memory_barriers_vk.len() as u32,
+ p_buffer_memory_barriers: buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barrier_count: image_memory_barriers_vk.len() as u32,
+ p_image_memory_barriers: image_memory_barriers_vk.as_ptr(),
+ ..Default::default()
+ };
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_set_event2)(self.handle(), event.handle(), &dependency_info_vk);
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_set_event2_khr)(
+ self.handle(),
+ event.handle(),
+ &dependency_info_vk,
+ );
+ }
+ } else {
+ // The original function only takes a source stage mask; the rest of the info is
+ // provided with `wait_events` instead. Therefore, we condense the source stages
+ // here and ignore the rest.
+
+ let mut stage_mask = ash::vk::PipelineStageFlags::empty();
+
+ for barrier in memory_barriers {
+ stage_mask |= barrier.src_stages.into();
+ }
+
+ for barrier in buffer_memory_barriers {
+ stage_mask |= barrier.src_stages.into();
+ }
+
+ for barrier in image_memory_barriers {
+ stage_mask |= barrier.src_stages.into();
+ }
+
+ if stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the first scope."
+ stage_mask |= ash::vk::PipelineStageFlags::TOP_OF_PIPE;
+ }
+
+ (fns.v1_0.cmd_set_event)(self.handle(), event.handle(), stage_mask);
+ }
+
+ self.resources.push(Box::new(event));
+
+ // TODO: sync state update
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Waits for one or more [`Event`]s to be signaled.
+ ///
+ /// # Safety
+ ///
+ /// - For each element in `events`, if the event is signaled by [`set_event`], that command
+ /// must have already been recorded or previously submitted to the queue, and the
+ /// `DependencyInfo` provided here must be equal to the `DependencyInfo` used in that
+ /// command.
+ /// - For each element in `events`, if the event is signaled by [`Event::set`], that function
+ /// must have already been called before submitting this command to a queue.
+ ///
+ /// [`set_event`]: Self::set_event
+ /// [`Event::set`]: Event::set
+ #[inline]
+ pub unsafe fn wait_events(
+ &mut self,
+ events: impl IntoIterator<Item = (Arc<Event>, DependencyInfo)>,
+ ) -> Result<&mut Self, SynchronizationError> {
+ let events: SmallVec<[(Arc<Event>, DependencyInfo); 4]> = events.into_iter().collect();
+ self.validate_wait_events(&events)?;
+
+ unsafe { Ok(self.wait_events_unchecked(events)) }
+ }
+
+ fn validate_wait_events(
+ &self,
+ events: &[(Arc<Event>, DependencyInfo)],
+ ) -> Result<(), SynchronizationError> {
+ // VUID-vkCmdWaitEvents2-commandBuffer-03846
+ // TODO:
+
+ let device = self.device();
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdWaitEvents2-commandBuffer-cmdpool
+ if !queue_family_properties.queue_flags.intersects(
+ QueueFlags::GRAPHICS
+ | QueueFlags::COMPUTE
+ | QueueFlags::VIDEO_DECODE
+ | QueueFlags::VIDEO_ENCODE,
+ ) {
+ return Err(SynchronizationError::NotSupportedByQueueFamily);
+ }
+
+ if events.is_empty() {
+ return Ok(());
+ }
+
+ for (event, dependency_info) in events {
+ // VUID-vkCmdWaitEvents2-commonparent
+ assert_eq!(device, event.device());
+
+ // VUID-vkCmdWaitEvents2-pEvents-03838
+ // TODO:
+
+ // VUID-vkCmdWaitEvents2-pEvents-03839
+ // TODO:
+
+ // VUID-vkCmdWaitEvents2-pEvents-03840
+ // TODO:
+
+ // VUID-vkCmdWaitEvents2-pEvents-03841
+ // TODO:
+
+ let &DependencyInfo {
+ dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ // VUID-VkDependencyInfo-dependencyFlags-parameter
+ dependency_flags.validate_device(device)?;
+
+ let check_stages_access = |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ src_access: AccessFlags,
+ dst_stages: PipelineStages,
+ dst_access: AccessFlags|
+ -> Result<(), SynchronizationError> {
+ for (stages, access) in [(src_stages, src_access), (dst_stages, dst_access)] {
+ // VUID-vkCmdWaitEvents2-synchronization2-03836
+ if !device.enabled_features().synchronization2 {
+ if stages.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_stages` or `dst_stages` contains flags from \
+ `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ if access.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` or `dst_access` contains flags from \
+ `VkAccessFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcStageMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstStageMask-parameter
+ stages.validate_device(device)?;
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-parameter
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-parameter
+ access.validate_device(device)?;
+
+ // VUID-vkCmdWaitEvents2-srcStageMask-03842
+ // VUID-vkCmdWaitEvents2-dstStageMask-03843
+ if !PipelineStages::from(queue_family_properties.queue_flags).contains(stages) {
+ match ty {
+ 'm' => {
+ return Err(SynchronizationError::MemoryBarrierStageNotSupported {
+ barrier_index,
+ })
+ }
+ 'b' => {
+ return Err(
+ SynchronizationError::BufferMemoryBarrierStageNotSupported {
+ barrier_index,
+ },
+ )
+ }
+ 'i' => {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierStageNotSupported {
+ barrier_index,
+ },
+ )
+ }
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03929
+ // VUID-VkMemoryBarrier2-dstStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03929
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03929
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(PipelineStages::GEOMETRY_SHADER)
+ && !device.enabled_features().geometry_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::GEOMETRY_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03930
+ // VUID-VkMemoryBarrier2-dstStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03930
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03930
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03930
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03930
+ if stages.intersects(
+ PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER,
+ ) && !device.enabled_features().tessellation_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
+ `PipelineStages::TESSELLATION_EVALUATION_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03931
+ // VUID-VkMemoryBarrier2-dstStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03931
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03931
+ // VUID-VImagekMemoryBarrier2-srcStageMask-03931
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03931
+ if stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
+ && !device.enabled_features().conditional_rendering
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::CONDITIONAL_RENDERING`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03932
+ // VUID-VkMemoryBarrier2-dstStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03932
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03932
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03932
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03932
+ if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
+ && !device.enabled_features().fragment_density_map
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03933
+ // VUID-VkMemoryBarrier2-dstStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03933
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03933
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03933
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03933
+ if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
+ && !device.enabled_features().transform_feedback
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TRANSFORM_FEEDBACK`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03934
+ // VUID-VkMemoryBarrier2-dstStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03934
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03934
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03934
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03934
+ if stages.intersects(PipelineStages::MESH_SHADER)
+ && !device.enabled_features().mesh_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::MESH_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-03935
+ // VUID-VkMemoryBarrier2-dstStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03935
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-03935
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03935
+ // VUID-VkImageMemoryBarrier2-dstStageMask-03935
+ if stages.intersects(PipelineStages::TASK_SHADER)
+ && !device.enabled_features().task_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::TASK_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkBufferMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ // VUID-VkImageMemoryBarrier2-shadingRateImage-07316
+ if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
+ && !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`",
+ requires_one_of: RequiresOneOf {
+ features: &[
+ "attachment_fragment_shading_rate",
+ "shading_rate_image",
+ ],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04957
+ // VUID-VkMemoryBarrier2-dstStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04957
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04957
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04957
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04957
+ if stages.intersects(PipelineStages::SUBPASS_SHADING)
+ && !device.enabled_features().subpass_shading
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::SUBPASS_SHADING`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-VkMemoryBarrier2-srcStageMask-04995
+ // VUID-VkMemoryBarrier2-dstStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-04995
+ // VUID-VkBufferMemoryBarrier2-dstStageMask-04995
+ // VUID-VkImageMemoryBarrier2-srcStageMask-04995
+ // VUID-VkImageMemoryBarrier2-dstStageMask-04995
+ if stages.intersects(PipelineStages::INVOCATION_MASK)
+ && !device.enabled_features().invocation_mask
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ contains `PipelineStages::INVOCATION_MASK`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdWaitEvents-srcStageMask-03937
+ // VUID-vkCmdWaitEvents-dstStageMask-03937
+ if stages.is_empty() && !device.enabled_features().synchronization2 {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where `stages` \
+ is empty",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // A bit of a ridiculous number of VUIDs...
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkBufferMemoryBarrier2-dstAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-07458
+
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-03900
+ // ..
+ // VUID-VkImageMemoryBarrier2-dstAccessMask-07458
+
+ if !AccessFlags::from(stages).contains(access) {
+ match ty {
+ 'm' => {
+ return Err(
+ SynchronizationError::MemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ )
+ }
+ 'b' => return Err(
+ SynchronizationError::BufferMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ 'i' => return Err(
+ SynchronizationError::ImageMemoryBarrierAccessNotSupportedByStages {
+ barrier_index,
+ },
+ ),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ // VUID-VkMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkBufferMemoryBarrier2-srcAccessMask-06256
+ // VUID-VkImageMemoryBarrier2-srcAccessMask-06256
+ if !device.enabled_features().ray_query
+ && src_access.intersects(AccessFlags::ACCELERATION_STRUCTURE_READ)
+ && src_stages.intersects(
+ PipelineStages::VERTEX_SHADER
+ | PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER
+ | PipelineStages::GEOMETRY_SHADER
+ | PipelineStages::FRAGMENT_SHADER
+ | PipelineStages::COMPUTE_SHADER
+ | PipelineStages::PRE_RASTERIZATION_SHADERS
+ | PipelineStages::TASK_SHADER
+ | PipelineStages::MESH_SHADER,
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "One of `dependency_info.memory_barriers`, \
+ `dependency_info.buffer_memory_barriers` or \
+ `dependency_info.image_memory_barriers` has an element where \
+ `src_access` contains `ACCELERATION_STRUCTURE_READ`, and \
+ `src_stages` contains a shader stage other than `RAY_TRACING_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["ray_query"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdWaitEvents2-dependencyFlags-03844
+ if self.builder_state.render_pass.is_some()
+ && src_stages.intersects(PipelineStages::HOST)
+ {
+ todo!()
+ }
+
+ Ok(())
+ };
+
+ let check_queue_family_ownership_transfer =
+ |ty: char,
+ barrier_index: usize,
+ src_stages: PipelineStages,
+ dst_stages: PipelineStages,
+ queue_family_ownership_transfer: Option<QueueFamilyOwnershipTransfer>,
+ sharing: &Sharing<_>|
+ -> Result<(), SynchronizationError> {
+ if let Some(transfer) = queue_family_ownership_transfer {
+ // VUID?
+ transfer.validate_device(device)?;
+
+ // VUID-VkBufferMemoryBarrier2-srcQueueFamilyIndex-04087
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04070
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04088
+ // VUID-VkImageMemoryBarrier2-image-04071
+ // Ensured by the definition of `QueueFamilyOwnershipTransfer`.
+
+ let queue_family_count =
+ device.physical_device().queue_family_properties().len() as u32;
+
+ let provided_queue_family_index = match (sharing, transfer) {
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveBetweenLocal {
+ src_index,
+ dst_index,
+ },
+ ) => Some(max(src_index, dst_index)),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveToExternal { src_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveToForeign { src_index },
+ ) => Some(src_index),
+ (
+ Sharing::Exclusive,
+ QueueFamilyOwnershipTransfer::ExclusiveFromExternal { dst_index }
+ | QueueFamilyOwnershipTransfer::ExclusiveFromForeign { dst_index },
+ ) => Some(dst_index),
+ (
+ Sharing::Concurrent(_),
+ QueueFamilyOwnershipTransfer::ConcurrentToExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentFromExternal
+ | QueueFamilyOwnershipTransfer::ConcurrentToForeign
+ | QueueFamilyOwnershipTransfer::ConcurrentFromForeign,
+ ) => None,
+ _ => match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferSharingMismatch {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ },
+ }.filter(|&index| index >= queue_family_count);
+
+ // VUID-VkBufferMemoryBarrier2-buffer-04089
+ // VUID-VkImageMemoryBarrier2-image-04072
+
+ if let Some(provided_queue_family_index) = provided_queue_family_index {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ }),
+ _ => unreachable!(),
+ }
+ }
+
+ // VUID-VkBufferMemoryBarrier2-srcStageMask-03851
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03854
+ if src_stages.intersects(PipelineStages::HOST)
+ || dst_stages.intersects(PipelineStages::HOST)
+ {
+ match ty {
+ 'b' => return Err(SynchronizationError::BufferMemoryBarrierOwnershipTransferHostNotAllowed {
+ barrier_index,
+ }),
+ 'i' => return Err(SynchronizationError::ImageMemoryBarrierOwnershipTransferHostForbidden {
+ barrier_index,
+ }),
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ Ok(())
+ };
+
+ for (barrier_index, barrier) in memory_barriers.iter().enumerate() {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'm',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+ }
+
+ for (barrier_index, barrier) in buffer_memory_barriers.iter().enumerate() {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkBufferMemoryBarrier2-buffer-01931
+ // Ensured by Buffer type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'b',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check queue family transfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'b',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ buffer.sharing(),
+ )?;
+
+ /*
+ Check range
+ */
+
+ // VUID-VkBufferMemoryBarrier2-size-01188
+ assert!(!range.is_empty());
+
+ // VUID-VkBufferMemoryBarrier2-offset-01187
+ // VUID-VkBufferMemoryBarrier2-size-01189
+ if range.end > buffer.size() {
+ return Err(SynchronizationError::BufferMemoryBarrierOutOfRange {
+ barrier_index,
+ range_end: range.end,
+ buffer_size: buffer.size(),
+ });
+ }
+ }
+
+ for (barrier_index, barrier) in image_memory_barriers.iter().enumerate() {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ // VUID-VkImageMemoryBarrier2-image-01932
+ // Ensured by Image type construction.
+
+ /*
+ Check stages and access
+ */
+
+ check_stages_access(
+ 'i',
+ barrier_index,
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ )?;
+
+ /*
+ Check layouts
+ */
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-parameter
+ old_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-newLayout-parameter
+ new_layout.validate_device(device)?;
+
+ // VUID-VkImageMemoryBarrier2-srcStageMask-03855
+ if src_stages.intersects(PipelineStages::HOST)
+ && !matches!(
+ old_layout,
+ ImageLayout::Preinitialized | ImageLayout::Undefined | ImageLayout::General
+ )
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierOldLayoutFromHostInvalid {
+ barrier_index,
+ old_layout,
+ },
+ );
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01197
+ // Not checked yet, therefore unsafe.
+
+ // VUID-VkImageMemoryBarrier2-newLayout-01198
+ if matches!(
+ new_layout,
+ ImageLayout::Undefined | ImageLayout::Preinitialized
+ ) {
+ return Err(SynchronizationError::ImageMemoryBarrierNewLayoutInvalid {
+ barrier_index,
+ });
+ }
+
+ // VUID-VkImageMemoryBarrier2-attachmentFeedbackLoopLayout-07313
+ /*if !device.enabled_features().attachment_feedback_loop_layout
+ && matches!(new_layout, ImageLayout::AttachmentFeedbackLoopOptimal)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element where \
+ `new_layout` is `AttachmentFeedbackLoopOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_feedback_loop_layout"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ for layout in [old_layout, new_layout] {
+ // VUID-VkImageMemoryBarrier2-synchronization2-06911
+ /*if !device.enabled_features().synchronization2
+ && matches!(
+ layout,
+ ImageLayout::AttachmentOptimal | ImageLayout::ReadOnlyOptimal
+ )
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `old_layout` or `new_layout` is `AttachmentOptimal` or \
+ `ReadOnlyOptimal`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }*/
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-07006
+ /*if layout == ImageLayout::AttachmentFeedbackLoopOptimal {
+ if !image.usage().intersects(
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ ) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::COLOR_ATTACHMENT
+ | ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::INPUT_ATTACHMENT | ImageUsage::SAMPLED)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::INPUT_ATTACHMENT
+ | ImageUsage::SAMPLED,
+ },
+ );
+ }
+
+ if !image
+ .usage()
+ .intersects(ImageUsage::ATTACHMENT_FEEDBACK_LOOP)
+ {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage: ImageUsage::ATTACHMENT_FEEDBACK_LOOP,
+ },
+ );
+ }
+ }*/
+
+ let requires_one_of_usage = match layout {
+ // VUID-VkImageMemoryBarrier2-oldLayout-01208
+ ImageLayout::ColorAttachmentOptimal => ImageUsage::COLOR_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01209
+ ImageLayout::DepthStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01210
+ ImageLayout::DepthStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01211
+ ImageLayout::ShaderReadOnlyOptimal => {
+ ImageUsage::SAMPLED | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01212
+ ImageLayout::TransferSrcOptimal => ImageUsage::TRANSFER_SRC,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01213
+ ImageLayout::TransferDstOptimal => ImageUsage::TRANSFER_DST,
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01658
+ ImageLayout::DepthReadOnlyStencilAttachmentOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-01659
+ ImageLayout::DepthAttachmentStencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ /*
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04065
+ ImageLayout::DepthReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04066
+ ImageLayout::DepthAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04067
+ ImageLayout::StencilReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-04068
+ ImageLayout::StencilAttachmentOptimal => ImageUsage::DEPTH_STENCIL_ATTACHMENT,
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03938
+ ImageLayout::AttachmentOptimal => {
+ ImageUsage::COLOR_ATTACHMENT | ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-srcQueueFamilyIndex-03939
+ ImageLayout::ReadOnlyOptimal => {
+ ImageUsage::DEPTH_STENCIL_ATTACHMENT
+ | ImageUsage::SAMPLED
+ | ImageUsage::INPUT_ATTACHMENT
+ }
+
+ // VUID-VkImageMemoryBarrier2-oldLayout-02088
+ ImageLayout::FragmentShadingRateAttachmentOptimal => {
+ ImageUsage::FRAGMENT_SHADING_RATE_ATTACHMENT
+ }
+ */
+ _ => continue,
+ };
+
+ if !image.usage().intersects(requires_one_of_usage) {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage,
+ },
+ );
+ }
+ }
+
+ /*
+ Check queue family tansfer
+ */
+
+ check_queue_family_ownership_transfer(
+ 'i',
+ barrier_index,
+ src_stages,
+ dst_stages,
+ queue_family_ownership_transfer,
+ image.sharing(),
+ )?;
+
+ /*
+ Check subresource range
+ */
+
+ // VUID-VkImageSubresourceRange-aspectMask-requiredbitmask
+ assert!(!subresource_range.aspects.is_empty());
+
+ // VUID-VkImageSubresourceRange-aspectMask-parameter
+ subresource_range.aspects.validate_device(device)?;
+
+ let image_aspects = image.format().unwrap().aspects();
+
+ // VUID-VkImageMemoryBarrier2-image-01673
+ // VUID-VkImageMemoryBarrier2-image-03319
+ if image_aspects.contains(subresource_range.aspects) {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - image_aspects,
+ });
+ }
+
+ if image_aspects.intersects(ImageAspects::DEPTH | ImageAspects::STENCIL) {
+ // VUID-VkImageMemoryBarrier2-image-03320
+ if !device.enabled_features().separate_depth_stencil_layouts
+ && image_aspects.contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ && !subresource_range
+ .aspects
+ .contains(ImageAspects::DEPTH | ImageAspects::STENCIL)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`dependency_info.image_memory_barriers` has an element \
+ where `image` has both a depth and a stencil aspect, and \
+ `subresource_range.aspects` does not contain both aspects",
+ requires_one_of: RequiresOneOf {
+ features: &["separate_depth_stencil_layouts"],
+ ..Default::default()
+ },
+ });
+ }
+ } else {
+ // VUID-VkImageMemoryBarrier2-image-01671
+ if !image.flags().intersects(ImageCreateFlags::DISJOINT)
+ && subresource_range.aspects != ImageAspects::COLOR
+ {
+ return Err(SynchronizationError::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects: subresource_range.aspects - ImageAspects::COLOR,
+ });
+ }
+ }
+
+ // VUID-VkImageSubresourceRange-levelCount-01720
+ assert!(!subresource_range.mip_levels.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01486
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01724
+ if subresource_range.mip_levels.end > image.mip_levels() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierMipLevelsOutOfRange {
+ barrier_index,
+ mip_levels_range_end: subresource_range.mip_levels.end,
+ image_mip_levels: image.mip_levels(),
+ },
+ );
+ }
+
+ // VUID-VkImageSubresourceRange-layerCount-01721
+ assert!(!subresource_range.array_layers.is_empty());
+
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01488
+ // VUID-VkImageMemoryBarrier2-subresourceRange-01725
+ if subresource_range.array_layers.end > image.dimensions().array_layers() {
+ return Err(
+ SynchronizationError::ImageMemoryBarrierArrayLayersOutOfRange {
+ barrier_index,
+ array_layers_range_end: subresource_range.array_layers.end,
+ image_array_layers: image.dimensions().array_layers(),
+ },
+ );
+ }
+ }
+ }
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn wait_events_unchecked(
+ &mut self,
+ events: impl IntoIterator<Item = (Arc<Event>, DependencyInfo)>,
+ ) -> &mut Self {
+ let events: SmallVec<[(Arc<Event>, DependencyInfo); 4]> = events.into_iter().collect();
+ let fns = self.device().fns();
+
+ // VUID-vkCmdWaitEvents2-pEvents-03837
+ // Ensured by using `vkCmdSetEvent2` and `vkCmdWaitEvents2` under the exact same
+ // conditions, i.e. when `synchronization2` is enabled.
+
+ if self.device().enabled_features().synchronization2 {
+ struct PerDependencyInfo {
+ memory_barriers_vk: SmallVec<[ash::vk::MemoryBarrier2; 2]>,
+ buffer_memory_barriers_vk: SmallVec<[ash::vk::BufferMemoryBarrier2; 8]>,
+ image_memory_barriers_vk: SmallVec<[ash::vk::ImageMemoryBarrier2; 8]>,
+ }
+
+ let mut events_vk: SmallVec<[_; 4]> = SmallVec::new();
+ let mut dependency_infos_vk: SmallVec<[_; 4]> = SmallVec::new();
+ let mut per_dependency_info_vk: SmallVec<[_; 4]> = SmallVec::new();
+
+ for (event, dependency_info) in &events {
+ let &DependencyInfo {
+ dependency_flags,
+ ref memory_barriers,
+ ref buffer_memory_barriers,
+ ref image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ ash::vk::MemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier2 {
+ src_stage_mask: src_stages.into(),
+ src_access_mask: src_access.into(),
+ dst_stage_mask: dst_stages.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ events_vk.push(event.handle());
+ dependency_infos_vk.push(ash::vk::DependencyInfo {
+ dependency_flags: dependency_flags.into(),
+ memory_barrier_count: 0,
+ p_memory_barriers: ptr::null(),
+ buffer_memory_barrier_count: 0,
+ p_buffer_memory_barriers: ptr::null(),
+ image_memory_barrier_count: 0,
+ p_image_memory_barriers: ptr::null(),
+ ..Default::default()
+ });
+ per_dependency_info_vk.push(PerDependencyInfo {
+ memory_barriers_vk,
+ buffer_memory_barriers_vk,
+ image_memory_barriers_vk,
+ });
+ }
+
+ for (
+ dependency_info_vk,
+ PerDependencyInfo {
+ memory_barriers_vk,
+ buffer_memory_barriers_vk,
+ image_memory_barriers_vk,
+ },
+ ) in (dependency_infos_vk.iter_mut()).zip(per_dependency_info_vk.iter_mut())
+ {
+ *dependency_info_vk = ash::vk::DependencyInfo {
+ memory_barrier_count: memory_barriers_vk.len() as u32,
+ p_memory_barriers: memory_barriers_vk.as_ptr(),
+ buffer_memory_barrier_count: buffer_memory_barriers_vk.len() as u32,
+ p_buffer_memory_barriers: buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barrier_count: image_memory_barriers_vk.len() as u32,
+ p_image_memory_barriers: image_memory_barriers_vk.as_ptr(),
+ ..*dependency_info_vk
+ }
+ }
+
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_wait_events2)(
+ self.handle(),
+ events_vk.len() as u32,
+ events_vk.as_ptr(),
+ dependency_infos_vk.as_ptr(),
+ );
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_wait_events2_khr)(
+ self.handle(),
+ events_vk.len() as u32,
+ events_vk.as_ptr(),
+ dependency_infos_vk.as_ptr(),
+ );
+ }
+ } else {
+ // With the original function, you can only specify a single dependency info for all
+ // events at once, rather than separately for each event. Therefore, to achieve the
+ // same behaviour as the "2" function, we split it up into multiple Vulkan API calls,
+ // one per event.
+
+ for (event, dependency_info) in &events {
+ let events_vk = [event.handle()];
+
+ let DependencyInfo {
+ dependency_flags: _,
+ memory_barriers,
+ buffer_memory_barriers,
+ image_memory_barriers,
+ _ne: _,
+ } = dependency_info;
+
+ let mut src_stage_mask = ash::vk::PipelineStageFlags::empty();
+ let mut dst_stage_mask = ash::vk::PipelineStageFlags::empty();
+
+ let memory_barriers_vk: SmallVec<[_; 2]> = memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &MemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ ash::vk::MemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &BufferMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ queue_family_ownership_transfer,
+ ref buffer,
+ ref range,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::BufferMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ buffer: buffer.handle(),
+ offset: range.start,
+ size: range.end - range.start,
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ let image_memory_barriers_vk: SmallVec<[_; 8]> = image_memory_barriers
+ .iter()
+ .map(|barrier| {
+ let &ImageMemoryBarrier {
+ src_stages,
+ src_access,
+ dst_stages,
+ dst_access,
+ old_layout,
+ new_layout,
+ queue_family_ownership_transfer,
+ ref image,
+ ref subresource_range,
+ _ne: _,
+ } = barrier;
+
+ src_stage_mask |= src_stages.into();
+ dst_stage_mask |= dst_stages.into();
+
+ let (src_queue_family_index, dst_queue_family_index) =
+ queue_family_ownership_transfer.map_or(
+ (ash::vk::QUEUE_FAMILY_IGNORED, ash::vk::QUEUE_FAMILY_IGNORED),
+ Into::into,
+ );
+
+ ash::vk::ImageMemoryBarrier {
+ src_access_mask: src_access.into(),
+ dst_access_mask: dst_access.into(),
+ old_layout: old_layout.into(),
+ new_layout: new_layout.into(),
+ src_queue_family_index,
+ dst_queue_family_index,
+ image: image.handle(),
+ subresource_range: subresource_range.clone().into(),
+ ..Default::default()
+ }
+ })
+ .collect();
+
+ if src_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_TOP_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the first scope."
+ src_stage_mask |= ash::vk::PipelineStageFlags::TOP_OF_PIPE;
+ }
+
+ if dst_stage_mask.is_empty() {
+ // "VK_PIPELINE_STAGE_2_BOTTOM_OF_PIPE_BIT is [...] equivalent to
+ // VK_PIPELINE_STAGE_2_NONE in the second scope."
+ dst_stage_mask |= ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE;
+ }
+
+ (fns.v1_0.cmd_wait_events)(
+ self.handle(),
+ 1,
+ events_vk.as_ptr(),
+ src_stage_mask,
+ dst_stage_mask,
+ memory_barriers_vk.len() as u32,
+ memory_barriers_vk.as_ptr(),
+ buffer_memory_barriers_vk.len() as u32,
+ buffer_memory_barriers_vk.as_ptr(),
+ image_memory_barriers_vk.len() as u32,
+ image_memory_barriers_vk.as_ptr(),
+ );
+ }
+ }
+
+ self.resources
+ .extend(events.into_iter().map(|(event, _)| Box::new(event) as _));
+
+ // TODO: sync state update
+
+ self.next_command_index += 1;
+ self
+ }
+
+ /// Resets an [`Event`] back to the unsignaled state.
+ ///
+ /// # Safety
+ ///
+ /// - Appropriate synchronization must be provided for `event` against any previous
+ /// [`set_event`] or [`wait_events`] command.
+ ///
+ /// [`set_event`]: Self::set_event
+ /// [`wait_events`]: Self::wait_events
+ #[inline]
+ pub unsafe fn reset_event(
+ &mut self,
+ event: Arc<Event>,
+ stages: PipelineStages,
+ ) -> Result<&mut Self, SynchronizationError> {
+ self.validate_reset_event(&event, stages)?;
+
+ unsafe { Ok(self.reset_event_unchecked(event, stages)) }
+ }
+
+ fn validate_reset_event(
+ &self,
+ event: &Event,
+ stages: PipelineStages,
+ ) -> Result<(), SynchronizationError> {
+ // VUID-vkCmdResetEvent2-renderpass
+ if self.builder_state.render_pass.is_some() {
+ return Err(SynchronizationError::ForbiddenInsideRenderPass);
+ }
+
+ // VUID-vkCmdResetEvent2-commandBuffer-03833
+ // TODO:
+
+ let device = self.device();
+ let queue_family_properties = self.queue_family_properties();
+
+ // VUID-vkCmdResetEvent2-commandBuffer-cmdpool
+ if !queue_family_properties.queue_flags.intersects(
+ QueueFlags::GRAPHICS
+ | QueueFlags::COMPUTE
+ | QueueFlags::VIDEO_DECODE
+ | QueueFlags::VIDEO_ENCODE,
+ ) {
+ return Err(SynchronizationError::NotSupportedByQueueFamily);
+ }
+
+ // VUID-vkCmdResetEvent2-commonparent
+ assert_eq!(device, event.device());
+
+ // VUID-vkCmdResetEvent2-stageMask-parameter
+ stages.validate_device(device)?;
+
+ // VUID-vkCmdResetEvent2-synchronization2-03829
+ if !device.enabled_features().synchronization2 {
+ if stages.is_2() {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains flags from `VkPipelineStageFlagBits2`",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03929
+ if stages.intersects(PipelineStages::GEOMETRY_SHADER)
+ && !device.enabled_features().geometry_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::GEOMETRY_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["geometry_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03930
+ if stages.intersects(
+ PipelineStages::TESSELLATION_CONTROL_SHADER
+ | PipelineStages::TESSELLATION_EVALUATION_SHADER,
+ ) && !device.enabled_features().tessellation_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::TESSELLATION_CONTROL_SHADER` or \
+ `PipelineStages::TESSELLATION_EVALUATION_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["tessellation_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03931
+ if stages.intersects(PipelineStages::CONDITIONAL_RENDERING)
+ && !device.enabled_features().conditional_rendering
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::CONDITIONAL_RENDERING`",
+ requires_one_of: RequiresOneOf {
+ features: &["conditional_rendering"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03932
+ if stages.intersects(PipelineStages::FRAGMENT_DENSITY_PROCESS)
+ && !device.enabled_features().fragment_density_map
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::FRAGMENT_DENSITY_PROCESS`",
+ requires_one_of: RequiresOneOf {
+ features: &["fragment_density_map"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03933
+ if stages.intersects(PipelineStages::TRANSFORM_FEEDBACK)
+ && !device.enabled_features().transform_feedback
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::TRANSFORM_FEEDBACK`",
+ requires_one_of: RequiresOneOf {
+ features: &["transform_feedback"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03934
+ if stages.intersects(PipelineStages::MESH_SHADER) && !device.enabled_features().mesh_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::MESH_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["mesh_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03935
+ if stages.intersects(PipelineStages::TASK_SHADER) && !device.enabled_features().task_shader
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::TASK_SHADER`",
+ requires_one_of: RequiresOneOf {
+ features: &["task_shader"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-shadingRateImage-07316
+ if stages.intersects(PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT)
+ && !(device.enabled_features().attachment_fragment_shading_rate
+ || device.enabled_features().shading_rate_image)
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains \
+ `PipelineStages::FRAGMENT_SHADING_RATE_ATTACHMENT`",
+ requires_one_of: RequiresOneOf {
+ features: &["attachment_fragment_shading_rate", "shading_rate_image"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-04957
+ if stages.intersects(PipelineStages::SUBPASS_SHADING)
+ && !device.enabled_features().subpass_shading
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::SUBPASS_SHADING`",
+ requires_one_of: RequiresOneOf {
+ features: &["subpass_shading"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-04995
+ if stages.intersects(PipelineStages::INVOCATION_MASK)
+ && !device.enabled_features().invocation_mask
+ {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` contains `PipelineStages::INVOCATION_MASK`",
+ requires_one_of: RequiresOneOf {
+ features: &["invocation_mask"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent-stageMask-03937
+ if stages.is_empty() && !device.enabled_features().synchronization2 {
+ return Err(SynchronizationError::RequirementNotMet {
+ required_for: "`stages` is empty",
+ requires_one_of: RequiresOneOf {
+ features: &["synchronization2"],
+ ..Default::default()
+ },
+ });
+ }
+
+ // VUID-vkCmdResetEvent2-stageMask-03830
+ if stages.intersects(PipelineStages::HOST) {
+ todo!()
+ }
+
+ // VUID-vkCmdResetEvent2-event-03831
+ // VUID-vkCmdResetEvent2-event-03832
+ // TODO:
+
+ Ok(())
+ }
+
+ #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
+ pub unsafe fn reset_event_unchecked(
+ &mut self,
+ event: Arc<Event>,
+ stages: PipelineStages,
+ ) -> &mut Self {
+ let fns = self.device().fns();
+
+ if self.device().enabled_features().synchronization2 {
+ if self.device().api_version() >= Version::V1_3 {
+ (fns.v1_3.cmd_reset_event2)(self.handle(), event.handle(), stages.into());
+ } else {
+ debug_assert!(self.device().enabled_extensions().khr_synchronization2);
+ (fns.khr_synchronization2.cmd_reset_event2_khr)(
+ self.handle(),
+ event.handle(),
+ stages.into(),
+ );
+ }
+ } else {
+ (fns.v1_0.cmd_reset_event)(self.handle(), event.handle(), stages.into());
+ }
+
+ self.resources.push(Box::new(event));
+
+ // TODO: sync state update
+
+ self.next_command_index += 1;
+ self
+ }
+}
+
+/// Error that can happen when recording a synchronization command.
+#[derive(Clone, Debug)]
+pub enum SynchronizationError {
+ RequirementNotMet {
+ required_for: &'static str,
+ requires_one_of: RequiresOneOf,
+ },
+
+ /// One or more accesses of a buffer memory barrier are not supported by the corresponding
+ /// pipeline stages.
+ BufferMemoryBarrierAccessNotSupportedByStages { barrier_index: usize },
+
+ /// Buffer memory barriers are forbidden inside a render pass instance.
+ BufferMemoryBarrierForbiddenInsideRenderPass,
+
+ /// The end of `range` of a buffer memory barrier is greater than the size of `buffer`.
+ BufferMemoryBarrierOutOfRange {
+ barrier_index: usize,
+ range_end: DeviceSize,
+ buffer_size: DeviceSize,
+ },
+
+ /// A buffer memory barrier contains a queue family ownership transfer, but either the
+ /// `src_stages` or `dst_stages` contain [`HOST`].
+ ///
+ /// [`HOST`]: crate::sync::PipelineStages::HOST
+ BufferMemoryBarrierOwnershipTransferHostNotAllowed { barrier_index: usize },
+
+ /// The provided `src_index` or `dst_index` in the queue family ownership transfer of a
+ /// buffer memory barrier is not less than the number of queue families in the physical device.
+ BufferMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index: usize,
+ provided_queue_family_index: u32,
+ queue_family_count: u32,
+ },
+
+ /// The provided `queue_family_ownership_transfer` value of a buffer memory barrier does not
+ /// match the sharing mode of `buffer`.
+ BufferMemoryBarrierOwnershipTransferSharingMismatch { barrier_index: usize },
+
+ /// One or more pipeline stages of a buffer memory barrier are not supported by the queue
+ /// family of the command buffer.
+ BufferMemoryBarrierStageNotSupported { barrier_index: usize },
+
+ /// A render pass instance is not active, and the `VIEW_LOCAL` dependency flag was provided.
+ DependencyFlagsViewLocalNotAllowed,
+
+ /// Operation forbidden inside a render pass.
+ ForbiddenInsideRenderPass,
+
+ /// Operation forbidden inside a render pass instance that was begun with `begin_rendering`.
+ ForbiddenWithBeginRendering,
+
+ /// One or more accesses of an image memory barrier are not supported by the corresponding
+ /// pipeline stages.
+ ImageMemoryBarrierAccessNotSupportedByStages { barrier_index: usize },
+
+ /// The end of the range of array layers of the subresource range of an image memory barrier
+ /// is greater than the number of array layers in the image.
+ ImageMemoryBarrierArrayLayersOutOfRange {
+ barrier_index: usize,
+ array_layers_range_end: u32,
+ image_array_layers: u32,
+ },
+
+ /// The aspects of the subresource range of an image memory barrier contain aspects that are
+ /// not present in the image, or that are not allowed.
+ ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index: usize,
+ aspects: ImageAspects,
+ },
+
+ /// For the `old_layout` or `new_layout` of an image memory barrier, `image` does not have a
+ /// usage that is required.
+ ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index: usize,
+ layout: ImageLayout,
+ requires_one_of_usage: ImageUsage,
+ },
+
+ /// An image memory barrier contains an image layout transition, but a render pass
+ /// instance is active.
+ ImageMemoryBarrierLayoutTransitionForbiddenInsideRenderPass { barrier_index: usize },
+
+ /// The end of the range of mip levels of the subresource range of an image memory barrier
+ /// is greater than the number of mip levels in the image.
+ ImageMemoryBarrierMipLevelsOutOfRange {
+ barrier_index: usize,
+ mip_levels_range_end: u32,
+ image_mip_levels: u32,
+ },
+
+ /// The `new_layout` of an image memory barrier is `Undefined` or `Preinitialized`.
+ ImageMemoryBarrierNewLayoutInvalid { barrier_index: usize },
+
+ /// A render pass instance is active, and the image of an image memory barrier is not a color
+ /// or depth/stencil attachment of the current subpass.
+ ImageMemoryBarrierNotColorDepthStencilAttachment { barrier_index: usize },
+
+ /// A render pass instance is active, and the image of an image memory barrier is not an input
+ /// attachment of the current subpass.
+ ImageMemoryBarrierNotInputAttachment { barrier_index: usize },
+
+ /// The `src_stages` of an image memory barrier contains [`HOST`], but `old_layout` is not
+ /// `Preinitialized`, `Undefined` or `General`.
+ ///
+ /// [`HOST`]: crate::sync::PipelineStages::HOST
+ ImageMemoryBarrierOldLayoutFromHostInvalid {
+ barrier_index: usize,
+ old_layout: ImageLayout,
+ },
+
+ /// An image memory barrier contains a queue family ownership transfer, but a render pass
+ /// instance is active.
+ ImageMemoryBarrierOwnershipTransferForbiddenInsideRenderPass { barrier_index: usize },
+
+ /// An image memory barrier contains a queue family ownership transfer, but either the
+ /// `src_stages` or `dst_stages` contain [`HOST`].
+ ///
+ /// [`HOST`]: crate::sync::PipelineStages::HOST
+ ImageMemoryBarrierOwnershipTransferHostForbidden { barrier_index: usize },
+
+ /// The provided `src_index` or `dst_index` in the queue family ownership transfer of an
+ /// image memory barrier is not less than the number of queue families in the physical device.
+ ImageMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index: usize,
+ provided_queue_family_index: u32,
+ queue_family_count: u32,
+ },
+
+ /// The provided `queue_family_ownership_transfer` value of an image memory barrier does not
+ /// match the sharing mode of `image`.
+ ImageMemoryBarrierOwnershipTransferSharingMismatch { barrier_index: usize },
+
+ /// One or more pipeline stages of an image memory barrier are not supported by the queue
+ /// family of the command buffer.
+ ImageMemoryBarrierStageNotSupported { barrier_index: usize },
+
+ /// One or more accesses of a memory barrier are not supported by the corresponding
+ /// pipeline stages.
+ MemoryBarrierAccessNotSupportedByStages { barrier_index: usize },
+
+ /// A render pass instance is active, but the render pass does not have a subpass
+ /// self-dependency for the current subpass that is a superset of the barriers.
+ MemoryBarrierNoMatchingSubpassSelfDependency,
+
+ /// One or more pipeline stages of a memory barrier are not supported by the queue
+ /// family of the command buffer.
+ MemoryBarrierStageNotSupported { barrier_index: usize },
+
+ /// The queue family doesn't allow this operation.
+ NotSupportedByQueueFamily,
+}
+
+impl Error for SynchronizationError {}
+
+impl Display for SynchronizationError {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
+ match self {
+ Self::RequirementNotMet {
+ required_for,
+ requires_one_of,
+ } => write!(
+ f,
+ "a requirement was not met for: {}; requires one of: {}",
+ required_for, requires_one_of,
+ ),
+
+ Self::BufferMemoryBarrierAccessNotSupportedByStages { barrier_index } => write!(
+ f,
+ "one or more accesses of buffer memory barrier {} are not supported by the \
+ corresponding pipeline stages",
+ barrier_index,
+ ),
+ Self::BufferMemoryBarrierForbiddenInsideRenderPass => write!(
+ f,
+ "buffer memory barriers are forbidden inside a render pass instance",
+ ),
+ Self::BufferMemoryBarrierOutOfRange {
+ barrier_index,
+ range_end,
+ buffer_size,
+ } => write!(
+ f,
+ "the end of `range` ({}) of buffer memory barrier {} is greater than the size of \
+ `buffer` ({})",
+ range_end, barrier_index, buffer_size,
+ ),
+ Self::BufferMemoryBarrierOwnershipTransferHostNotAllowed { barrier_index } => write!(
+ f,
+ "buffer memory barrier {} contains a queue family ownership transfer, but either \
+ the `src_stages` or `dst_stages` contain `HOST`",
+ barrier_index,
+ ),
+ Self::BufferMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ } => write!(
+ f,
+ "the provided `src_index` or `dst_index` ({}) in the queue family ownership \
+ transfer of buffer memory barrier {} is not less than the number of queue \
+ families in the physical device ({})",
+ provided_queue_family_index, barrier_index, queue_family_count,
+ ),
+ Self::BufferMemoryBarrierOwnershipTransferSharingMismatch { barrier_index } => write!(
+ f,
+ "the provided `queue_family_ownership_transfer` value of buffer memory barrier {} \
+ does not match the sharing mode of `buffer`",
+ barrier_index,
+ ),
+ Self::BufferMemoryBarrierStageNotSupported { barrier_index } => write!(
+ f,
+ "one or more pipeline stages of buffer memory barrier {} are not supported by the \
+ queue family of the command buffer",
+ barrier_index,
+ ),
+ Self::DependencyFlagsViewLocalNotAllowed => write!(
+ f,
+ "a render pass instance is not active, and the `VIEW_LOCAL` dependency flag was \
+ provided",
+ ),
+ Self::ForbiddenInsideRenderPass => {
+ write!(f, "operation forbidden inside a render pass")
+ }
+ Self::ForbiddenWithBeginRendering => write!(
+ f,
+ "operation forbidden inside a render pass instance that was begun with \
+ `begin_rendering`",
+ ),
+ Self::ImageMemoryBarrierAccessNotSupportedByStages { barrier_index } => write!(
+ f,
+ "one or more accesses of image memory barrier {} are not supported by the \
+ corresponding pipeline stages",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierArrayLayersOutOfRange {
+ barrier_index,
+ array_layers_range_end,
+ image_array_layers,
+ } => write!(
+ f,
+ "the end of the range of array layers ({}) of the subresource range of image \
+ memory barrier {} is greater than the number of array layers in the image ({})",
+ array_layers_range_end, barrier_index, image_array_layers,
+ ),
+ Self::ImageMemoryBarrierAspectsNotAllowed {
+ barrier_index,
+ aspects,
+ } => write!(
+ f,
+ "the aspects of the subresource range of image memory barrier {} contain aspects \
+ that are not present in the image, or that are not allowed ({:?})",
+ barrier_index, aspects,
+ ),
+ Self::ImageMemoryBarrierImageMissingUsageForLayout {
+ barrier_index,
+ layout,
+ requires_one_of_usage,
+ } => write!(
+ f,
+ "for the `old_layout` or `new_layout` ({:?}) of image memory barrier {}, `image` \
+ does not have a usage that is required ({}{:?})",
+ layout,
+ barrier_index,
+ if requires_one_of_usage.count() > 1 {
+ "one of "
+ } else {
+ ""
+ },
+ requires_one_of_usage,
+ ),
+ Self::ImageMemoryBarrierLayoutTransitionForbiddenInsideRenderPass { barrier_index } => {
+ write!(
+ f,
+ "image memory barrier {} contains an image layout transition, but a render \
+ pass instance is active",
+ barrier_index,
+ )
+ }
+ Self::ImageMemoryBarrierMipLevelsOutOfRange {
+ barrier_index,
+ mip_levels_range_end,
+ image_mip_levels,
+ } => write!(
+ f,
+ "the end of the range of mip levels ({}) of the subresource range of image \
+ memory barrier {} is greater than the number of mip levels in the image ({})",
+ mip_levels_range_end, barrier_index, image_mip_levels,
+ ),
+ Self::ImageMemoryBarrierNewLayoutInvalid { barrier_index } => write!(
+ f,
+ "the `new_layout` of image memory barrier {} is `Undefined` or `Preinitialized`",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierNotColorDepthStencilAttachment { barrier_index } => write!(
+ f,
+ "a render pass instance is active, and the image of image memory barrier {} is \
+ not a color or depth/stencil attachment of the current subpass",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierNotInputAttachment { barrier_index } => write!(
+ f,
+ "a render pass instance is active, and the image of image memory barrier {} is \
+ not an input attachment of the current subpass",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierOldLayoutFromHostInvalid {
+ barrier_index,
+ old_layout,
+ } => write!(
+ f,
+ "the `src_stages` of image memory barrier {} contains `HOST`, but `old_layout`
+ ({:?}) is not `Preinitialized`, `Undefined` or `General`",
+ barrier_index, old_layout,
+ ),
+ Self::ImageMemoryBarrierOwnershipTransferForbiddenInsideRenderPass {
+ barrier_index,
+ } => write!(
+ f,
+ "image memory barrier {} contains a queue family ownership transfer, but a render \
+ pass instance is active",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierOwnershipTransferHostForbidden { barrier_index } => write!(
+ f,
+ "image memory barrier {} contains a queue family ownership transfer, but either \
+ the `src_stages` or `dst_stages` contain `HOST`",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierOwnershipTransferIndexOutOfRange {
+ barrier_index,
+ provided_queue_family_index,
+ queue_family_count,
+ } => write!(
+ f,
+ "the provided `src_index` or `dst_index` ({}) in the queue family ownership \
+ transfer of image memory barrier {} is not less than the number of queue
+ families in the physical device ({})",
+ provided_queue_family_index, barrier_index, queue_family_count,
+ ),
+ Self::ImageMemoryBarrierOwnershipTransferSharingMismatch { barrier_index } => write!(
+ f,
+ "the provided `queue_family_ownership_transfer` value of image memory barrier {} \
+ does not match the sharing mode of `image`",
+ barrier_index,
+ ),
+ Self::ImageMemoryBarrierStageNotSupported { barrier_index } => write!(
+ f,
+ "one or more pipeline stages of image memory barrier {} are not supported by the \
+ queue family of the command buffer",
+ barrier_index,
+ ),
+ Self::MemoryBarrierAccessNotSupportedByStages { barrier_index } => write!(
+ f,
+ "one or more accesses of memory barrier {} are not supported by the \
+ corresponding pipeline stages",
+ barrier_index,
+ ),
+ Self::MemoryBarrierNoMatchingSubpassSelfDependency => write!(
+ f,
+ "a render pass instance is active, but the render pass does not have a subpass \
+ self-dependency for the current subpass that is a superset of the barriers",
+ ),
+ Self::MemoryBarrierStageNotSupported { barrier_index } => write!(
+ f,
+ "one or more pipeline stages of memory barrier {} are not supported by the \
+ queue family of the command buffer",
+ barrier_index,
+ ),
+ Self::NotSupportedByQueueFamily => {
+ write!(f, "the queue family doesn't allow this operation")
+ }
+ }
+ }
+}
+
+impl From<RequirementNotMet> for SynchronizationError {
+ fn from(err: RequirementNotMet) -> Self {
+ Self::RequirementNotMet {
+ required_for: err.required_for,
+ requires_one_of: err.requires_one_of,
+ }
+ }
+}