Impl Present Wait Feature (#1965)

* impl present_wait feature

* handle timeout case

* add missing doc

* document the return type of wait_for_present

* impl check for VUID-04999

* don't enforce gt if present_id is zero

* impl PresentInfoExt

* Remove NonZeroU64 from wait_for_present in favor of an error

* fix gl-interop example

* fix docs and fmt

* PresentInfoExt -> PresentInfo, Added swapchain + index to info

* fix doc test,  didn't save file...

* fix gl-interop

* Remove Whitespace
This commit is contained in:
Austin Johnson 2022-09-17 02:38:32 -05:00 committed by GitHub
parent e0af8af960
commit 8e8482016a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 503 additions and 161 deletions

View File

@ -45,7 +45,8 @@ use vulkano::{
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -359,7 +360,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -20,7 +20,8 @@ use vulkano::{
instance::{Instance, InstanceCreateInfo},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -267,7 +268,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -37,7 +37,8 @@ use vulkano::{
image::{view::ImageView, ImageUsage},
instance::{Instance, InstanceCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -247,7 +248,13 @@ fn main() {
let future = after_future
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -41,7 +41,9 @@ mod linux {
},
render_pass::{Framebuffer, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError},
swapchain::{
AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync::{
now, ExternalSemaphoreHandleType, ExternalSemaphoreHandleTypes, FlushError, GpuFuture,
PipelineStages, Semaphore, SemaphoreCreateInfo,
@ -344,7 +346,13 @@ mod linux {
let future = future
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -39,7 +39,8 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -440,7 +441,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -37,7 +37,8 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -357,7 +358,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -46,7 +46,8 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -368,7 +369,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -50,7 +50,8 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
single_pass_renderpass,
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -441,7 +442,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -36,7 +36,8 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
single_pass_renderpass,
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -405,7 +406,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -39,7 +39,7 @@ use vulkano::{
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
acquire_next_image, AcquireError, PresentInfo, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
@ -445,7 +445,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -38,7 +38,8 @@ use vulkano::{
query::{QueryControlFlags, QueryPool, QueryPoolCreateInfo, QueryResultFlags, QueryType},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -460,7 +461,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -37,7 +37,8 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -353,7 +354,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -44,7 +44,8 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
shader::ShaderModule,
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -336,7 +337,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -43,7 +43,8 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -491,7 +492,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -37,7 +37,7 @@ use vulkano::{
GraphicsPipeline, PipelineBindPoint,
},
render_pass::{Framebuffer, FramebufferCreateInfo, Subpass},
swapchain::{PresentMode, Swapchain, SwapchainCreateInfo},
swapchain::{PresentInfo, PresentMode, Swapchain, SwapchainCreateInfo},
sync::{FenceSignalFuture, GpuFuture},
VulkanLibrary,
};
@ -534,7 +534,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_index)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_index,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
// Update this frame's future with current fence.

View File

@ -34,7 +34,8 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
shader::ShaderModule,
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -360,7 +361,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -44,7 +44,8 @@ use vulkano::{
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -443,7 +444,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -37,7 +37,8 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
sampler::{Sampler, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -358,7 +359,13 @@ fn main() {
.join(acquire_future)
.then_execute(queue.clone(), command_buffer)
.unwrap()
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -46,7 +46,8 @@ use vulkano::{
},
render_pass::{LoadOp, StoreOp},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
Version, VulkanLibrary,
@ -568,7 +569,13 @@ fn main() {
// This function does not actually present the image immediately. Instead it submits a
// present command at the end of the queue. This means that it will only be presented once
// the GPU has finished executing the command buffer that draws the triangle.
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -39,7 +39,8 @@ use vulkano::{
},
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo,
SwapchainCreationError,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -576,7 +577,13 @@ fn main() {
// This function does not actually present the image immediately. Instead it submits a
// present command at the end of the queue. This means that it will only be presented once
// the GPU has finished executing the command buffer that draws the triangle.
.then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
.then_swapchain_present(
queue.clone(),
PresentInfo {
index: image_num,
..PresentInfo::swapchain(swapchain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -19,7 +19,9 @@ use vulkano::{
format::Format,
image::{view::ImageView, ImageAccess, ImageViewAbstract},
swapchain,
swapchain::{AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError},
swapchain::{
AcquireError, PresentInfo, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
},
sync,
sync::{FlushError, GpuFuture},
};
@ -279,8 +281,10 @@ impl VulkanoWindowRenderer {
let future = after_future
.then_swapchain_present(
self.graphics_queue.clone(),
self.swap_chain.clone(),
self.image_index,
PresentInfo {
index: self.image_index,
..PresentInfo::swapchain(self.swap_chain.clone())
},
)
.then_signal_fence_and_flush();
match future {

View File

@ -9,7 +9,7 @@
use crate::{
device::{DeviceOwned, Queue},
swapchain::{PresentRegion, Swapchain},
swapchain::PresentInfo,
sync::Semaphore,
OomError, SynchronizedVulkanObject, VulkanError, VulkanObject,
};
@ -19,6 +19,7 @@ use std::{
fmt::{Debug, Display, Error as FmtError, Formatter},
marker::PhantomData,
ptr,
sync::atomic::{AtomicU64, Ordering},
};
/// Prototype for a submission that presents a swapchain on the screen.
@ -27,6 +28,8 @@ pub struct SubmitPresentBuilder<'a> {
wait_semaphores: SmallVec<[ash::vk::Semaphore; 8]>,
swapchains: SmallVec<[ash::vk::SwapchainKHR; 4]>,
image_indices: SmallVec<[u32; 4]>,
present_ids: SmallVec<[u64; 4]>,
prev_present_ids: SmallVec<[&'a AtomicU64; 4]>,
present_regions: SmallVec<[ash::vk::PresentRegionKHR; 4]>,
rect_layers: SmallVec<[ash::vk::RectLayerKHR; 4]>,
marker: PhantomData<&'a ()>,
@ -40,6 +43,8 @@ impl<'a> SubmitPresentBuilder<'a> {
wait_semaphores: SmallVec::new(),
swapchains: SmallVec::new(),
image_indices: SmallVec::new(),
present_ids: SmallVec::new(),
prev_present_ids: SmallVec::new(),
present_regions: SmallVec::new(),
rect_layers: SmallVec::new(),
marker: PhantomData,
@ -76,21 +81,25 @@ impl<'a> SubmitPresentBuilder<'a> {
///
/// If `VK_KHR_incremental_present` is not enabled, the `present_region` parameter is ignored.
///
/// If `present_id` feature is not enabled, then the `present_id` parameter is ignored.
///
/// # Safety
///
/// - If you submit this builder, the swapchain must be kept alive until you are
/// guaranteed that the GPU has finished presenting.
///
/// - The swapchains and semaphores must all belong to the same device.
///
#[inline]
pub unsafe fn add_swapchain<W>(
&mut self,
swapchain: &'a Swapchain<W>,
image_num: u32,
present_region: Option<&'a PresentRegion>,
) {
debug_assert!(image_num < swapchain.image_count());
pub unsafe fn add_swapchain<W>(&mut self, info: &'a PresentInfo<W>) {
let PresentInfo {
swapchain,
index,
present_id,
present_region,
..
} = info;
debug_assert!((*index as u32) < swapchain.image_count());
if swapchain
.device()
@ -117,8 +126,13 @@ impl<'a> SubmitPresentBuilder<'a> {
self.present_regions.push(vk_present_region);
}
if swapchain.device().enabled_features().present_id {
self.present_ids.push(present_id.unwrap_or(0));
self.prev_present_ids.push(swapchain.prev_present_id());
}
self.swapchains.push(swapchain.internal_object());
self.image_indices.push(image_num);
self.image_indices.push(*index as u32);
}
/// Submits the command. Calls `vkQueuePresentKHR`.
@ -135,7 +149,7 @@ impl<'a> SubmitPresentBuilder<'a> {
"Tried to submit a present command without any swapchain"
);
let present_regions = {
let mut present_regions = {
if !self.present_regions.is_empty() {
debug_assert!(queue.device().enabled_extensions().khr_incremental_present);
debug_assert_eq!(self.swapchains.len(), self.present_regions.len());
@ -154,16 +168,35 @@ impl<'a> SubmitPresentBuilder<'a> {
}
};
let mut results = vec![ash::vk::Result::SUCCESS; self.swapchains.len()];
let mut present_ids = {
if !self.present_ids.is_empty() {
debug_assert!(queue.device().enabled_features().present_id);
debug_assert_eq!(self.swapchains.len(), self.present_ids.len());
// VUID-VkPresentIdKHR-presentIds-04999
for (id, prev_id) in self.present_ids.iter().zip(self.prev_present_ids.iter()) {
if *id != 0 {
if prev_id.fetch_max(*id, Ordering::SeqCst) >= *id {
return Err(SubmitPresentError::PresentIdLessThanOrEqual);
}
}
}
Some(ash::vk::PresentIdKHR {
swapchain_count: self.swapchains.len() as u32,
p_present_ids: self.present_ids.as_ptr(),
..Default::default()
})
} else {
None
}
};
let mut results = vec![ash::vk::Result::SUCCESS; self.swapchains.len()];
let fns = queue.device().fns();
let queue = queue.internal_object_guard();
let infos = ash::vk::PresentInfoKHR {
p_next: present_regions
.as_ref()
.map(|pr| pr as *const ash::vk::PresentRegionsKHR as *const _)
.unwrap_or(ptr::null()),
let mut present_info = ash::vk::PresentInfoKHR {
wait_semaphore_count: self.wait_semaphores.len() as u32,
p_wait_semaphores: self.wait_semaphores.as_ptr(),
swapchain_count: self.swapchains.len() as u32,
@ -173,7 +206,17 @@ impl<'a> SubmitPresentBuilder<'a> {
..Default::default()
};
(fns.khr_swapchain.queue_present_khr)(*queue, &infos)
if let Some(present_regions) = present_regions.as_mut() {
present_regions.p_next = present_info.p_next as *mut _;
present_info.p_next = present_regions as *const _ as *const _;
}
if let Some(present_ids) = present_ids.as_mut() {
present_ids.p_next = present_info.p_next as *mut _;
present_info.p_next = present_ids as *const _ as *const _;
}
(fns.khr_swapchain.queue_present_khr)(*queue, &present_info)
.result()
.map_err(VulkanError::from)?;
@ -216,6 +259,10 @@ pub enum SubmitPresentError {
/// The surface has changed in a way that makes the swapchain unusable. You must query the
/// surface's new properties and recreate a new swapchain if you want to continue drawing.
OutOfDate,
/// A non-zero present_id must be greater than any non-zero present_id passed previously
/// for the same swapchain.
PresentIdLessThanOrEqual,
}
impl Error for SubmitPresentError {
@ -243,6 +290,9 @@ impl Display for SubmitPresentError {
SubmitPresentError::FullScreenExclusiveModeLost => {
"the swapchain no longer has full-screen exclusivity"
}
SubmitPresentError::PresentIdLessThanOrEqual => {
"present id is less than or equal to previous"
}
}
)
}

View File

@ -607,6 +607,7 @@ impl Device {
/// # Safety
///
/// - `file` must be a handle to external memory that was created outside the Vulkan API.
#[cfg_attr(not(unix), allow(unused_variables))]
pub unsafe fn memory_fd_properties(
&self,
handle_type: ExternalMemoryHandleType,

View File

@ -243,7 +243,7 @@
//! command to present the image on the screen after the draw operations are finished.
//!
//! ```
//! use vulkano::swapchain;
//! use vulkano::swapchain::{self, PresentInfo};
//! use vulkano::sync::GpuFuture;
//! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return;
//! # let mut swapchain: ::std::sync::Arc<swapchain::Swapchain<()>> = return;
@ -257,7 +257,13 @@
//! // constructed from images[image_num]
//! acquire_future
//! .then_execute(queue.clone(), command_buffer).unwrap()
//! .then_swapchain_present(queue.clone(), swapchain.clone(), image_num)
//! .then_swapchain_present(
//! queue.clone(),
//! PresentInfo {
//! index: image_num,
//! .. PresentInfo::swapchain(swapchain.clone())
//! },
//! )
//! .then_signal_fence_and_flush().unwrap();
//! }
//! ```
@ -276,7 +282,7 @@
//!
//! ```
//! use vulkano::swapchain;
//! use vulkano::swapchain::{AcquireError, SwapchainCreateInfo};
//! use vulkano::swapchain::{AcquireError, SwapchainCreateInfo, PresentInfo};
//! use vulkano::sync::GpuFuture;
//!
//! // let (swapchain, images) = Swapchain::new(...);
@ -307,7 +313,13 @@
//!
//! let final_future = acq_future
//! // .then_execute(...)
//! .then_swapchain_present(queue.clone(), swapchain.clone(), index)
//! .then_swapchain_present(
//! queue.clone(),
//! PresentInfo {
//! index,
//! .. PresentInfo::swapchain(swapchain.clone())
//! },
//! )
//! .then_signal_fence_and_flush().unwrap(); // TODO: PresentError?
//!
//! if suboptimal {
@ -325,9 +337,10 @@ pub use self::{
SurfaceInfo, SurfaceTransform,
},
swapchain::{
acquire_next_image, acquire_next_image_raw, present, present_incremental, AcquireError,
AcquiredImage, FullScreenExclusive, FullScreenExclusiveError, PresentFuture, Swapchain,
SwapchainAcquireFuture, SwapchainCreateInfo, SwapchainCreationError, Win32Monitor,
acquire_next_image, acquire_next_image_raw, present, wait_for_present, AcquireError,
AcquiredImage, FullScreenExclusive, FullScreenExclusiveError, PresentFuture, PresentInfo,
PresentWaitError, Swapchain, SwapchainAcquireFuture, SwapchainCreateInfo,
SwapchainCreationError, Win32Monitor,
},
};
#[cfg(target_os = "ios")]

View File

@ -12,7 +12,7 @@ use crate::swapchain::Swapchain;
/// Represents a region on an image.
///
/// A region consists of an arbitrary amount of rectangles.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PresentRegion {
pub rectangles: Vec<RectangleLayer>,
}

View File

@ -43,7 +43,7 @@ use std::{
ops::Range,
ptr,
sync::{
atomic::{AtomicBool, Ordering},
atomic::{AtomicBool, AtomicU64, Ordering},
Arc,
},
time::Duration,
@ -69,6 +69,7 @@ pub struct Swapchain<W> {
clipped: bool,
full_screen_exclusive: FullScreenExclusive,
win32_monitor: Option<Win32Monitor>,
prev_present_id: AtomicU64,
// Whether full-screen exclusive is currently held.
full_screen_exclusive_held: AtomicBool,
@ -173,6 +174,7 @@ impl<W> Swapchain<W> {
clipped,
full_screen_exclusive,
win32_monitor,
prev_present_id: Default::default(),
full_screen_exclusive_held: AtomicBool::new(false),
images,
@ -267,6 +269,7 @@ impl<W> Swapchain<W> {
clipped,
full_screen_exclusive,
win32_monitor,
prev_present_id: Default::default(),
full_screen_exclusive_held: AtomicBool::new(full_screen_exclusive_held),
images,
@ -898,6 +901,10 @@ impl<W> Swapchain<W> {
false
}
}
pub(crate) fn prev_present_id(&self) -> &AtomicU64 {
&self.prev_present_id
}
}
impl<W> Drop for Swapchain<W> {
@ -1491,23 +1498,54 @@ pub fn acquire_next_image<W>(
))
}
/// Parameters for
/// [`swapchain::present`](crate::swapchain::present)
/// and
/// [`GpuFuture::then_swapchain_present`](crate::sync::GpuFuture::then_swapchain_present).
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct PresentInfo<W> {
/// The `Swapchain` to present to.
pub swapchain: Arc<Swapchain<W>>,
/// The same index that `acquire_next_image` returned. The image must have been acquired first.
pub index: usize,
/// A present id used for this present call.
///
/// Must be greater than previously used.
///
/// If this value is zero it is equivalent to `None`.
///
/// If the `present_id` feature is not enabled on the device, the parameter will be ignored.
pub present_id: Option<u64>,
/// Areas outside the present region may be ignored by Vulkan in order to optimize presentation.
///
/// This is just an optimization hint, as the Vulkan driver is free to ignore the given present region.
///
/// If `khr_incremental_present` extension is not enabled on the device, the parameter will be ignored.
pub present_region: Option<PresentRegion>,
pub _ne: crate::NonExhaustive,
}
impl<W> PresentInfo<W> {
pub fn swapchain(swapchain: Arc<Swapchain<W>>) -> Self {
Self {
swapchain,
index: 0,
present_id: None,
present_region: None,
_ne: crate::NonExhaustive(()),
}
}
}
/// Presents an image on the screen.
///
/// The parameter is the same index as what `acquire_next_image` returned. The image must
/// have been acquired first.
///
/// The actual behavior depends on the present mode that you passed when creating the
/// swapchain.
pub fn present<F, W>(
swapchain: Arc<Swapchain<W>>,
before: F,
queue: Arc<Queue>,
index: usize,
) -> PresentFuture<F, W>
pub fn present<F, W>(before: F, queue: Arc<Queue>, info: PresentInfo<W>) -> PresentFuture<F, W>
where
F: GpuFuture,
{
assert!(index < swapchain.images.len());
assert!(info.index < info.swapchain.images.len());
// TODO: restore this check with a dummy ImageAccess implementation
/*let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap(); // TODO: return error instead
@ -1519,47 +1557,69 @@ where
PresentFuture {
previous: before,
queue,
swapchain,
image_id: index,
present_region: None,
info,
flushed: AtomicBool::new(false),
finished: AtomicBool::new(false),
}
}
/// Same as `swapchain::present`, except it allows specifying a present region.
/// Areas outside the present region may be ignored by Vulkan in order to optimize presentation.
/// Wait for an image to be presented to the user. Must be used with a `present_id` given to `present_with_id`.
///
/// This is just an optimization hint, as the Vulkan driver is free to ignore the given present region.
///
/// If `VK_KHR_incremental_present` is not enabled on the device, the parameter will be ignored.
pub fn present_incremental<F, W>(
/// Returns a bool to represent if the presentation was suboptimal. In this case the swapchain is still
/// usable, but the swapchain should be recreated as the Surface's properties no longer match the swapchain.
pub fn wait_for_present<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());
present_id: u64,
timeout: Option<Duration>,
) -> Result<bool, PresentWaitError> {
let retired = swapchain.retired.lock();
// TODO: restore this check with a dummy ImageAccess implementation
/*let swapchain_image = me.images.lock().unwrap().get(index).unwrap().0.upgrade().unwrap(); // TODO: return error instead
// Normally if `check_image_access` returns false we're supposed to call the `gpu_access`
// function on the image instead. But since we know that this method on `SwapchainImage`
// always returns false anyway (by design), we don't need to do it.
assert!(before.check_image_access(&swapchain_image, ImageLayout::PresentSrc, true, &queue).is_ok()); // TODO: return error instead*/
// VUID-vkWaitForPresentKHR-swapchain-04997
if *retired {
return Err(PresentWaitError::OutOfDate);
}
PresentFuture {
previous: before,
queue,
swapchain,
image_id: index,
present_region: Some(present_region),
flushed: AtomicBool::new(false),
finished: AtomicBool::new(false),
if present_id == 0 {
return Err(PresentWaitError::PresentIdZero);
}
// VUID-vkWaitForPresentKHR-presentWait-06234
if !swapchain.device.enabled_features().present_wait {
return Err(PresentWaitError::RequirementNotMet {
required_for: "`wait_for_present`",
requires_one_of: RequiresOneOf {
features: &["present_wait"],
..Default::default()
},
});
}
let timeout_ns = timeout.map(|dur| dur.as_nanos() as u64).unwrap_or(0);
let result = unsafe {
(swapchain.device.fns().khr_present_wait.wait_for_present_khr)(
swapchain.device.internal_object(),
swapchain.handle,
present_id.into(),
timeout_ns,
)
};
match result {
ash::vk::Result::SUCCESS => Ok(false),
ash::vk::Result::SUBOPTIMAL_KHR => Ok(true),
ash::vk::Result::TIMEOUT => return Err(PresentWaitError::Timeout),
err => {
let err = VulkanError::from(err).into();
if let PresentWaitError::FullScreenExclusiveModeLost = &err {
swapchain
.full_screen_exclusive_held
.store(false, Ordering::SeqCst);
}
Err(err)
}
}
}
@ -1790,6 +1850,106 @@ impl From<VulkanError> for AcquireError {
}
}
/// Error that can happen when calling `acquire_next_image`.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(u32)]
pub enum PresentWaitError {
/// Not enough memory.
OomError(OomError),
/// The connection to the device has been lost.
DeviceLost,
/// The surface has changed in a way that makes the swapchain unusable. You must query the
/// surface's new properties and recreate a new swapchain if you want to continue drawing.
OutOfDate,
/// The surface is no longer accessible and must be recreated.
SurfaceLost,
/// The swapchain has lost or doesn't have full-screen exclusivity possibly for
/// implementation-specific reasons outside of the applications control.
FullScreenExclusiveModeLost,
/// The timeout of the function has been reached before the present occured.
Timeout,
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// Present id of zero is invalid.
PresentIdZero,
}
impl Error for PresentWaitError {
#[inline]
fn source(&self) -> Option<&(dyn Error + 'static)> {
match *self {
Self::OomError(ref err) => Some(err),
_ => None,
}
}
}
impl Display for PresentWaitError {
#[inline]
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
match *self {
Self::OomError(e) => write!(f, "{}", e),
Self::DeviceLost => write!(f, "the connection to the device has been lost"),
Self::Timeout => write!(f, "no image is available for acquiring yet"),
Self::SurfaceLost => write!(f, "the surface of this swapchain is no longer valid"),
Self::OutOfDate => write!(f, "the swapchain needs to be recreated"),
Self::FullScreenExclusiveModeLost => {
write!(f, "the swapchain no longer has full-screen exclusivity")
}
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::PresentIdZero => write!(f, "present id of zero is invalid"),
}
}
}
impl From<OomError> for PresentWaitError {
#[inline]
fn from(err: OomError) -> PresentWaitError {
Self::OomError(err)
}
}
impl From<RequirementNotMet> for PresentWaitError {
#[inline]
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
impl From<VulkanError> for PresentWaitError {
#[inline]
fn from(err: VulkanError) -> PresentWaitError {
match err {
err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)),
err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
VulkanError::DeviceLost => Self::DeviceLost,
VulkanError::SurfaceLost => Self::SurfaceLost,
VulkanError::OutOfDate => Self::OutOfDate,
VulkanError::FullScreenExclusiveModeLost => Self::FullScreenExclusiveModeLost,
_ => panic!("unexpected error: {:?}", err),
}
}
}
/// Represents a swapchain image being presented on the screen.
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
pub struct PresentFuture<P, W>
@ -1798,9 +1958,7 @@ where
{
previous: P,
queue: Arc<Queue>,
swapchain: Arc<Swapchain<W>>,
image_id: usize,
present_region: Option<PresentRegion>,
info: PresentInfo<W>,
// True if `flush()` has been called on the future, which means that the present command has
// been submitted.
flushed: AtomicBool,
@ -1816,13 +1974,13 @@ where
/// Returns the index of the image in the list of images returned when creating the swapchain.
#[inline]
pub fn image_id(&self) -> usize {
self.image_id
self.info.index
}
/// Returns the corresponding swapchain.
#[inline]
pub fn swapchain(&self) -> &Arc<Swapchain<W>> {
&self.swapchain
&self.info.swapchain
}
}
@ -1849,20 +2007,12 @@ where
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(),
);
builder.add_swapchain(&self.info);
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(),
);
builder.add_swapchain(&self.info);
SubmitAnyBuilder::QueuePresent(builder)
}
SubmitAnyBuilder::CommandBuffer(_) => {
@ -1871,11 +2021,7 @@ where
self.previous.flush()?;
let mut builder = SubmitPresentBuilder::new();
builder.add_swapchain(
&self.swapchain,
self.image_id as u32,
self.present_region.as_ref(),
);
builder.add_swapchain(&self.info);
SubmitAnyBuilder::QueuePresent(builder)
}
SubmitAnyBuilder::BindSparse(_) => {
@ -1884,11 +2030,7 @@ where
self.previous.flush()?;
let mut builder = SubmitPresentBuilder::new();
builder.add_swapchain(
&self.swapchain,
self.image_id as u32,
self.present_region.as_ref(),
);
builder.add_swapchain(&self.info);
SubmitAnyBuilder::QueuePresent(builder)
}
SubmitAnyBuilder::QueuePresent(_present) => {
@ -1910,7 +2052,8 @@ where
self.flushed.store(true, Ordering::SeqCst);
if let &Err(FlushError::FullScreenExclusiveModeLost) = &build_submission_result {
self.swapchain
self.info
.swapchain
.full_screen_exclusive_held
.store(false, Ordering::SeqCst);
}
@ -1921,7 +2064,8 @@ where
let present_result = present.submit(&self.queue);
if let &Err(SubmitPresentError::FullScreenExclusiveModeLost) = &present_result {
self.swapchain
self.info
.swapchain
.full_screen_exclusive_held
.store(false, Ordering::SeqCst);
}
@ -1978,7 +2122,8 @@ where
expected_layout: ImageLayout,
queue: &Queue,
) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> {
let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap();
let swapchain_image = self.info.swapchain.raw_image(self.info.index).unwrap();
if swapchain_image.image.internal_object() == image.internal_object() {
// This future presents the swapchain image, which "unlocks" it. Therefore any attempt
// to use this swapchain image afterwards shouldn't get granted automatic access.

View File

@ -24,7 +24,7 @@ use crate::{
},
device::{DeviceOwned, Queue},
image::{sys::UnsafeImage, ImageLayout},
swapchain::{self, PresentFuture, PresentRegion, Swapchain},
swapchain::{self, PresentFuture, PresentInfo},
DeviceSize, OomError,
};
use std::{
@ -257,30 +257,12 @@ pub unsafe trait GpuFuture: DeviceOwned {
fn then_swapchain_present<W>(
self,
queue: Arc<Queue>,
swapchain: Arc<Swapchain<W>>,
image_index: usize,
info: PresentInfo<W>,
) -> PresentFuture<Self, W>
where
Self: Sized,
{
swapchain::present(swapchain, self, queue, image_index)
}
/// Same as `then_swapchain_present`, except it allows specifying a present region.
///
/// > **Note**: This is just a shortcut for the `Swapchain::present_incremental()` function.
#[inline]
fn then_swapchain_present_incremental<W>(
self,
queue: Arc<Queue>,
swapchain: Arc<Swapchain<W>>,
image_index: usize,
present_region: PresentRegion,
) -> PresentFuture<Self, W>
where
Self: Sized,
{
swapchain::present_incremental(swapchain, self, queue, image_index, present_region)
swapchain::present(self, queue, info)
}
/// Turn the current future into a `Box<dyn GpuFuture>`.
@ -499,6 +481,10 @@ pub enum FlushError {
/// The flush operation needed to block, but the timeout has elapsed.
Timeout,
/// A non-zero present_id must be greater than any non-zero present_id passed previously
/// for the same swapchain.
PresentIdLessThanOrEqual,
}
impl Error for FlushError {
@ -531,6 +517,9 @@ impl Display for FlushError {
"the flush operation needed to block, but the timeout has \
elapsed"
}
FlushError::PresentIdLessThanOrEqual => {
"present id is less than or equal to previous"
}
}
)
}
@ -554,6 +543,7 @@ impl From<SubmitPresentError> for FlushError {
SubmitPresentError::FullScreenExclusiveModeLost => {
FlushError::FullScreenExclusiveModeLost
}
SubmitPresentError::PresentIdLessThanOrEqual => FlushError::PresentIdLessThanOrEqual,
}
}
}