use std::marker::PhantomData;
use std::ops::Range;
use std::ptr;
use std::u32;
use smallvec::SmallVec;
use buffer::BufferAccess;
use buffer::BufferInner;
use command_buffer::CommandAddError;
use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use image::ImageAccess;
use image::ImageLayout;
use sync::AccessFlagBits;
use sync::PipelineStages;
use device::DeviceOwned;
use VulkanObject;
use VulkanPointers;
use vk;
pub struct CmdPipelineBarrier<'a> {
src_stage_mask: vk::PipelineStageFlags,
dst_stage_mask: vk::PipelineStageFlags,
dependency_flags: vk::DependencyFlags,
memory_barriers: SmallVec<[vk::MemoryBarrier; 2]>,
buffer_barriers: SmallVec<[vk::BufferMemoryBarrier; 8]>,
image_barriers: SmallVec<[vk::ImageMemoryBarrier; 8]>,
marker: PhantomData<&'a ()>,
}
impl<'a> CmdPipelineBarrier<'a> {
#[inline]
pub fn new() -> CmdPipelineBarrier<'a> {
CmdPipelineBarrier {
src_stage_mask: 0,
dst_stage_mask: 0,
dependency_flags: vk::DEPENDENCY_BY_REGION_BIT,
memory_barriers: SmallVec::new(),
buffer_barriers: SmallVec::new(),
image_barriers: SmallVec::new(),
marker: PhantomData,
}
}
#[inline]
pub fn is_empty(&self) -> bool {
self.src_stage_mask == 0 || self.dst_stage_mask == 0
}
#[inline]
pub fn merge(&mut self, other: CmdPipelineBarrier<'a>) {
self.src_stage_mask |= other.src_stage_mask;
self.dst_stage_mask |= other.dst_stage_mask;
self.dependency_flags &= other.dependency_flags;
self.memory_barriers.extend(other.memory_barriers.into_iter());
self.buffer_barriers.extend(other.buffer_barriers.into_iter());
self.image_barriers.extend(other.image_barriers.into_iter());
}
#[inline]
pub unsafe fn add_execution_dependency(&mut self, source: PipelineStages, dest: PipelineStages,
by_region: bool)
{
if !by_region {
self.dependency_flags = 0;
}
self.src_stage_mask |= Into::<vk::PipelineStageFlags>::into(source);
self.dst_stage_mask |= Into::<vk::PipelineStageFlags>::into(dest);
}
pub unsafe fn add_memory_barrier(&mut self, source_stage: PipelineStages,
source_access: AccessFlagBits, dest_stage: PipelineStages,
dest_access: AccessFlagBits, by_region: bool)
{
self.add_execution_dependency(source_stage, dest_stage, by_region);
self.memory_barriers.push(vk::MemoryBarrier {
sType: vk::STRUCTURE_TYPE_MEMORY_BARRIER,
pNext: ptr::null(),
srcAccessMask: source_access.into(),
dstAccessMask: dest_access.into(),
});
}
pub unsafe fn add_buffer_memory_barrier<B: ?Sized>
(&mut self, buffer: &'a B, source_stage: PipelineStages,
source_access: AccessFlagBits, dest_stage: PipelineStages,
dest_access: AccessFlagBits, by_region: bool,
queue_transfer: Option<(u32, u32)>, offset: usize, size: usize)
where B: BufferAccess
{
self.add_execution_dependency(source_stage, dest_stage, by_region);
debug_assert!(size <= buffer.size());
let BufferInner { buffer, offset: org_offset } = buffer.inner();
let offset = offset + org_offset;
let (src_queue, dest_queue) = if let Some((src_queue, dest_queue)) = queue_transfer {
(src_queue, dest_queue)
} else {
(vk::QUEUE_FAMILY_IGNORED, vk::QUEUE_FAMILY_IGNORED)
};
self.buffer_barriers.push(vk::BufferMemoryBarrier {
sType: vk::STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER,
pNext: ptr::null(),
srcAccessMask: source_access.into(),
dstAccessMask: dest_access.into(),
srcQueueFamilyIndex: src_queue,
dstQueueFamilyIndex: dest_queue,
buffer: buffer.internal_object(),
offset: offset as vk::DeviceSize,
size: size as vk::DeviceSize,
});
}
pub unsafe fn add_image_memory_barrier<I: ?Sized>(&mut self, image: &'a I, mipmaps: Range<u32>,
layers: Range<u32>, source_stage: PipelineStages, source_access: AccessFlagBits,
dest_stage: PipelineStages, dest_access: AccessFlagBits, by_region: bool,
queue_transfer: Option<(u32, u32)>, current_layout: ImageLayout, new_layout: ImageLayout)
where I: ImageAccess
{
self.add_execution_dependency(source_stage, dest_stage, by_region);
debug_assert!(mipmaps.start < mipmaps.end);
debug_assert!(layers.start < layers.end);
debug_assert!(layers.end <= image.dimensions().array_layers());
let (src_queue, dest_queue) = if let Some((src_queue, dest_queue)) = queue_transfer {
(src_queue, dest_queue)
} else {
(vk::QUEUE_FAMILY_IGNORED, vk::QUEUE_FAMILY_IGNORED)
};
self.image_barriers.push(vk::ImageMemoryBarrier {
sType: vk::STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
pNext: ptr::null(),
srcAccessMask: source_access.into(),
dstAccessMask: dest_access.into(),
oldLayout: current_layout as u32,
newLayout: new_layout as u32,
srcQueueFamilyIndex: src_queue,
dstQueueFamilyIndex: dest_queue,
image: image.inner().internal_object(),
subresourceRange: vk::ImageSubresourceRange {
aspectMask: 1 | 2 | 4 | 8, baseMipLevel: mipmaps.start,
levelCount: mipmaps.end - mipmaps.start,
baseArrayLayer: layers.start,
layerCount: layers.end - layers.start,
},
});
}
}
unsafe impl<'a, P> AddCommand<&'a CmdPipelineBarrier<'a>> for UnsafeCommandBufferBuilder<P>
where P: CommandPool
{
type Out = UnsafeCommandBufferBuilder<P>;
#[inline]
fn add(self, command: &'a CmdPipelineBarrier<'a>) -> Result<Self::Out, CommandAddError> {
if command.src_stage_mask == 0 || command.dst_stage_mask == 0 {
debug_assert!(command.src_stage_mask == 0 && command.dst_stage_mask == 0);
debug_assert!(command.memory_barriers.is_empty());
debug_assert!(command.buffer_barriers.is_empty());
debug_assert!(command.image_barriers.is_empty());
return Ok(self);
}
unsafe {
let vk = self.device().pointers();
let cmd = self.internal_object();
vk.CmdPipelineBarrier(cmd, command.src_stage_mask, command.dst_stage_mask,
command.dependency_flags, command.memory_barriers.len() as u32,
command.memory_barriers.as_ptr(),
command.buffer_barriers.len() as u32,
command.buffer_barriers.as_ptr(),
command.image_barriers.len() as u32,
command.image_barriers.as_ptr());
}
Ok(self)
}
}