use std::error;
use std::fmt;
use std::marker::PhantomData;
use std::mem;
use std::ptr;
use smallvec::SmallVec;
use device::Queue;
use swapchain::Swapchain;
use sync::Semaphore;
use check_errors;
use vk;
use Error;
use OomError;
use VulkanObject;
use VulkanPointers;
use SynchronizedVulkanObject;
#[derive(Debug)]
pub struct SubmitPresentBuilder<'a> {
wait_semaphores: SmallVec<[vk::Semaphore; 8]>,
swapchains: SmallVec<[vk::SwapchainKHR; 4]>,
image_indices: SmallVec<[u32; 4]>,
marker: PhantomData<&'a ()>,
}
impl<'a> SubmitPresentBuilder<'a> {
#[inline]
pub fn new() -> SubmitPresentBuilder<'a> {
SubmitPresentBuilder {
wait_semaphores: SmallVec::new(),
swapchains: SmallVec::new(),
image_indices: SmallVec::new(),
marker: PhantomData,
}
}
#[inline]
pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore) {
self.wait_semaphores.push(semaphore.internal_object());
}
#[inline]
pub unsafe fn add_swapchain(&mut self, swapchain: &'a Swapchain, image_num: u32) {
debug_assert!(image_num < swapchain.num_images());
self.swapchains.push(swapchain.internal_object());
self.image_indices.push(image_num);
}
pub fn submit(self, queue: &Queue) -> Result<(), SubmitPresentError> {
unsafe {
debug_assert_eq!(self.swapchains.len(), self.image_indices.len());
assert!(!self.swapchains.is_empty(),
"Tried to submit a present command without any swapchain");
let vk = queue.device().pointers();
let queue = queue.internal_object_guard();
let mut results = vec![mem::uninitialized(); self.swapchains.len()];
let infos = vk::PresentInfoKHR {
sType: vk::STRUCTURE_TYPE_PRESENT_INFO_KHR,
pNext: ptr::null(),
waitSemaphoreCount: self.wait_semaphores.len() as u32,
pWaitSemaphores: self.wait_semaphores.as_ptr(),
swapchainCount: self.swapchains.len() as u32,
pSwapchains: self.swapchains.as_ptr(),
pImageIndices: self.image_indices.as_ptr(),
pResults: results.as_mut_ptr(),
};
try!(check_errors(vk.QueuePresentKHR(*queue, &infos)));
for result in results {
}
Ok(())
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum SubmitPresentError {
OomError(OomError),
DeviceLost,
SurfaceLost,
OutOfDate,
}
impl error::Error for SubmitPresentError {
#[inline]
fn description(&self) -> &str {
match *self {
SubmitPresentError::OomError(_) => "not enough memory",
SubmitPresentError::DeviceLost => "the connection to the device has been lost",
SubmitPresentError::SurfaceLost => "the surface of this swapchain is no longer valid",
SubmitPresentError::OutOfDate => "the swapchain needs to be recreated",
}
}
#[inline]
fn cause(&self) -> Option<&error::Error> {
match *self {
SubmitPresentError::OomError(ref err) => Some(err),
_ => None
}
}
}
impl fmt::Display for SubmitPresentError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
impl From<Error> for SubmitPresentError {
#[inline]
fn from(err: Error) -> SubmitPresentError {
match err {
err @ Error::OutOfHostMemory => SubmitPresentError::OomError(OomError::from(err)),
err @ Error::OutOfDeviceMemory => SubmitPresentError::OomError(OomError::from(err)),
Error::DeviceLost => SubmitPresentError::DeviceLost,
Error::SurfaceLost => SubmitPresentError::SurfaceLost,
Error::OutOfDate => SubmitPresentError::OutOfDate,
_ => panic!("unexpected error: {:?}", err)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[should_panic(expected = "Tried to submit a present command without any swapchain")]
fn no_swapchain_added() {
let (_, queue) = gfx_dev_and_queue!();
let _ = SubmitPresentBuilder::new().submit(&queue);
}
}