From 0ee73a619b45643473b63665256c0324a33d2960 Mon Sep 17 00:00:00 2001 From: Rua Date: Thu, 22 Sep 2022 13:50:39 +0200 Subject: [PATCH] Queue operations refactoring --- examples/src/bin/buffer-pool.rs | 15 +- examples/src/bin/clear_attachments.rs | 15 +- examples/src/bin/deferred/main.rs | 18 +- examples/src/bin/gl-interop.rs | 21 +- examples/src/bin/image-self-copy-blit/main.rs | 15 +- examples/src/bin/image/main.rs | 15 +- examples/src/bin/immutable-sampler/main.rs | 15 +- examples/src/bin/indirect.rs | 15 +- examples/src/bin/instancing.rs | 15 +- examples/src/bin/multi-window.rs | 15 +- examples/src/bin/occlusion-query.rs | 15 +- examples/src/bin/push-descriptors/main.rs | 15 +- examples/src/bin/runtime-shader/main.rs | 15 +- examples/src/bin/runtime_array/main.rs | 15 +- examples/src/bin/simple-particles.rs | 21 +- examples/src/bin/teapot/main.rs | 15 +- examples/src/bin/tessellation.rs | 15 +- examples/src/bin/texture_array/main.rs | 15 +- examples/src/bin/triangle-v1_3.rs | 13 +- examples/src/bin/triangle.rs | 15 +- vulkano-util/src/renderer.rs | 39 +- vulkano/src/buffer/device_local.rs | 5 +- vulkano/src/command_buffer/mod.rs | 74 ++ .../src/command_buffer/submit/bind_sparse.rs | 316 +++----- vulkano/src/command_buffer/submit/mod.rs | 12 +- .../command_buffer/submit/queue_present.rs | 182 ++--- .../src/command_buffer/submit/queue_submit.rs | 127 ++-- .../command_buffer/submit/semaphores_wait.rs | 21 +- vulkano/src/command_buffer/traits.rs | 29 +- vulkano/src/device/mod.rs | 2 +- vulkano/src/device/queue.rs | 696 +++++++++++++++++- vulkano/src/image/immutable.rs | 19 +- vulkano/src/image/swapchain.rs | 20 +- vulkano/src/memory/device_memory.rs | 6 + vulkano/src/memory/mod.rs | 167 ++++- vulkano/src/swapchain/mod.rs | 160 +++- vulkano/src/swapchain/present_region.rs | 69 -- vulkano/src/swapchain/swapchain.rs | 401 +++++----- vulkano/src/sync/future/fence_signal.rs | 16 +- vulkano/src/sync/future/mod.rs | 14 +- vulkano/src/sync/future/semaphore_signal.rs | 14 +- 41 files changed, 1716 insertions(+), 986 deletions(-) delete mode 100644 vulkano/src/swapchain/present_region.rs diff --git a/examples/src/bin/buffer-pool.rs b/examples/src/bin/buffer-pool.rs index 8487178bb6..952a9974bc 100644 --- a/examples/src/bin/buffer-pool.rs +++ b/examples/src/bin/buffer-pool.rs @@ -45,8 +45,8 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, SwapchainCreateInfo, + SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -281,7 +281,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -339,7 +339,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -362,10 +364,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/clear_attachments.rs b/examples/src/bin/clear_attachments.rs index ff19d1fb9a..000959a394 100644 --- a/examples/src/bin/clear_attachments.rs +++ b/examples/src/bin/clear_attachments.rs @@ -20,8 +20,8 @@ use vulkano::{ instance::{Instance, InstanceCreateInfo}, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, SwapchainCreateInfo, + SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -198,7 +198,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -222,7 +222,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -270,10 +272,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/deferred/main.rs b/examples/src/bin/deferred/main.rs index 4428e0c195..bf1932515f 100644 --- a/examples/src/bin/deferred/main.rs +++ b/examples/src/bin/deferred/main.rs @@ -37,8 +37,8 @@ use vulkano::{ image::{view::ImageView, ImageUsage}, instance::{Instance, InstanceCreateInfo}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, SwapchainCreateInfo, + SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -209,7 +209,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -224,8 +224,11 @@ fn main() { } let future = previous_frame_end.take().unwrap().join(acquire_future); - let mut frame = - frame_system.frame(future, images[image_num].clone(), Matrix4::identity()); + let mut frame = frame_system.frame( + future, + images[image_index as usize].clone(), + Matrix4::identity(), + ); let mut after_future = None; while let Some(pass) = frame.next_pass() { match pass { @@ -250,10 +253,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/gl-interop.rs b/examples/src/bin/gl-interop.rs index b9683f846b..10e84f95b2 100644 --- a/examples/src/bin/gl-interop.rs +++ b/examples/src/bin/gl-interop.rs @@ -44,7 +44,8 @@ mod linux { render_pass::{Framebuffer, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, swapchain::{ - AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, SwapchainCreationError, + AcquireError, Swapchain, SwapchainAbstract, SwapchainCreateInfo, + SwapchainCreationError, SwapchainPresentInfo, }, sync::{ now, ExternalSemaphoreHandleType, ExternalSemaphoreHandleTypes, FlushError, GpuFuture, @@ -255,7 +256,7 @@ mod linux { Event::RedrawEventsCleared => { unsafe { let mut builder = SubmitCommandBufferBuilder::new(); - builder.add_signal_semaphore(&acquire_sem); + builder.add_signal_semaphore(acquire_sem.clone()); builder.submit(&queue).unwrap(); }; @@ -265,7 +266,7 @@ mod linux { unsafe { let mut builder = SubmitCommandBufferBuilder::new(); builder.add_wait_semaphore( - &release_sem, + release_sem.clone(), PipelineStages { all_commands: true, ..PipelineStages::empty() @@ -298,7 +299,7 @@ mod linux { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match vulkano::swapchain::acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -322,7 +323,9 @@ mod linux { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -349,10 +352,10 @@ mod linux { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index( + swapchain.clone(), + image_index, + ), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/image-self-copy-blit/main.rs b/examples/src/bin/image-self-copy-blit/main.rs index 7ecb6a642a..46698df533 100644 --- a/examples/src/bin/image-self-copy-blit/main.rs +++ b/examples/src/bin/image-self-copy-blit/main.rs @@ -39,8 +39,8 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -391,7 +391,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -415,7 +415,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -443,10 +445,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/image/main.rs b/examples/src/bin/image/main.rs index 669e49a875..e96c8b6672 100644 --- a/examples/src/bin/image/main.rs +++ b/examples/src/bin/image/main.rs @@ -37,8 +37,8 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -308,7 +308,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -332,7 +332,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -360,10 +362,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/immutable-sampler/main.rs b/examples/src/bin/immutable-sampler/main.rs index d4154ef397..a228b8af47 100644 --- a/examples/src/bin/immutable-sampler/main.rs +++ b/examples/src/bin/immutable-sampler/main.rs @@ -46,8 +46,8 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -319,7 +319,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -343,7 +343,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -371,10 +373,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/indirect.rs b/examples/src/bin/indirect.rs index 34a8b53c9d..eb7f9e647e 100644 --- a/examples/src/bin/indirect.rs +++ b/examples/src/bin/indirect.rs @@ -50,8 +50,8 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, single_pass_renderpass, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -357,7 +357,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -420,7 +420,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -444,10 +446,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/instancing.rs b/examples/src/bin/instancing.rs index 07fbaabb0a..93423629c2 100644 --- a/examples/src/bin/instancing.rs +++ b/examples/src/bin/instancing.rs @@ -36,8 +36,8 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, single_pass_renderpass, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -356,7 +356,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -380,7 +380,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -408,10 +410,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/multi-window.rs b/examples/src/bin/multi-window.rs index 58299a35c7..4469539700 100644 --- a/examples/src/bin/multi-window.rs +++ b/examples/src/bin/multi-window.rs @@ -39,8 +39,8 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Surface, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Surface, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -400,7 +400,7 @@ fn main() { *recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -425,7 +425,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -447,10 +449,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/occlusion-query.rs b/examples/src/bin/occlusion-query.rs index 0fd4e361e3..50ad4ee4bf 100644 --- a/examples/src/bin/occlusion-query.rs +++ b/examples/src/bin/occlusion-query.rs @@ -38,8 +38,8 @@ use vulkano::{ query::{QueryControlFlags, QueryPool, QueryPoolCreateInfo, QueryResultFlags, QueryType}, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -363,7 +363,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -396,7 +396,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into()), Some(1.0.into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -463,10 +465,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/push-descriptors/main.rs b/examples/src/bin/push-descriptors/main.rs index ae14f1b24b..e17d102668 100644 --- a/examples/src/bin/push-descriptors/main.rs +++ b/examples/src/bin/push-descriptors/main.rs @@ -37,8 +37,8 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -304,7 +304,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -328,7 +328,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -356,10 +358,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/runtime-shader/main.rs b/examples/src/bin/runtime-shader/main.rs index 824eada7b2..c42e4e86a5 100644 --- a/examples/src/bin/runtime-shader/main.rs +++ b/examples/src/bin/runtime-shader/main.rs @@ -44,8 +44,8 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, shader::ShaderModule, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -293,7 +293,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -317,7 +317,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -339,10 +341,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/runtime_array/main.rs b/examples/src/bin/runtime_array/main.rs index 97895ca9d0..41d71d052e 100644 --- a/examples/src/bin/runtime_array/main.rs +++ b/examples/src/bin/runtime_array/main.rs @@ -43,8 +43,8 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -442,7 +442,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -466,7 +466,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -494,10 +496,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/simple-particles.rs b/examples/src/bin/simple-particles.rs index eada17a100..11372922bb 100644 --- a/examples/src/bin/simple-particles.rs +++ b/examples/src/bin/simple-particles.rs @@ -37,7 +37,9 @@ use vulkano::{ GraphicsPipeline, PipelineBindPoint, }, render_pass::{Framebuffer, FramebufferCreateInfo, Subpass}, - swapchain::{PresentInfo, PresentMode, Swapchain, SwapchainCreateInfo}, + swapchain::{ + PresentMode, Swapchain, SwapchainAbstract, SwapchainCreateInfo, SwapchainPresentInfo, + }, sync::{FenceSignalFuture, GpuFuture}, VulkanLibrary, }; @@ -432,7 +434,7 @@ fn main() { .unwrap(); let mut fences: Vec>>> = vec![None; framebuffers.len()]; - let mut previous_fence_index = 0; + let mut previous_fence_index = 0u32; let start_time = SystemTime::now(); let mut last_frame_time = start_time; @@ -481,12 +483,12 @@ fn main() { // If this image buffer already has a future then attempt to cleanup fence resources. // Usually the future for this index will have completed by the time we are rendering it again. - if let Some(image_fence) = &mut fences[image_index] { + if let Some(image_fence) = &mut fences[image_index as usize] { image_fence.cleanup_finished() } // If the previous image has a fence then use it for synchronization, else create a new one. - let previous_future = match fences[previous_fence_index].clone() { + let previous_future = match fences[previous_fence_index as usize].clone() { // Ensure current frame is synchronized with previous. Some(fence) => fence.boxed(), @@ -517,7 +519,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0., 0., 0., 1.].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_index].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -536,15 +540,12 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_index, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); // Update this frame's future with current fence. - fences[image_index] = match future { + fences[image_index as usize] = match future { // Success, store result into vector. Ok(future) => Some(Arc::new(future)), diff --git a/examples/src/bin/teapot/main.rs b/examples/src/bin/teapot/main.rs index 7d382b465e..93f29eab65 100644 --- a/examples/src/bin/teapot/main.rs +++ b/examples/src/bin/teapot/main.rs @@ -34,8 +34,8 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, shader::ShaderModule, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -308,7 +308,7 @@ fn main() { ) .unwrap(); - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -335,7 +335,9 @@ fn main() { Some([0.0, 0.0, 1.0, 1.0].into()), Some(1f32.into()), ], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -363,10 +365,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/tessellation.rs b/examples/src/bin/tessellation.rs index d94bfd6ffb..6e7097d689 100644 --- a/examples/src/bin/tessellation.rs +++ b/examples/src/bin/tessellation.rs @@ -44,8 +44,8 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -400,7 +400,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -424,7 +424,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 0.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -446,10 +448,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/texture_array/main.rs b/examples/src/bin/texture_array/main.rs index db13a326ac..1848ba33d9 100644 --- a/examples/src/bin/texture_array/main.rs +++ b/examples/src/bin/texture_array/main.rs @@ -37,8 +37,8 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, sampler::{Sampler, SamplerCreateInfo}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -309,7 +309,7 @@ fn main() { recreate_swapchain = false; } - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -333,7 +333,9 @@ fn main() { .begin_render_pass( RenderPassBeginInfo { clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, SubpassContents::Inline, ) @@ -361,10 +363,7 @@ fn main() { .unwrap() .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/triangle-v1_3.rs b/examples/src/bin/triangle-v1_3.rs index e2bd4e55ee..55ae0b4678 100644 --- a/examples/src/bin/triangle-v1_3.rs +++ b/examples/src/bin/triangle-v1_3.rs @@ -46,8 +46,8 @@ use vulkano::{ }, render_pass::{LoadOp, StoreOp}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, Version, VulkanLibrary, @@ -479,7 +479,7 @@ fn main() { // // This function can block if no image is available. The parameter is an optional timeout // after which the function call will return an error. - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -535,7 +535,7 @@ fn main() { ..RenderingAttachmentInfo::image_view( // We specify image view corresponding to the currently acquired // swapchain image, to use for this attachment. - attachment_image_views[image_num].clone(), + attachment_image_views[image_index as usize].clone(), ) })], ..Default::default() @@ -571,10 +571,7 @@ fn main() { // the GPU has finished executing the command buffer that draws the triangle. .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/examples/src/bin/triangle.rs b/examples/src/bin/triangle.rs index 37767ab6fb..87024b974e 100644 --- a/examples/src/bin/triangle.rs +++ b/examples/src/bin/triangle.rs @@ -39,8 +39,8 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, PresentInfo, Swapchain, SwapchainCreateInfo, - SwapchainCreationError, + acquire_next_image, AcquireError, Swapchain, SwapchainAbstract, + SwapchainCreateInfo, SwapchainCreationError, SwapchainPresentInfo, }, sync::{self, FlushError, GpuFuture}, VulkanLibrary, @@ -496,7 +496,7 @@ fn main() { // // This function can block if no image is available. The parameter is an optional timeout // after which the function call will return an error. - let (image_num, suboptimal, acquire_future) = + let (image_index, suboptimal, acquire_future) = match acquire_next_image(swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { @@ -540,7 +540,9 @@ fn main() { // Only attachments that have `LoadOp::Clear` are provided with clear // values, any others should use `ClearValue::None` as the clear value. clear_values: vec![Some([0.0, 0.0, 1.0, 1.0].into())], - ..RenderPassBeginInfo::framebuffer(framebuffers[image_num].clone()) + ..RenderPassBeginInfo::framebuffer( + framebuffers[image_index as usize].clone(), + ) }, // The contents of the first (and only) subpass. This can be either // `Inline` or `SecondaryCommandBuffers`. The latter is a bit more advanced @@ -579,10 +581,7 @@ fn main() { // the GPU has finished executing the command buffer that draws the triangle. .then_swapchain_present( queue.clone(), - PresentInfo { - index: image_num, - ..PresentInfo::swapchain(swapchain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), ) .then_signal_fence_and_flush(); diff --git a/vulkano-util/src/renderer.rs b/vulkano-util/src/renderer.rs index 3c003c30cb..950ac76f26 100644 --- a/vulkano-util/src/renderer.rs +++ b/vulkano-util/src/renderer.rs @@ -14,14 +14,13 @@ use crate::context::VulkanoContext; use crate::window::WindowDescriptor; use vulkano::device::Device; use vulkano::image::{ImageUsage, StorageImage, SwapchainImage}; +use vulkano::swapchain::SwapchainPresentInfo; use vulkano::{ device::Queue, format::Format, image::{view::ImageView, ImageAccess, ImageViewAbstract}, swapchain, - swapchain::{ - AcquireError, PresentInfo, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError, - }, + swapchain::{AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError}, sync, sync::{FlushError, GpuFuture}, }; @@ -47,14 +46,14 @@ pub struct VulkanoWindowRenderer { surface: Arc>, graphics_queue: Arc, compute_queue: Arc, - swap_chain: Arc>, + swapchain: Arc>, final_views: Vec, /// Additional image views that you can add which are resized with the window. /// Use associated functions to get access to these. additional_image_views: HashMap, recreate_swapchain: bool, previous_frame_end: Option>, - image_index: usize, + image_index: u32, present_mode: vulkano::swapchain::PresentMode, } @@ -85,7 +84,7 @@ impl VulkanoWindowRenderer { surface, graphics_queue: vulkano_context.graphics_queue().clone(), compute_queue: vulkano_context.compute_queue().clone(), - swap_chain, + swapchain: swap_chain, final_views, additional_image_views: HashMap::default(), recreate_swapchain: false, @@ -154,11 +153,13 @@ impl VulkanoWindowRenderer { /// Return swapchain image format pub fn swapchain_format(&self) -> Format { - self.final_views[self.image_index].format().unwrap() + self.final_views[self.image_index as usize] + .format() + .unwrap() } /// Returns the index of last swapchain image that is the next render target - pub fn image_index(&self) -> usize { + pub fn image_index(&self) -> u32 { self.image_index } @@ -195,7 +196,7 @@ impl VulkanoWindowRenderer { /// Return the current swapchain image view pub fn swapchain_image_view(&self) -> SwapchainImageView { - self.final_views[self.image_index].clone() + self.final_views[self.image_index as usize].clone() } /// Return scale factor accounted window size @@ -253,8 +254,8 @@ impl VulkanoWindowRenderer { } // Acquire next image in the swapchain - let (image_num, suboptimal, acquire_future) = - match swapchain::acquire_next_image(self.swap_chain.clone(), None) { + let (image_index, suboptimal, acquire_future) = + match swapchain::acquire_next_image(self.swapchain.clone(), None) { Ok(r) => r, Err(AcquireError::OutOfDate) => { self.recreate_swapchain = true; @@ -266,7 +267,7 @@ impl VulkanoWindowRenderer { self.recreate_swapchain = true; } // Update our image index - self.image_index = image_num; + self.image_index = image_index; let future = self.previous_frame_end.take().unwrap().join(acquire_future); @@ -281,10 +282,10 @@ impl VulkanoWindowRenderer { let future = after_future .then_swapchain_present( self.graphics_queue.clone(), - PresentInfo { - index: self.image_index, - ..PresentInfo::swapchain(self.swap_chain.clone()) - }, + SwapchainPresentInfo::swapchain_image_index( + self.swapchain.clone(), + self.image_index, + ), ) .then_signal_fence_and_flush(); match future { @@ -317,18 +318,18 @@ impl VulkanoWindowRenderer { /// Recreates swapchain images and image views which follow the window size fn recreate_swapchain_and_views(&mut self) { let dimensions: [u32; 2] = self.window().inner_size().into(); - let (new_swapchain, new_images) = match self.swap_chain.recreate(SwapchainCreateInfo { + let (new_swapchain, new_images) = match self.swapchain.recreate(SwapchainCreateInfo { image_extent: dimensions, // Use present mode from current state present_mode: self.present_mode, - ..self.swap_chain.create_info() + ..self.swapchain.create_info() }) { Ok(r) => r, Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return, Err(e) => panic!("Failed to recreate swapchain: {:?}", e), }; - self.swap_chain = new_swapchain; + self.swapchain = new_swapchain; let new_images = new_images .into_iter() .map(|image| ImageView::new_default(image).unwrap()) diff --git a/vulkano/src/buffer/device_local.rs b/vulkano/src/buffer/device_local.rs index 349956ab45..9d9d669f8b 100644 --- a/vulkano/src/buffer/device_local.rs +++ b/vulkano/src/buffer/device_local.rs @@ -22,7 +22,7 @@ use super::{ use crate::{ command_buffer::{ AutoCommandBufferBuilder, CommandBufferBeginError, CommandBufferExecFuture, - CommandBufferUsage, CopyBufferInfo, PrimaryAutoCommandBuffer, PrimaryCommandBuffer, + CommandBufferUsage, CopyBufferInfo, PrimaryCommandBuffer, }, device::{Device, DeviceOwned, Queue}, memory::{ @@ -171,8 +171,7 @@ where } // TODO: make this prettier -type DeviceLocalBufferFromBufferFuture = - CommandBufferExecFuture; +type DeviceLocalBufferFromBufferFuture = CommandBufferExecFuture; impl DeviceLocalBuffer where diff --git a/vulkano/src/command_buffer/mod.rs b/vulkano/src/command_buffer/mod.rs index df8325a050..beb65d853c 100644 --- a/vulkano/src/command_buffer/mod.rs +++ b/vulkano/src/command_buffer/mod.rs @@ -124,6 +124,7 @@ use crate::{ macros::vulkan_enum, query::{QueryControlFlags, QueryPipelineStatisticFlags}, render_pass::{Framebuffer, Subpass}, + sync::{PipelineStages, Semaphore}, }; use bytemuck::{Pod, Zeroable}; use std::sync::Arc; @@ -395,3 +396,76 @@ impl From for ash::vk::CommandBufferUsageFlags { Self::from_raw(val as u32) } } + +/// Parameters to submit command buffers to a queue. +#[derive(Clone, Debug)] +pub struct SubmitInfo { + /// The semaphores to wait for before beginning the execution of this batch of + /// command buffer operations. + /// + /// The default value is empty. + pub wait_semaphores: Vec, + + /// The command buffers to execute. + /// + /// The default value is empty. + pub command_buffers: Vec>, + + /// The semaphores to signal after the execution of this batch of command buffer operations + /// has completed. + /// + /// The default value is empty. + pub signal_semaphores: Vec, + + pub _ne: crate::NonExhaustive, +} + +impl Default for SubmitInfo { + #[inline] + fn default() -> Self { + Self { + wait_semaphores: Vec::new(), + command_buffers: Vec::new(), + signal_semaphores: Vec::new(), + _ne: crate::NonExhaustive(()), + } + } +} + +/// Parameters for a semaphore signal or wait operation in a command buffer submission. +#[derive(Clone, Debug)] +pub struct SemaphoreSubmitInfo { + /// The semaphore to signal or wait for. + pub semaphore: Arc, + + /// For a semaphore wait operation, specifies the pipeline stages in the second synchronization + /// scope: stages of queue operations following the wait operation that can start executing + /// after the semaphore is signalled. + /// + /// For a semaphore signal operation, specifies the pipeline stages in the first synchronization + /// scope: stages of queue operations preceding the signal operation that must complete before + /// the semaphore is signalled. + /// If not set to `all_commands` only, the + /// [`synchronization2`](crate::device::Features::synchronization2) feature must be enabled + /// on the device. + /// + /// The default value has only `all_commands` set. + pub stages: PipelineStages, + + pub _ne: crate::NonExhaustive, +} + +impl SemaphoreSubmitInfo { + /// Returns a `SemaphoreSubmitInfo` with the specified `semaphore`. + #[inline] + pub fn semaphore(semaphore: Arc) -> Self { + Self { + semaphore, + stages: PipelineStages { + all_commands: true, + ..PipelineStages::empty() + }, + _ne: crate::NonExhaustive(()), + } + } +} diff --git a/vulkano/src/command_buffer/submit/bind_sparse.rs b/vulkano/src/command_buffer/submit/bind_sparse.rs index 9b2a038173..40c108bc4e 100644 --- a/vulkano/src/command_buffer/submit/bind_sparse.rs +++ b/vulkano/src/command_buffer/submit/bind_sparse.rs @@ -8,36 +8,40 @@ // according to those terms. use crate::{ - buffer::sys::UnsafeBuffer, + buffer::BufferAccess, device::Queue, - image::sys::UnsafeImage, - memory::DeviceMemory, + image::ImageAccess, + memory::{ + BindSparseInfo, DeviceMemory, SparseBufferMemoryBind, SparseImageMemoryBind, + SparseImageOpaqueMemoryBind, + }, sync::{Fence, Semaphore}, - DeviceSize, OomError, SynchronizedVulkanObject, VulkanError, VulkanObject, + DeviceSize, OomError, VulkanError, }; use smallvec::SmallVec; use std::{ error::Error, fmt::{Debug, Display, Error as FmtError, Formatter}, - marker::PhantomData, + sync::Arc, }; // TODO: correctly implement Debug on all the structs of this module /// Prototype for a submission that binds sparse memory. // TODO: example here -pub struct SubmitBindSparseBuilder<'a> { - infos: SmallVec<[SubmitBindSparseBatchBuilder<'a>; 1]>, - fence: ash::vk::Fence, +#[derive(Debug)] +pub struct SubmitBindSparseBuilder { + bind_infos: SmallVec<[BindSparseInfo; 1]>, + fence: Option>, } -impl<'a> SubmitBindSparseBuilder<'a> { +impl SubmitBindSparseBuilder { /// Builds a new empty `SubmitBindSparseBuilder`. #[inline] - pub fn new() -> SubmitBindSparseBuilder<'a> { + pub fn new() -> Self { SubmitBindSparseBuilder { - infos: SmallVec::new(), - fence: ash::vk::Fence::null(), + bind_infos: SmallVec::new(), + fence: None, } } @@ -47,8 +51,8 @@ impl<'a> SubmitBindSparseBuilder<'a> { /// wait semaphore added to a batch will apply to further batches as well, but when a semaphore /// is signalled, it does **not** mean that previous batches have been completed. #[inline] - pub fn add(&mut self, builder: SubmitBindSparseBatchBuilder<'a>) { - self.infos.push(builder); + pub fn add(&mut self, builder: SubmitBindSparseBatchBuilder) { + self.bind_infos.push(builder.bind_info); } /// Returns true if this builder will signal a fence when submitted. @@ -58,20 +62,21 @@ impl<'a> SubmitBindSparseBuilder<'a> { /// ``` /// use vulkano::command_buffer::submit::SubmitBindSparseBuilder; /// use vulkano::sync::Fence; + /// # use std::sync::Arc; /// # let device: std::sync::Arc = return; /// /// unsafe { - /// let fence = Fence::from_pool(device.clone()).unwrap(); + /// let fence = Arc::new(Fence::from_pool(device.clone()).unwrap()); /// /// let mut builder = SubmitBindSparseBuilder::new(); /// assert!(!builder.has_fence()); - /// builder.set_fence_signal(&fence); + /// builder.set_fence_signal(fence); /// assert!(builder.has_fence()); /// } /// ``` #[inline] pub fn has_fence(&self) -> bool { - self.fence != ash::vk::Fence::null() + self.fence.is_some() } /// Adds an operation that signals a fence after this submission ends. @@ -82,14 +87,15 @@ impl<'a> SubmitBindSparseBuilder<'a> { /// use std::time::Duration; /// use vulkano::command_buffer::submit::SubmitBindSparseBuilder; /// use vulkano::sync::Fence; + /// # use std::sync::Arc; /// # let device: std::sync::Arc = return; /// # let queue: std::sync::Arc = return; /// /// unsafe { - /// let fence = Fence::from_pool(device.clone()).unwrap(); + /// let fence = Arc::new(Fence::from_pool(device.clone()).unwrap()); /// /// let mut builder = SubmitBindSparseBuilder::new(); - /// builder.set_fence_signal(&fence); + /// builder.set_fence_signal(fence.clone()); /// /// builder.submit(&queue).unwrap(); /// @@ -112,8 +118,8 @@ impl<'a> SubmitBindSparseBuilder<'a> { /// - The fence, buffers, images, and semaphores must all belong to the same device. /// #[inline] - pub unsafe fn set_fence_signal(&mut self, fence: &'a Fence) { - self.fence = fence.internal_object(); + pub unsafe fn set_fence_signal(&mut self, fence: Arc) { + self.fence = Some(fence); } /// Attempts to merge this builder with another one. @@ -121,15 +127,12 @@ impl<'a> SubmitBindSparseBuilder<'a> { /// If both builders have a fence already set, then this function will return `other` as an /// error. #[inline] - pub fn merge( - &mut self, - other: SubmitBindSparseBuilder<'a>, - ) -> Result<(), SubmitBindSparseBuilder<'a>> { - if self.fence != ash::vk::Fence::null() && other.fence != ash::vk::Fence::null() { + pub fn merge(&mut self, other: SubmitBindSparseBuilder) -> Result<(), SubmitBindSparseBuilder> { + if self.fence.is_some() && other.fence.is_some() { return Err(other); } - self.infos.extend(other.infos.into_iter()); + self.bind_infos.extend(other.bind_infos.into_iter()); Ok(()) } @@ -143,162 +146,45 @@ impl<'a> SubmitBindSparseBuilder<'a> { .sparse_binding ); - let fns = queue.device().fns(); - let queue = queue.internal_object_guard(); - - // We start by storing all the `VkSparseBufferMemoryBindInfo`s of the whole command - // in the same collection. - let buffer_binds_storage: SmallVec<[_; 4]> = self - .infos - .iter() - .flat_map(|infos| infos.buffer_binds.iter()) - .map(|buf_bind| ash::vk::SparseBufferMemoryBindInfo { - buffer: buf_bind.buffer, - bind_count: buf_bind.binds.len() as u32, - p_binds: buf_bind.binds.as_ptr(), - }) - .collect(); - - // Same for all the `VkSparseImageOpaqueMemoryBindInfo`s. - let image_opaque_binds_storage: SmallVec<[_; 4]> = self - .infos - .iter() - .flat_map(|infos| infos.image_opaque_binds.iter()) - .map(|img_bind| ash::vk::SparseImageOpaqueMemoryBindInfo { - image: img_bind.image, - bind_count: img_bind.binds.len() as u32, - p_binds: img_bind.binds.as_ptr(), - }) - .collect(); - - // And finally the `VkSparseImageMemoryBindInfo`s. - let image_binds_storage: SmallVec<[_; 4]> = self - .infos - .iter() - .flat_map(|infos| infos.image_binds.iter()) - .map(|img_bind| ash::vk::SparseImageMemoryBindInfo { - image: img_bind.image, - bind_count: img_bind.binds.len() as u32, - p_binds: img_bind.binds.as_ptr(), - }) - .collect(); - - // Now building the collection of `VkBindSparseInfo`s. - let bs_infos = { - let mut bs_infos: SmallVec<[_; 4]> = SmallVec::new(); - - // Since we stores all the bind infos contiguously, we keep track of the current - // offset within these containers. - 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(ash::vk::BindSparseInfo { - wait_semaphore_count: builder.wait_semaphores.len() as u32, - p_wait_semaphores: builder.wait_semaphores.as_ptr(), - buffer_bind_count: builder.buffer_binds.len() as u32, - p_buffer_binds: if next_buffer_bind != 0 { - // We need that `if` because `.as_ptr().offset(0)` is technically UB. - buffer_binds_storage.as_ptr().offset(next_buffer_bind) - } else { - buffer_binds_storage.as_ptr() - }, - image_opaque_bind_count: builder.image_opaque_binds.len() as u32, - p_image_opaque_binds: if next_image_opaque_bind != 0 { - // We need that `if` because `.as_ptr().offset(0)` is technically UB. - image_opaque_binds_storage - .as_ptr() - .offset(next_image_opaque_bind) - } else { - image_opaque_binds_storage.as_ptr() - }, - image_bind_count: builder.image_binds.len() as u32, - p_image_binds: if next_image_bind != 0 { - // We need that `if` because `.as_ptr().offset(0)` is technically UB. - image_binds_storage.as_ptr().offset(next_image_bind) - } else { - image_binds_storage.as_ptr() - }, - signal_semaphore_count: builder.signal_semaphores.len() as u32, - p_signal_semaphores: builder.signal_semaphores.as_ptr(), - ..Default::default() - }); - - 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; - } - - // If these assertions fail, then there's something wrong in the code above. - 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 - }; - - // Finally executing the command. - (fns.v1_0.queue_bind_sparse)( - *queue, - bs_infos.len() as u32, - bs_infos.as_ptr(), - self.fence, - ) - .result() - .map_err(VulkanError::from)?; - Ok(()) + let mut queue_guard = queue.lock(); + Ok(queue_guard.bind_sparse_unchecked(self.bind_infos, self.fence)?) } } } -impl<'a> Debug for SubmitBindSparseBuilder<'a> { - #[inline] - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - write!(f, "") - } -} - /// A single batch of a sparse bind operation. -pub struct SubmitBindSparseBatchBuilder<'a> { - wait_semaphores: SmallVec<[ash::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<[ash::vk::Semaphore; 8]>, - marker: PhantomData<&'a ()>, +pub struct SubmitBindSparseBatchBuilder { + bind_info: BindSparseInfo, } -impl<'a> SubmitBindSparseBatchBuilder<'a> { +impl SubmitBindSparseBatchBuilder { /// Builds a new empty `SubmitBindSparseBatchBuilder`. #[inline] - pub fn new() -> SubmitBindSparseBatchBuilder<'a> { + pub fn new() -> Self { SubmitBindSparseBatchBuilder { - wait_semaphores: SmallVec::new(), - buffer_binds: SmallVec::new(), - image_opaque_binds: SmallVec::new(), - image_binds: SmallVec::new(), - signal_semaphores: SmallVec::new(), - marker: PhantomData, + bind_info: Default::default(), } } /// Adds an operation that binds memory to a buffer. - pub fn add_buffer(&mut self, cmd: SubmitBindSparseBufferBindBuilder<'a>) { - self.buffer_binds.push(cmd); + pub fn add_buffer(&mut self, cmd: SubmitBindSparseBufferBindBuilder) { + self.bind_info + .buffer_binds + .push((cmd.buffer, cmd.binds.into_iter().collect())); } /// Adds an operation that binds memory to an opaque image. - pub fn add_image_opaque(&mut self, cmd: SubmitBindSparseImageOpaqueBindBuilder<'a>) { - self.image_opaque_binds.push(cmd); + pub fn add_image_opaque(&mut self, cmd: SubmitBindSparseImageOpaqueBindBuilder) { + self.bind_info + .image_opaque_binds + .push((cmd.image, cmd.binds.into_iter().collect())); } /// Adds an operation that binds memory to an image. - pub fn add_image(&mut self, cmd: SubmitBindSparseImageBindBuilder<'a>) { - self.image_binds.push(cmd); + pub fn add_image(&mut self, cmd: SubmitBindSparseImageBindBuilder) { + self.bind_info + .image_binds + .push((cmd.image, cmd.binds.into_iter().collect())); } /// Adds a semaphore to be waited upon before the sparse binding is executed. @@ -319,8 +205,8 @@ impl<'a> SubmitBindSparseBatchBuilder<'a> { /// - The fence, buffers, images, and semaphores must all belong to the same device. /// #[inline] - pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore) { - self.wait_semaphores.push(semaphore.internal_object()); + pub unsafe fn add_wait_semaphore(&mut self, semaphore: Arc) { + self.bind_info.wait_semaphores.push(semaphore); } /// Returns the number of semaphores to signal. @@ -328,7 +214,7 @@ impl<'a> SubmitBindSparseBatchBuilder<'a> { /// In other words, this is the number of times `add_signal_semaphore` has been called. #[inline] pub fn num_signal_semaphores(&self) -> usize { - self.signal_semaphores.len() + self.bind_info.signal_semaphores.len() } /// Adds a semaphore that is going to be signaled at the end of the submission. @@ -344,124 +230,108 @@ impl<'a> SubmitBindSparseBatchBuilder<'a> { /// - The fence, buffers, images, and semaphores must all belong to the same device. /// #[inline] - pub unsafe fn add_signal_semaphore(&mut self, semaphore: &'a Semaphore) { - self.signal_semaphores.push(semaphore.internal_object()); + pub unsafe fn add_signal_semaphore(&mut self, semaphore: Arc) { + self.bind_info.signal_semaphores.push(semaphore); } } -pub struct SubmitBindSparseBufferBindBuilder<'a> { - buffer: ash::vk::Buffer, - binds: SmallVec<[ash::vk::SparseMemoryBind; 1]>, - marker: PhantomData<&'a ()>, +pub struct SubmitBindSparseBufferBindBuilder { + buffer: Arc, + binds: SmallVec<[SparseBufferMemoryBind; 1]>, } -impl<'a> SubmitBindSparseBufferBindBuilder<'a> { +impl SubmitBindSparseBufferBindBuilder { /// /// # Safety /// /// - `buffer` must be a buffer with sparse binding enabled. - pub unsafe fn new(buffer: &'a UnsafeBuffer) -> SubmitBindSparseBufferBindBuilder { + pub unsafe fn new(buffer: Arc) -> Self { SubmitBindSparseBufferBindBuilder { - buffer: buffer.internal_object(), + buffer, binds: SmallVec::new(), - marker: PhantomData, } } pub unsafe fn add_bind( &mut self, - offset: DeviceSize, + resource_offset: DeviceSize, size: DeviceSize, - memory: &DeviceMemory, + memory: Arc, memory_offset: DeviceSize, ) { - self.binds.push(ash::vk::SparseMemoryBind { - resource_offset: offset, + self.binds.push(SparseBufferMemoryBind { + resource_offset, size, - memory: memory.internal_object(), - memory_offset, - flags: ash::vk::SparseMemoryBindFlags::empty(), // Flags are only relevant for images. + memory: Some((memory, memory_offset)), }); } - pub unsafe fn add_unbind(&mut self, offset: DeviceSize, size: DeviceSize) { - self.binds.push(ash::vk::SparseMemoryBind { - resource_offset: offset, + pub unsafe fn add_unbind(&mut self, resource_offset: DeviceSize, size: DeviceSize) { + self.binds.push(SparseBufferMemoryBind { + resource_offset, size, - memory: ash::vk::DeviceMemory::null(), - memory_offset: 0, - flags: ash::vk::SparseMemoryBindFlags::empty(), + memory: None, }); } } -pub struct SubmitBindSparseImageOpaqueBindBuilder<'a> { - image: ash::vk::Image, - binds: SmallVec<[ash::vk::SparseMemoryBind; 1]>, - marker: PhantomData<&'a ()>, +pub struct SubmitBindSparseImageOpaqueBindBuilder { + image: Arc, + binds: SmallVec<[SparseImageOpaqueMemoryBind; 1]>, } -impl<'a> SubmitBindSparseImageOpaqueBindBuilder<'a> { +impl SubmitBindSparseImageOpaqueBindBuilder { /// /// # Safety /// /// - `image` must be an image with sparse binding enabled. - pub unsafe fn new(image: &'a UnsafeImage) -> SubmitBindSparseImageOpaqueBindBuilder { + pub unsafe fn new(image: Arc) -> Self { SubmitBindSparseImageOpaqueBindBuilder { - image: image.internal_object(), + image, binds: SmallVec::new(), - marker: PhantomData, } } pub unsafe fn add_bind( &mut self, - offset: DeviceSize, + resource_offset: DeviceSize, size: DeviceSize, - memory: &DeviceMemory, + memory: Arc, memory_offset: DeviceSize, - bind_metadata: bool, + metadata: bool, ) { - self.binds.push(ash::vk::SparseMemoryBind { - resource_offset: offset, + self.binds.push(SparseImageOpaqueMemoryBind { + resource_offset, size, - memory: memory.internal_object(), - memory_offset, - flags: if bind_metadata { - ash::vk::SparseMemoryBindFlags::METADATA - } else { - ash::vk::SparseMemoryBindFlags::empty() - }, + memory: Some((memory, memory_offset)), + metadata, }); } - pub unsafe fn add_unbind(&mut self, offset: DeviceSize, size: DeviceSize) { - self.binds.push(ash::vk::SparseMemoryBind { - resource_offset: offset, + pub unsafe fn add_unbind(&mut self, resource_offset: DeviceSize, size: DeviceSize) { + self.binds.push(SparseImageOpaqueMemoryBind { + resource_offset, size, - memory: ash::vk::DeviceMemory::null(), - memory_offset: 0, - flags: ash::vk::SparseMemoryBindFlags::empty(), // TODO: is that relevant? + memory: None, + metadata: false, }); } } -pub struct SubmitBindSparseImageBindBuilder<'a> { - image: ash::vk::Image, - binds: SmallVec<[ash::vk::SparseImageMemoryBind; 1]>, - marker: PhantomData<&'a ()>, +pub struct SubmitBindSparseImageBindBuilder { + image: Arc, + binds: SmallVec<[SparseImageMemoryBind; 1]>, } -impl<'a> SubmitBindSparseImageBindBuilder<'a> { +impl SubmitBindSparseImageBindBuilder { /// /// # Safety /// /// - `image` must be an image with sparse binding enabled. - pub unsafe fn new(image: &'a UnsafeImage) -> SubmitBindSparseImageBindBuilder { + pub unsafe fn new(image: Arc) -> Self { SubmitBindSparseImageBindBuilder { - image: image.internal_object(), + image, binds: SmallVec::new(), - marker: PhantomData, } } diff --git a/vulkano/src/command_buffer/submit/mod.rs b/vulkano/src/command_buffer/submit/mod.rs index 86789832ce..0e15954825 100644 --- a/vulkano/src/command_buffer/submit/mod.rs +++ b/vulkano/src/command_buffer/submit/mod.rs @@ -31,15 +31,15 @@ mod semaphores_wait; /// Contains all the possible submission builders. #[derive(Debug)] -pub enum SubmitAnyBuilder<'a> { +pub enum SubmitAnyBuilder { Empty, - SemaphoresWait(SubmitSemaphoresWaitBuilder<'a>), - CommandBuffer(SubmitCommandBufferBuilder<'a>), - QueuePresent(SubmitPresentBuilder<'a>), - BindSparse(SubmitBindSparseBuilder<'a>), + SemaphoresWait(SubmitSemaphoresWaitBuilder), + CommandBuffer(SubmitCommandBufferBuilder), + QueuePresent(SubmitPresentBuilder), + BindSparse(SubmitBindSparseBuilder), } -impl<'a> SubmitAnyBuilder<'a> { +impl SubmitAnyBuilder { /// Returns true if equal to `SubmitAnyBuilder::Empty`. #[inline] pub fn is_empty(&self) -> bool { diff --git a/vulkano/src/command_buffer/submit/queue_present.rs b/vulkano/src/command_buffer/submit/queue_present.rs index 8953286ca1..65729ead44 100644 --- a/vulkano/src/command_buffer/submit/queue_present.rs +++ b/vulkano/src/command_buffer/submit/queue_present.rs @@ -9,45 +9,29 @@ use crate::{ device::{DeviceOwned, Queue}, - swapchain::PresentInfo, + swapchain::{PresentInfo, SwapchainPresentInfo}, sync::Semaphore, - OomError, SynchronizedVulkanObject, VulkanError, VulkanObject, + OomError, VulkanError, }; -use smallvec::SmallVec; use std::{ error::Error, fmt::{Debug, Display, Error as FmtError, Formatter}, - marker::PhantomData, - ptr, - sync::atomic::{AtomicU64, Ordering}, + sync::{atomic::Ordering, Arc}, }; /// Prototype for a submission that presents a swapchain on the screen. // TODO: example here -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 ()>, +#[derive(Debug)] +pub struct SubmitPresentBuilder { + present_info: PresentInfo, } -impl<'a> SubmitPresentBuilder<'a> { +impl SubmitPresentBuilder { /// Builds a new empty `SubmitPresentBuilder`. #[inline] - pub fn new() -> SubmitPresentBuilder<'a> { + pub fn new() -> SubmitPresentBuilder { SubmitPresentBuilder { - 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, + present_info: Default::default(), } } @@ -69,8 +53,8 @@ impl<'a> SubmitPresentBuilder<'a> { /// - The swapchains and semaphores must all belong to the same device. /// #[inline] - pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore) { - self.wait_semaphores.push(semaphore.internal_object()); + pub unsafe fn add_wait_semaphore(&mut self, semaphore: Arc) { + self.present_info.wait_semaphores.push(semaphore); } /// Adds an image of a swapchain to be presented. @@ -90,49 +74,34 @@ impl<'a> SubmitPresentBuilder<'a> { /// /// - The swapchains and semaphores must all belong to the same device. #[inline] - pub unsafe fn add_swapchain(&mut self, info: &'a PresentInfo) { - let PresentInfo { + pub unsafe fn add_swapchain(&mut self, mut swapchain_info: SwapchainPresentInfo) { + let SwapchainPresentInfo { swapchain, - index, + image_index, present_id, - present_region, - .. - } = info; + present_regions, + _ne: _, + } = &mut swapchain_info; - debug_assert!((*index as u32) < swapchain.image_count()); + debug_assert!((*image_index as u32) < swapchain.image_count()); + + if !swapchain.device().enabled_features().present_id { + *present_id = None; + } if swapchain .device() .enabled_extensions() .khr_incremental_present { - let vk_present_region = match present_region { - Some(present_region) => { - assert!(present_region.is_compatible_with(swapchain)); - for rectangle in &present_region.rectangles { - self.rect_layers.push(rectangle.into()); - } - ash::vk::PresentRegionKHR { - rectangle_count: present_region.rectangles.len() as u32, - // Set this to null for now; in submit fill it with self.rect_layers - p_rectangles: ptr::null(), - } - } - None => ash::vk::PresentRegionKHR { - rectangle_count: 0, - p_rectangles: ptr::null(), - }, - }; - 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()); + for rectangle in present_regions { + assert!(rectangle.is_compatible_with(swapchain.as_ref())); + } + } else { + *present_regions = Default::default(); } - self.swapchains.push(swapchain.internal_object()); - self.image_indices.push(*index as u32); + self.present_info.swapchain_infos.push(swapchain_info); } /// Submits the command. Calls `vkQueuePresentKHR`. @@ -141,87 +110,32 @@ impl<'a> SubmitPresentBuilder<'a> { /// /// Panics if no swapchain image has been added to the builder. /// - pub fn submit(mut self, queue: &Queue) -> Result<(), SubmitPresentError> { + pub fn submit(self, queue: &Queue) -> Result<(), SubmitPresentError> { unsafe { - debug_assert_eq!(self.swapchains.len(), self.image_indices.len()); assert!( - !self.swapchains.is_empty(), + !self.present_info.swapchain_infos.is_empty(), "Tried to submit a present command without any swapchain" ); - 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()); - let mut current_index = 0; - for present_region in &mut self.present_regions { - present_region.p_rectangles = self.rect_layers[current_index..].as_ptr(); - current_index += present_region.rectangle_count as usize; - } - Some(ash::vk::PresentRegionsKHR { - swapchain_count: self.present_regions.len() as u32, - p_regions: self.present_regions.as_ptr(), - ..Default::default() - }) - } else { - None - } - }; - - 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); - } - } + // VUID-VkPresentIdKHR-presentIds-04999 + for swapchain_info in &self.present_info.swapchain_infos { + if let Some(present_id) = swapchain_info.present_id.map(Into::into) { + if swapchain_info + .swapchain + .prev_present_id() + .fetch_max(present_id, Ordering::SeqCst) + >= present_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 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, - p_swapchains: self.swapchains.as_ptr(), - p_image_indices: self.image_indices.as_ptr(), - p_results: results.as_mut_ptr(), - ..Default::default() - }; - - 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)?; + let mut queue_guard = queue.lock(); + let results = queue_guard.present_unchecked(self.present_info); for result in results { - result.result().map_err(VulkanError::from)?; + result? } Ok(()) @@ -229,16 +143,6 @@ impl<'a> SubmitPresentBuilder<'a> { } } -impl<'a> Debug for SubmitPresentBuilder<'a> { - fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { - f.debug_struct("SubmitPresentBuilder") - .field("wait_semaphores", &self.wait_semaphores) - .field("swapchains", &self.swapchains) - .field("image_indices", &self.image_indices) - .finish() - } -} - /// Error that can happen when submitting the present prototype. #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[repr(u32)] diff --git a/vulkano/src/command_buffer/submit/queue_submit.rs b/vulkano/src/command_buffer/submit/queue_submit.rs index 3654627517..59d35f7aef 100644 --- a/vulkano/src/command_buffer/submit/queue_submit.rs +++ b/vulkano/src/command_buffer/submit/queue_submit.rs @@ -8,41 +8,32 @@ // according to those terms. use crate::{ - command_buffer::sys::UnsafeCommandBuffer, + command_buffer::{PrimaryCommandBuffer, SemaphoreSubmitInfo, SubmitInfo}, device::Queue, sync::{Fence, PipelineStages, Semaphore}, - OomError, SynchronizedVulkanObject, VulkanError, VulkanObject, + OomError, VulkanError, }; -use smallvec::SmallVec; use std::{ error::Error, fmt::{Display, Error as FmtError, Formatter}, - marker::PhantomData, + sync::Arc, }; /// Prototype for a submission that executes command buffers. // TODO: example here #[derive(Debug)] -pub struct SubmitCommandBufferBuilder<'a> { - wait_semaphores: SmallVec<[ash::vk::Semaphore; 16]>, - destination_stages: SmallVec<[ash::vk::PipelineStageFlags; 8]>, - signal_semaphores: SmallVec<[ash::vk::Semaphore; 16]>, - command_buffers: SmallVec<[ash::vk::CommandBuffer; 4]>, - fence: ash::vk::Fence, - marker: PhantomData<&'a ()>, +pub struct SubmitCommandBufferBuilder { + submit_info: SubmitInfo, + fence: Option>, } -impl<'a> SubmitCommandBufferBuilder<'a> { +impl SubmitCommandBufferBuilder { /// Builds a new empty `SubmitCommandBufferBuilder`. #[inline] - pub fn new() -> SubmitCommandBufferBuilder<'a> { + pub fn new() -> Self { SubmitCommandBufferBuilder { - wait_semaphores: SmallVec::new(), - destination_stages: SmallVec::new(), - signal_semaphores: SmallVec::new(), - command_buffers: SmallVec::new(), - fence: ash::vk::Fence::null(), - marker: PhantomData, + submit_info: Default::default(), + fence: None, } } @@ -53,20 +44,21 @@ impl<'a> SubmitCommandBufferBuilder<'a> { /// ``` /// use vulkano::command_buffer::submit::SubmitCommandBufferBuilder; /// use vulkano::sync::Fence; + /// # use std::sync::Arc; /// # let device: std::sync::Arc = return; /// /// unsafe { - /// let fence = Fence::from_pool(device.clone()).unwrap(); + /// let fence = Arc::new(Fence::from_pool(device.clone()).unwrap()); /// /// let mut builder = SubmitCommandBufferBuilder::new(); /// assert!(!builder.has_fence()); - /// builder.set_fence_signal(&fence); + /// builder.set_fence_signal(fence); /// assert!(builder.has_fence()); /// } /// ``` #[inline] pub fn has_fence(&self) -> bool { - self.fence != ash::vk::Fence::null() + self.fence.is_some() } /// Adds an operation that signals a fence after this submission ends. @@ -77,14 +69,15 @@ impl<'a> SubmitCommandBufferBuilder<'a> { /// use std::time::Duration; /// use vulkano::command_buffer::submit::SubmitCommandBufferBuilder; /// use vulkano::sync::Fence; + /// # use std::sync::Arc; /// # let device: std::sync::Arc = return; /// # let queue: std::sync::Arc = return; /// /// unsafe { - /// let fence = Fence::from_pool(device.clone()).unwrap(); + /// let fence = Arc::new(Fence::from_pool(device.clone()).unwrap()); /// /// let mut builder = SubmitCommandBufferBuilder::new(); - /// builder.set_fence_signal(&fence); + /// builder.set_fence_signal(fence); /// /// builder.submit(&queue).unwrap(); /// @@ -107,8 +100,8 @@ impl<'a> SubmitCommandBufferBuilder<'a> { /// - The fence, command buffers, and semaphores must all belong to the same device. /// #[inline] - pub unsafe fn set_fence_signal(&mut self, fence: &'a Fence) { - self.fence = fence.internal_object(); + pub unsafe fn set_fence_signal(&mut self, fence: Arc) { + self.fence = Some(fence); } /// Adds a semaphore to be waited upon before the command buffers are executed. @@ -134,11 +127,13 @@ impl<'a> SubmitCommandBufferBuilder<'a> { /// - The fence, command buffers, and semaphores must all belong to the same device. /// #[inline] - pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore, stages: PipelineStages) { - debug_assert!(!ash::vk::PipelineStageFlags::from(stages).is_empty()); + pub unsafe fn add_wait_semaphore(&mut self, semaphore: Arc, stages: PipelineStages) { + debug_assert!(!stages.is_empty()); // TODO: debug assert that the device supports the stages - self.wait_semaphores.push(semaphore.internal_object()); - self.destination_stages.push(stages.into()); + self.submit_info.wait_semaphores.push(SemaphoreSubmitInfo { + stages, + ..SemaphoreSubmitInfo::semaphore(semaphore) + }); } /// Adds a command buffer that is executed as part of this command. @@ -160,8 +155,8 @@ impl<'a> SubmitCommandBufferBuilder<'a> { /// TODO: more here /// #[inline] - pub unsafe fn add_command_buffer(&mut self, command_buffer: &'a UnsafeCommandBuffer) { - self.command_buffers.push(command_buffer.internal_object()); + pub unsafe fn add_command_buffer(&mut self, command_buffer: Arc) { + self.submit_info.command_buffers.push(command_buffer); } /// Returns the number of semaphores to signal. @@ -169,7 +164,7 @@ impl<'a> SubmitCommandBufferBuilder<'a> { /// In other words, this is the number of times `add_signal_semaphore` has been called. #[inline] pub fn num_signal_semaphores(&self) -> usize { - self.signal_semaphores.len() + self.submit_info.signal_semaphores.len() } /// Adds a semaphore that is going to be signaled at the end of the submission. @@ -185,8 +180,10 @@ impl<'a> SubmitCommandBufferBuilder<'a> { /// - The fence, command buffers, and semaphores must all belong to the same device. /// #[inline] - pub unsafe fn add_signal_semaphore(&mut self, semaphore: &'a Semaphore) { - self.signal_semaphores.push(semaphore.internal_object()); + pub unsafe fn add_signal_semaphore(&mut self, semaphore: Arc) { + self.submit_info + .signal_semaphores + .push(SemaphoreSubmitInfo::semaphore(semaphore)); } /// Submits the command buffer to the given queue. @@ -195,28 +192,9 @@ impl<'a> SubmitCommandBufferBuilder<'a> { /// > possible together and avoid submitting them one by one. /// pub fn submit(self, queue: &Queue) -> Result<(), SubmitCommandBufferError> { - unsafe { - let fns = queue.device().fns(); - let queue = queue.internal_object_guard(); - - debug_assert_eq!(self.wait_semaphores.len(), self.destination_stages.len()); - - let batch = ash::vk::SubmitInfo { - wait_semaphore_count: self.wait_semaphores.len() as u32, - p_wait_semaphores: self.wait_semaphores.as_ptr(), - p_wait_dst_stage_mask: self.destination_stages.as_ptr(), - command_buffer_count: self.command_buffers.len() as u32, - p_command_buffers: self.command_buffers.as_ptr(), - signal_semaphore_count: self.signal_semaphores.len() as u32, - p_signal_semaphores: self.signal_semaphores.as_ptr(), - ..Default::default() - }; - - (fns.v1_0.queue_submit)(*queue, 1, &batch, self.fence) - .result() - .map_err(VulkanError::from)?; - Ok(()) - } + let mut queue_guard = queue.lock(); + + unsafe { Ok(queue_guard.submit_unchecked([self.submit_info], self.fence)?) } } /// Merges this builder with another builder. @@ -227,16 +205,21 @@ impl<'a> SubmitCommandBufferBuilder<'a> { // TODO: create multiple batches instead pub fn merge(mut self, other: Self) -> Self { assert!( - self.fence == ash::vk::Fence::null() || other.fence == ash::vk::Fence::null(), + self.fence.is_none() || other.fence.is_none(), "Can't merge two queue submits that both have a fence" ); - self.wait_semaphores.extend(other.wait_semaphores); - self.destination_stages.extend(other.destination_stages); // TODO: meh? will be solved if we submit multiple batches - self.signal_semaphores.extend(other.signal_semaphores); - self.command_buffers.extend(other.command_buffers); - - if self.fence == ash::vk::Fence::null() { + self.submit_info + .wait_semaphores + .extend(other.submit_info.wait_semaphores); + self.submit_info + .command_buffers + .extend(other.submit_info.command_buffers); + self.submit_info + .signal_semaphores + .extend(other.submit_info.signal_semaphores); + + if self.fence.is_none() { self.fence = other.fence; } @@ -314,11 +297,11 @@ mod tests { unsafe { let (device, queue) = gfx_dev_and_queue!(); - let fence = Fence::new(device, Default::default()).unwrap(); + let fence = Arc::new(Fence::new(device, Default::default()).unwrap()); assert!(!fence.is_signaled().unwrap()); let mut builder = SubmitCommandBufferBuilder::new(); - builder.set_fence_signal(&fence); + builder.set_fence_signal(fence.clone()); builder.submit(&queue).unwrap(); fence.wait(Some(Duration::from_secs(5))).unwrap(); @@ -331,11 +314,11 @@ mod tests { unsafe { let (device, _queue) = gfx_dev_and_queue!(); - let fence = Fence::new(device, Default::default()).unwrap(); + let fence = Arc::new(Fence::new(device, Default::default()).unwrap()); let mut builder = SubmitCommandBufferBuilder::new(); assert!(!builder.has_fence()); - builder.set_fence_signal(&fence); + builder.set_fence_signal(fence); assert!(builder.has_fence()); } } @@ -345,13 +328,13 @@ mod tests { unsafe { let (device, _) = gfx_dev_and_queue!(); - let fence1 = Fence::new(device.clone(), Default::default()).unwrap(); - let fence2 = Fence::new(device, Default::default()).unwrap(); + let fence1 = Arc::new(Fence::new(device.clone(), Default::default()).unwrap()); + let fence2 = Arc::new(Fence::new(device, Default::default()).unwrap()); let mut builder1 = SubmitCommandBufferBuilder::new(); - builder1.set_fence_signal(&fence1); + builder1.set_fence_signal(fence1); let mut builder2 = SubmitCommandBufferBuilder::new(); - builder2.set_fence_signal(&fence2); + builder2.set_fence_signal(fence2); assert_should_panic!("Can't merge two queue submits that both have a fence", { let _ = builder1.merge(builder2); diff --git a/vulkano/src/command_buffer/submit/semaphores_wait.rs b/vulkano/src/command_buffer/submit/semaphores_wait.rs index 9b1c590756..08afe675aa 100644 --- a/vulkano/src/command_buffer/submit/semaphores_wait.rs +++ b/vulkano/src/command_buffer/submit/semaphores_wait.rs @@ -12,20 +12,21 @@ use crate::{ sync::{PipelineStages, Semaphore}, }; use smallvec::SmallVec; +use std::sync::Arc; /// Prototype for a submission that waits on semaphores. /// /// This prototype can't actually be submitted because it doesn't correspond to anything in Vulkan. /// However you can convert it into another builder prototype through the `Into` trait. #[derive(Debug)] -pub struct SubmitSemaphoresWaitBuilder<'a> { - semaphores: SmallVec<[&'a Semaphore; 8]>, +pub struct SubmitSemaphoresWaitBuilder { + pub(crate) semaphores: SmallVec<[Arc; 8]>, } -impl<'a> SubmitSemaphoresWaitBuilder<'a> { +impl SubmitSemaphoresWaitBuilder { /// Builds a new empty `SubmitSemaphoresWaitBuilder`. #[inline] - pub fn new() -> SubmitSemaphoresWaitBuilder<'a> { + pub fn new() -> Self { SubmitSemaphoresWaitBuilder { semaphores: SmallVec::new(), } @@ -35,20 +36,20 @@ impl<'a> SubmitSemaphoresWaitBuilder<'a> { /// /// The semaphore must be signaled by a previous submission. #[inline] - pub unsafe fn add_wait_semaphore(&mut self, semaphore: &'a Semaphore) { + pub unsafe fn add_wait_semaphore(&mut self, semaphore: Arc) { self.semaphores.push(semaphore); } /// Merges this builder with another builder. #[inline] - pub fn merge(&mut self, mut other: SubmitSemaphoresWaitBuilder<'a>) { + pub fn merge(&mut self, mut other: SubmitSemaphoresWaitBuilder) { self.semaphores.extend(other.semaphores.drain(..)); } } -impl<'a> From> for SubmitCommandBufferBuilder<'a> { +impl From for SubmitCommandBufferBuilder { #[inline] - fn from(mut val: SubmitSemaphoresWaitBuilder<'a>) -> Self { + fn from(mut val: SubmitSemaphoresWaitBuilder) -> Self { unsafe { let mut builder = SubmitCommandBufferBuilder::new(); for sem in val.semaphores.drain(..) { @@ -66,9 +67,9 @@ impl<'a> From> for SubmitCommandBufferBuilder<'a } } -impl<'a> From> for SubmitPresentBuilder<'a> { +impl From for SubmitPresentBuilder { #[inline] - fn from(mut val: SubmitSemaphoresWaitBuilder<'a>) -> Self { + fn from(mut val: SubmitSemaphoresWaitBuilder) -> Self { unsafe { let mut builder = SubmitPresentBuilder::new(); for sem in val.semaphores.drain(..) { diff --git a/vulkano/src/command_buffer/traits.rs b/vulkano/src/command_buffer/traits.rs index 6bacb02154..a7f87d0a76 100644 --- a/vulkano/src/command_buffer/traits.rs +++ b/vulkano/src/command_buffer/traits.rs @@ -77,7 +77,7 @@ pub unsafe trait PrimaryCommandBuffer: DeviceOwned + Send + Sync { fn execute( self, queue: Arc, - ) -> Result, CommandBufferExecError> + ) -> Result, CommandBufferExecError> where Self: Sized + 'static, { @@ -112,7 +112,7 @@ pub unsafe trait PrimaryCommandBuffer: DeviceOwned + Send + Sync { self, future: F, queue: Arc, - ) -> Result, CommandBufferExecError> + ) -> Result, CommandBufferExecError> where Self: Sized + 'static, F: GpuFuture, @@ -130,7 +130,7 @@ pub unsafe trait PrimaryCommandBuffer: DeviceOwned + Send + Sync { Ok(CommandBufferExecFuture { previous: future, - command_buffer: self, + command_buffer: Arc::new(self), queue, submitted: Mutex::new(false), finished: AtomicBool::new(false), @@ -328,13 +328,12 @@ where /// Represents a command buffer being executed by the GPU and the moment when the execution /// finishes. #[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"] -pub struct CommandBufferExecFuture +pub struct CommandBufferExecFuture where F: GpuFuture, - Cb: PrimaryCommandBuffer, { previous: F, - command_buffer: Cb, + command_buffer: Arc, queue: Arc, // True if the command buffer has already been submitted. // If flush is called multiple times, we want to block so that only one flushing is executed. @@ -343,10 +342,9 @@ where finished: AtomicBool, } -impl CommandBufferExecFuture +impl CommandBufferExecFuture where F: GpuFuture, - Cb: PrimaryCommandBuffer, { // Implementation of `build_submission`. Doesn't check whenever the future was already flushed. // You must make sure to not submit same command buffer multiple times. @@ -354,17 +352,17 @@ where Ok(match self.previous.build_submission()? { SubmitAnyBuilder::Empty => { let mut builder = SubmitCommandBufferBuilder::new(); - builder.add_command_buffer(self.command_buffer.inner()); + builder.add_command_buffer(self.command_buffer.clone()); SubmitAnyBuilder::CommandBuffer(builder) } SubmitAnyBuilder::SemaphoresWait(sem) => { let mut builder: SubmitCommandBufferBuilder = sem.into(); - builder.add_command_buffer(self.command_buffer.inner()); + builder.add_command_buffer(self.command_buffer.clone()); SubmitAnyBuilder::CommandBuffer(builder) } SubmitAnyBuilder::CommandBuffer(mut builder) => { // FIXME: add pipeline barrier - builder.add_command_buffer(self.command_buffer.inner()); + builder.add_command_buffer(self.command_buffer.clone()); SubmitAnyBuilder::CommandBuffer(builder) } SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_) => { @@ -378,10 +376,9 @@ where } } -unsafe impl GpuFuture for CommandBufferExecFuture +unsafe impl GpuFuture for CommandBufferExecFuture where F: GpuFuture, - Cb: PrimaryCommandBuffer, { #[inline] fn cleanup_finished(&mut self) { @@ -485,10 +482,9 @@ where } } -unsafe impl DeviceOwned for CommandBufferExecFuture +unsafe impl DeviceOwned for CommandBufferExecFuture where F: GpuFuture, - Cb: PrimaryCommandBuffer, { #[inline] fn device(&self) -> &Arc { @@ -496,10 +492,9 @@ where } } -impl Drop for CommandBufferExecFuture +impl Drop for CommandBufferExecFuture where F: GpuFuture, - Cb: PrimaryCommandBuffer, { fn drop(&mut self) { unsafe { diff --git a/vulkano/src/device/mod.rs b/vulkano/src/device/mod.rs index 745f767c5e..77c4c2dba8 100644 --- a/vulkano/src/device/mod.rs +++ b/vulkano/src/device/mod.rs @@ -106,7 +106,7 @@ pub(crate) use self::{features::FeaturesFfi, properties::PropertiesFfi}; pub use self::{ features::{FeatureRestriction, FeatureRestrictionError, Features}, properties::Properties, - queue::{DebugUtilsError, Queue, QueueFamilyProperties, QueueFlags, QueueGuard}, + queue::{Queue, QueueError, QueueFamilyProperties, QueueFlags, QueueGuard}, }; use crate::{ command_buffer::pool::StandardCommandPool, diff --git a/vulkano/src/device/queue.rs b/vulkano/src/device/queue.rs index 82d1b01577..672d6ca4d5 100644 --- a/vulkano/src/device/queue.rs +++ b/vulkano/src/device/queue.rs @@ -9,18 +9,27 @@ use super::{Device, DeviceOwned}; use crate::{ - command_buffer::PrimaryCommandBuffer, + buffer::BufferAccess, + command_buffer::{SemaphoreSubmitInfo, SubmitInfo}, + image::ImageAccess, instance::debug::DebugUtilsLabel, macros::vulkan_bitflags, - sync::{PipelineStage, PipelineStages, Semaphore}, - OomError, RequiresOneOf, SynchronizedVulkanObject, VulkanError, + memory::{ + BindSparseInfo, SparseBufferMemoryBind, SparseImageMemoryBind, SparseImageOpaqueMemoryBind, + }, + swapchain::{PresentInfo, SwapchainPresentInfo}, + sync::{Fence, PipelineStage}, + OomError, RequirementNotMet, RequiresOneOf, SynchronizedVulkanObject, Version, VulkanError, + VulkanObject, }; use parking_lot::{Mutex, MutexGuard}; +use smallvec::SmallVec; use std::{ error::Error, ffi::CString, fmt::{Display, Error as FmtError, Formatter}, hash::{Hash, Hasher}, + ptr, sync::Arc, }; @@ -133,6 +142,618 @@ impl<'a> QueueGuard<'a> { } } + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] + pub(crate) unsafe fn bind_sparse_unchecked( + &mut self, + bind_infos: impl IntoIterator, + fence: Option>, + ) -> Result<(), VulkanError> { + let bind_infos = bind_infos.into_iter(); + + #[allow(unused)] + struct PerBindSparseInfo { + wait_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>, + buffer_bind_infos_vk: SmallVec<[ash::vk::SparseBufferMemoryBindInfo; 4]>, + buffer_binds_vk: SmallVec<[SmallVec<[ash::vk::SparseMemoryBind; 4]>; 4]>, + image_opaque_bind_infos_vk: SmallVec<[ash::vk::SparseImageOpaqueMemoryBindInfo; 4]>, + image_opaque_binds_vk: SmallVec<[SmallVec<[ash::vk::SparseMemoryBind; 4]>; 4]>, + image_bind_infos_vk: SmallVec<[ash::vk::SparseImageMemoryBindInfo; 4]>, + image_binds_vk: SmallVec<[SmallVec<[ash::vk::SparseImageMemoryBind; 4]>; 4]>, + signal_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>, + } + + let (mut bind_infos_vk, mut per_bind_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) = bind_infos + .map(|bind_info| { + let &BindSparseInfo { + ref wait_semaphores, + ref buffer_binds, + ref image_opaque_binds, + ref image_binds, + ref signal_semaphores, + _ne: _, + } = &bind_info; + + let wait_semaphores_vk: SmallVec<[_; 4]> = wait_semaphores + .iter() + .map(|semaphore| semaphore.internal_object()) + .collect(); + + let (buffer_bind_infos_vk, buffer_binds_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) = + buffer_binds + .iter() + .map(|(buffer, memory_binds)| { + ( + ash::vk::SparseBufferMemoryBindInfo { + buffer: buffer.inner().buffer.internal_object(), + bind_count: 0, + p_binds: ptr::null(), + }, + memory_binds + .iter() + .map(|memory_bind| { + let &SparseBufferMemoryBind { + resource_offset, + size, + ref memory, + } = memory_bind; + + let (memory, memory_offset) = memory.as_ref().map_or_else( + Default::default, + |(memory, memory_offset)| { + (memory.internal_object(), *memory_offset) + }, + ); + + ash::vk::SparseMemoryBind { + resource_offset, + size, + memory, + memory_offset, + flags: ash::vk::SparseMemoryBindFlags::empty(), + } + }) + .collect::>(), + ) + }) + .unzip(); + + let (image_opaque_bind_infos_vk, image_opaque_binds_vk): ( + SmallVec<[_; 4]>, + SmallVec<[_; 4]>, + ) = image_opaque_binds + .iter() + .map(|(image, memory_binds)| { + ( + ash::vk::SparseImageOpaqueMemoryBindInfo { + image: image.inner().image.internal_object(), + bind_count: 0, + p_binds: ptr::null(), + }, + memory_binds + .iter() + .map(|memory_bind| { + let &SparseImageOpaqueMemoryBind { + resource_offset, + size, + ref memory, + metadata, + } = memory_bind; + + let (memory, memory_offset) = memory.as_ref().map_or_else( + Default::default, + |(memory, memory_offset)| { + (memory.internal_object(), *memory_offset) + }, + ); + + ash::vk::SparseMemoryBind { + resource_offset, + size, + memory, + memory_offset, + flags: if metadata { + ash::vk::SparseMemoryBindFlags::METADATA + } else { + ash::vk::SparseMemoryBindFlags::empty() + }, + } + }) + .collect::>(), + ) + }) + .unzip(); + + let (image_bind_infos_vk, image_binds_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) = + image_binds + .iter() + .map(|(image, memory_binds)| { + ( + ash::vk::SparseImageMemoryBindInfo { + image: image.inner().image.internal_object(), + bind_count: 0, + p_binds: ptr::null(), + }, + memory_binds + .iter() + .map(|memory_bind| { + let &SparseImageMemoryBind { + aspects, + mip_level, + array_layer, + offset, + extent, + ref memory, + } = memory_bind; + + let (memory, memory_offset) = memory.as_ref().map_or_else( + Default::default, + |(memory, memory_offset)| { + (memory.internal_object(), *memory_offset) + }, + ); + + ash::vk::SparseImageMemoryBind { + subresource: ash::vk::ImageSubresource { + aspect_mask: aspects.into(), + mip_level, + array_layer, + }, + offset: ash::vk::Offset3D { + x: offset[0] as i32, + y: offset[1] as i32, + z: offset[2] as i32, + }, + extent: ash::vk::Extent3D { + width: extent[0], + height: extent[1], + depth: extent[2], + }, + memory, + memory_offset, + flags: ash::vk::SparseMemoryBindFlags::empty(), + } + }) + .collect::>(), + ) + }) + .unzip(); + + let signal_semaphores_vk: SmallVec<[_; 4]> = signal_semaphores + .iter() + .map(|semaphore| semaphore.internal_object()) + .collect(); + + ( + ash::vk::BindSparseInfo::default(), + PerBindSparseInfo { + wait_semaphores_vk, + buffer_bind_infos_vk, + buffer_binds_vk, + image_opaque_bind_infos_vk, + image_opaque_binds_vk, + image_bind_infos_vk, + image_binds_vk, + signal_semaphores_vk, + }, + ) + }) + .unzip(); + + for ( + bind_info_vk, + PerBindSparseInfo { + wait_semaphores_vk, + buffer_bind_infos_vk, + buffer_binds_vk, + image_opaque_bind_infos_vk, + image_opaque_binds_vk, + image_bind_infos_vk, + image_binds_vk, + signal_semaphores_vk, + }, + ) in (bind_infos_vk.iter_mut()).zip(per_bind_vk.iter_mut()) + { + for (buffer_bind_infos_vk, buffer_binds_vk) in + (buffer_bind_infos_vk.iter_mut()).zip(buffer_binds_vk.iter()) + { + *buffer_bind_infos_vk = ash::vk::SparseBufferMemoryBindInfo { + bind_count: buffer_binds_vk.len() as u32, + p_binds: buffer_binds_vk.as_ptr(), + ..*buffer_bind_infos_vk + }; + } + + for (image_opaque_bind_infos_vk, image_opaque_binds_vk) in + (image_opaque_bind_infos_vk.iter_mut()).zip(image_opaque_binds_vk.iter()) + { + *image_opaque_bind_infos_vk = ash::vk::SparseImageOpaqueMemoryBindInfo { + bind_count: image_opaque_binds_vk.len() as u32, + p_binds: image_opaque_binds_vk.as_ptr(), + ..*image_opaque_bind_infos_vk + }; + } + + for (image_bind_infos_vk, image_binds_vk) in + (image_bind_infos_vk.iter_mut()).zip(image_binds_vk.iter()) + { + *image_bind_infos_vk = ash::vk::SparseImageMemoryBindInfo { + bind_count: image_binds_vk.len() as u32, + p_binds: image_binds_vk.as_ptr(), + ..*image_bind_infos_vk + }; + } + + *bind_info_vk = ash::vk::BindSparseInfo { + wait_semaphore_count: wait_semaphores_vk.len() as u32, + p_wait_semaphores: wait_semaphores_vk.as_ptr(), + buffer_bind_count: buffer_bind_infos_vk.len() as u32, + p_buffer_binds: buffer_bind_infos_vk.as_ptr(), + image_opaque_bind_count: image_opaque_bind_infos_vk.len() as u32, + p_image_opaque_binds: image_opaque_bind_infos_vk.as_ptr(), + image_bind_count: image_bind_infos_vk.len() as u32, + p_image_binds: image_bind_infos_vk.as_ptr(), + signal_semaphore_count: signal_semaphores_vk.len() as u32, + p_signal_semaphores: signal_semaphores_vk.as_ptr(), + ..*bind_info_vk + } + } + + let fns = self.queue.device.fns(); + (fns.v1_0.queue_bind_sparse)( + *self.handle, + bind_infos_vk.len() as u32, + bind_infos_vk.as_ptr(), + fence.map_or_else(Default::default, |fence| fence.internal_object()), + ) + .result() + .map_err(VulkanError::from)?; + + Ok(()) + } + + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] + pub(crate) unsafe fn present_unchecked( + &mut self, + present_info: PresentInfo, + ) -> impl ExactSizeIterator> { + let &PresentInfo { + ref wait_semaphores, + ref swapchain_infos, + _ne: _, + } = &present_info; + + let wait_semaphores_vk: SmallVec<[_; 4]> = wait_semaphores + .iter() + .map(|semaphore| semaphore.internal_object()) + .collect(); + + let mut swapchains_vk: SmallVec<[_; 4]> = SmallVec::with_capacity(swapchain_infos.len()); + let mut image_indices_vk: SmallVec<[_; 4]> = SmallVec::with_capacity(swapchain_infos.len()); + let mut present_ids_vk: SmallVec<[_; 4]> = SmallVec::with_capacity(swapchain_infos.len()); + let mut present_regions_vk: SmallVec<[_; 4]> = + SmallVec::with_capacity(swapchain_infos.len()); + let mut rectangles_vk: SmallVec<[_; 4]> = SmallVec::with_capacity(swapchain_infos.len()); + + let mut has_present_ids = false; + let mut has_present_regions = false; + + for swapchain_info in swapchain_infos { + let &SwapchainPresentInfo { + ref swapchain, + image_index, + present_id, + ref present_regions, + _ne: _, + } = swapchain_info; + + swapchains_vk.push(swapchain.internal_object()); + image_indices_vk.push(image_index); + present_ids_vk.push(present_id.map_or(0, u64::from)); + present_regions_vk.push(ash::vk::PresentRegionKHR::default()); + rectangles_vk.push( + present_regions + .iter() + .map(ash::vk::RectLayerKHR::from) + .collect::>(), + ); + + if present_id.is_some() { + has_present_ids = true; + } + + if !present_regions.is_empty() { + has_present_regions = true; + } + } + + let mut results = vec![ash::vk::Result::SUCCESS; swapchain_infos.len()]; + let mut info_vk = ash::vk::PresentInfoKHR { + wait_semaphore_count: wait_semaphores_vk.len() as u32, + p_wait_semaphores: wait_semaphores_vk.as_ptr(), + swapchain_count: swapchains_vk.len() as u32, + p_swapchains: swapchains_vk.as_ptr(), + p_image_indices: image_indices_vk.as_ptr(), + p_results: results.as_mut_ptr(), + ..Default::default() + }; + let mut present_id_info_vk = None; + let mut present_region_info_vk = None; + + if has_present_ids { + let next = present_id_info_vk.insert(ash::vk::PresentIdKHR { + swapchain_count: present_ids_vk.len() as u32, + p_present_ids: present_ids_vk.as_ptr(), + ..Default::default() + }); + + next.p_next = info_vk.p_next; + info_vk.p_next = next as *const _ as *const _; + } + + if has_present_regions { + for (present_regions_vk, rectangles_vk) in + (present_regions_vk.iter_mut()).zip(rectangles_vk.iter()) + { + *present_regions_vk = ash::vk::PresentRegionKHR { + rectangle_count: rectangles_vk.len() as u32, + p_rectangles: rectangles_vk.as_ptr(), + }; + } + + let next = present_region_info_vk.insert(ash::vk::PresentRegionsKHR { + swapchain_count: present_regions_vk.len() as u32, + p_regions: present_regions_vk.as_ptr(), + ..Default::default() + }); + + next.p_next = info_vk.p_next; + info_vk.p_next = next as *const _ as *const _; + } + + let fns = self.queue.device().fns(); + let _ = (fns.khr_swapchain.queue_present_khr)(*self.handle, &info_vk); + + results + .into_iter() + .map(|result| result.result().map_err(VulkanError::from)) + } + + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] + pub(crate) unsafe fn submit_unchecked( + &mut self, + submits: impl IntoIterator, + fence: Option>, + ) -> Result<(), VulkanError> { + let submits = submits.into_iter(); + + if self.queue.device.enabled_features().synchronization2 { + struct PerSubmitInfo { + wait_semaphore_infos_vk: SmallVec<[ash::vk::SemaphoreSubmitInfo; 4]>, + command_buffer_infos_vk: SmallVec<[ash::vk::CommandBufferSubmitInfo; 4]>, + signal_semaphore_infos_vk: SmallVec<[ash::vk::SemaphoreSubmitInfo; 4]>, + } + + let (mut submit_info_vk, per_submit_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) = submits + .map(|submit_info| { + let SubmitInfo { + wait_semaphores, + command_buffers, + signal_semaphores, + _ne: _, + } = submit_info; + + let wait_semaphore_infos_vk = wait_semaphores + .into_iter() + .map(|semaphore_submit_info| { + let SemaphoreSubmitInfo { + semaphore, + stages, + _ne: _, + } = semaphore_submit_info; + + ash::vk::SemaphoreSubmitInfo { + semaphore: semaphore.internal_object(), + value: 0, // TODO: + stage_mask: stages.into(), + device_index: 0, // TODO: + ..Default::default() + } + }) + .collect(); + + let command_buffer_infos_vk = command_buffers + .into_iter() + .map(|cb| ash::vk::CommandBufferSubmitInfo { + command_buffer: cb.inner().internal_object(), + device_mask: 0, // TODO: + ..Default::default() + }) + .collect(); + + let signal_semaphore_infos_vk = signal_semaphores + .into_iter() + .map(|semaphore_submit_info| { + let SemaphoreSubmitInfo { + semaphore, + stages, + _ne: _, + } = semaphore_submit_info; + + ash::vk::SemaphoreSubmitInfo { + semaphore: semaphore.internal_object(), + value: 0, // TODO: + stage_mask: stages.into(), + device_index: 0, // TODO: + ..Default::default() + } + }) + .collect(); + + ( + ash::vk::SubmitInfo2 { + flags: ash::vk::SubmitFlags::empty(), // TODO: + wait_semaphore_info_count: 0, + p_wait_semaphore_infos: ptr::null(), + command_buffer_info_count: 0, + p_command_buffer_infos: ptr::null(), + signal_semaphore_info_count: 0, + p_signal_semaphore_infos: ptr::null(), + ..Default::default() + }, + PerSubmitInfo { + wait_semaphore_infos_vk, + command_buffer_infos_vk, + signal_semaphore_infos_vk, + }, + ) + }) + .unzip(); + + for ( + submit_info_vk, + PerSubmitInfo { + wait_semaphore_infos_vk, + command_buffer_infos_vk, + signal_semaphore_infos_vk, + }, + ) in (submit_info_vk.iter_mut()).zip(per_submit_vk.iter()) + { + *submit_info_vk = ash::vk::SubmitInfo2 { + wait_semaphore_info_count: wait_semaphore_infos_vk.len() as u32, + p_wait_semaphore_infos: wait_semaphore_infos_vk.as_ptr(), + command_buffer_info_count: command_buffer_infos_vk.len() as u32, + p_command_buffer_infos: command_buffer_infos_vk.as_ptr(), + signal_semaphore_info_count: signal_semaphore_infos_vk.len() as u32, + p_signal_semaphore_infos: signal_semaphore_infos_vk.as_ptr(), + ..*submit_info_vk + }; + } + + let fns = self.queue.device.fns(); + + if self.queue.device.api_version() >= Version::V1_3 { + (fns.v1_3.queue_submit2)( + *self.handle, + submit_info_vk.len() as u32, + submit_info_vk.as_ptr(), + fence.map_or_else(Default::default, |fence| fence.internal_object()), + ) + } else { + debug_assert!(self.queue.device.enabled_extensions().khr_synchronization2); + (fns.khr_synchronization2.queue_submit2_khr)( + *self.handle, + submit_info_vk.len() as u32, + submit_info_vk.as_ptr(), + fence.map_or_else(Default::default, |fence| fence.internal_object()), + ) + } + .result() + .map_err(VulkanError::from)?; + } else { + struct PerSubmitInfo { + wait_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>, + wait_dst_stage_mask_vk: SmallVec<[ash::vk::PipelineStageFlags; 4]>, + command_buffers_vk: SmallVec<[ash::vk::CommandBuffer; 4]>, + signal_semaphores_vk: SmallVec<[ash::vk::Semaphore; 4]>, + } + + let (mut submit_info_vk, per_submit_vk): (SmallVec<[_; 4]>, SmallVec<[_; 4]>) = submits + .map(|submit_info| { + let SubmitInfo { + wait_semaphores, + command_buffers, + signal_semaphores, + _ne: _, + } = submit_info; + + let (wait_semaphores_vk, wait_dst_stage_mask_vk) = wait_semaphores + .into_iter() + .map(|semaphore_submit_info| { + let SemaphoreSubmitInfo { + semaphore, + stages, + _ne: _, + } = semaphore_submit_info; + + (semaphore.internal_object(), stages.into()) + }) + .unzip(); + + let command_buffers_vk = command_buffers + .into_iter() + .map(|cb| cb.inner().internal_object()) + .collect(); + + let signal_semaphores_vk = signal_semaphores + .into_iter() + .map(|semaphore_submit_info| { + let SemaphoreSubmitInfo { + semaphore, + stages: _, + _ne: _, + } = semaphore_submit_info; + + semaphore.internal_object() + }) + .collect(); + + ( + ash::vk::SubmitInfo { + wait_semaphore_count: 0, + p_wait_semaphores: ptr::null(), + p_wait_dst_stage_mask: ptr::null(), + command_buffer_count: 0, + p_command_buffers: ptr::null(), + signal_semaphore_count: 0, + p_signal_semaphores: ptr::null(), + ..Default::default() + }, + PerSubmitInfo { + wait_semaphores_vk, + wait_dst_stage_mask_vk, + command_buffers_vk, + signal_semaphores_vk, + }, + ) + }) + .unzip(); + + for ( + submit_info_vk, + PerSubmitInfo { + wait_semaphores_vk, + wait_dst_stage_mask_vk, + command_buffers_vk, + signal_semaphores_vk, + }, + ) in (submit_info_vk.iter_mut()).zip(per_submit_vk.iter()) + { + *submit_info_vk = ash::vk::SubmitInfo { + wait_semaphore_count: wait_semaphores_vk.len() as u32, + p_wait_semaphores: wait_semaphores_vk.as_ptr(), + p_wait_dst_stage_mask: wait_dst_stage_mask_vk.as_ptr(), + command_buffer_count: command_buffers_vk.len() as u32, + p_command_buffers: command_buffers_vk.as_ptr(), + signal_semaphore_count: signal_semaphores_vk.len() as u32, + p_signal_semaphores: signal_semaphores_vk.as_ptr(), + ..*submit_info_vk + }; + } + + let fns = self.queue.device.fns(); + (fns.v1_0.queue_submit)( + *self.handle, + submit_info_vk.len() as u32, + submit_info_vk.as_ptr(), + fence.map_or_else(Default::default, |fence| fence.internal_object()), + ) + .result() + .map_err(VulkanError::from)?; + } + + Ok(()) + } + /// Opens a queue debug label region. /// /// The [`ext_debug_utils`](crate::instance::InstanceExtensions::ext_debug_utils) must be @@ -141,7 +762,7 @@ impl<'a> QueueGuard<'a> { pub fn begin_debug_utils_label( &mut self, label_info: DebugUtilsLabel, - ) -> Result<(), DebugUtilsError> { + ) -> Result<(), QueueError> { self.validate_begin_debug_utils_label(&label_info)?; unsafe { @@ -153,7 +774,7 @@ impl<'a> QueueGuard<'a> { fn validate_begin_debug_utils_label( &self, _label_info: &DebugUtilsLabel, - ) -> Result<(), DebugUtilsError> { + ) -> Result<(), QueueError> { if !self .queue .device @@ -161,7 +782,7 @@ impl<'a> QueueGuard<'a> { .enabled_extensions() .ext_debug_utils { - return Err(DebugUtilsError::RequirementNotMet { + return Err(QueueError::RequirementNotMet { required_for: "`begin_debug_utils_label`", requires_one_of: RequiresOneOf { instance_extensions: &["ext_debug_utils"], @@ -202,14 +823,14 @@ impl<'a> QueueGuard<'a> { /// - There must be an outstanding queue label region begun with `begin_debug_utils_label` in /// the queue. #[inline] - pub unsafe fn end_debug_utils_label(&mut self) -> Result<(), DebugUtilsError> { + pub unsafe fn end_debug_utils_label(&mut self) -> Result<(), QueueError> { self.validate_end_debug_utils_label()?; self.end_debug_utils_label_unchecked(); Ok(()) } - fn validate_end_debug_utils_label(&self) -> Result<(), DebugUtilsError> { + fn validate_end_debug_utils_label(&self) -> Result<(), QueueError> { if !self .queue .device @@ -217,7 +838,7 @@ impl<'a> QueueGuard<'a> { .enabled_extensions() .ext_debug_utils { - return Err(DebugUtilsError::RequirementNotMet { + return Err(QueueError::RequirementNotMet { required_for: "`end_debug_utils_label`", requires_one_of: RequiresOneOf { instance_extensions: &["ext_debug_utils"], @@ -246,7 +867,7 @@ impl<'a> QueueGuard<'a> { pub fn insert_debug_utils_label( &mut self, label_info: DebugUtilsLabel, - ) -> Result<(), DebugUtilsError> { + ) -> Result<(), QueueError> { self.validate_insert_debug_utils_label(&label_info)?; unsafe { @@ -258,7 +879,7 @@ impl<'a> QueueGuard<'a> { fn validate_insert_debug_utils_label( &self, _label_info: &DebugUtilsLabel, - ) -> Result<(), DebugUtilsError> { + ) -> Result<(), QueueError> { if !self .queue .device @@ -266,7 +887,7 @@ impl<'a> QueueGuard<'a> { .enabled_extensions() .ext_debug_utils { - return Err(DebugUtilsError::RequirementNotMet { + return Err(QueueError::RequirementNotMet { required_for: "`insert_debug_utils_label`", requires_one_of: RequiresOneOf { instance_extensions: &["ext_debug_utils"], @@ -298,21 +919,6 @@ impl<'a> QueueGuard<'a> { } } -#[derive(Clone, Debug)] -pub struct SubmitInfo { - pub wait_semaphores: Vec, - pub command_buffers: Vec>, - pub signal_semaphores: Vec, - pub _ne: crate::NonExhaustive, -} - -#[derive(Clone, Debug)] -pub struct SemaphoreSubmitInfo { - pub semaphore: Arc, - pub stages: PipelineStages, - pub _ne: crate::NonExhaustive, -} - /// Properties of a queue family in a physical device. #[derive(Clone, Debug)] #[non_exhaustive] @@ -393,21 +999,32 @@ vulkan_bitflags! { }, } -/// Error that can happen when submitting a debug utils command to a queue. +/// Error that can happen when submitting work to a queue. #[derive(Clone, Debug)] -pub enum DebugUtilsError { +pub enum QueueError { + VulkanError(VulkanError), + RequirementNotMet { required_for: &'static str, requires_one_of: RequiresOneOf, }, } -impl Error for DebugUtilsError {} +impl Error for QueueError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + QueueError::VulkanError(err) => Some(err), + _ => None, + } + } +} -impl Display for DebugUtilsError { +impl Display for QueueError { #[inline] fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { match self { + Self::VulkanError(_) => write!(f, "a runtime error occurred",), + Self::RequirementNotMet { required_for, requires_one_of, @@ -419,3 +1036,20 @@ impl Display for DebugUtilsError { } } } + +impl From for QueueError { + #[inline] + fn from(err: VulkanError) -> Self { + Self::VulkanError(err) + } +} + +impl From for QueueError { + #[inline] + fn from(err: RequirementNotMet) -> Self { + Self::RequirementNotMet { + required_for: err.required_for, + requires_one_of: err.requires_one_of, + } + } +} diff --git a/vulkano/src/image/immutable.rs b/vulkano/src/image/immutable.rs index 12b5520310..3f8d576d21 100644 --- a/vulkano/src/image/immutable.rs +++ b/vulkano/src/image/immutable.rs @@ -16,8 +16,7 @@ use crate::{ buffer::{BufferAccess, BufferContents, BufferUsage, CpuAccessibleBuffer}, command_buffer::{ AutoCommandBufferBuilder, BlitImageInfo, CommandBufferBeginError, CommandBufferExecFuture, - CommandBufferUsage, CopyBufferToImageInfo, ImageBlit, PrimaryAutoCommandBuffer, - PrimaryCommandBuffer, + CommandBufferUsage, CopyBufferToImageInfo, ImageBlit, PrimaryCommandBuffer, }, device::{Device, DeviceOwned, Queue}, format::Format, @@ -230,13 +229,7 @@ impl ImmutableImage { mip_levels: MipmapsCount, format: Format, queue: Arc, - ) -> Result< - ( - Arc, - CommandBufferExecFuture, - ), - ImmutableImageCreationError, - > + ) -> Result<(Arc, CommandBufferExecFuture), ImmutableImageCreationError> where [Px]: BufferContents, I: IntoIterator, @@ -261,13 +254,7 @@ impl ImmutableImage { mip_levels: MipmapsCount, format: Format, queue: Arc, - ) -> Result< - ( - Arc, - CommandBufferExecFuture, - ), - ImmutableImageCreationError, - > { + ) -> Result<(Arc, CommandBufferExecFuture), ImmutableImageCreationError> { let need_to_generate_mipmaps = has_mipmaps(mip_levels); let usage = ImageUsage { transfer_dst: true, diff --git a/vulkano/src/image/swapchain.rs b/vulkano/src/image/swapchain.rs index 035d37688c..ba836d00c9 100644 --- a/vulkano/src/image/swapchain.rs +++ b/vulkano/src/image/swapchain.rs @@ -10,7 +10,7 @@ use super::{traits::ImageContent, ImageAccess, ImageDescriptorLayouts, ImageInner, ImageLayout}; use crate::{ device::{Device, DeviceOwned}, - swapchain::Swapchain, + swapchain::{Swapchain, SwapchainAbstract}, OomError, }; use std::{ @@ -34,20 +34,23 @@ use std::{ #[derive(Debug)] pub struct SwapchainImage { swapchain: Arc>, - image_offset: usize, + image_index: u32, } -impl SwapchainImage { +impl SwapchainImage +where + W: Send + Sync, +{ /// Builds a `SwapchainImage` from raw components. /// /// This is an internal method that you shouldn't call. pub unsafe fn from_raw( swapchain: Arc>, - id: usize, + image_index: u32, ) -> Result>, OomError> { Ok(Arc::new(SwapchainImage { swapchain, - image_offset: id, + image_index, })) } @@ -59,18 +62,17 @@ impl SwapchainImage { #[inline] fn my_image(&self) -> ImageInner { - self.swapchain.raw_image(self.image_offset).unwrap() + self.swapchain.raw_image(self.image_index).unwrap() } #[inline] fn layout_initialized(&self) { - self.swapchain.image_layout_initialized(self.image_offset); + self.swapchain.image_layout_initialized(self.image_index); } #[inline] fn is_layout_initialized(&self) -> bool { - self.swapchain - .is_image_layout_initialized(self.image_offset) + self.swapchain.is_image_layout_initialized(self.image_index) } } diff --git a/vulkano/src/memory/device_memory.rs b/vulkano/src/memory/device_memory.rs index f82d3ea7fa..93373fa407 100644 --- a/vulkano/src/memory/device_memory.rs +++ b/vulkano/src/memory/device_memory.rs @@ -481,6 +481,12 @@ impl DeviceMemory { self.allocation_size } + /// Returns the handle types that can be exported from the memory allocation. + #[inline] + pub fn export_handle_types(&self) -> ExternalMemoryHandleTypes { + self.export_handle_types + } + /// Retrieves the amount of lazily-allocated memory that is currently commited to this /// memory object. /// diff --git a/vulkano/src/memory/mod.rs b/vulkano/src/memory/mod.rs index 7523bea35c..7bb86fe153 100644 --- a/vulkano/src/memory/mod.rs +++ b/vulkano/src/memory/mod.rs @@ -100,8 +100,13 @@ pub use self::{ pool::MemoryPool, }; use crate::{ - buffer::sys::UnsafeBuffer, image::sys::UnsafeImage, macros::vulkan_bitflags, DeviceSize, + buffer::{sys::UnsafeBuffer, BufferAccess}, + image::{sys::UnsafeImage, ImageAccess, ImageAspects}, + macros::vulkan_bitflags, + sync::Semaphore, + DeviceSize, }; +use std::sync::Arc; mod device_memory; pub mod pool; @@ -311,3 +316,163 @@ impl From for ExternalMemoryProperties { } } } + +/// Parameters to execute sparse bind operations on a queue. +#[derive(Clone, Debug)] +pub struct BindSparseInfo { + /// The semaphores to wait for before beginning the execution of this batch of + /// sparse bind operations. + /// + /// The default value is empty. + pub wait_semaphores: Vec>, + + /// The bind operations to perform for buffers. + /// + /// The default value is empty. + pub buffer_binds: Vec<(Arc, Vec)>, + + /// The bind operations to perform for images with an opaque memory layout. + /// + /// This should be used for mip tail regions, the metadata aspect, and for the normal regions + /// of images that do not have the `sparse_residency` flag set. + /// + /// The default value is empty. + pub image_opaque_binds: Vec<(Arc, Vec)>, + + /// The bind operations to perform for images with a known memory layout. + /// + /// This type of sparse bind can only be used for images that have the `sparse_residency` + /// flag set. + /// Only the normal texel regions can be bound this way, not the mip tail regions or metadata + /// aspect. + /// + /// The default value is empty. + pub image_binds: Vec<(Arc, Vec)>, + + /// The semaphores to signal after the execution of this batch of sparse bind operations + /// has completed. + /// + /// The default value is empty. + pub signal_semaphores: Vec>, + + pub _ne: crate::NonExhaustive, +} + +impl Default for BindSparseInfo { + #[inline] + fn default() -> Self { + Self { + wait_semaphores: Vec::new(), + buffer_binds: Vec::new(), + image_opaque_binds: Vec::new(), + image_binds: Vec::new(), + signal_semaphores: Vec::new(), + _ne: crate::NonExhaustive(()), + } + } +} + +/// Parameters for a single sparse bind operation on a buffer. +#[derive(Clone, Debug, Default)] +pub struct SparseBufferMemoryBind { + /// The offset in bytes from the start of the buffer's memory, where memory is to be (un)bound. + /// + /// The default value is `0`. + pub resource_offset: DeviceSize, + + /// The size in bytes of the memory to be (un)bound. + /// + /// The default value is `0`, which must be overridden. + pub size: DeviceSize, + + /// If `Some`, specifies the memory and an offset into that memory that is to be bound. + /// The provided memory must match the buffer's memory requirements. + /// + /// If `None`, specifies that existing memory at the specified location is to be unbound. + /// + /// The default value is `None`. + pub memory: Option<(Arc, DeviceSize)>, +} + +/// Parameters for a single sparse bind operation on parts of an image with an opaque memory layout. +/// +/// This type of sparse bind should be used for mip tail regions, the metadata aspect, and for the +/// normal regions of images that do not have the `sparse_residency` flag set. +#[derive(Clone, Debug, Default)] +pub struct SparseImageOpaqueMemoryBind { + /// The offset in bytes from the start of the image's memory, where memory is to be (un)bound. + /// + /// The default value is `0`. + pub resource_offset: DeviceSize, + + /// The size in bytes of the memory to be (un)bound. + /// + /// The default value is `0`, which must be overridden. + pub size: DeviceSize, + + /// If `Some`, specifies the memory and an offset into that memory that is to be bound. + /// The provided memory must match the image's memory requirements. + /// + /// If `None`, specifies that existing memory at the specified location is to be unbound. + /// + /// The default value is `None`. + pub memory: Option<(Arc, DeviceSize)>, + + /// Sets whether the binding should apply to the metadata aspect of the image, or to the + /// normal texel data. + /// + /// The default value is `false`. + pub metadata: bool, +} + +/// Parameters for a single sparse bind operation on parts of an image with a known memory layout. +/// +/// This type of sparse bind can only be used for images that have the `sparse_residency` flag set. +/// Only the normal texel regions can be bound this way, not the mip tail regions or metadata +/// aspect. +#[derive(Clone, Debug, Default)] +pub struct SparseImageMemoryBind { + /// The aspects of the image where memory is to be (un)bound. + /// + /// The default value is `ImageAspects::empty()`, which must be overridden. + pub aspects: ImageAspects, + + /// The mip level of the image where memory is to be (un)bound. + /// + /// The default value is `0`. + pub mip_level: u32, + + /// The array layer of the image where memory is to be (un)bound. + /// + /// The default value is `0`. + pub array_layer: u32, + + /// The offset in texels (or for compressed images, texel blocks) from the origin of the image, + /// where memory is to be (un)bound. + /// + /// This must be a multiple of the + /// [`SparseImageFormatProperties::image_granularity`](crate::image::SparseImageFormatProperties::image_granularity) + /// value of the image. + /// + /// The default value is `[0; 3]`. + pub offset: [u32; 3], + + /// The extent in texels (or for compressed images, texel blocks) of the image where + /// memory is to be (un)bound. + /// + /// This must be a multiple of the + /// [`SparseImageFormatProperties::image_granularity`](crate::image::SparseImageFormatProperties::image_granularity) + /// value of the image, or `offset + extent` for that dimension must equal the image's total + /// extent. + /// + /// The default value is `[0; 3]`, which must be overridden. + pub extent: [u32; 3], + + /// If `Some`, specifies the memory and an offset into that memory that is to be bound. + /// The provided memory must match the image's memory requirements. + /// + /// If `None`, specifies that existing memory at the specified location is to be unbound. + /// + /// The default value is `None`. + pub memory: Option<(Arc, DeviceSize)>, +} diff --git a/vulkano/src/swapchain/mod.rs b/vulkano/src/swapchain/mod.rs index 241728469d..78d92c4289 100644 --- a/vulkano/src/swapchain/mod.rs +++ b/vulkano/src/swapchain/mod.rs @@ -243,26 +243,23 @@ //! command to present the image on the screen after the draw operations are finished. //! //! ``` -//! use vulkano::swapchain::{self, PresentInfo}; +//! use vulkano::swapchain::{self, SwapchainPresentInfo}; //! use vulkano::sync::GpuFuture; //! # let queue: ::std::sync::Arc<::vulkano::device::Queue> = return; //! # let mut swapchain: ::std::sync::Arc> = return; //! // let mut (swapchain, images) = Swapchain::new(...); //! loop { //! # let mut command_buffer: ::vulkano::command_buffer::PrimaryAutoCommandBuffer = return; -//! let (image_num, suboptimal, acquire_future) +//! let (image_index, suboptimal, acquire_future) //! = swapchain::acquire_next_image(swapchain.clone(), None).unwrap(); //! //! // The command_buffer contains the draw commands that modify the framebuffer -//! // constructed from images[image_num] +//! // constructed from images[image_index] //! acquire_future //! .then_execute(queue.clone(), command_buffer).unwrap() //! .then_swapchain_present( //! queue.clone(), -//! PresentInfo { -//! index: image_num, -//! .. PresentInfo::swapchain(swapchain.clone()) -//! }, +//! SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), //! ) //! .then_signal_fence_and_flush().unwrap(); //! } @@ -282,7 +279,7 @@ //! //! ``` //! use vulkano::swapchain; -//! use vulkano::swapchain::{AcquireError, SwapchainCreateInfo, PresentInfo}; +//! use vulkano::swapchain::{AcquireError, SwapchainCreateInfo, SwapchainPresentInfo}; //! use vulkano::sync::GpuFuture; //! //! // let (swapchain, images) = Swapchain::new(...); @@ -303,7 +300,7 @@ //! recreate_swapchain = false; //! } //! -//! let (index, suboptimal, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { +//! let (image_index, suboptimal, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { //! Ok(r) => r, //! Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; }, //! Err(err) => panic!("{:?}", err) @@ -315,10 +312,7 @@ //! // .then_execute(...) //! .then_swapchain_present( //! queue.clone(), -//! PresentInfo { -//! index, -//! .. PresentInfo::swapchain(swapchain.clone()) -//! }, +//! SwapchainPresentInfo::swapchain_image_index(swapchain.clone(), image_index), //! ) //! .then_signal_fence_and_flush().unwrap(); // TODO: PresentError? //! @@ -330,7 +324,6 @@ //! pub use self::{ - present_region::{PresentRegion, RectangleLayer}, surface::{ ColorSpace, CompositeAlpha, PresentMode, SupportedCompositeAlpha, SupportedSurfaceTransforms, Surface, SurfaceApi, SurfaceCapabilities, SurfaceCreationError, @@ -338,21 +331,150 @@ pub use self::{ }, swapchain::{ acquire_next_image, acquire_next_image_raw, present, wait_for_present, AcquireError, - AcquiredImage, FullScreenExclusive, FullScreenExclusiveError, PresentFuture, PresentInfo, - PresentWaitError, Swapchain, SwapchainAcquireFuture, SwapchainCreateInfo, - SwapchainCreationError, Win32Monitor, + AcquiredImage, FullScreenExclusive, FullScreenExclusiveError, PresentFuture, + PresentWaitError, Swapchain, SwapchainAbstract, SwapchainAcquireFuture, + SwapchainCreateInfo, SwapchainCreationError, Win32Monitor, }, }; #[cfg(target_os = "ios")] pub use surface::IOSMetalLayer; -use std::sync::atomic::AtomicBool; +use crate::sync::Semaphore; +use std::{ + num::NonZeroU64, + sync::{atomic::AtomicBool, Arc}, +}; pub mod display; -mod present_region; mod surface; mod swapchain; +/// Parameters to execute present operations on a queue. +#[derive(Clone, Debug)] +pub struct PresentInfo { + /// The semaphores to wait for before beginning the execution of the present operations. + /// + /// The default value is empty. + pub wait_semaphores: Vec>, + + /// The present operations to perform. + /// + /// The default value is empty. + pub swapchain_infos: Vec, + + pub _ne: crate::NonExhaustive, +} + +impl Default for PresentInfo { + #[inline] + fn default() -> Self { + Self { + wait_semaphores: Vec::new(), + swapchain_infos: Vec::new(), + _ne: crate::NonExhaustive(()), + } + } +} + +/// Parameters for a single present operation on a swapchain. +#[derive(Clone, Debug)] +pub struct SwapchainPresentInfo { + /// The swapchain to present to. + /// + /// There is no default value. + pub swapchain: Arc, + + /// The index of the swapchain image to present to. + /// + /// The image must have been acquired first; this is the index that `acquire_next_image` + /// returns. + /// + /// There is no default value. + pub image_index: u32, + + /// An id used to identify this present operation. + /// + /// If `present_id` is `Some`, the [`present_id`](crate::device::Features::present_id) feature + /// must be enabled on the device. The id must be greater than any id previously used for + /// `swapchain`. If a swapchain is recreated, this resets. + /// + /// The default value is `None`. + pub present_id: Option, + + /// Am optimization hint to the implementation, that only some parts of the swapchain image are + /// going to be updated by the present operation. + /// + /// If `present_regions` is not empty, the + /// [`khr_incremental_present`](crate::device::DeviceExtension::khr_incremental_present) + /// extension must be enabled on the device. The implementation will update the provided + /// regions of the swapchain image, and _may_ ignore the other areas. However, as this is just + /// a hint, the Vulkan implementation is free to ignore the regions altogether and update + /// everything. + /// + /// If `present_regions` is empty, that means that all of the swapchain image must be updated. + /// + /// The default value is empty. + pub present_regions: Vec, + + pub _ne: crate::NonExhaustive, +} + +impl SwapchainPresentInfo { + /// Returns a `SwapchainPresentInfo` with the specified `swapchain` and `image_index`. + #[inline] + pub fn swapchain_image_index(swapchain: Arc, image_index: u32) -> Self { + Self { + swapchain, + image_index, + present_id: None, + present_regions: Vec::new(), + _ne: crate::NonExhaustive(()), + } + } +} + +/// Represents a rectangular region on an image layer. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct RectangleLayer { + /// Coordinates in pixels of the top-left hand corner of the rectangle. + pub offset: [i32; 2], + + /// Dimensions in pixels of the rectangle. + pub extent: [u32; 2], + + /// The layer of the image. For images with only one layer, the value of layer must be 0. + pub layer: u32, +} + +impl RectangleLayer { + /// Returns true if this rectangle layer is compatible with swapchain. + pub fn is_compatible_with(&self, swapchain: &dyn SwapchainAbstract) -> bool { + // FIXME negative offset is not disallowed by spec, but semantically should not be possible + debug_assert!(self.offset[0] >= 0); + debug_assert!(self.offset[1] >= 0); + self.offset[0] as u32 + self.extent[0] <= swapchain.image_extent()[0] + && self.offset[1] as u32 + self.extent[1] <= swapchain.image_extent()[1] + && self.layer < swapchain.image_array_layers() + } +} + +impl From<&RectangleLayer> for ash::vk::RectLayerKHR { + #[inline] + fn from(val: &RectangleLayer) -> Self { + ash::vk::RectLayerKHR { + offset: ash::vk::Offset2D { + x: val.offset[0], + y: val.offset[1], + }, + extent: ash::vk::Extent2D { + width: val.extent[0], + height: val.extent[1], + }, + layer: val.layer, + } + } +} + /// Internal trait so that creating/destroying a swapchain can access the surface's "has_swapchain" /// flag. // TODO: use pub(crate) maybe? diff --git a/vulkano/src/swapchain/present_region.rs b/vulkano/src/swapchain/present_region.rs deleted file mode 100644 index 40d36f3049..0000000000 --- a/vulkano/src/swapchain/present_region.rs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) 2017 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// or the MIT -// license , -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -use crate::swapchain::Swapchain; - -/// Represents a region on an image. -/// -/// A region consists of an arbitrary amount of rectangles. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct PresentRegion { - pub rectangles: Vec, -} - -impl PresentRegion { - /// Returns true if this present region is compatible with swapchain. - pub fn is_compatible_with(&self, swapchain: &Swapchain) -> bool { - self.rectangles - .iter() - .all(|rect| rect.is_compatible_with(swapchain)) - } -} - -/// Represents a rectangular region on an image layer. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct RectangleLayer { - /// Coordinates in pixels of the top-left hand corner of the rectangle. - pub offset: [i32; 2], - - /// Dimensions in pixels of the rectangle. - pub extent: [u32; 2], - - /// The layer of the image. For images with only one layer, the value of layer must be 0. - pub layer: u32, -} - -impl RectangleLayer { - /// Returns true if this rectangle layer is compatible with swapchain. - pub fn is_compatible_with(&self, swapchain: &Swapchain) -> bool { - // FIXME negative offset is not disallowed by spec, but semantically should not be possible - debug_assert!(self.offset[0] >= 0); - debug_assert!(self.offset[1] >= 0); - self.offset[0] as u32 + self.extent[0] <= swapchain.image_extent()[0] - && self.offset[1] as u32 + self.extent[1] <= swapchain.image_extent()[1] - && self.layer < swapchain.image_array_layers() - } -} - -impl From<&RectangleLayer> for ash::vk::RectLayerKHR { - #[inline] - fn from(val: &RectangleLayer) -> Self { - ash::vk::RectLayerKHR { - offset: ash::vk::Offset2D { - x: val.offset[0], - y: val.offset[1], - }, - extent: ash::vk::Extent2D { - width: val.extent[0], - height: val.extent[1], - }, - layer: val.layer, - } - } -} diff --git a/vulkano/src/swapchain/swapchain.rs b/vulkano/src/swapchain/swapchain.rs index fba73a2eec..962cb5045a 100644 --- a/vulkano/src/swapchain/swapchain.rs +++ b/vulkano/src/swapchain/swapchain.rs @@ -8,8 +8,8 @@ // according to those terms. use super::{ - ColorSpace, CompositeAlpha, PresentMode, PresentRegion, SupportedCompositeAlpha, - SupportedSurfaceTransforms, Surface, SurfaceTransform, + ColorSpace, CompositeAlpha, PresentMode, SupportedCompositeAlpha, SupportedSurfaceTransforms, + Surface, SurfaceTransform, SwapchainPresentInfo, }; use crate::{ buffer::sys::UnsafeBuffer, @@ -34,7 +34,7 @@ use parking_lot::Mutex; use smallvec::SmallVec; use std::{ error::Error, - fmt::{Display, Error as FmtError, Formatter}, + fmt::{Debug, Display, Error as FmtError, Formatter}, hash::{Hash, Hasher}, mem::MaybeUninit, ops::Range, @@ -47,7 +47,6 @@ use std::{ }; /// Contains the swapping system and the images that can be shown on a surface. -#[derive(Debug)] pub struct Swapchain { handle: ash::vk::SwapchainKHR, device: Arc, @@ -90,7 +89,10 @@ struct ImageEntry { undefined_layout: AtomicBool, } -impl Swapchain { +impl Swapchain +where + W: Send + Sync, +{ /// Creates a new `Swapchain`. /// /// This function returns the swapchain plus a list of the images that belong to the @@ -164,7 +166,7 @@ impl Swapchain { }); let swapchain_images = (0..swapchain.images.len()) - .map(|n| unsafe { SwapchainImage::from_raw(swapchain.clone(), n) }) + .map(|n| unsafe { SwapchainImage::from_raw(swapchain.clone(), n as u32) }) .collect::>()?; Ok((swapchain, swapchain_images)) @@ -259,7 +261,7 @@ impl Swapchain { }); let swapchain_images = (0..swapchain.images.len()) - .map(|n| unsafe { SwapchainImage::from_raw(swapchain.clone(), n) }) + .map(|n| unsafe { SwapchainImage::from_raw(swapchain.clone(), n as u32) }) .collect::>()?; Ok((swapchain, swapchain_images)) @@ -570,27 +572,7 @@ impl Swapchain { ), }; - let mut surface_full_screen_exclusive_info = - if full_screen_exclusive != FullScreenExclusive::Default { - Some(ash::vk::SurfaceFullScreenExclusiveInfoEXT { - full_screen_exclusive: full_screen_exclusive.into(), - ..Default::default() - }) - } else { - None - }; - - let mut surface_full_screen_exclusive_win32_info = - if let Some(Win32Monitor(hmonitor)) = win32_monitor { - Some(ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT { - hmonitor, - ..Default::default() - }) - } else { - None - }; - - let mut create_info = ash::vk::SwapchainCreateInfoKHR { + let mut info_vk = ash::vk::SwapchainCreateInfoKHR { flags: ash::vk::SwapchainCreateFlagsKHR::empty(), surface: surface.internal_object(), min_image_count, @@ -612,19 +594,31 @@ impl Swapchain { old_swapchain: old_swapchain.map_or(ash::vk::SwapchainKHR::null(), |os| os.handle), ..Default::default() }; + let mut surface_full_screen_exclusive_info_vk = None; + let mut surface_full_screen_exclusive_win32_info_vk = None; - if let Some(surface_full_screen_exclusive_info) = - surface_full_screen_exclusive_info.as_mut() - { - surface_full_screen_exclusive_info.p_next = create_info.p_next as *mut _; - create_info.p_next = surface_full_screen_exclusive_info as *const _ as *const _; + if full_screen_exclusive != FullScreenExclusive::Default { + let next = surface_full_screen_exclusive_info_vk.insert( + ash::vk::SurfaceFullScreenExclusiveInfoEXT { + full_screen_exclusive: full_screen_exclusive.into(), + ..Default::default() + }, + ); + + next.p_next = info_vk.p_next as *mut _; + info_vk.p_next = next as *const _ as *const _; } - if let Some(surface_full_screen_exclusive_win32_info) = - surface_full_screen_exclusive_win32_info.as_mut() - { - surface_full_screen_exclusive_win32_info.p_next = create_info.p_next as *mut _; - create_info.p_next = surface_full_screen_exclusive_win32_info as *const _ as *const _; + if let Some(Win32Monitor(hmonitor)) = win32_monitor { + let next = surface_full_screen_exclusive_win32_info_vk.insert( + ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT { + hmonitor, + ..Default::default() + }, + ); + + next.p_next = info_vk.p_next as *mut _; + info_vk.p_next = next as *const _ as *const _; } let fns = device.fns(); @@ -633,7 +627,7 @@ impl Swapchain { let mut output = MaybeUninit::uninit(); (fns.khr_swapchain.create_swapchain_khr)( device.internal_object(), - &create_info, + &info_vk, ptr::null(), output.as_mut_ptr(), ) @@ -745,48 +739,6 @@ impl Swapchain { &self.surface } - /// Returns of the images that belong to this swapchain. - #[inline] - pub fn raw_image(&self, offset: usize) -> Option { - self.images.get(offset).map(|i| ImageInner { - image: &i.image, - first_layer: 0, - num_layers: self.image_array_layers, - first_mipmap_level: 0, - num_mipmap_levels: 1, - }) - } - - /// Returns the number of images of the swapchain. - #[inline] - pub fn image_count(&self) -> u32 { - self.images.len() as u32 - } - - /// Returns the format of the images of the swapchain. - #[inline] - pub fn image_format(&self) -> Format { - self.image_format - } - - /// Returns the color space of the images of the swapchain. - #[inline] - pub fn image_color_space(&self) -> ColorSpace { - self.image_color_space - } - - /// Returns the extent of the images of the swapchain. - #[inline] - pub fn image_extent(&self) -> [u32; 2] { - self.image_extent - } - - /// Returns the number of array layers of the images of the swapchain. - #[inline] - pub fn image_array_layers(&self) -> u32 { - self.image_array_layers - } - /// Returns the pre-transform that was passed when creating the swapchain. #[inline] pub fn pre_transform(&self) -> SurfaceTransform { @@ -892,25 +844,21 @@ impl Swapchain { // transitioned out of their initial `undefined` image layout. // // See the `ImageAccess::layout_initialized` method documentation for more details. - pub(crate) fn image_layout_initialized(&self, image_offset: usize) { - let image_entry = self.images.get(image_offset); + pub(crate) fn image_layout_initialized(&self, image_index: u32) { + let image_entry = self.images.get(image_index as usize); if let Some(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); + pub(crate) fn is_image_layout_initialized(&self, image_index: u32) -> bool { + let image_entry = self.images.get(image_index as usize); if let Some(image_entry) = image_entry { !image_entry.undefined_layout.load(Ordering::SeqCst) } else { false } } - - pub(crate) fn prev_present_id(&self) -> &AtomicU64 { - &self.prev_present_id - } } impl Drop for Swapchain { @@ -960,6 +908,154 @@ impl Hash for Swapchain { } } +impl Debug for Swapchain { + #[inline] + fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { + let Self { + handle, + device, + surface, + min_image_count, + image_format, + image_color_space, + image_extent, + image_array_layers, + image_usage, + image_sharing, + pre_transform, + composite_alpha, + present_mode, + clipped, + full_screen_exclusive, + win32_monitor, + prev_present_id, + full_screen_exclusive_held, + images, + retired, + } = self; + + f.debug_struct("Swapchain") + .field("handle", &handle) + .field("device", &device.internal_object()) + .field("surface", &surface.internal_object()) + .field("min_image_count", &min_image_count) + .field("image_format", &image_format) + .field("image_color_space", &image_color_space) + .field("image_extent", &image_extent) + .field("image_array_layers", &image_array_layers) + .field("image_usage", &image_usage) + .field("image_sharing", &image_sharing) + .field("pre_transform", &pre_transform) + .field("composite_alpha", &composite_alpha) + .field("present_mode", &present_mode) + .field("clipped", &clipped) + .field("full_screen_exclusive", &full_screen_exclusive) + .field("win32_monitor", &win32_monitor) + .field("prev_present_id", &prev_present_id) + .field("full_screen_exclusive_held", &full_screen_exclusive_held) + .field("images", &images) + .field("retired", &retired) + .finish() + } +} + +/// Trait for types that represent the GPU can access an image view. +pub unsafe trait SwapchainAbstract: + VulkanObject + DeviceOwned + Debug + Send + Sync +{ + /// Returns one of the images that belongs to this swapchain. + fn raw_image(&self, index: u32) -> Option; + + /// Returns the number of images of the swapchain. + fn image_count(&self) -> u32; + + /// Returns the format of the images of the swapchain. + fn image_format(&self) -> Format; + + /// Returns the color space of the images of the swapchain. + fn image_color_space(&self) -> ColorSpace; + + /// Returns the extent of the images of the swapchain. + fn image_extent(&self) -> [u32; 2]; + + /// Returns the number of array layers of the images of the swapchain. + fn image_array_layers(&self) -> u32; + + #[doc(hidden)] + unsafe fn prev_present_id(&self) -> &AtomicU64; + + #[doc(hidden)] + unsafe fn full_screen_exclusive_held(&self) -> &AtomicBool; +} + +unsafe impl SwapchainAbstract for Swapchain +where + W: Send + Sync, +{ + #[inline] + fn raw_image(&self, image_index: u32) -> Option { + self.images.get(image_index as usize).map(|i| ImageInner { + image: &i.image, + first_layer: 0, + num_layers: self.image_array_layers, + first_mipmap_level: 0, + num_mipmap_levels: 1, + }) + } + + #[inline] + fn image_count(&self) -> u32 { + self.images.len() as u32 + } + + #[inline] + fn image_format(&self) -> Format { + self.image_format + } + + #[inline] + fn image_color_space(&self) -> ColorSpace { + self.image_color_space + } + + #[inline] + fn image_extent(&self) -> [u32; 2] { + self.image_extent + } + + #[inline] + fn image_array_layers(&self) -> u32 { + self.image_array_layers + } + + #[inline] + unsafe fn full_screen_exclusive_held(&self) -> &AtomicBool { + &self.full_screen_exclusive_held + } + + #[inline] + unsafe fn prev_present_id(&self) -> &AtomicU64 { + &self.prev_present_id + } +} + +impl PartialEq for dyn SwapchainAbstract { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.internal_object() == other.internal_object() && self.device() == other.device() + } +} + +impl Eq for dyn SwapchainAbstract {} + +impl Hash for dyn SwapchainAbstract { + #[inline] + fn hash(&self, state: &mut H) { + self.internal_object().hash(state); + self.device().hash(state); + } +} + /// Parameters to create a new `Swapchain`. /// /// Many of the values here must be supported by the physical device. @@ -1437,11 +1533,14 @@ impl From for FullScreenExclusiveError { pub fn acquire_next_image( swapchain: Arc>, timeout: Option, -) -> Result<(usize, bool, SwapchainAcquireFuture), AcquireError> { - let semaphore = Semaphore::from_pool(swapchain.device.clone())?; +) -> Result<(u32, bool, SwapchainAcquireFuture), AcquireError> { + let semaphore = Arc::new(Semaphore::from_pool(swapchain.device.clone())?); let fence = Fence::from_pool(swapchain.device.clone())?; - let AcquiredImage { id, suboptimal } = { + let AcquiredImage { + image_index, + suboptimal, + } = { // Check that this is not an old swapchain. From specs: // > swapchain must not have been replaced by being passed as the // > VkSwapchainCreateInfoKHR::oldSwapchain value to vkCreateSwapchainKHR @@ -1463,66 +1562,31 @@ pub fn acquire_next_image( }; Ok(( - id, + image_index, suboptimal, SwapchainAcquireFuture { swapchain, semaphore: Some(semaphore), fence: Some(fence), - image_id: id, + image_index, finished: AtomicBool::new(false), }, )) } -/// 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 { - /// The `Swapchain` to present to. - pub swapchain: Arc>, - /// 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, - /// 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, - pub _ne: crate::NonExhaustive, -} - -impl PresentInfo { - pub fn swapchain(swapchain: Arc>) -> Self { - Self { - swapchain, - index: 0, - present_id: None, - present_region: None, - _ne: crate::NonExhaustive(()), - } - } -} - /// Presents an image on the screen. /// /// The actual behavior depends on the present mode that you passed when creating the /// swapchain. -pub fn present(before: F, queue: Arc, info: PresentInfo) -> PresentFuture +pub fn present( + before: F, + queue: Arc, + swapchain_info: SwapchainPresentInfo, +) -> PresentFuture where F: GpuFuture, { - assert!(info.index < info.swapchain.images.len()); + assert!(swapchain_info.image_index < swapchain_info.swapchain.image_count()); // 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 @@ -1534,7 +1598,7 @@ where PresentFuture { previous: before, queue, - info, + swapchain_info, flushed: AtomicBool::new(false), finished: AtomicBool::new(false), } @@ -1604,10 +1668,10 @@ pub fn wait_for_present( #[must_use] pub struct SwapchainAcquireFuture { swapchain: Arc>, - image_id: usize, + image_index: u32, // Semaphore that is signalled when the acquire is complete. Empty if the acquire has already // happened. - semaphore: Option, + semaphore: Option>, // Fence that is signalled when the acquire is complete. Empty if the acquire has already // happened. fence: Option, @@ -1617,8 +1681,8 @@ pub struct SwapchainAcquireFuture { impl SwapchainAcquireFuture { /// 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 + pub fn image_index(&self) -> u32 { + self.image_index } /// Returns the corresponding swapchain. @@ -1628,7 +1692,10 @@ impl SwapchainAcquireFuture { } } -unsafe impl GpuFuture for SwapchainAcquireFuture { +unsafe impl GpuFuture for SwapchainAcquireFuture +where + W: Send + Sync, +{ #[inline] fn cleanup_finished(&mut self) {} @@ -1636,7 +1703,7 @@ unsafe impl GpuFuture for SwapchainAcquireFuture { unsafe fn build_submission(&self) -> Result { if let Some(ref semaphore) = self.semaphore { let mut sem = SubmitSemaphoresWaitBuilder::new(); - sem.add_wait_semaphore(semaphore); + sem.add_wait_semaphore(semaphore.clone()); Ok(SubmitAnyBuilder::SemaphoresWait(sem)) } else { Ok(SubmitAnyBuilder::Empty) @@ -1683,12 +1750,12 @@ unsafe impl GpuFuture for SwapchainAcquireFuture { expected_layout: ImageLayout, _queue: &Queue, ) -> Result, AccessCheckError> { - let swapchain_image = self.swapchain.raw_image(self.image_id).unwrap(); + let swapchain_image = self.swapchain.raw_image(self.image_index).unwrap(); if swapchain_image.image.internal_object() != image.internal_object() { return Err(AccessCheckError::Unknown); } - if self.swapchain.images[self.image_id] + if self.swapchain.images[self.image_index as usize] .undefined_layout .load(Ordering::Relaxed) && expected_layout != ImageLayout::Undefined @@ -1929,13 +1996,13 @@ impl From for PresentWaitError { /// 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 +pub struct PresentFuture

where P: GpuFuture, { previous: P, queue: Arc, - info: PresentInfo, + swapchain_info: SwapchainPresentInfo, // True if `flush()` has been called on the future, which means that the present command has // been submitted. flushed: AtomicBool, @@ -1944,24 +2011,24 @@ where finished: AtomicBool, } -impl PresentFuture +impl

PresentFuture

where P: GpuFuture, { /// Returns the index of the image in the list of images returned when creating the swapchain. #[inline] - pub fn image_id(&self) -> usize { - self.info.index + pub fn image_id(&self) -> u32 { + self.swapchain_info.image_index } /// Returns the corresponding swapchain. #[inline] - pub fn swapchain(&self) -> &Arc> { - &self.info.swapchain + pub fn swapchain(&self) -> &Arc { + &self.swapchain_info.swapchain } } -unsafe impl GpuFuture for PresentFuture +unsafe impl

GpuFuture for PresentFuture

where P: GpuFuture, { @@ -1984,12 +2051,12 @@ where Ok(match self.previous.build_submission()? { SubmitAnyBuilder::Empty => { let mut builder = SubmitPresentBuilder::new(); - builder.add_swapchain(&self.info); + builder.add_swapchain(self.swapchain_info.clone()); SubmitAnyBuilder::QueuePresent(builder) } SubmitAnyBuilder::SemaphoresWait(sem) => { let mut builder: SubmitPresentBuilder = sem.into(); - builder.add_swapchain(&self.info); + builder.add_swapchain(self.swapchain_info.clone()); SubmitAnyBuilder::QueuePresent(builder) } SubmitAnyBuilder::CommandBuffer(_) => { @@ -1998,7 +2065,7 @@ where self.previous.flush()?; let mut builder = SubmitPresentBuilder::new(); - builder.add_swapchain(&self.info); + builder.add_swapchain(self.swapchain_info.clone()); SubmitAnyBuilder::QueuePresent(builder) } SubmitAnyBuilder::BindSparse(_) => { @@ -2007,7 +2074,7 @@ where self.previous.flush()?; let mut builder = SubmitPresentBuilder::new(); - builder.add_swapchain(&self.info); + builder.add_swapchain(self.swapchain_info.clone()); SubmitAnyBuilder::QueuePresent(builder) } SubmitAnyBuilder::QueuePresent(_present) => { @@ -2029,9 +2096,9 @@ where self.flushed.store(true, Ordering::SeqCst); if let &Err(FlushError::FullScreenExclusiveModeLost) = &build_submission_result { - self.info + self.swapchain_info .swapchain - .full_screen_exclusive_held + .full_screen_exclusive_held() .store(false, Ordering::SeqCst); } @@ -2041,9 +2108,9 @@ where let present_result = present.submit(&self.queue); if let &Err(SubmitPresentError::FullScreenExclusiveModeLost) = &present_result { - self.info + self.swapchain_info .swapchain - .full_screen_exclusive_held + .full_screen_exclusive_held() .store(false, Ordering::SeqCst); } @@ -2099,7 +2166,11 @@ where expected_layout: ImageLayout, queue: &Queue, ) -> Result, AccessCheckError> { - let swapchain_image = self.info.swapchain.raw_image(self.info.index).unwrap(); + let swapchain_image = self + .swapchain_info + .swapchain + .raw_image(self.swapchain_info.image_index) + .unwrap(); if swapchain_image.image.internal_object() == image.internal_object() { // This future presents the swapchain image, which "unlocks" it. Therefore any attempt @@ -2114,7 +2185,7 @@ where } } -unsafe impl DeviceOwned for PresentFuture +unsafe impl

DeviceOwned for PresentFuture

where P: GpuFuture, { @@ -2124,7 +2195,7 @@ where } } -impl Drop for PresentFuture +impl

Drop for PresentFuture

where P: GpuFuture, { @@ -2146,7 +2217,7 @@ where } pub struct AcquiredImage { - pub id: usize, + pub image_index: u32, pub suboptimal: bool, } @@ -2197,7 +2268,7 @@ pub unsafe fn acquire_next_image_raw( }; Ok(AcquiredImage { - id: out.assume_init() as usize, + image_index: out.assume_init(), suboptimal, }) } diff --git a/vulkano/src/sync/future/fence_signal.rs b/vulkano/src/sync/future/fence_signal.rs index 1254946376..f9f1249972 100644 --- a/vulkano/src/sync/future/fence_signal.rs +++ b/vulkano/src/sync/future/fence_signal.rs @@ -29,7 +29,7 @@ where assert!(future.queue().is_some()); // TODO: document - let fence = Fence::from_pool(device.clone()).unwrap(); + let fence = Arc::new(Fence::from_pool(device.clone()).unwrap()); FenceSignalFuture { device, state: Mutex::new(FenceSignalFutureState::Pending(future, fence)), @@ -98,17 +98,17 @@ where // been dropped). enum FenceSignalFutureState { // Newly-created. Not submitted yet. - Pending(F, Fence), + Pending(F, Arc), // Partially submitted to the queue. Only happens in situations where submitting requires two // steps, and when the first step succeeded while the second step failed. // // Note that if there's ever a submit operation that needs three steps we will need to rework // this code, as it was designed for two-step operations only. - PartiallyFlushed(F, Fence), + PartiallyFlushed(F, Arc), // Submitted to the queue. - Flushed(F, Fence), + Flushed(F, Arc), // The submission is finished. The previous future and the fence have been cleaned. Cleaned, @@ -233,7 +233,7 @@ where SubmitAnyBuilder::Empty => { debug_assert!(!partially_flushed); let mut b = SubmitCommandBufferBuilder::new(); - b.set_fence_signal(&fence); + b.set_fence_signal(fence.clone()); b.submit(&queue).map_err(|err| OutcomeErr::Full(err.into())) } SubmitAnyBuilder::SemaphoresWait(sem) => { @@ -250,7 +250,7 @@ where // disastrous and hard to debug. Therefore we prefer to just use a regular // assertion. assert!(!cb_builder.has_fence()); - cb_builder.set_fence_signal(&fence); + cb_builder.set_fence_signal(fence.clone()); cb_builder .submit(&queue) .map_err(|err| OutcomeErr::Full(err.into())) @@ -259,7 +259,7 @@ where debug_assert!(!partially_flushed); // Same remark as `CommandBuffer`. assert!(!sparse.has_fence()); - sparse.set_fence_signal(&fence); + sparse.set_fence_signal(fence.clone()); sparse .submit(&queue) .map_err(|err| OutcomeErr::Full(err.into())) @@ -273,7 +273,7 @@ where match intermediary_result { Ok(()) => { let mut b = SubmitCommandBufferBuilder::new(); - b.set_fence_signal(&fence); + b.set_fence_signal(fence.clone()); b.submit(&queue) .map_err(|err| OutcomeErr::Partial(err.into())) } diff --git a/vulkano/src/sync/future/mod.rs b/vulkano/src/sync/future/mod.rs index 67a71ce171..6e93d1f0a3 100644 --- a/vulkano/src/sync/future/mod.rs +++ b/vulkano/src/sync/future/mod.rs @@ -24,7 +24,7 @@ use crate::{ }, device::{DeviceOwned, Queue}, image::{sys::UnsafeImage, ImageLayout}, - swapchain::{self, PresentFuture, PresentInfo}, + swapchain::{self, PresentFuture, SwapchainPresentInfo}, DeviceSize, OomError, }; use std::{ @@ -162,7 +162,7 @@ pub unsafe trait GpuFuture: DeviceOwned { self, queue: Arc, command_buffer: Cb, - ) -> Result, CommandBufferExecError> + ) -> Result, CommandBufferExecError> where Self: Sized, Cb: PrimaryCommandBuffer + 'static, @@ -178,7 +178,7 @@ pub unsafe trait GpuFuture: DeviceOwned { fn then_execute_same_queue( self, command_buffer: Cb, - ) -> Result, CommandBufferExecError> + ) -> Result, CommandBufferExecError> where Self: Sized, Cb: PrimaryCommandBuffer + 'static, @@ -254,15 +254,15 @@ pub unsafe trait GpuFuture: DeviceOwned { /// /// > **Note**: This is just a shortcut for the `Swapchain::present()` function. #[inline] - fn then_swapchain_present( + fn then_swapchain_present( self, queue: Arc, - info: PresentInfo, - ) -> PresentFuture + swapchain_info: SwapchainPresentInfo, + ) -> PresentFuture where Self: Sized, { - swapchain::present(self, queue, info) + swapchain::present(self, queue, swapchain_info) } /// Turn the current future into a `Box`. diff --git a/vulkano/src/sync/future/semaphore_signal.rs b/vulkano/src/sync/future/semaphore_signal.rs index 9d1b8c9105..635c584709 100644 --- a/vulkano/src/sync/future/semaphore_signal.rs +++ b/vulkano/src/sync/future/semaphore_signal.rs @@ -39,7 +39,7 @@ where SemaphoreSignalFuture { previous: future, - semaphore: Semaphore::from_pool(device).unwrap(), + semaphore: Arc::new(Semaphore::from_pool(device).unwrap()), wait_submitted: Mutex::new(false), finished: AtomicBool::new(false), } @@ -53,7 +53,7 @@ where F: GpuFuture, { previous: F, - semaphore: Semaphore, + semaphore: Arc, // True if the signaling command has already been submitted. // If flush is called multiple times, we want to block so that only one flushing is executed. // Therefore we use a `Mutex` and not an `AtomicBool`. @@ -76,7 +76,7 @@ where self.flush()?; let mut sem = SubmitSemaphoresWaitBuilder::new(); - sem.add_wait_semaphore(&self.semaphore); + sem.add_wait_semaphore(self.semaphore.clone()); Ok(SubmitAnyBuilder::SemaphoresWait(sem)) } @@ -93,17 +93,17 @@ where match self.previous.build_submission()? { SubmitAnyBuilder::Empty => { let mut builder = SubmitCommandBufferBuilder::new(); - builder.add_signal_semaphore(&self.semaphore); + builder.add_signal_semaphore(self.semaphore.clone()); builder.submit(&queue)?; } SubmitAnyBuilder::SemaphoresWait(sem) => { let mut builder: SubmitCommandBufferBuilder = sem.into(); - builder.add_signal_semaphore(&self.semaphore); + builder.add_signal_semaphore(self.semaphore.clone()); builder.submit(&queue)?; } SubmitAnyBuilder::CommandBuffer(mut builder) => { debug_assert_eq!(builder.num_signal_semaphores(), 0); - builder.add_signal_semaphore(&self.semaphore); + builder.add_signal_semaphore(self.semaphore.clone()); builder.submit(&queue)?; } SubmitAnyBuilder::BindSparse(_) => { @@ -115,7 +115,7 @@ where SubmitAnyBuilder::QueuePresent(present) => { present.submit(&queue)?; let mut builder = SubmitCommandBufferBuilder::new(); - builder.add_signal_semaphore(&self.semaphore); + builder.add_signal_semaphore(self.semaphore.clone()); builder.submit(&queue)?; // FIXME: problematic because if we return an error and flush() is called again, then we'll submit the present twice } };