use crate::{
command_buffer::{RecordingCommandBuffer, Result},
Id,
};
use ash::vk;
use smallvec::SmallVec;
use std::ops::Range;
use vulkano::{
buffer::Buffer,
device::DeviceOwned,
image::{Image, ImageAspects, ImageLayout, ImageSubresourceRange},
sync::{AccessFlags, DependencyFlags, PipelineStages},
DeviceSize, Version, VulkanObject,
};
impl RecordingCommandBuffer<'_> {
pub unsafe fn pipeline_barrier(
&mut self,
dependency_info: &DependencyInfo<'_>,
) -> Result<&mut Self> {
Ok(unsafe { self.pipeline_barrier_unchecked(dependency_info) })
}
pub unsafe fn pipeline_barrier_unchecked(
&mut self,
dependency_info: &DependencyInfo<'_>,
) -> &mut Self {
if dependency_info.is_empty() {
return self;
}
let &DependencyInfo {
dependency_flags,
memory_barriers,
buffer_memory_barriers,
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;
vk::MemoryBarrier2::default()
.src_stage_mask(src_stages.into())
.src_access_mask(src_access.into())
.dst_stage_mask(dst_stages.into())
.dst_access_mask(dst_access.into())
})
.collect();
let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
.iter()
.map(|barrier| {
let &BufferMemoryBarrier {
src_stages,
src_access,
dst_stages,
dst_access,
buffer,
ref range,
_ne: _,
} = barrier;
let buffer = unsafe { self.accesses.buffer_unchecked(buffer) };
vk::BufferMemoryBarrier2::default()
.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(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.buffer(buffer.handle())
.offset(range.start)
.size(range.end - range.start)
})
.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,
image,
ref subresource_range,
_ne: _,
} = barrier;
let image = unsafe { self.accesses.image_unchecked(image) };
vk::ImageMemoryBarrier2::default()
.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(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.image(image.handle())
.subresource_range(subresource_range.clone().to_vk())
})
.collect();
let dependency_info_vk = vk::DependencyInfo::default()
.dependency_flags(dependency_flags.into())
.memory_barriers(&memory_barriers_vk)
.buffer_memory_barriers(&buffer_memory_barriers_vk)
.image_memory_barriers(&image_memory_barriers_vk);
let fns = self.device().fns();
let cmd_pipeline_barrier2 = if self.device().api_version() >= Version::V1_3 {
fns.v1_3.cmd_pipeline_barrier2
} else {
fns.khr_synchronization2.cmd_pipeline_barrier2_khr
};
unsafe { cmd_pipeline_barrier2(self.handle(), &dependency_info_vk) };
} else {
let mut src_stage_mask = vk::PipelineStageFlags::empty();
let mut dst_stage_mask = 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();
vk::MemoryBarrier::default()
.src_access_mask(src_access.into())
.dst_access_mask(dst_access.into())
})
.collect();
let buffer_memory_barriers_vk: SmallVec<[_; 8]> = buffer_memory_barriers
.iter()
.map(|barrier| {
let &BufferMemoryBarrier {
src_stages,
src_access,
dst_stages,
dst_access,
buffer,
ref range,
_ne: _,
} = barrier;
src_stage_mask |= src_stages.into();
dst_stage_mask |= dst_stages.into();
let buffer = unsafe { self.accesses.buffer_unchecked(buffer) };
vk::BufferMemoryBarrier::default()
.src_access_mask(src_access.into())
.dst_access_mask(dst_access.into())
.src_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.buffer(buffer.handle())
.offset(range.start)
.size(range.end - range.start)
})
.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,
image,
ref subresource_range,
_ne: _,
} = barrier;
src_stage_mask |= src_stages.into();
dst_stage_mask |= dst_stages.into();
let image = unsafe { self.accesses.image_unchecked(image) };
vk::ImageMemoryBarrier::default()
.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(vk::QUEUE_FAMILY_IGNORED)
.dst_queue_family_index(vk::QUEUE_FAMILY_IGNORED)
.image(image.handle())
.subresource_range(subresource_range.clone().to_vk())
})
.collect();
if src_stage_mask.is_empty() {
src_stage_mask |= vk::PipelineStageFlags::TOP_OF_PIPE;
}
if dst_stage_mask.is_empty() {
dst_stage_mask |= vk::PipelineStageFlags::BOTTOM_OF_PIPE;
}
let fns = self.device().fns();
unsafe {
(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(),
)
};
}
self
}
}
#[derive(Clone, Debug)]
pub struct DependencyInfo<'a> {
pub dependency_flags: DependencyFlags,
pub memory_barriers: &'a [MemoryBarrier<'a>],
pub buffer_memory_barriers: &'a [BufferMemoryBarrier<'a>],
pub image_memory_barriers: &'a [ImageMemoryBarrier<'a>],
pub _ne: crate::NonExhaustive<'a>,
}
impl DependencyInfo<'_> {
#[inline]
pub fn is_empty(&self) -> bool {
self.memory_barriers.is_empty()
&& self.buffer_memory_barriers.is_empty()
&& self.image_memory_barriers.is_empty()
}
}
impl Default for DependencyInfo<'_> {
#[inline]
fn default() -> Self {
DependencyInfo {
dependency_flags: DependencyFlags::default(),
memory_barriers: &[],
buffer_memory_barriers: &[],
image_memory_barriers: &[],
_ne: crate::NE,
}
}
}
#[derive(Clone, Debug)]
pub struct MemoryBarrier<'a> {
pub src_stages: PipelineStages,
pub src_access: AccessFlags,
pub dst_stages: PipelineStages,
pub dst_access: AccessFlags,
pub _ne: crate::NonExhaustive<'a>,
}
impl Default for MemoryBarrier<'_> {
#[inline]
fn default() -> Self {
Self {
src_stages: PipelineStages::empty(),
src_access: AccessFlags::empty(),
dst_stages: PipelineStages::empty(),
dst_access: AccessFlags::empty(),
_ne: crate::NE,
}
}
}
#[derive(Clone, Debug)]
pub struct BufferMemoryBarrier<'a> {
pub src_stages: PipelineStages,
pub src_access: AccessFlags,
pub dst_stages: PipelineStages,
pub dst_access: AccessFlags,
pub buffer: Id<Buffer>,
pub range: Range<DeviceSize>,
pub _ne: crate::NonExhaustive<'a>,
}
impl Default for BufferMemoryBarrier<'_> {
#[inline]
fn default() -> Self {
BufferMemoryBarrier {
src_stages: PipelineStages::empty(),
src_access: AccessFlags::empty(),
dst_stages: PipelineStages::empty(),
dst_access: AccessFlags::empty(),
buffer: Id::INVALID,
range: 0..0,
_ne: crate::NE,
}
}
}
#[derive(Clone, Debug)]
pub struct ImageMemoryBarrier<'a> {
pub src_stages: PipelineStages,
pub src_access: AccessFlags,
pub dst_stages: PipelineStages,
pub dst_access: AccessFlags,
pub old_layout: ImageLayout,
pub new_layout: ImageLayout,
pub image: Id<Image>,
pub subresource_range: ImageSubresourceRange,
pub _ne: crate::NonExhaustive<'a>,
}
impl Default for ImageMemoryBarrier<'_> {
#[inline]
fn default() -> Self {
ImageMemoryBarrier {
src_stages: PipelineStages::empty(),
src_access: AccessFlags::empty(),
dst_stages: PipelineStages::empty(),
dst_access: AccessFlags::empty(),
old_layout: ImageLayout::Undefined,
new_layout: ImageLayout::Undefined,
image: Id::INVALID,
subresource_range: ImageSubresourceRange {
aspects: ImageAspects::empty(),
mip_levels: 0..0,
array_layers: 0..0,
},
_ne: crate::NE,
}
}
}