use smallvec::SmallVec;
use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::ptr;
use buffer::sys::UnsafeBuffer;
use device::Queue;
use image::sys::UnsafeImage;
use memory::DeviceMemory;
use sync::Fence;
use sync::Semaphore;
use Error;
use OomError;
use SynchronizedVulkanObject;
use VulkanObject;
use check_errors;
use vk;
pub struct SubmitBindSparseBuilder<'a> {
infos: SmallVec<[SubmitBindSparseBatchBuilder<'a>; 1]>,
fence: vk::Fence,
}
impl<'a> SubmitBindSparseBuilder<'a> {
#[inline]
pub fn new() -> SubmitBindSparseBuilder<'a> {
SubmitBindSparseBuilder {
infos: SmallVec::new(),
fence: 0,
}
}
#[inline]
pub fn add(&mut self, builder: SubmitBindSparseBatchBuilder<'a>) {
self.infos.push(builder);
}
#[inline]
pub fn has_fence(&self) -> bool {
self.fence != 0
}
#[inline]
pub unsafe fn set_fence_signal(&mut self, fence: &'a Fence) {
self.fence = fence.internal_object();
}
#[inline]
pub fn merge(&mut self, other: SubmitBindSparseBuilder<'a>)
-> Result<(), SubmitBindSparseBuilder<'a>> {
if self.fence != 0 && other.fence != 0 {
return Err(other);
}
self.infos.extend(other.infos.into_iter());
Ok(())
}
pub fn submit(self, queue: &Queue) -> Result<(), SubmitBindSparseError> {
unsafe {
debug_assert!(queue.family().supports_sparse_binding());
let vk = queue.device().pointers();
let queue = queue.internal_object_guard();
let buffer_binds_storage: SmallVec<[_; 4]> = self.infos
.iter()
.flat_map(|infos| infos.buffer_binds.iter())
.map(|buf_bind| {
vk::SparseBufferMemoryBindInfo {
buffer: buf_bind.buffer,
bindCount: buf_bind.binds.len() as u32,
pBinds: buf_bind.binds.as_ptr(),
}
})
.collect();
let image_opaque_binds_storage: SmallVec<[_; 4]> = self.infos
.iter()
.flat_map(|infos| infos.image_opaque_binds.iter())
.map(|img_bind| {
vk::SparseImageOpaqueMemoryBindInfo {
image: img_bind.image,
bindCount: img_bind.binds.len() as u32,
pBinds: img_bind.binds.as_ptr(),
}
})
.collect();
let image_binds_storage: SmallVec<[_; 4]> = self.infos
.iter()
.flat_map(|infos| infos.image_binds.iter())
.map(|img_bind| {
vk::SparseImageMemoryBindInfo {
image: img_bind.image,
bindCount: img_bind.binds.len() as u32,
pBinds: img_bind.binds.as_ptr(),
}
})
.collect();
let bs_infos = {
let mut bs_infos: SmallVec<[_; 4]> = SmallVec::new();
let mut next_buffer_bind = 0;
let mut next_image_opaque_bind = 0;
let mut next_image_bind = 0;
for builder in self.infos.iter() {
bs_infos.push(vk::BindSparseInfo {
sType: vk::STRUCTURE_TYPE_BIND_SPARSE_INFO,
pNext: ptr::null(),
waitSemaphoreCount: builder.wait_semaphores.len() as u32,
pWaitSemaphores: builder.wait_semaphores.as_ptr(),
bufferBindCount: builder.buffer_binds.len() as u32,
pBufferBinds: if next_buffer_bind != 0 {
buffer_binds_storage.as_ptr().offset(next_buffer_bind)
} else {
buffer_binds_storage.as_ptr()
},
imageOpaqueBindCount: builder.image_opaque_binds.len() as u32,
pImageOpaqueBinds: if next_image_opaque_bind != 0 {
image_opaque_binds_storage.as_ptr().offset(next_image_opaque_bind)
} else {
image_opaque_binds_storage.as_ptr()
},
imageBindCount: builder.image_binds.len() as u32,
pImageBinds: if next_image_bind != 0 {
image_binds_storage.as_ptr().offset(next_image_bind)
} else {
image_binds_storage.as_ptr()
},
signalSemaphoreCount: builder.signal_semaphores.len() as u32,
pSignalSemaphores: builder.signal_semaphores.as_ptr(),
});
next_buffer_bind += builder.buffer_binds.len() as isize;
next_image_opaque_bind += builder.image_opaque_binds.len() as isize;
next_image_bind += builder.image_binds.len() as isize;
}
debug_assert_eq!(next_buffer_bind as usize, buffer_binds_storage.len());
debug_assert_eq!(next_image_opaque_bind as usize,
image_opaque_binds_storage.len());
debug_assert_eq!(next_image_bind as usize, image_binds_storage.len());
bs_infos
};
check_errors(vk.QueueBindSparse(*queue,
bs_infos.len() as u32,
bs_infos.as_ptr(),
self.fence))?;
Ok(())
}
}
}
impl<'a> fmt::Debug for SubmitBindSparseBuilder<'a> {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Bind sparse operation>")
}
}
pub struct SubmitBindSparseBatchBuilder<'a> {
wait_semaphores: SmallVec<[vk::Semaphore; 8]>,
buffer_binds: SmallVec<[SubmitBindSparseBufferBindBuilder<'a>; 2]>,
image_opaque_binds: SmallVec<[SubmitBindSparseImageOpaqueBindBuilder<'a>; 2]>,
image_binds: SmallVec<[SubmitBindSparseImageBindBuilder<'a>; 2]>,
signal_semaphores: SmallVec<[vk::Semaphore; 8]>,
marker: PhantomData<&'a ()>,
}
impl<'a> SubmitBindSparseBatchBuilder<'a> {
#[inline]
pub fn new() -> SubmitBindSparseBatchBuilder<'a> {
SubmitBindSparseBatchBuilder {
wait_semaphores: SmallVec::new(),
buffer_binds: SmallVec::new(),
image_opaque_binds: SmallVec::new(),
image_binds: SmallVec::new(),
signal_semaphores: SmallVec::new(),
marker: PhantomData,
}
}
pub fn add_buffer(&mut self, cmd: SubmitBindSparseBufferBindBuilder<'a>) {
self.buffer_binds.push(cmd);
}
pub fn add_image_opaque(&mut self, cmd: SubmitBindSparseImageOpaqueBindBuilder<'a>) {
self.image_opaque_binds.push(cmd);
}
pub fn add_image(&mut self, cmd: SubmitBindSparseImageBindBuilder<'a>) {
self.image_binds.push(cmd);
}
#[inline]
pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore) {
self.wait_semaphores.push(semaphore.internal_object());
}
#[inline]
pub fn num_signal_semaphores(&self) -> usize {
self.signal_semaphores.len()
}
#[inline]
pub unsafe fn add_signal_semaphore(&mut self, semaphore: &'a Semaphore) {
self.signal_semaphores.push(semaphore.internal_object());
}
}
pub struct SubmitBindSparseBufferBindBuilder<'a> {
buffer: vk::Buffer,
binds: SmallVec<[vk::SparseMemoryBind; 1]>,
marker: PhantomData<&'a ()>,
}
impl<'a> SubmitBindSparseBufferBindBuilder<'a> {
pub unsafe fn new(buffer: &'a UnsafeBuffer) -> SubmitBindSparseBufferBindBuilder {
SubmitBindSparseBufferBindBuilder {
buffer: buffer.internal_object(),
binds: SmallVec::new(),
marker: PhantomData,
}
}
pub unsafe fn add_bind(&mut self, offset: usize, size: usize, memory: &DeviceMemory,
memory_offset: usize) {
self.binds.push(vk::SparseMemoryBind {
resourceOffset: offset as vk::DeviceSize,
size: size as vk::DeviceSize,
memory: memory.internal_object(),
memoryOffset: memory_offset as vk::DeviceSize,
flags: 0,
});
}
pub unsafe fn add_unbind(&mut self, offset: usize, size: usize) {
self.binds.push(vk::SparseMemoryBind {
resourceOffset: offset as vk::DeviceSize,
size: size as vk::DeviceSize,
memory: 0,
memoryOffset: 0,
flags: 0,
});
}
}
pub struct SubmitBindSparseImageOpaqueBindBuilder<'a> {
image: vk::Image,
binds: SmallVec<[vk::SparseMemoryBind; 1]>,
marker: PhantomData<&'a ()>,
}
impl<'a> SubmitBindSparseImageOpaqueBindBuilder<'a> {
pub unsafe fn new(image: &'a UnsafeImage) -> SubmitBindSparseImageOpaqueBindBuilder {
SubmitBindSparseImageOpaqueBindBuilder {
image: image.internal_object(),
binds: SmallVec::new(),
marker: PhantomData,
}
}
pub unsafe fn add_bind(&mut self, offset: usize, size: usize, memory: &DeviceMemory,
memory_offset: usize, bind_metadata: bool) {
self.binds.push(vk::SparseMemoryBind {
resourceOffset: offset as vk::DeviceSize,
size: size as vk::DeviceSize,
memory: memory.internal_object(),
memoryOffset: memory_offset as vk::DeviceSize,
flags: if bind_metadata {
vk::SPARSE_MEMORY_BIND_METADATA_BIT
} else {
0
},
});
}
pub unsafe fn add_unbind(&mut self, offset: usize, size: usize) {
self.binds.push(vk::SparseMemoryBind {
resourceOffset: offset as vk::DeviceSize,
size: size as vk::DeviceSize,
memory: 0,
memoryOffset: 0,
flags: 0,
});
}
}
pub struct SubmitBindSparseImageBindBuilder<'a> {
image: vk::Image,
binds: SmallVec<[vk::SparseImageMemoryBind; 1]>,
marker: PhantomData<&'a ()>,
}
impl<'a> SubmitBindSparseImageBindBuilder<'a> {
pub unsafe fn new(image: &'a UnsafeImage) -> SubmitBindSparseImageBindBuilder {
SubmitBindSparseImageBindBuilder {
image: image.internal_object(),
binds: SmallVec::new(),
marker: PhantomData,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum SubmitBindSparseError {
OomError(OomError),
DeviceLost,
}
impl error::Error for SubmitBindSparseError {
#[inline]
fn description(&self) -> &str {
match *self {
SubmitBindSparseError::OomError(_) => "not enough memory",
SubmitBindSparseError::DeviceLost => "the connection to the device has been lost",
}
}
#[inline]
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
SubmitBindSparseError::OomError(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for SubmitBindSparseError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
impl From<Error> for SubmitBindSparseError {
#[inline]
fn from(err: Error) -> SubmitBindSparseError {
match err {
err @ Error::OutOfHostMemory => SubmitBindSparseError::OomError(OomError::from(err)),
err @ Error::OutOfDeviceMemory => SubmitBindSparseError::OomError(OomError::from(err)),
Error::DeviceLost => SubmitBindSparseError::DeviceLost,
_ => panic!("unexpected error: {:?}", err),
}
}
}