use super::{PresentMode, Swapchain};
use crate::{
buffer::Buffer,
device::{Device, DeviceOwned, Queue},
image::{Image, ImageLayout},
sync::{
fence::Fence,
future::{queue_present, AccessCheckError, AccessError, GpuFuture, SubmitAnyBuilder},
semaphore::{Semaphore, SemaphoreType},
},
DeviceSize, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError,
VulkanObject,
};
use smallvec::{smallvec, SmallVec};
use std::{
fmt::Debug,
mem::MaybeUninit,
num::NonZeroU64,
ops::Range,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread,
time::Duration,
};
#[derive(Clone, Debug)]
pub struct AcquireNextImageInfo {
pub timeout: Option<Duration>,
pub semaphore: Option<Arc<Semaphore>>,
pub fence: Option<Arc<Fence>>,
pub _ne: crate::NonExhaustive,
}
impl Default for AcquireNextImageInfo {
#[inline]
fn default() -> Self {
Self {
timeout: None,
semaphore: None,
fence: None,
_ne: crate::NonExhaustive(()),
}
}
}
impl AcquireNextImageInfo {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
timeout,
ref semaphore,
ref fence,
_ne: _,
} = self;
if let Some(timeout) = timeout {
if timeout.as_nanos() >= u64::MAX as u128 {
return Err(Box::new(ValidationError {
context: "timeout".into(),
problem: "is not less than `u64::MAX` nanoseconds".into(),
..Default::default()
}));
}
}
if semaphore.is_none() && fence.is_none() {
return Err(Box::new(ValidationError {
problem: "`semaphore` and `fence` are both `None`".into(),
vuids: &["VUID-VkAcquireNextImageInfoKHR-semaphore-01782"],
..Default::default()
}));
}
if let Some(semaphore) = semaphore {
assert_eq!(device, semaphore.device().as_ref());
if semaphore.semaphore_type() != SemaphoreType::Binary {
return Err(Box::new(ValidationError {
context: "semaphore.semaphore_type()".into(),
problem: "is not `SemaphoreType::Binary`".into(),
vuids: &["VUID-VkAcquireNextImageInfoKHR-semaphore-03266"],
..Default::default()
}));
}
}
if let Some(fence) = fence {
assert_eq!(device, fence.device().as_ref());
}
Ok(())
}
pub(crate) fn to_vk(
&self,
swapchain_vk: ash::vk::SwapchainKHR,
device_mask_vk: u32,
) -> ash::vk::AcquireNextImageInfoKHR<'static> {
let &Self {
timeout,
ref semaphore,
ref fence,
_ne: _,
} = self;
ash::vk::AcquireNextImageInfoKHR::default()
.swapchain(swapchain_vk)
.timeout(timeout.map_or(u64::MAX, |duration| {
u64::try_from(duration.as_nanos()).unwrap()
}))
.semaphore(
semaphore
.as_ref()
.map(VulkanObject::handle)
.unwrap_or_default(),
)
.fence(fence.as_ref().map(VulkanObject::handle).unwrap_or_default())
.device_mask(device_mask_vk)
}
}
pub fn acquire_next_image(
swapchain: Arc<Swapchain>,
timeout: Option<Duration>,
) -> Result<(u32, bool, SwapchainAcquireFuture), Validated<VulkanError>> {
let semaphore = Arc::new(Semaphore::from_pool(swapchain.device.clone())?);
let fence = Arc::new(Fence::from_pool(swapchain.device.clone())?);
let AcquiredImage {
image_index,
is_suboptimal,
} = unsafe {
swapchain.acquire_next_image(&AcquireNextImageInfo {
timeout,
semaphore: Some(semaphore.clone()),
fence: Some(fence.clone()),
..Default::default()
})
}?;
Ok((
image_index,
is_suboptimal,
SwapchainAcquireFuture {
swapchain,
semaphore: Some(semaphore),
fence: Some(fence),
image_index,
finished: AtomicBool::new(false),
},
))
}
#[deprecated(
since = "0.35.0",
note = "use `Swapchain::acquire_next_image_unchecked` instead"
)]
pub unsafe fn acquire_next_image_raw(
swapchain: &Swapchain,
timeout: Option<Duration>,
semaphore: Option<&Semaphore>,
fence: Option<&Fence>,
) -> Result<AcquiredImage, Validated<VulkanError>> {
let fns = swapchain.device.fns();
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
};
let (image_index, is_suboptimal) = {
let mut output = MaybeUninit::uninit();
let result = unsafe {
(fns.khr_swapchain.acquire_next_image_khr)(
swapchain.device.handle(),
swapchain.handle,
timeout_ns,
semaphore
.map(|s| s.handle())
.unwrap_or(ash::vk::Semaphore::null()),
fence.map(|f| f.handle()).unwrap_or(ash::vk::Fence::null()),
output.as_mut_ptr(),
)
};
match result {
ash::vk::Result::SUCCESS => (unsafe { output.assume_init() }, false),
ash::vk::Result::SUBOPTIMAL_KHR => (unsafe { output.assume_init() }, true),
ash::vk::Result::NOT_READY => return Err(VulkanError::NotReady.into()),
ash::vk::Result::TIMEOUT => return Err(VulkanError::Timeout.into()),
err => return Err(VulkanError::from(err).into()),
}
};
Ok(AcquiredImage {
image_index,
is_suboptimal,
})
}
#[derive(Clone, Copy, Debug)]
pub struct AcquiredImage {
pub image_index: u32,
pub is_suboptimal: bool,
}
#[must_use]
pub struct SwapchainAcquireFuture {
swapchain: Arc<Swapchain>,
image_index: u32,
semaphore: Option<Arc<Semaphore>>,
fence: Option<Arc<Fence>>,
finished: AtomicBool,
}
impl SwapchainAcquireFuture {
pub fn image_index(&self) -> u32 {
self.image_index
}
pub fn swapchain(&self) -> &Arc<Swapchain> {
&self.swapchain
}
pub fn wait(&self, timeout: Option<Duration>) -> Result<(), VulkanError> {
match &self.fence {
Some(fence) => fence.wait(timeout),
None => Ok(()),
}
}
}
unsafe impl GpuFuture for SwapchainAcquireFuture {
fn cleanup_finished(&mut self) {}
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, Validated<VulkanError>> {
if let Some(ref semaphore) = self.semaphore {
let sem = smallvec![semaphore.clone()];
Ok(SubmitAnyBuilder::SemaphoresWait(sem))
} else {
Ok(SubmitAnyBuilder::Empty)
}
}
fn flush(&self) -> Result<(), Validated<VulkanError>> {
Ok(())
}
unsafe fn signal_finished(&self) {
self.finished.store(true, Ordering::SeqCst);
}
fn queue_change_allowed(&self) -> bool {
true
}
fn queue(&self) -> Option<Arc<Queue>> {
None
}
fn check_buffer_access(
&self,
_buffer: &Buffer,
_range: Range<DeviceSize>,
_exclusive: bool,
_queue: &Queue,
) -> Result<(), AccessCheckError> {
Err(AccessCheckError::Unknown)
}
fn check_image_access(
&self,
image: &Image,
_range: Range<DeviceSize>,
_exclusive: bool,
expected_layout: ImageLayout,
_queue: &Queue,
) -> Result<(), AccessCheckError> {
if self.swapchain.index_of_image(image) != Some(self.image_index) {
return Err(AccessCheckError::Unknown);
}
if !self.swapchain.images[self.image_index as usize]
.layout_initialized
.load(Ordering::Relaxed)
&& expected_layout != ImageLayout::Undefined
{
return Err(AccessCheckError::Denied(AccessError::ImageNotInitialized {
requested: expected_layout,
}));
}
if expected_layout != ImageLayout::Undefined && expected_layout != ImageLayout::PresentSrc {
return Err(AccessCheckError::Denied(
AccessError::UnexpectedImageLayout {
allowed: ImageLayout::PresentSrc,
requested: expected_layout,
},
));
}
Ok(())
}
#[inline]
fn check_swapchain_image_acquired(
&self,
swapchain: &Swapchain,
image_index: u32,
before: bool,
) -> Result<(), AccessCheckError> {
if before {
Ok(())
} else {
if swapchain == self.swapchain.as_ref() && image_index == self.image_index {
Ok(())
} else {
Err(AccessCheckError::Unknown)
}
}
}
}
impl Drop for SwapchainAcquireFuture {
fn drop(&mut self) {
if thread::panicking() {
return;
}
if let Some(fence) = &self.fence {
fence.wait(None).unwrap(); self.semaphore = None;
}
}
}
unsafe impl DeviceOwned for SwapchainAcquireFuture {
fn device(&self) -> &Arc<Device> {
&self.swapchain.device
}
}
pub fn present<F>(
before: F,
queue: Arc<Queue>,
swapchain_info: SwapchainPresentInfo,
) -> PresentFuture<F>
where
F: GpuFuture,
{
assert!(swapchain_info.image_index < swapchain_info.swapchain.image_count());
PresentFuture {
previous: before,
queue,
swapchain_info,
flushed: AtomicBool::new(false),
finished: AtomicBool::new(false),
}
}
#[derive(Clone, Debug)]
pub struct PresentInfo {
pub wait_semaphores: Vec<SemaphorePresentInfo>,
pub swapchain_infos: Vec<SwapchainPresentInfo>,
pub _ne: crate::NonExhaustive,
}
impl Default for PresentInfo {
#[inline]
fn default() -> Self {
Self {
wait_semaphores: Vec::new(),
swapchain_infos: Vec::new(),
_ne: crate::NonExhaustive(()),
}
}
}
impl PresentInfo {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref wait_semaphores,
ref swapchain_infos,
_ne: _,
} = self;
for (index, semaphore_present_info) in wait_semaphores.iter().enumerate() {
semaphore_present_info
.validate(device)
.map_err(|err| err.add_context(format!("wait_semaphores[{}]", index)))?;
}
assert!(!swapchain_infos.is_empty());
let has_present_mode = swapchain_infos
.first()
.is_some_and(|first| first.present_mode.is_some());
for (index, swapchain_info) in swapchain_infos.iter().enumerate() {
swapchain_info
.validate(device)
.map_err(|err| err.add_context(format!("swapchain_infos[{}]", index)))?;
let &SwapchainPresentInfo {
swapchain: _,
image_index: _,
present_id: _,
present_mode,
present_region: _,
_ne: _,
} = swapchain_info;
if has_present_mode {
if present_mode.is_none() {
return Err(Box::new(ValidationError {
problem: format!(
"`swapchain_infos[0].present_mode` is `Some`, but \
`swapchain_infos[{}].present_mode` is not also `Some`",
index
)
.into(),
vuids: &["VUID-VkPresentInfoKHR-pSwapchains-09199"],
..Default::default()
}));
}
} else {
if present_mode.is_some() {
return Err(Box::new(ValidationError {
problem: format!(
"`swapchain_infos[0].present_mode` is `None`, but \
`swapchain_infos[{}].present_mode` is not also `None`",
index
)
.into(),
vuids: &["VUID-VkPresentInfoKHR-pSwapchains-09199"],
..Default::default()
}));
}
}
}
Ok(())
}
pub(crate) fn to_vk<'a>(
&self,
fields1_vk: &'a PresentInfoFields1Vk<'_>,
results_vk: &'a mut [ash::vk::Result],
extensions_vk: &'a mut PresentInfoExtensionsVk<'_>,
) -> ash::vk::PresentInfoKHR<'a> {
let &Self {
wait_semaphores: _,
swapchain_infos: _,
_ne: _,
} = self;
let PresentInfoFields1Vk {
wait_semaphores_vk,
swapchains_vk,
image_indices_vk,
present_ids_vk: _,
present_modes_vk: _,
present_regions_vk: _,
} = fields1_vk;
let PresentInfoExtensionsVk {
present_id_vk,
present_mode_vk,
present_regions_vk,
} = extensions_vk;
let mut val_vk = ash::vk::PresentInfoKHR::default()
.wait_semaphores(wait_semaphores_vk)
.swapchains(swapchains_vk)
.image_indices(image_indices_vk)
.results(results_vk);
if let Some(next) = present_id_vk {
val_vk = val_vk.push_next(next);
}
if let Some(next) = present_mode_vk {
val_vk = val_vk.push_next(next);
}
if let Some(next) = present_regions_vk {
val_vk = val_vk.push_next(next);
}
val_vk
}
pub(crate) fn to_vk_results(&self) -> Vec<ash::vk::Result> {
vec![ash::vk::Result::SUCCESS; self.swapchain_infos.len()]
}
pub(crate) fn to_vk_extensions<'a>(
&self,
fields1_vk: &'a PresentInfoFields1Vk<'_>,
) -> PresentInfoExtensionsVk<'a> {
let PresentInfoFields1Vk {
wait_semaphores_vk: _,
swapchains_vk: _,
image_indices_vk: _,
present_ids_vk,
present_modes_vk,
present_regions_vk,
} = fields1_vk;
let mut has_present_ids = false;
let mut has_present_modes = false;
let mut has_present_regions = false;
for swapchain_info in &self.swapchain_infos {
let &SwapchainPresentInfo {
swapchain: _,
image_index: _,
present_id,
present_mode,
ref present_region,
_ne: _,
} = swapchain_info;
has_present_ids |= present_id.is_some();
has_present_modes |= present_mode.is_some();
has_present_regions |= !present_region.is_empty();
}
let present_id_vk =
has_present_ids.then(|| ash::vk::PresentIdKHR::default().present_ids(present_ids_vk));
let present_mode_vk = has_present_modes.then(|| {
ash::vk::SwapchainPresentModeInfoEXT::default().present_modes(present_modes_vk)
});
let present_regions_vk = has_present_regions
.then(|| ash::vk::PresentRegionsKHR::default().regions(present_regions_vk));
PresentInfoExtensionsVk {
present_id_vk,
present_mode_vk,
present_regions_vk,
}
}
pub(crate) fn to_vk_fields1<'a>(
&self,
fields2_vk: &'a PresentInfoFields2Vk,
) -> PresentInfoFields1Vk<'a> {
let &Self {
ref wait_semaphores,
ref swapchain_infos,
_ne: _,
} = self;
let PresentInfoFields2Vk {
swapchain_infos_fields1_vk,
} = fields2_vk;
let wait_semaphores_vk = wait_semaphores
.iter()
.map(SemaphorePresentInfo::to_vk)
.collect();
let mut swapchains_vk = SmallVec::with_capacity(swapchain_infos.len());
let mut image_indices_vk = SmallVec::with_capacity(swapchain_infos.len());
let mut present_ids_vk = SmallVec::with_capacity(swapchain_infos.len());
let mut present_modes_vk = SmallVec::with_capacity(swapchain_infos.len());
let mut present_regions_vk = SmallVec::with_capacity(swapchain_infos.len());
for (swapchain_info, fields1_vk) in swapchain_infos.iter().zip(swapchain_infos_fields1_vk) {
let &SwapchainPresentInfo {
ref swapchain,
image_index,
present_id,
present_mode,
present_region: _,
_ne: _,
} = swapchain_info;
let SwapchainPresentInfoFields1Vk {
present_region_rectangles_vk,
} = fields1_vk;
swapchains_vk.push(swapchain.handle());
image_indices_vk.push(image_index);
present_ids_vk.push(present_id.map_or(0, u64::from));
present_modes_vk.push(present_mode.map_or_else(Default::default, Into::into));
present_regions_vk.push(
ash::vk::PresentRegionKHR::default().rectangles(present_region_rectangles_vk),
);
}
PresentInfoFields1Vk {
wait_semaphores_vk,
swapchains_vk,
image_indices_vk,
present_ids_vk,
present_modes_vk,
present_regions_vk,
}
}
pub(crate) fn to_vk_fields2(&self) -> PresentInfoFields2Vk {
let swapchain_infos_fields1_vk = self
.swapchain_infos
.iter()
.map(SwapchainPresentInfo::to_vk_fields1)
.collect();
PresentInfoFields2Vk {
swapchain_infos_fields1_vk,
}
}
}
pub(crate) struct PresentInfoExtensionsVk<'a> {
pub(crate) present_id_vk: Option<ash::vk::PresentIdKHR<'a>>,
pub(crate) present_mode_vk: Option<ash::vk::SwapchainPresentModeInfoEXT<'a>>,
pub(crate) present_regions_vk: Option<ash::vk::PresentRegionsKHR<'a>>,
}
pub(crate) struct PresentInfoFields1Vk<'a> {
pub(crate) wait_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>,
pub(crate) swapchains_vk: SmallVec<[ash::vk::SwapchainKHR; 4]>,
pub(crate) image_indices_vk: SmallVec<[u32; 4]>,
pub(crate) present_ids_vk: SmallVec<[u64; 4]>,
pub(crate) present_modes_vk: SmallVec<[ash::vk::PresentModeKHR; 4]>,
pub(crate) present_regions_vk: SmallVec<[ash::vk::PresentRegionKHR<'a>; 4]>,
}
pub(crate) struct PresentInfoFields2Vk {
pub(crate) swapchain_infos_fields1_vk: SmallVec<[SwapchainPresentInfoFields1Vk; 4]>,
}
#[derive(Clone, Debug)]
pub struct SwapchainPresentInfo {
pub swapchain: Arc<Swapchain>,
pub image_index: u32,
pub present_id: Option<NonZeroU64>,
pub present_mode: Option<PresentMode>,
pub present_region: Vec<RectangleLayer>,
pub _ne: crate::NonExhaustive,
}
impl SwapchainPresentInfo {
#[inline]
pub fn swapchain_image_index(swapchain: Arc<Swapchain>, image_index: u32) -> Self {
Self {
swapchain,
image_index,
present_id: None,
present_mode: None,
present_region: Vec::new(),
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref swapchain,
image_index,
present_id,
present_mode,
ref present_region,
_ne: _,
} = self;
assert_eq!(device, swapchain.device().as_ref());
if image_index >= swapchain.image_count() {
return Err(Box::new(ValidationError {
problem: "`image_index` is not less than `swapchain.image_count()`".into(),
vuids: &["VUID-VkPresentInfoKHR-pImageIndices-01430"],
..Default::default()
}));
}
if present_id.is_some() && !device.enabled_features().present_id {
return Err(Box::new(ValidationError {
context: "present_id".into(),
problem: "is `Some`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceFeature(
"present_id",
)])]),
vuids: &["VUID-VkPresentInfoKHR-pNext-06235"],
}));
}
if let Some(present_mode) = present_mode {
if !swapchain.present_modes().contains(&present_mode) {
return Err(Box::new(ValidationError {
problem: "`swapchain.present_modes()` does not contain `present_mode`".into(),
vuids: &["VUID-VkSwapchainPresentModeInfoEXT-pPresentModes-07761"],
..Default::default()
}));
}
}
if !present_region.is_empty() && !device.enabled_extensions().khr_incremental_present {
return Err(Box::new(ValidationError {
context: "present_regions".into(),
problem: "is not empty".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"khr_incremental_present",
)])]),
..Default::default()
}));
}
for (index, rectangle_layer) in present_region.iter().enumerate() {
let &RectangleLayer {
offset,
extent,
layer,
} = rectangle_layer;
if offset[0] + extent[0] > swapchain.image_extent()[0] {
return Err(Box::new(ValidationError {
problem: format!(
"`present_region[{0}].offset[0]` + `present_regions[{0}].extent[0]` is \
greater than `swapchain.image_extent()[0]`",
index
)
.into(),
vuids: &["VUID-VkRectLayerKHR-offset-04864"],
..Default::default()
}));
}
if offset[1] + extent[1] > swapchain.image_extent()[1] {
return Err(Box::new(ValidationError {
problem: format!(
"`present_region[{0}].offset[1]` + `present_regions[{0}].extent[1]` is \
greater than `swapchain.image_extent()[1]`",
index
)
.into(),
vuids: &["VUID-VkRectLayerKHR-offset-04864"],
..Default::default()
}));
}
if layer >= swapchain.image_array_layers() {
return Err(Box::new(ValidationError {
problem: format!(
"`present_region[{0}].layer` is greater than \
`swapchain.image_array_layers()`",
index
)
.into(),
vuids: &["VUID-VkRectLayerKHR-layer-01262"],
..Default::default()
}));
}
}
Ok(())
}
pub(crate) fn to_vk_fields1(&self) -> SwapchainPresentInfoFields1Vk {
let present_region_rectangles_vk = self
.present_region
.iter()
.map(RectangleLayer::to_vk)
.collect();
SwapchainPresentInfoFields1Vk {
present_region_rectangles_vk,
}
}
}
pub(crate) struct SwapchainPresentInfoFields1Vk {
pub(crate) present_region_rectangles_vk: SmallVec<[ash::vk::RectLayerKHR; 4]>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct RectangleLayer {
pub offset: [u32; 2],
pub extent: [u32; 2],
pub layer: u32,
}
impl RectangleLayer {
#[inline]
pub fn is_compatible_with(&self, swapchain: &Swapchain) -> bool {
self.offset[0] + self.extent[0] <= swapchain.image_extent()[0]
&& self.offset[1] + self.extent[1] <= swapchain.image_extent()[1]
&& self.layer < swapchain.image_array_layers()
}
#[allow(clippy::wrong_self_convention)]
pub(crate) fn to_vk(&self) -> ash::vk::RectLayerKHR {
let &Self {
offset,
extent,
layer,
} = self;
ash::vk::RectLayerKHR {
offset: ash::vk::Offset2D {
x: offset[0] as i32,
y: offset[1] as i32,
},
extent: ash::vk::Extent2D {
width: extent[0],
height: extent[1],
},
layer,
}
}
}
#[derive(Clone, Debug)]
pub struct SemaphorePresentInfo {
pub semaphore: Arc<Semaphore>,
pub _ne: crate::NonExhaustive,
}
impl SemaphorePresentInfo {
#[inline]
pub fn new(semaphore: Arc<Semaphore>) -> Self {
Self {
semaphore,
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref semaphore,
_ne: _,
} = self;
assert_eq!(device, semaphore.device().as_ref());
if semaphore.semaphore_type() != SemaphoreType::Binary {
return Err(Box::new(ValidationError {
context: "semaphore.semaphore_type()".into(),
problem: "is not `SemaphoreType::Binary`".into(),
vuids: &["VUID-vkQueuePresentKHR-pWaitSemaphores-03267"],
..Default::default()
}));
}
Ok(())
}
pub(crate) fn to_vk(&self) -> ash::vk::Semaphore {
let &Self {
ref semaphore,
_ne: _,
} = self;
semaphore.handle()
}
}
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
pub struct PresentFuture<P>
where
P: GpuFuture,
{
previous: P,
queue: Arc<Queue>,
swapchain_info: SwapchainPresentInfo,
flushed: AtomicBool,
finished: AtomicBool,
}
impl<P> PresentFuture<P>
where
P: GpuFuture,
{
pub fn image_id(&self) -> u32 {
self.swapchain_info.image_index
}
pub fn swapchain(&self) -> &Arc<Swapchain> {
&self.swapchain_info.swapchain
}
}
unsafe impl<P> GpuFuture for PresentFuture<P>
where
P: GpuFuture,
{
fn cleanup_finished(&mut self) {
self.previous.cleanup_finished();
}
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, Validated<VulkanError>> {
if self.flushed.load(Ordering::SeqCst) {
return Ok(SubmitAnyBuilder::Empty);
}
let mut swapchain_info = self.swapchain_info.clone();
debug_assert!(swapchain_info.image_index < swapchain_info.swapchain.image_count());
let device = swapchain_info.swapchain.device();
if !device.enabled_features().present_id {
swapchain_info.present_id = None;
}
if device.enabled_extensions().khr_incremental_present {
for rectangle in &swapchain_info.present_region {
assert!(rectangle.is_compatible_with(swapchain_info.swapchain.as_ref()));
}
} else {
swapchain_info.present_region = Default::default();
}
let _queue = self.previous.queue();
Ok(match unsafe { self.previous.build_submission() }? {
SubmitAnyBuilder::Empty => SubmitAnyBuilder::QueuePresent(PresentInfo {
swapchain_infos: vec![self.swapchain_info.clone()],
..Default::default()
}),
SubmitAnyBuilder::SemaphoresWait(semaphores) => {
SubmitAnyBuilder::QueuePresent(PresentInfo {
wait_semaphores: semaphores
.into_iter()
.map(SemaphorePresentInfo::new)
.collect(),
swapchain_infos: vec![self.swapchain_info.clone()],
..Default::default()
})
}
SubmitAnyBuilder::CommandBuffer(_, _) => {
self.previous.flush()?;
SubmitAnyBuilder::QueuePresent(PresentInfo {
swapchain_infos: vec![self.swapchain_info.clone()],
..Default::default()
})
}
SubmitAnyBuilder::BindSparse(_, _) => {
self.previous.flush()?;
SubmitAnyBuilder::QueuePresent(PresentInfo {
swapchain_infos: vec![self.swapchain_info.clone()],
..Default::default()
})
}
SubmitAnyBuilder::QueuePresent(mut present_info) => {
if present_info.swapchain_infos.first().is_some_and(|prev| {
prev.present_mode.is_some() != self.swapchain_info.present_mode.is_some()
}) {
self.previous.flush()?;
SubmitAnyBuilder::QueuePresent(PresentInfo {
swapchain_infos: vec![self.swapchain_info.clone()],
..Default::default()
})
} else {
present_info
.swapchain_infos
.push(self.swapchain_info.clone());
SubmitAnyBuilder::QueuePresent(present_info)
}
}
})
}
fn flush(&self) -> Result<(), Validated<VulkanError>> {
let build_submission_result = unsafe { self.build_submission() };
self.flushed.store(true, Ordering::SeqCst);
match build_submission_result? {
SubmitAnyBuilder::Empty => Ok(()),
SubmitAnyBuilder::QueuePresent(present_info) => {
let PresentInfo {
wait_semaphores: _,
swapchain_infos: swapchains,
_ne: _,
} = &present_info;
for swapchain_info in swapchains {
let &SwapchainPresentInfo {
ref swapchain,
image_index: _,
present_id,
present_region: _,
present_mode: _,
_ne: _,
} = swapchain_info;
if present_id.is_some_and(|present_id| !unsafe {
swapchain.try_claim_present_id(present_id)
}) {
return Err(Box::new(ValidationError {
problem: "the provided `present_id` was not greater than any \
`present_id` passed previously for the same swapchain"
.into(),
vuids: &["VUID-VkPresentIdKHR-presentIds-04999"],
..Default::default()
})
.into());
}
}
match self.previous.check_swapchain_image_acquired(
&self.swapchain_info.swapchain,
self.swapchain_info.image_index,
true,
) {
Ok(_) => (),
Err(AccessCheckError::Unknown) => {
return Err(Box::new(ValidationError::from_error(
AccessError::SwapchainImageNotAcquired,
))
.into());
}
Err(AccessCheckError::Denied(err)) => {
return Err(Box::new(ValidationError::from_error(err)).into());
}
}
Ok(unsafe { queue_present(&self.queue, present_info) }?
.map(|r| r.map(|_| ()))
.fold(Ok(()), Result::and)?)
}
_ => unreachable!(),
}
}
unsafe fn signal_finished(&self) {
self.flushed.store(true, Ordering::SeqCst);
self.finished.store(true, Ordering::SeqCst);
unsafe { self.previous.signal_finished() };
}
fn queue_change_allowed(&self) -> bool {
false
}
fn queue(&self) -> Option<Arc<Queue>> {
debug_assert!(match self.previous.queue() {
None => true,
Some(q) => q == self.queue,
});
Some(self.queue.clone())
}
fn check_buffer_access(
&self,
buffer: &Buffer,
range: Range<DeviceSize>,
exclusive: bool,
queue: &Queue,
) -> Result<(), AccessCheckError> {
self.previous
.check_buffer_access(buffer, range, exclusive, queue)
}
fn check_image_access(
&self,
image: &Image,
range: Range<DeviceSize>,
exclusive: bool,
expected_layout: ImageLayout,
queue: &Queue,
) -> Result<(), AccessCheckError> {
if self.swapchain_info.swapchain.index_of_image(image)
== Some(self.swapchain_info.image_index)
{
Err(AccessCheckError::Unknown)
} else {
self.previous
.check_image_access(image, range, exclusive, expected_layout, queue)
}
}
#[inline]
fn check_swapchain_image_acquired(
&self,
swapchain: &Swapchain,
image_index: u32,
before: bool,
) -> Result<(), AccessCheckError> {
if before {
self.previous
.check_swapchain_image_acquired(swapchain, image_index, false)
} else if swapchain == self.swapchain_info.swapchain.as_ref()
&& image_index == self.swapchain_info.image_index
{
Err(AccessError::SwapchainImageNotAcquired.into())
} else {
self.previous
.check_swapchain_image_acquired(swapchain, image_index, false)
}
}
}
unsafe impl<P> DeviceOwned for PresentFuture<P>
where
P: GpuFuture,
{
fn device(&self) -> &Arc<Device> {
self.queue.device()
}
}
impl<P> Drop for PresentFuture<P>
where
P: GpuFuture,
{
fn drop(&mut self) {
if thread::panicking() {
return;
}
if !*self.flushed.get_mut() {
self.flush().ok();
}
if !*self.finished.get_mut() {
self.queue().unwrap().with(|mut q| q.wait_idle()).unwrap();
unsafe { self.previous.signal_finished() };
}
}
}
#[deprecated(since = "0.35.0", note = "use `Swapchain::wait_for_present` instead")]
pub fn wait_for_present(
swapchain: Arc<Swapchain>,
present_id: u64,
timeout: Option<Duration>,
) -> Result<bool, Validated<VulkanError>> {
swapchain.wait_for_present(present_id.try_into().unwrap(), timeout)
}