use std::error;
use std::fmt;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use std::time::Duration;
use buffer::BufferAccess;
use command_buffer::submit::SubmitAnyBuilder;
use command_buffer::submit::SubmitPresentBuilder;
use command_buffer::submit::SubmitSemaphoresWaitBuilder;
use device::Device;
use device::DeviceOwned;
use device::Queue;
use format::Format;
use format::FormatDesc;
use image::ImageAccess;
use image::ImageDimensions;
use image::ImageInner;
use image::ImageLayout;
use image::ImageUsage;
use image::swapchain::SwapchainImage;
use image::sys::UnsafeImage;
use swapchain::CapabilitiesError;
use swapchain::ColorSpace;
use swapchain::CompositeAlpha;
use swapchain::PresentMode;
use swapchain::PresentRegion;
use swapchain::Surface;
use swapchain::SurfaceSwapchainLock;
use swapchain::SurfaceTransform;
use sync::AccessCheckError;
use sync::AccessError;
use sync::AccessFlagBits;
use sync::Fence;
use sync::FlushError;
use sync::GpuFuture;
use sync::PipelineStages;
use sync::Semaphore;
use sync::SharingMode;
use Error;
use OomError;
use Success;
use VulkanObject;
use check_errors;
use vk;
pub fn acquire_next_image<W>(swapchain: Arc<Swapchain<W>>, timeout: Option<Duration>)
-> Result<(usize, SwapchainAcquireFuture<W>), AcquireError> {
let semaphore = Semaphore::from_pool(swapchain.device.clone())?;
let fence = Fence::from_pool(swapchain.device.clone())?;
let AcquiredImage { id, suboptimal } = {
let stale = swapchain.stale.lock().unwrap();
if *stale {
return Err(AcquireError::OutOfDate);
}
unsafe { acquire_next_image_raw(&swapchain, timeout, Some(&semaphore), Some(&fence)) }?
};
Ok((id,
SwapchainAcquireFuture {
swapchain: swapchain,
semaphore: Some(semaphore),
fence: Some(fence),
image_id: id,
finished: AtomicBool::new(false),
}))
}
pub fn present<F, W>(swapchain: Arc<Swapchain<W>>, before: F, queue: Arc<Queue>, index: usize)
-> PresentFuture<F,W>
where F: GpuFuture
{
assert!(index < swapchain.images.len());
PresentFuture {
previous: before,
queue: queue,
swapchain: swapchain,
image_id: index,
present_region: None,
flushed: AtomicBool::new(false),
finished: AtomicBool::new(false),
}
}
pub fn present_incremental<F, W>(swapchain: Arc<Swapchain<W>>, before: F, queue: Arc<Queue>,
index: usize, present_region: PresentRegion)
-> PresentFuture<F, W>
where F: GpuFuture
{
assert!(index < swapchain.images.len());
PresentFuture {
previous: before,
queue: queue,
swapchain: swapchain,
image_id: index,
present_region: Some(present_region),
flushed: AtomicBool::new(false),
finished: AtomicBool::new(false),
}
}
pub struct Swapchain<W> {
device: Arc<Device>,
surface: Arc<Surface<W>>,
swapchain: vk::SwapchainKHR,
images: Vec<ImageEntry>,
stale: Mutex<bool>,
num_images: u32,
format: Format,
color_space: ColorSpace,
dimensions: [u32; 2],
layers: u32,
usage: ImageUsage,
sharing: SharingMode,
transform: SurfaceTransform,
alpha: CompositeAlpha,
mode: PresentMode,
clipped: bool,
}
struct ImageEntry {
image: UnsafeImage,
undefined_layout: AtomicBool,
}
impl <W> Swapchain<W> {
#[inline]
pub fn new<F, S>(
device: Arc<Device>, surface: Arc<Surface<W>>, num_images: u32, format: F,
dimensions: [u32; 2], layers: u32, usage: ImageUsage, sharing: S,
transform: SurfaceTransform, alpha: CompositeAlpha, mode: PresentMode, clipped: bool,
old_swapchain: Option<&Arc<Swapchain<W>>>)
-> Result<(Arc<Swapchain<W>>, Vec<Arc<SwapchainImage<W>>>), SwapchainCreationError>
where F: FormatDesc,
S: Into<SharingMode>
{
Swapchain::new_inner(device,
surface,
num_images,
format.format(),
ColorSpace::SrgbNonLinear,
Some(dimensions),
layers,
usage,
sharing.into(),
transform,
alpha,
mode,
clipped,
old_swapchain.map(|s| &**s))
}
pub fn recreate(&self)
-> Result<(Arc<Swapchain<W>>, Vec<Arc<SwapchainImage<W>>>), SwapchainCreationError> {
Swapchain::new_inner(self.device.clone(),
self.surface.clone(),
self.num_images,
self.format,
self.color_space,
None,
self.layers,
self.usage,
self.sharing.clone(),
self.transform,
self.alpha,
self.mode,
self.clipped,
Some(self))
}
pub fn recreate_with_dimension(
&self, dimensions: [u32; 2])
-> Result<(Arc<Swapchain<W>>, Vec<Arc<SwapchainImage<W>>>), SwapchainCreationError> {
Swapchain::new_inner(self.device.clone(),
self.surface.clone(),
self.num_images,
self.format,
self.color_space,
Some(dimensions),
self.layers,
self.usage,
self.sharing.clone(),
self.transform,
self.alpha,
self.mode,
self.clipped,
Some(self))
}
fn new_inner(device: Arc<Device>, surface: Arc<Surface<W>>, num_images: u32, format: Format,
color_space: ColorSpace, dimensions: Option<[u32; 2]>, layers: u32, usage: ImageUsage,
sharing: SharingMode, transform: SurfaceTransform, alpha: CompositeAlpha,
mode: PresentMode, clipped: bool, old_swapchain: Option<&Swapchain<W>>)
-> Result<(Arc<Swapchain<W>>, Vec<Arc<SwapchainImage<W>>>), SwapchainCreationError> {
assert_eq!(device.instance().internal_object(),
surface.instance().internal_object());
let capabilities = surface.capabilities(device.physical_device())?;
if num_images < capabilities.min_image_count {
return Err(SwapchainCreationError::UnsupportedMinImagesCount);
}
if let Some(c) = capabilities.max_image_count {
if num_images > c {
return Err(SwapchainCreationError::UnsupportedMaxImagesCount);
}
}
if !capabilities
.supported_formats
.iter()
.any(|&(f, c)| f == format && c == color_space)
{
return Err(SwapchainCreationError::UnsupportedFormat);
}
let dimensions = if let Some(dimensions) = dimensions {
if dimensions[0] < capabilities.min_image_extent[0] {
return Err(SwapchainCreationError::UnsupportedDimensions);
}
if dimensions[1] < capabilities.min_image_extent[1] {
return Err(SwapchainCreationError::UnsupportedDimensions);
}
if dimensions[0] > capabilities.max_image_extent[0] {
return Err(SwapchainCreationError::UnsupportedDimensions);
}
if dimensions[1] > capabilities.max_image_extent[1] {
return Err(SwapchainCreationError::UnsupportedDimensions);
}
dimensions
} else {
capabilities.current_extent.unwrap()
};
if layers < 1 || layers > capabilities.max_image_array_layers {
return Err(SwapchainCreationError::UnsupportedArrayLayers);
}
if (usage.to_usage_bits() & capabilities.supported_usage_flags.to_usage_bits()) !=
usage.to_usage_bits()
{
return Err(SwapchainCreationError::UnsupportedUsageFlags);
}
if !capabilities.supported_transforms.supports(transform) {
return Err(SwapchainCreationError::UnsupportedSurfaceTransform);
}
if !capabilities.supported_composite_alpha.supports(alpha) {
return Err(SwapchainCreationError::UnsupportedCompositeAlpha);
}
if !capabilities.present_modes.supports(mode) {
return Err(SwapchainCreationError::UnsupportedPresentMode);
}
if let Some(sc) = old_swapchain {
if surface.internal_object() != sc.surface.internal_object() {
return Err(SwapchainCreationError::OldSwapchainSurfaceMismatch);
}
}
if old_swapchain.is_none() {
let has_already = surface.flag().swap(true, Ordering::AcqRel);
if has_already {
return Err(SwapchainCreationError::SurfaceInUse);
}
}
if !device.loaded_extensions().khr_swapchain {
return Err(SwapchainCreationError::MissingExtension);
}
assert_ne!(usage, ImageUsage::none());
if let Some(ref old_swapchain) = old_swapchain {
let mut stale = old_swapchain.stale.lock().unwrap();
if *stale {
return Err(SwapchainCreationError::OldSwapchainAlreadyUsed);
} else {
*stale = true;
}
}
let vk = device.pointers();
let swapchain = unsafe {
let (sh_mode, sh_count, sh_indices) = match sharing {
SharingMode::Exclusive(_) => (vk::SHARING_MODE_EXCLUSIVE, 0, ptr::null()),
SharingMode::Concurrent(ref ids) => (vk::SHARING_MODE_CONCURRENT,
ids.len() as u32,
ids.as_ptr()),
};
let infos = vk::SwapchainCreateInfoKHR {
sType: vk::STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
pNext: ptr::null(),
flags: 0,
surface: surface.internal_object(),
minImageCount: num_images,
imageFormat: format as u32,
imageColorSpace: color_space as u32,
imageExtent: vk::Extent2D {
width: dimensions[0],
height: dimensions[1],
},
imageArrayLayers: layers,
imageUsage: usage.to_usage_bits(),
imageSharingMode: sh_mode,
queueFamilyIndexCount: sh_count,
pQueueFamilyIndices: sh_indices,
preTransform: transform as u32,
compositeAlpha: alpha as u32,
presentMode: mode as u32,
clipped: if clipped { vk::TRUE } else { vk::FALSE },
oldSwapchain: if let Some(ref old_swapchain) = old_swapchain {
old_swapchain.swapchain
} else {
0
},
};
let mut output = MaybeUninit::uninit();
check_errors(vk.CreateSwapchainKHR(device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr()))?;
output.assume_init()
};
let image_handles = unsafe {
let mut num = 0;
check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
swapchain,
&mut num,
ptr::null_mut()))?;
let mut images = Vec::with_capacity(num as usize);
check_errors(vk.GetSwapchainImagesKHR(device.internal_object(),
swapchain,
&mut num,
images.as_mut_ptr()))?;
images.set_len(num as usize);
images
};
let images = image_handles
.into_iter()
.map(|image| unsafe {
let dims = ImageDimensions::Dim2d {
width: dimensions[0],
height: dimensions[1],
array_layers: layers,
cubemap_compatible: false,
};
let img = UnsafeImage::from_raw(device.clone(),
image,
usage.to_usage_bits(),
format,
dims,
1,
1);
ImageEntry {
image: img,
undefined_layout: AtomicBool::new(true),
}
})
.collect::<Vec<_>>();
let swapchain = Arc::new(Swapchain {
device: device.clone(),
surface: surface.clone(),
swapchain: swapchain,
images: images,
stale: Mutex::new(false),
num_images: num_images,
format: format,
color_space: color_space,
dimensions: dimensions,
layers: layers,
usage: usage.clone(),
sharing: sharing,
transform: transform,
alpha: alpha,
mode: mode,
clipped: clipped,
});
let swapchain_images = unsafe {
let mut swapchain_images = Vec::with_capacity(swapchain.images.len());
for n in 0 .. swapchain.images.len() {
swapchain_images.push(SwapchainImage::from_raw(swapchain.clone(), n)?);
}
swapchain_images
};
Ok((swapchain, swapchain_images))
}
#[inline]
pub fn raw_image(&self, offset: usize) -> Option<ImageInner> {
self.images.get(offset).map(|i| {
ImageInner {
image: &i.image,
first_layer: 0,
num_layers: self.layers as usize,
first_mipmap_level: 0,
num_mipmap_levels: 1,
}
})
}
#[inline]
pub fn num_images(&self) -> u32 {
self.images.len() as u32
}
#[inline]
pub fn format(&self) -> Format {
self.format
}
#[inline]
pub fn dimensions(&self) -> [u32; 2] {
self.dimensions
}
#[inline]
pub fn layers(&self) -> u32 {
self.layers
}
#[inline]
pub fn transform(&self) -> SurfaceTransform {
self.transform
}
#[inline]
pub fn composite_alpha(&self) -> CompositeAlpha {
self.alpha
}
#[inline]
pub fn present_mode(&self) -> PresentMode {
self.mode
}
#[inline]
pub fn clipped(&self) -> bool {
self.clipped
}
pub(crate) fn image_layout_initialized(&self, image_offset: usize) {
let image_entry = self.images.get(image_offset);
if let Some(ref image_entry) = image_entry {
image_entry.undefined_layout.store(false, Ordering::SeqCst);
}
}
pub(crate) fn is_image_layout_initialized(&self, image_offset: usize) -> bool {
let image_entry = self.images.get(image_offset);
if let Some(ref image_entry) = image_entry {
!image_entry.undefined_layout.load(Ordering::SeqCst)
} else { false }
}
}
unsafe impl<W> VulkanObject for Swapchain<W> {
type Object = vk::SwapchainKHR;
const TYPE: vk::ObjectType = vk::OBJECT_TYPE_SWAPCHAIN_KHR;
#[inline]
fn internal_object(&self) -> vk::SwapchainKHR {
self.swapchain
}
}
unsafe impl<W> DeviceOwned for Swapchain<W> {
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl<W> fmt::Debug for Swapchain<W> {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan swapchain {:?}>", self.swapchain)
}
}
impl<W> Drop for Swapchain<W> {
#[inline]
fn drop(&mut self) {
unsafe {
let vk = self.device.pointers();
vk.DestroySwapchainKHR(self.device.internal_object(), self.swapchain, ptr::null());
self.surface.flag().store(false, Ordering::Release);
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum SwapchainCreationError {
OomError(OomError),
DeviceLost,
SurfaceLost,
SurfaceInUse,
NativeWindowInUse,
MissingExtension,
OldSwapchainSurfaceMismatch,
OldSwapchainAlreadyUsed,
UnsupportedMinImagesCount,
UnsupportedMaxImagesCount,
UnsupportedFormat,
UnsupportedDimensions,
UnsupportedArrayLayers,
UnsupportedUsageFlags,
UnsupportedSurfaceTransform,
UnsupportedCompositeAlpha,
UnsupportedPresentMode,
}
impl error::Error for SwapchainCreationError {
#[inline]
fn description(&self) -> &str {
match *self {
SwapchainCreationError::OomError(_) => {
"not enough memory available"
},
SwapchainCreationError::DeviceLost => {
"the device was lost"
},
SwapchainCreationError::SurfaceLost => {
"the surface was lost"
},
SwapchainCreationError::SurfaceInUse => {
"the surface is already used by another swapchain"
},
SwapchainCreationError::NativeWindowInUse => {
"the window is already in use by another API"
},
SwapchainCreationError::MissingExtension => {
"the `VK_KHR_swapchain` extension was not enabled"
},
SwapchainCreationError::OldSwapchainSurfaceMismatch => {
"surface mismatch between old and new swapchain"
},
SwapchainCreationError::OldSwapchainAlreadyUsed => {
"old swapchain has already been used to recreate a new one"
},
SwapchainCreationError::UnsupportedMinImagesCount => {
"the requested number of swapchain images is not supported by the surface"
},
SwapchainCreationError::UnsupportedMaxImagesCount => {
"the requested number of swapchain images is not supported by the surface"
},
SwapchainCreationError::UnsupportedFormat => {
"the requested image format is not supported by the surface"
},
SwapchainCreationError::UnsupportedDimensions => {
"the requested dimensions are not supported by the surface"
},
SwapchainCreationError::UnsupportedArrayLayers => {
"the requested array layers count is not supported by the surface"
},
SwapchainCreationError::UnsupportedUsageFlags => {
"the requested image usage is not supported by the surface"
},
SwapchainCreationError::UnsupportedSurfaceTransform => {
"the requested surface transform is not supported by the surface"
},
SwapchainCreationError::UnsupportedCompositeAlpha => {
"the requested composite alpha is not supported by the surface"
},
SwapchainCreationError::UnsupportedPresentMode => {
"the requested present mode is not supported by the surface"
},
}
}
#[inline]
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
SwapchainCreationError::OomError(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for SwapchainCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
impl From<Error> for SwapchainCreationError {
#[inline]
fn from(err: Error) -> SwapchainCreationError {
match err {
err @ Error::OutOfHostMemory => {
SwapchainCreationError::OomError(OomError::from(err))
},
err @ Error::OutOfDeviceMemory => {
SwapchainCreationError::OomError(OomError::from(err))
},
Error::DeviceLost => {
SwapchainCreationError::DeviceLost
},
Error::SurfaceLost => {
SwapchainCreationError::SurfaceLost
},
Error::NativeWindowInUse => {
SwapchainCreationError::NativeWindowInUse
},
_ => panic!("unexpected error: {:?}", err),
}
}
}
impl From<OomError> for SwapchainCreationError {
#[inline]
fn from(err: OomError) -> SwapchainCreationError {
SwapchainCreationError::OomError(err)
}
}
impl From<CapabilitiesError> for SwapchainCreationError {
#[inline]
fn from(err: CapabilitiesError) -> SwapchainCreationError {
match err {
CapabilitiesError::OomError(err) => SwapchainCreationError::OomError(err),
CapabilitiesError::SurfaceLost => SwapchainCreationError::SurfaceLost,
}
}
}
#[must_use]
pub struct SwapchainAcquireFuture<W> {
swapchain: Arc<Swapchain<W>>,
image_id: usize,
semaphore: Option<Semaphore>,
fence: Option<Fence>,
finished: AtomicBool,
}
impl<W> SwapchainAcquireFuture<W> {
#[inline]
pub fn image_id(&self) -> usize {
self.image_id
}
#[inline]
pub fn swapchain(&self) -> &Arc<Swapchain<W>> {
&self.swapchain
}
}
unsafe impl<W> GpuFuture for SwapchainAcquireFuture<W> {
#[inline]
fn cleanup_finished(&mut self) {
}
#[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
if let Some(ref semaphore) = self.semaphore {
let mut sem = SubmitSemaphoresWaitBuilder::new();
sem.add_wait_semaphore(&semaphore);
Ok(SubmitAnyBuilder::SemaphoresWait(sem))
} else {
Ok(SubmitAnyBuilder::Empty)
}
}
#[inline]
fn flush(&self) -> Result<(), FlushError> {
Ok(())
}
#[inline]
unsafe fn signal_finished(&self) {
self.finished.store(true, Ordering::SeqCst);
}
#[inline]
fn queue_change_allowed(&self) -> bool {
true
}
#[inline]
fn queue(&self) -> Option<Arc<Queue>> {
None
}
#[inline]
fn check_buffer_access(
&self, _: &dyn BufferAccess, _: bool, _: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
Err(AccessCheckError::Unknown)
}
#[inline]
fn check_image_access(&self, image: &dyn ImageAccess, layout: ImageLayout, _: bool, _: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap();
if swapchain_image.image.internal_object() != image.inner().image.internal_object() {
return Err(AccessCheckError::Unknown);
}
if self.swapchain.images[self.image_id]
.undefined_layout
.load(Ordering::Relaxed) && layout != ImageLayout::Undefined
{
return Err(AccessCheckError::Denied(AccessError::ImageNotInitialized {
requested: layout,
}));
}
if layout != ImageLayout::Undefined && layout != ImageLayout::PresentSrc {
return Err(AccessCheckError::Denied(AccessError::UnexpectedImageLayout {
allowed: ImageLayout::PresentSrc,
requested: layout,
}));
}
Ok(None)
}
}
unsafe impl<W> DeviceOwned for SwapchainAcquireFuture<W> {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.swapchain.device
}
}
impl<W> Drop for SwapchainAcquireFuture<W> {
fn drop(&mut self) {
if let Some(ref fence) = self.fence {
fence.wait(None).unwrap();
self.semaphore = None;
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum AcquireError {
OomError(OomError),
DeviceLost,
Timeout,
SurfaceLost,
OutOfDate,
}
impl error::Error for AcquireError {
#[inline]
fn description(&self) -> &str {
match *self {
AcquireError::OomError(_) => "not enough memory",
AcquireError::DeviceLost => "the connection to the device has been lost",
AcquireError::Timeout => "no image is available for acquiring yet",
AcquireError::SurfaceLost => "the surface of this swapchain is no longer valid",
AcquireError::OutOfDate => "the swapchain needs to be recreated",
}
}
#[inline]
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
AcquireError::OomError(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for AcquireError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "{}", error::Error::description(self))
}
}
impl From<OomError> for AcquireError {
#[inline]
fn from(err: OomError) -> AcquireError {
AcquireError::OomError(err)
}
}
impl From<Error> for AcquireError {
#[inline]
fn from(err: Error) -> AcquireError {
match err {
err @ Error::OutOfHostMemory => AcquireError::OomError(OomError::from(err)),
err @ Error::OutOfDeviceMemory => AcquireError::OomError(OomError::from(err)),
Error::DeviceLost => AcquireError::DeviceLost,
Error::SurfaceLost => AcquireError::SurfaceLost,
Error::OutOfDate => AcquireError::OutOfDate,
_ => panic!("unexpected error: {:?}", err),
}
}
}
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
pub struct PresentFuture<P, W>
where P: GpuFuture
{
previous: P,
queue: Arc<Queue>,
swapchain: Arc<Swapchain<W>>,
image_id: usize,
present_region: Option<PresentRegion>,
flushed: AtomicBool,
finished: AtomicBool,
}
impl<P, W> PresentFuture<P, W>
where P: GpuFuture
{
#[inline]
pub fn image_id(&self) -> usize {
self.image_id
}
#[inline]
pub fn swapchain(&self) -> &Arc<Swapchain<W>> {
&self.swapchain
}
}
unsafe impl<P, W> GpuFuture for PresentFuture<P, W>
where P: GpuFuture
{
#[inline]
fn cleanup_finished(&mut self) {
self.previous.cleanup_finished();
}
#[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
if self.flushed.load(Ordering::SeqCst) {
return Ok(SubmitAnyBuilder::Empty);
}
let queue = self.previous.queue().map(|q| q.clone());
Ok(match self.previous.build_submission()? {
SubmitAnyBuilder::Empty => {
let mut builder = SubmitPresentBuilder::new();
builder.add_swapchain(&self.swapchain,
self.image_id as u32,
self.present_region.as_ref());
SubmitAnyBuilder::QueuePresent(builder)
},
SubmitAnyBuilder::SemaphoresWait(sem) => {
let mut builder: SubmitPresentBuilder = sem.into();
builder.add_swapchain(&self.swapchain,
self.image_id as u32,
self.present_region.as_ref());
SubmitAnyBuilder::QueuePresent(builder)
},
SubmitAnyBuilder::CommandBuffer(cb) => {
self.previous.flush()?;
let mut builder = SubmitPresentBuilder::new();
builder.add_swapchain(&self.swapchain,
self.image_id as u32,
self.present_region.as_ref());
SubmitAnyBuilder::QueuePresent(builder)
},
SubmitAnyBuilder::BindSparse(cb) => {
self.previous.flush()?;
let mut builder = SubmitPresentBuilder::new();
builder.add_swapchain(&self.swapchain,
self.image_id as u32,
self.present_region.as_ref());
SubmitAnyBuilder::QueuePresent(builder)
},
SubmitAnyBuilder::QueuePresent(present) => {
unimplemented!()
},
})
}
#[inline]
fn flush(&self) -> Result<(), FlushError> {
unsafe {
match self.build_submission()? {
SubmitAnyBuilder::Empty => {},
SubmitAnyBuilder::QueuePresent(present) => {
present.submit(&self.queue)?;
},
_ => unreachable!(),
}
self.flushed.store(true, Ordering::SeqCst);
Ok(())
}
}
#[inline]
unsafe fn signal_finished(&self) {
self.flushed.store(true, Ordering::SeqCst);
self.finished.store(true, Ordering::SeqCst);
self.previous.signal_finished();
}
#[inline]
fn queue_change_allowed(&self) -> bool {
false
}
#[inline]
fn queue(&self) -> Option<Arc<Queue>> {
debug_assert!(match self.previous.queue() {
None => true,
Some(q) => q.is_same(&self.queue),
});
Some(self.queue.clone())
}
#[inline]
fn check_buffer_access(
&self, buffer: &dyn BufferAccess, exclusive: bool, queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
self.previous.check_buffer_access(buffer, exclusive, queue)
}
#[inline]
fn check_image_access(&self, image: &dyn ImageAccess, layout: ImageLayout, exclusive: bool,
queue: &Queue)
-> Result<Option<(PipelineStages, AccessFlagBits)>, AccessCheckError> {
let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap();
if swapchain_image.image.internal_object() == image.inner().image.internal_object() {
Err(AccessCheckError::Unknown)
} else {
self.previous
.check_image_access(image, layout, exclusive, queue)
}
}
}
unsafe impl<P, W> DeviceOwned for PresentFuture<P, W>
where P: GpuFuture
{
#[inline]
fn device(&self) -> &Arc<Device> {
self.queue.device()
}
}
impl<P, W> Drop for PresentFuture<P, W>
where P: GpuFuture
{
fn drop(&mut self) {
unsafe {
if !*self.finished.get_mut() {
match self.flush() {
Ok(()) => {
self.queue().unwrap().wait().unwrap();
self.previous.signal_finished();
},
Err(_) => {
},
}
}
}
}
}
pub struct AcquiredImage {
pub id: usize,
pub suboptimal: bool,
}
pub unsafe fn acquire_next_image_raw<W>(swapchain: &Swapchain<W>, timeout: Option<Duration>,
semaphore: Option<&Semaphore>, fence: Option<&Fence>)
-> Result<AcquiredImage, AcquireError> {
let vk = swapchain.device.pointers();
let timeout_ns = if let Some(timeout) = timeout {
timeout
.as_secs()
.saturating_mul(1_000_000_000)
.saturating_add(timeout.subsec_nanos() as u64)
} else {
u64::max_value()
};
let mut out = MaybeUninit::uninit();
let r =
check_errors(vk.AcquireNextImageKHR(swapchain.device.internal_object(),
swapchain.swapchain,
timeout_ns,
semaphore.map(|s| s.internal_object()).unwrap_or(0),
fence.map(|f| f.internal_object()).unwrap_or(0),
out.as_mut_ptr()))?;
let out = out.assume_init();
let (id, suboptimal) = match r {
Success::Success => (out as usize, false),
Success::Suboptimal => (out as usize, true),
Success::NotReady => return Err(AcquireError::Timeout),
Success::Timeout => return Err(AcquireError::Timeout),
s => panic!("unexpected success value: {:?}", s),
};
Ok(AcquiredImage { id, suboptimal })
}