ValidationError-ify Surface and Swapchain (#2236)

* Add `RequiresAllOf`, automatically enable required extensions and features

* Add more missing backticks and backslashes to error messages

* Use updated VUIDs that require `acceleration_structure`

* ValidationError-ify `Surface` and `Swapchain`

* Update vulkano/src/lib.rs

Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>

* Update vulkano/src/lib.rs

Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>

* Don't draw if the window has zero size

---------

Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>
This commit is contained in:
Rua 2023-06-26 11:17:53 +02:00 committed by GitHub
parent 2d6ff1061c
commit da09477d01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 3599 additions and 2919 deletions

View File

@ -85,7 +85,7 @@ use vulkano::{
sampler::{Sampler, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -545,21 +545,19 @@ fn main() {
channel.send(()).unwrap();
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
if recreate_swapchain {
let (new_swapchain, new_images) =
match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers = window_size_dependent_setup(

View File

@ -45,7 +45,7 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -292,23 +292,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) =
match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers = window_size_dependent_setup(

View File

@ -22,7 +22,7 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -175,22 +175,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
width = swapchain.image_extent()[0];

View File

@ -42,7 +42,7 @@ use vulkano::{
memory::allocator::StandardMemoryAllocator,
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -199,22 +199,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
let new_images = new_images
.into_iter()
.map(|image| ImageView::new_default(image).unwrap())

View File

@ -50,10 +50,7 @@ mod linux {
},
render_pass::{Framebuffer, RenderPass, Subpass},
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
SwapchainPresentInfo,
},
swapchain::{AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo},
sync::{
now,
semaphore::{
@ -287,20 +284,21 @@ mod linux {
})
.unwrap();
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) =
match swapchain.recreate(SwapchainCreateInfo {
image_extent: window.inner_size().into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => {
return
}
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers = window_size_dependent_setup(

View File

@ -48,7 +48,7 @@ use vulkano::{
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -421,22 +421,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers =

View File

@ -46,7 +46,7 @@ use vulkano::{
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -347,22 +347,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers =

View File

@ -55,7 +55,7 @@ use vulkano::{
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -368,22 +368,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers =

View File

@ -62,7 +62,7 @@ use vulkano::{
single_pass_renderpass,
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -384,23 +384,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) =
match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers = window_size_dependent_setup(

View File

@ -43,7 +43,7 @@ use vulkano::{
single_pass_renderpass,
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -364,23 +364,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) =
match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers = window_size_dependent_setup(

View File

@ -46,7 +46,7 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -415,22 +415,21 @@ fn main() {
previous_frame_end,
} = window_surfaces.get_mut(&window_id).unwrap();
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if *recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
*swapchain = new_swapchain;
*framebuffers =

View File

@ -44,7 +44,7 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -382,22 +382,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers = window_size_dependent_setup(

View File

@ -44,7 +44,7 @@ use vulkano::{
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -341,22 +341,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers =

View File

@ -52,7 +52,7 @@ use vulkano::{
shader::ShaderModule,
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -312,22 +312,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers =

View File

@ -47,7 +47,7 @@ use vulkano::{
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -455,22 +455,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers =

View File

@ -524,8 +524,9 @@ fn main() {
*control_flow = ControlFlow::Exit;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}

View File

@ -49,7 +49,7 @@ use vulkano::{
shader::EntryPoint,
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -276,23 +276,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) =
match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
let (new_pipeline, new_framebuffers) = window_size_dependent_setup(

View File

@ -52,7 +52,7 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -424,22 +424,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers =

View File

@ -46,7 +46,7 @@ use vulkano::{
sampler::{Sampler, SamplerCreateInfo},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -352,22 +352,21 @@ fn main() {
recreate_swapchain = true;
}
Event::RedrawEventsCleared => {
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
previous_frame_end.as_mut().unwrap().cleanup_finished();
if recreate_swapchain {
let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;
framebuffers =

View File

@ -52,7 +52,7 @@ use vulkano::{
render_pass::{AttachmentLoadOp, AttachmentStoreOp},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
Version, VulkanLibrary,
@ -527,8 +527,9 @@ fn main() {
Event::RedrawEventsCleared => {
// Do not draw the frame when the screen dimensions are zero. On Windows, this can
// occur when minimizing the application.
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
@ -542,18 +543,12 @@ fn main() {
// window size. In this example that includes the swapchain, the framebuffers and
// the dynamic state viewport.
if recreate_swapchain {
let (new_swapchain, new_images) =
match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
// This error tends to happen when the user is manually resizing the
// window. Simply restarting the loop is the easiest way to fix this
// issue.
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;

View File

@ -46,7 +46,7 @@ use vulkano::{
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
swapchain::{
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
SwapchainCreationError, SwapchainPresentInfo,
SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
VulkanLibrary,
@ -522,8 +522,9 @@ fn main() {
Event::RedrawEventsCleared => {
// Do not draw the frame when the screen dimensions are zero. On Windows, this can
// occur when minimizing the application.
let dimensions = window.inner_size();
if dimensions.width == 0 || dimensions.height == 0 {
let image_extent: [u32; 2] = window.inner_size().into();
if image_extent.contains(&0) {
return;
}
@ -539,18 +540,12 @@ fn main() {
if recreate_swapchain {
// Use the new dimensions of the window.
let (new_swapchain, new_images) =
match swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions.into(),
let (new_swapchain, new_images) = swapchain
.recreate(SwapchainCreateInfo {
image_extent,
..swapchain.create_info()
}) {
Ok(r) => r,
// This error tends to happen when the user is manually resizing the
// window. Simply restarting the loop is the easiest way to fix this
// issue.
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
swapchain = new_swapchain;

View File

@ -18,8 +18,7 @@ use vulkano::{
},
memory::allocator::StandardMemoryAllocator,
swapchain::{
self, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
SwapchainPresentInfo,
self, AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo,
},
sync::{self, FlushError, GpuFuture},
};
@ -337,17 +336,21 @@ 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.swapchain.recreate(SwapchainCreateInfo {
image_extent: dimensions,
let image_extent: [u32; 2] = self.window().inner_size().into();
if image_extent.contains(&0) {
return;
}
let (new_swapchain, new_images) = self
.swapchain
.recreate(SwapchainCreateInfo {
image_extent,
// Use present mode from current state
present_mode: self.present_mode,
..self.swapchain.create_info()
}) {
Ok(r) => r,
Err(SwapchainCreationError::ImageExtentNotSupported { .. }) => return,
Err(e) => panic!("failed to recreate swapchain: {e}"),
};
})
.expect("failed to recreate swapchain");
self.swapchain = new_swapchain;
let new_images = new_images

View File

@ -14,7 +14,7 @@
`Surface::from_window` instead"
)]
#![doc(html_logo_url = "https://raw.githubusercontent.com/vulkano-rs/vulkano/master/logo.png")]
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::missing_safety_doc, clippy::result_large_err)]
#![warn(rust_2018_idioms, rust_2021_compatibility)]
#[cfg(feature = "raw-window-handle")]

View File

@ -6,17 +6,14 @@ use raw_window_handle::{
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
};
use std::{any::Any, sync::Arc};
use vulkano::{
instance::Instance,
swapchain::{Surface, SurfaceCreationError},
};
use vulkano::{instance::Instance, swapchain::Surface, VulkanError};
/// Creates a Vulkan surface from a generic window which implements `HasRawWindowHandle` and thus
/// can reveal the OS-dependent handle.
pub fn create_surface_from_handle(
window: Arc<impl Any + Send + Sync + HasRawWindowHandle + HasRawDisplayHandle>,
instance: Arc<Instance>,
) -> Result<Arc<Surface>, SurfaceCreationError> {
) -> Result<Arc<Surface>, VulkanError> {
unsafe {
match window.raw_window_handle() {
RawWindowHandle::AndroidNdk(h) => {
@ -85,7 +82,7 @@ pub fn create_surface_from_handle(
pub unsafe fn create_surface_from_handle_ref(
window: &(impl HasRawWindowHandle + HasRawDisplayHandle),
instance: Arc<Instance>,
) -> Result<Arc<Surface>, SurfaceCreationError> {
) -> Result<Arc<Surface>, VulkanError> {
unsafe {
match window.raw_window_handle() {
RawWindowHandle::AndroidNdk(h) => {

View File

@ -5,8 +5,8 @@ use std::{
};
use vulkano::{
instance::{Instance, InstanceExtensions},
swapchain::{Surface, SurfaceCreationError},
VulkanLibrary,
swapchain::Surface,
VulkanError, VulkanLibrary,
};
use winit::{
error::OsError as WindowCreationError,
@ -37,7 +37,7 @@ pub fn required_extensions(library: &VulkanLibrary) -> InstanceExtensions {
pub fn create_surface_from_winit(
window: Arc<Window>,
instance: Arc<Instance>,
) -> Result<Arc<Surface>, SurfaceCreationError> {
) -> Result<Arc<Surface>, VulkanError> {
unsafe { winit_to_surface(instance, window) }
}
@ -65,7 +65,8 @@ impl<E> VkSurfaceBuild<E> for WindowBuilder {
#[derive(Debug)]
pub enum CreationError {
/// Error when creating the surface.
SurfaceCreationError(SurfaceCreationError),
VulkanError(VulkanError),
/// Error when creating the window.
WindowCreationError(WindowCreationError),
}
@ -73,7 +74,7 @@ pub enum CreationError {
impl Error for CreationError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
CreationError::SurfaceCreationError(err) => Some(err),
CreationError::VulkanError(err) => Some(err),
CreationError::WindowCreationError(err) => Some(err),
}
}
@ -85,16 +86,16 @@ impl Display for CreationError {
f,
"{}",
match self {
CreationError::SurfaceCreationError(_) => "error while creating the surface",
CreationError::VulkanError(_) => "error while creating the surface",
CreationError::WindowCreationError(_) => "error while creating the window",
}
)
}
}
impl From<SurfaceCreationError> for CreationError {
fn from(err: SurfaceCreationError) -> CreationError {
CreationError::SurfaceCreationError(err)
impl From<VulkanError> for CreationError {
fn from(err: VulkanError) -> CreationError {
CreationError::VulkanError(err)
}
}
@ -108,7 +109,7 @@ impl From<WindowCreationError> for CreationError {
unsafe fn winit_to_surface(
instance: Arc<Instance>,
window: Arc<Window>,
) -> Result<Arc<Surface>, SurfaceCreationError> {
) -> Result<Arc<Surface>, VulkanError> {
use raw_window_handle::HasRawWindowHandle;
use raw_window_handle::RawWindowHandle::AndroidNdk;
if let AndroidNdk(handle) = window.raw_window_handle() {
@ -127,7 +128,7 @@ unsafe fn winit_to_surface(
unsafe fn winit_to_surface(
instance: Arc<Instance>,
window: Arc<Window>,
) -> Result<Arc<Surface>, SurfaceCreationError> {
) -> Result<Arc<Surface>, VulkanError> {
use winit::platform::{wayland::WindowExtWayland, x11::WindowExtX11};
match (window.wayland_display(), window.wayland_surface()) {
@ -193,7 +194,7 @@ pub(crate) unsafe fn get_metal_layer_macos(view: *mut std::ffi::c_void) -> *mut
unsafe fn winit_to_surface(
instance: Arc<Instance>,
window: Arc<Window>,
) -> Result<Arc<Surface>, SurfaceCreationError> {
) -> Result<Arc<Surface>, VulkanError> {
use winit::platform::macos::WindowExtMacOS;
let layer = get_metal_layer_macos(window.ns_view());
Surface::from_mac_os(instance, layer as *const (), Some(window))
@ -224,7 +225,7 @@ pub(crate) unsafe fn get_metal_layer_ios(view: *mut std::ffi::c_void) -> IOSMeta
unsafe fn winit_to_surface(
instance: Arc<Instance>,
window: Arc<Window>,
) -> Result<Arc<Surface>, SurfaceCreationError> {
) -> Result<Arc<Surface>, VulkanError> {
use winit::platform::ios::WindowExtIOS;
let layer = get_metal_layer_ios(window.ui_view());
Surface::from_ios(instance, layer, Some(window))
@ -234,7 +235,7 @@ unsafe fn winit_to_surface(
unsafe fn winit_to_surface(
instance: Arc<Instance>,
window: Arc<Window>,
) -> Result<Arc<Surface>, SurfaceCreationError> {
) -> Result<Arc<Surface>, VulkanError> {
use winit::platform::windows::WindowExtWindows;
Surface::from_win32(

View File

@ -1387,11 +1387,31 @@ impl PhysicalDevice {
.map_err(|err| err.add_context("surface_info"))?;
let &SurfaceInfo {
present_mode,
full_screen_exclusive,
win32_monitor,
_ne: _,
} = surface_info;
if let Some(present_mode) = present_mode {
let mut present_modes = unsafe {
self.surface_present_modes_unchecked(surface)
.map_err(|_err| ValidationError {
context: "PhysicalDevice::surface_present_modes".into(),
problem: "returned an error".into(),
..Default::default()
})?
};
if !present_modes.any(|mode| mode == present_mode) {
return Err(ValidationError {
problem: "`surface_info.present_mode` is not supported for `surface`".into(),
vuids: &["VUID-VkSurfacePresentModeEXT-presentMode-07780"],
..Default::default()
});
}
}
match (
surface.api() == SurfaceApi::Win32
&& full_screen_exclusive == FullScreenExclusive::ApplicationControlled,
@ -1433,6 +1453,7 @@ impl PhysicalDevice {
/* Input */
let SurfaceInfo {
present_mode,
full_screen_exclusive,
win32_monitor,
_ne: _,
@ -1442,10 +1463,21 @@ impl PhysicalDevice {
surface: surface.handle(),
..Default::default()
};
let mut present_mode_vk = None;
let mut full_screen_exclusive_info_vk = None;
let mut full_screen_exclusive_win32_info_vk = None;
if self.supported_extensions().ext_full_screen_exclusive && win32_monitor.is_some() {
if let Some(present_mode) = present_mode {
let next = present_mode_vk.insert(ash::vk::SurfacePresentModeEXT {
present_mode: present_mode.into(),
..Default::default()
});
next.p_next = info_vk.p_next as *mut _;
info_vk.p_next = next as *const _ as *const _;
}
if full_screen_exclusive != FullScreenExclusive::Default {
let next =
full_screen_exclusive_info_vk.insert(ash::vk::SurfaceFullScreenExclusiveInfoEXT {
full_screen_exclusive: full_screen_exclusive.into(),
@ -1472,7 +1504,11 @@ impl PhysicalDevice {
let mut capabilities_vk = ash::vk::SurfaceCapabilities2KHR::default();
let mut capabilities_full_screen_exclusive_vk = None;
let mut protected_capabilities_vk = None;
let mut capabilities_present_modes_vk =
[ash::vk::PresentModeKHR::default(); PresentMode::COUNT];
let mut capabilities_present_mode_compatibility_vk = None;
let mut capabilities_present_scaling_vk = None;
let mut capabilities_protected_vk = None;
if full_screen_exclusive_info_vk.is_some() {
let next = capabilities_full_screen_exclusive_vk
@ -1482,12 +1518,35 @@ impl PhysicalDevice {
capabilities_vk.p_next = next as *mut _ as *mut _;
}
if present_mode.is_some() {
{
let next = capabilities_present_mode_compatibility_vk.insert(
ash::vk::SurfacePresentModeCompatibilityEXT {
present_mode_count: capabilities_present_modes_vk.len() as u32,
p_present_modes: capabilities_present_modes_vk.as_mut_ptr(),
..Default::default()
},
);
next.p_next = capabilities_vk.p_next as *mut _;
capabilities_vk.p_next = next as *mut _ as *mut _;
}
{
let next = capabilities_present_scaling_vk
.insert(ash::vk::SurfacePresentScalingCapabilitiesEXT::default());
next.p_next = capabilities_vk.p_next as *mut _;
capabilities_vk.p_next = next as *mut _ as *mut _;
}
}
if self
.instance
.enabled_extensions()
.khr_surface_protected_capabilities
{
let next = protected_capabilities_vk
let next = capabilities_protected_vk
.insert(ash::vk::SurfaceProtectedCapabilitiesKHR::default());
next.p_next = capabilities_vk.p_next as *mut _;
@ -1521,22 +1580,19 @@ impl PhysicalDevice {
Ok(SurfaceCapabilities {
min_image_count: capabilities_vk.surface_capabilities.min_image_count,
max_image_count: if capabilities_vk.surface_capabilities.max_image_count == 0 {
None
} else {
Some(capabilities_vk.surface_capabilities.max_image_count)
},
current_extent: if capabilities_vk.surface_capabilities.current_extent.width
== 0xffffffff
&& capabilities_vk.surface_capabilities.current_extent.height == 0xffffffff
{
None
} else {
Some([
max_image_count: (capabilities_vk.surface_capabilities.max_image_count != 0)
.then_some(capabilities_vk.surface_capabilities.max_image_count),
current_extent: (!matches!(
capabilities_vk.surface_capabilities.current_extent,
ash::vk::Extent2D {
width: u32::MAX,
height: u32::MAX
}
))
.then_some([
capabilities_vk.surface_capabilities.current_extent.width,
capabilities_vk.surface_capabilities.current_extent.height,
])
},
]),
min_image_extent: [
capabilities_vk.surface_capabilities.min_image_extent.width,
capabilities_vk.surface_capabilities.min_image_extent.height,
@ -1561,14 +1617,75 @@ impl PhysicalDevice {
.surface_capabilities
.supported_composite_alpha
.into(),
supported_usage_flags: {
let usage =
ImageUsage::from(capabilities_vk.surface_capabilities.supported_usage_flags);
debug_assert!(usage.intersects(ImageUsage::COLOR_ATTACHMENT)); // specs say that this must be true
usage
},
supported_usage_flags: ImageUsage::from(
capabilities_vk.surface_capabilities.supported_usage_flags,
),
supports_protected: protected_capabilities_vk
compatible_present_modes: capabilities_present_mode_compatibility_vk.map_or_else(
Default::default,
|capabilities_present_mode_compatibility_vk| {
capabilities_present_modes_vk
[..capabilities_present_mode_compatibility_vk.present_mode_count as usize]
.iter()
.copied()
.map(PresentMode::try_from)
.filter_map(Result::ok)
.collect()
},
),
supported_present_scaling: capabilities_present_scaling_vk
.as_ref()
.map_or_else(Default::default, |c| c.supported_present_scaling.into()),
supported_present_gravity: capabilities_present_scaling_vk.as_ref().map_or_else(
Default::default,
|c| {
[
c.supported_present_gravity_x.into(),
c.supported_present_gravity_y.into(),
]
},
),
min_scaled_image_extent: capabilities_present_scaling_vk.as_ref().map_or(
Some([
capabilities_vk.surface_capabilities.min_image_extent.width,
capabilities_vk.surface_capabilities.min_image_extent.height,
]),
|c| {
(!matches!(
c.min_scaled_image_extent,
ash::vk::Extent2D {
width: u32::MAX,
height: u32::MAX,
}
))
.then_some([
c.min_scaled_image_extent.width,
c.min_scaled_image_extent.height,
])
},
),
max_scaled_image_extent: capabilities_present_scaling_vk.as_ref().map_or(
Some([
capabilities_vk.surface_capabilities.max_image_extent.width,
capabilities_vk.surface_capabilities.max_image_extent.height,
]),
|c| {
(!matches!(
c.max_scaled_image_extent,
ash::vk::Extent2D {
width: u32::MAX,
height: u32::MAX,
}
))
.then_some([
c.max_scaled_image_extent.width,
c.max_scaled_image_extent.height,
])
},
),
supports_protected: capabilities_protected_vk
.map_or(false, |c| c.supports_protected != 0),
full_screen_exclusive_supported: capabilities_full_screen_exclusive_vk
@ -1630,12 +1747,36 @@ impl PhysicalDevice {
});
}
surface_info
.validate(self)
.map_err(|err| err.add_context("surface_info"))?;
let &SurfaceInfo {
present_mode,
full_screen_exclusive,
win32_monitor,
_ne: _,
} = surface_info;
if let Some(present_mode) = present_mode {
let mut present_modes = unsafe {
self.surface_present_modes_unchecked(surface)
.map_err(|_err| ValidationError {
context: "PhysicalDevice::surface_present_modes".into(),
problem: "returned an error".into(),
..Default::default()
})?
};
if !present_modes.any(|mode| mode == present_mode) {
return Err(ValidationError {
problem: "`surface_info.present_mode` is not supported for `surface`".into(),
vuids: &["VUID-VkSurfacePresentModeEXT-presentMode-07780"],
..Default::default()
});
}
}
if !self
.instance
.enabled_extensions()
@ -1706,46 +1847,52 @@ impl PhysicalDevice {
(self.handle, surface_info),
|(_, surface_info)| {
let &SurfaceInfo {
present_mode,
full_screen_exclusive,
win32_monitor,
_ne: _,
} = surface_info;
let mut surface_full_screen_exclusive_info = (full_screen_exclusive
!= FullScreenExclusive::Default)
.then(|| ash::vk::SurfaceFullScreenExclusiveInfoEXT {
full_screen_exclusive: full_screen_exclusive.into(),
..Default::default()
});
let mut surface_full_screen_exclusive_win32_info =
win32_monitor.map(|win32_monitor| {
ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT {
hmonitor: win32_monitor.0,
..Default::default()
}
});
let mut surface_info2 = ash::vk::PhysicalDeviceSurfaceInfo2KHR {
let mut info_vk = ash::vk::PhysicalDeviceSurfaceInfo2KHR {
surface: surface.handle(),
..Default::default()
};
let mut present_mode_vk = None;
let mut full_screen_exclusive_info_vk = None;
let mut 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 = surface_info2.p_next as *mut _;
surface_info2.p_next =
surface_full_screen_exclusive_info as *const _ as *const _;
if let Some(present_mode) = present_mode {
let next = present_mode_vk.insert(ash::vk::SurfacePresentModeEXT {
present_mode: present_mode.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 =
surface_info2.p_next as *mut _;
surface_info2.p_next =
surface_full_screen_exclusive_win32_info as *const _ as *const _;
if full_screen_exclusive != FullScreenExclusive::Default {
let next = 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(win32_monitor) = win32_monitor {
let next = full_screen_exclusive_win32_info_vk.insert(
ash::vk::SurfaceFullScreenExclusiveWin32InfoEXT {
hmonitor: win32_monitor.0,
..Default::default()
},
);
next.p_next = info_vk.p_next as *mut _;
info_vk.p_next = next as *const _ as *const _;
}
let fns = self.instance.fns();
@ -1755,40 +1902,40 @@ impl PhysicalDevice {
.enabled_extensions()
.khr_get_surface_capabilities2
{
let surface_format2s = loop {
let surface_format2s_vk = loop {
let mut count = 0;
(fns.khr_get_surface_capabilities2
.get_physical_device_surface_formats2_khr)(
self.handle(),
&surface_info2,
&info_vk,
&mut count,
ptr::null_mut(),
)
.result()
.map_err(RuntimeError::from)?;
let mut surface_format2s =
let mut surface_format2s_vk =
vec![ash::vk::SurfaceFormat2KHR::default(); count as usize];
let result = (fns
.khr_get_surface_capabilities2
.get_physical_device_surface_formats2_khr)(
self.handle(),
&surface_info2,
&info_vk,
&mut count,
surface_format2s.as_mut_ptr(),
surface_format2s_vk.as_mut_ptr(),
);
match result {
ash::vk::Result::SUCCESS => {
surface_format2s.set_len(count as usize);
break surface_format2s;
surface_format2s_vk.set_len(count as usize);
break surface_format2s_vk;
}
ash::vk::Result::INCOMPLETE => (),
err => return Err(RuntimeError::from(err)),
}
};
Ok(surface_format2s
Ok(surface_format2s_vk
.into_iter()
.filter_map(|surface_format2| {
(surface_format2.surface_format.format.try_into().ok())

View File

@ -529,8 +529,8 @@ impl<'a> QueueGuard<'a> {
states: &mut States<'_>,
) -> Result<impl ExactSizeIterator<Item = Result<bool, RuntimeError>>, RuntimeError> {
let PresentInfo {
ref wait_semaphores,
ref swapchain_infos,
wait_semaphores,
swapchain_infos,
_ne: _,
} = present_info;
@ -542,11 +542,13 @@ impl<'a> QueueGuard<'a> {
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_modes_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_modes = false;
let mut has_present_regions = false;
for swapchain_info in swapchain_infos {
@ -554,6 +556,7 @@ impl<'a> QueueGuard<'a> {
ref swapchain,
image_index,
present_id,
present_mode,
ref present_regions,
_ne: _,
} = swapchain_info;
@ -561,6 +564,7 @@ impl<'a> QueueGuard<'a> {
swapchains_vk.push(swapchain.handle());
image_indices_vk.push(image_index);
present_ids_vk.push(present_id.map_or(0, u64::from));
present_modes_vk.push(present_mode.map_or_else(Default::default, Into::into));
present_regions_vk.push(ash::vk::PresentRegionKHR::default());
rectangles_vk.push(
present_regions
@ -573,6 +577,10 @@ impl<'a> QueueGuard<'a> {
has_present_ids = true;
}
if present_mode.is_some() {
has_present_modes = true;
}
if !present_regions.is_empty() {
has_present_regions = true;
}
@ -589,6 +597,7 @@ impl<'a> QueueGuard<'a> {
..Default::default()
};
let mut present_id_info_vk = None;
let mut present_mode_info_vk = None;
let mut present_region_info_vk = None;
if has_present_ids {
@ -602,6 +611,17 @@ impl<'a> QueueGuard<'a> {
info_vk.p_next = next as *const _ as *const _;
}
if has_present_modes {
let next = present_mode_info_vk.insert(ash::vk::SwapchainPresentModeInfoEXT {
swapchain_count: present_modes_vk.len() as u32,
p_present_modes: present_modes_vk.as_ptr(),
..Default::default()
});
next.p_next = info_vk.p_next as _;
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())

View File

@ -15,7 +15,6 @@ use super::{
use crate::{
device::{Device, DeviceOwned},
swapchain::Swapchain,
OomError,
};
use std::{
hash::{Hash, Hasher},
@ -45,10 +44,10 @@ impl SwapchainImage {
handle: ash::vk::Image,
swapchain: Arc<Swapchain>,
image_index: u32,
) -> Result<Arc<SwapchainImage>, OomError> {
Ok(Arc::new(SwapchainImage {
) -> Arc<SwapchainImage> {
Arc::new(SwapchainImage {
inner: Arc::new(Image::from_swapchain(handle, swapchain, image_index)),
}))
})
}
/// Returns the swapchain this image belongs to.

View File

@ -591,11 +591,16 @@ macro_rules! vulkan_enum {
)+
}
$(
impl $ty {
#[allow(dead_code)]
pub(crate) const COUNT: usize = [
$(ash::vk::$ty_ffi::$flag_name_ffi.as_raw()),+
].len();
$(
$($impls)*
}
)?
}
impl From<$ty> for ash::vk::$ty_ffi {
#[inline]
@ -653,6 +658,11 @@ macro_rules! vulkan_enum {
}
impl $ty {
#[allow(dead_code)]
pub(crate) const COUNT: usize = [
$(ash::vk::$ty_ffi::$flag_name_ffi.as_raw()),+
].len();
#[allow(dead_code)]
#[inline]
pub(crate) fn validate_device(

View File

@ -521,13 +521,13 @@ impl From<&Viewport> for ash::vk::Viewport {
}
}
/// State of a single scissor box.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
/// A two-dimensional subregion.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Scissor {
/// Coordinates in pixels of the top-left hand corner of the box.
/// Coordinates of the top-left hand corner of the box.
pub offset: [u32; 2],
/// Dimensions in pixels of the box.
/// Dimensions of the box.
pub extent: [u32; 2],
}
@ -565,3 +565,13 @@ impl From<&Scissor> for ash::vk::Rect2D {
}
}
}
impl From<ash::vk::Rect2D> for Scissor {
#[inline]
fn from(val: ash::vk::Rect2D) -> Self {
Scissor {
offset: [val.offset.x as u32, val.offset.y as u32],
extent: [val.extent.width, val.extent.height],
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::{FullScreenExclusive, Win32Monitor};
use super::{FullScreenExclusive, PresentGravityFlags, PresentScalingFlags, Win32Monitor};
use crate::{
cache::OnceCache,
device::physical::PhysicalDevice,
@ -15,25 +15,23 @@ use crate::{
image::ImageUsage,
instance::{Instance, InstanceExtensions},
macros::{impl_id_counter, vulkan_bitflags_enum, vulkan_enum},
swapchain::{
display::{DisplayMode, DisplayPlane},
SurfaceSwapchainLock,
},
OomError, Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, VulkanObject,
swapchain::display::{DisplayMode, DisplayPlane},
Requires, RequiresAllOf, RequiresOneOf, RuntimeError, ValidationError, VulkanError,
VulkanObject,
};
#[cfg(any(target_os = "macos", target_os = "ios"))]
use objc::{class, msg_send, runtime::Object, sel, sel_impl};
use raw_window_handle::{
HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
};
use smallvec::SmallVec;
use std::{
any::Any,
error::Error,
fmt::{Debug, Display, Error as FmtError, Formatter},
fmt::{Debug, Error as FmtError, Formatter},
mem::MaybeUninit,
num::NonZeroU64,
ptr,
sync::{atomic::AtomicBool, Arc},
sync::Arc,
};
/// Represents a surface on the screen.
@ -45,9 +43,6 @@ pub struct Surface {
id: NonZeroU64,
api: SurfaceApi,
object: Option<Arc<dyn Any + Send + Sync>>,
// If true, a swapchain has been associated to this surface, and that any new swapchain
// creation should be forbidden.
has_swapchain: AtomicBool,
// FIXME: This field is never set.
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer,
@ -88,7 +83,7 @@ impl Surface {
pub fn from_window(
instance: Arc<Instance>,
window: Arc<impl HasRawWindowHandle + HasRawDisplayHandle + Any + Send + Sync>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
let mut surface = unsafe { Self::from_window_ref(instance, &*window) }?;
Arc::get_mut(&mut surface).unwrap().object = Some(window);
@ -104,7 +99,7 @@ impl Surface {
pub unsafe fn from_window_ref(
instance: Arc<Instance>,
window: &(impl HasRawWindowHandle + HasRawDisplayHandle),
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
match (window.raw_window_handle(), window.raw_display_handle()) {
(RawWindowHandle::AndroidNdk(window), RawDisplayHandle::Android(_display)) => {
Self::from_android(instance, window.a_native_window, None)
@ -159,7 +154,6 @@ impl Surface {
id: Self::next_id(),
api,
object,
has_swapchain: AtomicBool::new(false),
#[cfg(target_os = "ios")]
metal_layer: IOSMetalLayer::new(std::ptr::null_mut(), std::ptr::null_mut()),
surface_formats: OnceCache::new(),
@ -175,19 +169,19 @@ impl Surface {
pub fn headless(
instance: Arc<Instance>,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_headless(&instance)?;
unsafe { Ok(Self::headless_unchecked(instance, object)?) }
}
fn validate_headless(instance: &Instance) -> Result<(), SurfaceCreationError> {
fn validate_headless(instance: &Instance) -> Result<(), ValidationError> {
if !instance.enabled_extensions().ext_headless_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::headless`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"ext_headless_surface",
)])]),
..Default::default()
});
}
@ -235,7 +229,7 @@ impl Surface {
pub fn from_display_plane(
display_mode: &DisplayMode,
plane: &DisplayPlane,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_display_plane(display_mode, plane)?;
unsafe { Ok(Self::from_display_plane_unchecked(display_mode, plane)?) }
@ -244,7 +238,7 @@ impl Surface {
fn validate_from_display_plane(
display_mode: &DisplayMode,
plane: &DisplayPlane,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !display_mode
.display()
.physical_device()
@ -252,11 +246,11 @@ impl Surface {
.enabled_extensions()
.khr_display
{
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_display_plane`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"khr_display",
)])]),
..Default::default()
});
}
@ -325,7 +319,7 @@ impl Surface {
instance: Arc<Instance>,
window: *const W,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_android(&instance, window)?;
Ok(Self::from_android_unchecked(instance, window, object)?)
@ -334,13 +328,13 @@ impl Surface {
fn validate_from_android<W>(
instance: &Instance,
_window: *const W,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().khr_android_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_android`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"khr_android_surface",
)])]),
..Default::default()
});
}
@ -397,7 +391,7 @@ impl Surface {
dfb: *const D,
surface: *const S,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_directfb(&instance, dfb, surface)?;
Ok(Self::from_directfb_unchecked(
@ -409,13 +403,13 @@ impl Surface {
instance: &Instance,
_dfb: *const D,
_surface: *const S,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().ext_directfb_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_directfb`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"ext_directfb_surface",
)])]),
..Default::default()
});
}
@ -475,7 +469,7 @@ impl Surface {
instance: Arc<Instance>,
image_pipe_handle: ash::vk::zx_handle_t,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_fuchsia_image_pipe(&instance, image_pipe_handle)?;
Ok(Self::from_fuchsia_image_pipe_unchecked(
@ -488,13 +482,13 @@ impl Surface {
fn validate_from_fuchsia_image_pipe(
instance: &Instance,
_image_pipe_handle: ash::vk::zx_handle_t,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().fuchsia_imagepipe_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_fuchsia_image_pipe`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"fuchsia_imagepipe_surface",
)])]),
..Default::default()
});
}
@ -550,7 +544,7 @@ impl Surface {
instance: Arc<Instance>,
stream_descriptor: ash::vk::GgpStreamDescriptor,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_ggp_stream_descriptor(&instance, stream_descriptor)?;
Ok(Self::from_ggp_stream_descriptor_unchecked(
@ -563,13 +557,13 @@ impl Surface {
fn validate_from_ggp_stream_descriptor(
instance: &Instance,
_stream_descriptor: ash::vk::GgpStreamDescriptor,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().ggp_stream_descriptor_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_ggp_stream_descriptor`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"ggp_stream_descriptor_surface",
)])]),
..Default::default()
});
}
@ -627,7 +621,7 @@ impl Surface {
instance: Arc<Instance>,
metal_layer: IOSMetalLayer,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_ios(&instance, &metal_layer)?;
Ok(Self::from_ios_unchecked(instance, metal_layer, object)?)
@ -637,13 +631,13 @@ impl Surface {
fn validate_from_ios(
instance: &Instance,
_metal_layer: &IOSMetalLayer,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().mvk_ios_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_ios`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"mvk_ios_surface",
)])]),
..Default::default()
});
}
@ -704,7 +698,7 @@ impl Surface {
instance: Arc<Instance>,
view: *const V,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_mac_os(&instance, view)?;
Ok(Self::from_mac_os_unchecked(instance, view, object)?)
@ -714,13 +708,13 @@ impl Surface {
fn validate_from_mac_os<V>(
instance: &Instance,
_view: *const V,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().mvk_macos_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_mac_os`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"mvk_macos_surface",
)])]),
..Default::default()
});
}
@ -779,7 +773,7 @@ impl Surface {
instance: Arc<Instance>,
layer: *const L,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_metal(&instance, layer)?;
Ok(Self::from_metal_unchecked(instance, layer, object)?)
@ -788,13 +782,13 @@ impl Surface {
fn validate_from_metal<L>(
instance: &Instance,
_layer: *const L,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().ext_metal_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_metal`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"ext_metal_surface",
)])]),
..Default::default()
});
}
@ -848,7 +842,7 @@ impl Surface {
context: *const C,
window: *const W,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_qnx_screen(&instance, context, window)?;
Ok(Self::from_qnx_screen_unchecked(
@ -860,13 +854,13 @@ impl Surface {
instance: &Instance,
_context: *const C,
_window: *const W,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().qnx_screen_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_qnx_screen`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"qnx_screen_surface",
)])]),
..Default::default()
});
}
@ -926,22 +920,19 @@ impl Surface {
instance: Arc<Instance>,
window: *const W,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_vi(&instance, window)?;
Ok(Self::from_vi_unchecked(instance, window, object)?)
}
fn validate_from_vi<W>(
instance: &Instance,
_window: *const W,
) -> Result<(), SurfaceCreationError> {
fn validate_from_vi<W>(instance: &Instance, _window: *const W) -> Result<(), ValidationError> {
if !instance.enabled_extensions().nn_vi_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_vi`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"nn_vi_surface",
)])]),
..Default::default()
});
}
@ -1000,7 +991,7 @@ impl Surface {
display: *const D,
surface: *const S,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_wayland(&instance, display, surface)?;
Ok(Self::from_wayland_unchecked(
@ -1012,13 +1003,13 @@ impl Surface {
instance: &Instance,
_display: *const D,
_surface: *const S,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().khr_wayland_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_wayland`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"khr_wayland_surface",
)])]),
..Default::default()
});
}
@ -1082,7 +1073,7 @@ impl Surface {
hinstance: *const I,
hwnd: *const W,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_win32(&instance, hinstance, hwnd)?;
Ok(Self::from_win32_unchecked(
@ -1094,13 +1085,13 @@ impl Surface {
instance: &Instance,
_hinstance: *const I,
_hwnd: *const W,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().khr_win32_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_win32`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"khr_win32_surface",
)])]),
..Default::default()
});
}
@ -1164,7 +1155,7 @@ impl Surface {
connection: *const C,
window: ash::vk::xcb_window_t,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_xcb(&instance, connection, window)?;
Ok(Self::from_xcb_unchecked(
@ -1176,13 +1167,13 @@ impl Surface {
instance: &Instance,
_connection: *const C,
_window: ash::vk::xcb_window_t,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().khr_xcb_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_xcb`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"khr_xcb_surface",
)])]),
..Default::default()
});
}
@ -1246,7 +1237,7 @@ impl Surface {
display: *const D,
window: ash::vk::Window,
object: Option<Arc<dyn Any + Send + Sync>>,
) -> Result<Arc<Self>, SurfaceCreationError> {
) -> Result<Arc<Self>, VulkanError> {
Self::validate_from_xlib(&instance, display, window)?;
Ok(Self::from_xlib_unchecked(
@ -1258,13 +1249,13 @@ impl Surface {
instance: &Instance,
_display: *const D,
_window: ash::vk::Window,
) -> Result<(), SurfaceCreationError> {
) -> Result<(), ValidationError> {
if !instance.enabled_extensions().khr_xlib_surface {
return Err(SurfaceCreationError::RequirementNotMet {
required_for: "`Surface::from_xlib`",
return Err(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::InstanceExtension(
"khr_xlib_surface",
)])]),
..Default::default()
});
}
@ -1379,7 +1370,6 @@ impl Debug for Surface {
instance,
api,
object: _,
has_swapchain,
..
} = self;
@ -1388,18 +1378,10 @@ impl Debug for Surface {
.field("instance", instance)
.field("api", api)
.field("window", &())
.field("has_swapchain", &has_swapchain)
.finish()
}
}
unsafe impl SurfaceSwapchainLock for Surface {
#[inline]
fn flag(&self) -> &AtomicBool {
&self.has_swapchain
}
}
/// Get sublayer from iOS main view (ui_view). The sublayer is created as `CAMetalLayer`.
#[cfg(target_os = "ios")]
unsafe fn get_metal_layer_ios(ui_view: *mut std::ffi::c_void) -> IOSMetalLayer {
@ -1447,63 +1429,6 @@ unsafe fn get_metal_layer_macos(ns_view: *mut std::ffi::c_void) -> *mut Object {
}
}
/// Error that can happen when creating a surface.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SurfaceCreationError {
/// Not enough memory.
OomError(OomError),
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
}
impl Error for SurfaceCreationError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
SurfaceCreationError::OomError(err) => Some(err),
_ => None,
}
}
}
impl Display for SurfaceCreationError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::OomError(_) => write!(f, "not enough memory available"),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
}
}
}
impl From<OomError> for SurfaceCreationError {
fn from(err: OomError) -> SurfaceCreationError {
SurfaceCreationError::OomError(err)
}
}
impl From<RuntimeError> for SurfaceCreationError {
fn from(err: RuntimeError) -> SurfaceCreationError {
match err {
err @ RuntimeError::OutOfHostMemory => {
SurfaceCreationError::OomError(OomError::from(err))
}
err @ RuntimeError::OutOfDeviceMemory => {
SurfaceCreationError::OomError(OomError::from(err))
}
_ => panic!("unexpected error: {:?}", err),
}
}
}
/// The windowing API that was used to construct a surface.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
@ -1882,8 +1807,21 @@ vulkan_enum! {
/// [`PhysicalDevice::surface_formats`]: crate::device::physical::PhysicalDevice::surface_formats
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct SurfaceInfo {
/// If this is `Some`, the
/// [`ext_surface_maintenance1`](crate::instance::InstanceExtensions::ext_surface_maintenance1)
/// extension must be enabled on the instance.
pub present_mode: Option<PresentMode>,
/// If this is not [`FullScreenExclusive::Default`], the
/// [`ext_full_screen_exclusive`](crate::device::DeviceExtensions::ext_full_screen_exclusive)
/// extension must be supported by the physical device.
pub full_screen_exclusive: FullScreenExclusive,
/// If `full_screen_exclusive` is [`FullScreenExclusive::ApplicationControlled`], and the
/// surface being queried is a Win32 surface, then this must be `Some`. Otherwise, it must be
/// `None`.
pub win32_monitor: Option<Win32Monitor>,
pub _ne: crate::NonExhaustive,
}
@ -1891,6 +1829,7 @@ impl Default for SurfaceInfo {
#[inline]
fn default() -> Self {
Self {
present_mode: None,
full_screen_exclusive: FullScreenExclusive::Default,
win32_monitor: None,
_ne: crate::NonExhaustive(()),
@ -1901,15 +1840,41 @@ impl Default for SurfaceInfo {
impl SurfaceInfo {
pub(crate) fn validate(&self, physical_device: &PhysicalDevice) -> Result<(), ValidationError> {
let &Self {
present_mode,
full_screen_exclusive,
win32_monitor: _,
_ne: _,
} = self;
if let Some(present_mode) = present_mode {
if !physical_device
.instance()
.enabled_extensions()
.ext_surface_maintenance1
{
return Err(ValidationError {
context: "present_mode".into(),
problem: "is `Some`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::InstanceExtension("ext_surface_maintenance1"),
])]),
..Default::default()
});
}
present_mode
.validate_physical_device(physical_device)
.map_err(|err| ValidationError {
context: "present_mode".into(),
vuids: &["VUID-VkSurfacePresentModeEXT-presentMode-parameter"],
..ValidationError::from_requirement(err)
})?;
}
if full_screen_exclusive != FullScreenExclusive::Default
&& !physical_device
.supported_extensions()
.ext_full_screen_exclusive
&& full_screen_exclusive != FullScreenExclusive::Default
{
return Err(ValidationError {
context: "full_screen_exclusive".into(),
@ -1972,8 +1937,9 @@ pub struct SurfaceCapabilities {
/// you may still get out of memory errors.
pub max_image_count: Option<u32>,
/// The current dimensions of the surface. `None` means that the surface's dimensions will
/// depend on the dimensions of the swapchain that you are going to create.
/// The current dimensions of the surface.
///
/// `None` means that the surface's dimensions will depend on the dimensions of the swapchain.
pub current_extent: Option<[u32; 2]>,
/// Minimum width and height of a swapchain that uses this surface.
@ -1998,6 +1964,49 @@ pub struct SurfaceCapabilities {
/// the `color_attachment` usage is guaranteed to be supported.
pub supported_usage_flags: ImageUsage,
/// When [`SurfaceInfo::present_mode`] is provided,
/// lists that present mode and any modes that are compatible with that present mode.
///
/// If [`SurfaceInfo::present_mode`] was not provided, the value will be empty.
pub compatible_present_modes: SmallVec<[PresentMode; PresentMode::COUNT]>,
/// When [`SurfaceInfo::present_mode`] is provided,
/// the supported present scaling modes for the queried present mode.
///
/// If [`SurfaceInfo::present_mode`] was not provided, the value will be empty.
pub supported_present_scaling: PresentScalingFlags,
/// When [`SurfaceInfo::present_mode`] is provided,
/// the supported present gravity modes, horizontally and vertically,
/// for the queried present mode.
///
/// If [`SurfaceInfo::present_mode`] was not provided, both values will be empty.
pub supported_present_gravity: [PresentGravityFlags; 2],
/// When [`SurfaceInfo::present_mode`] is provided,
/// the smallest allowed extent for a swapchain, if it uses the queried present mode, and
/// one of the scaling modes in `supported_present_scaling`.
///
/// This is never greater than [`SurfaceCapabilities::min_image_extent`].
///
/// `None` means that the surface's dimensions will depend on the dimensions of the swapchain.
///
/// If [`SurfaceInfo::present_mode`] was not provided, this is will be equal to
/// `min_image_extent`.
pub min_scaled_image_extent: Option<[u32; 2]>,
/// When [`SurfaceInfo::present_mode`] is provided,
/// the largest allowed extent for a swapchain, if it uses the queried present mode, and
/// one of the scaling modes in `supported_present_scaling`.
///
/// This is never less than [`SurfaceCapabilities::max_image_extent`].
///
/// `None` means that the surface's dimensions will depend on the dimensions of the swapchain.
///
/// If [`SurfaceInfo::present_mode`] was not provided, this is will be equal to
/// `max_image_extent`.
pub max_scaled_image_extent: Option<[u32; 2]>,
/// Whether creating a protected swapchain is supported.
pub supports_protected: bool,
@ -2008,8 +2017,7 @@ pub struct SurfaceCapabilities {
#[cfg(test)]
mod tests {
use crate::{
swapchain::{Surface, SurfaceCreationError},
Requires, RequiresAllOf, RequiresOneOf,
swapchain::Surface, Requires, RequiresAllOf, RequiresOneOf, ValidationError, VulkanError,
};
use std::ptr;
@ -2017,11 +2025,11 @@ mod tests {
fn khr_win32_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_win32(instance, ptr::null::<u8>(), ptr::null::<u8>(), None) } {
Err(SurfaceCreationError::RequirementNotMet {
Err(VulkanError::ValidationError(ValidationError {
requires_one_of:
RequiresOneOf([RequiresAllOf([Requires::InstanceExtension("khr_win32_surface")])]),
..
}) => (),
})) => (),
_ => panic!(),
}
}
@ -2030,11 +2038,11 @@ mod tests {
fn khr_xcb_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_xcb(instance, ptr::null::<u8>(), 0, None) } {
Err(SurfaceCreationError::RequirementNotMet {
Err(VulkanError::ValidationError(ValidationError {
requires_one_of:
RequiresOneOf([RequiresAllOf([Requires::InstanceExtension("khr_xcb_surface")])]),
..
}) => (),
})) => (),
_ => panic!(),
}
}
@ -2043,11 +2051,11 @@ mod tests {
fn khr_xlib_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_xlib(instance, ptr::null::<u8>(), 0, None) } {
Err(SurfaceCreationError::RequirementNotMet {
Err(VulkanError::ValidationError(ValidationError {
requires_one_of:
RequiresOneOf([RequiresAllOf([Requires::InstanceExtension("khr_xlib_surface")])]),
..
}) => (),
})) => (),
_ => panic!(),
}
}
@ -2057,11 +2065,11 @@ mod tests {
let instance = instance!();
match unsafe { Surface::from_wayland(instance, ptr::null::<u8>(), ptr::null::<u8>(), None) }
{
Err(SurfaceCreationError::RequirementNotMet {
Err(VulkanError::ValidationError(ValidationError {
requires_one_of:
RequiresOneOf([RequiresAllOf([Requires::InstanceExtension("khr_wayland_surface")])]),
..
}) => (),
})) => (),
_ => panic!(),
}
}
@ -2070,11 +2078,11 @@ mod tests {
fn khr_android_surface_ext_missing() {
let instance = instance!();
match unsafe { Surface::from_android(instance, ptr::null::<u8>(), None) } {
Err(SurfaceCreationError::RequirementNotMet {
Err(VulkanError::ValidationError(ValidationError {
requires_one_of:
RequiresOneOf([RequiresAllOf([Requires::InstanceExtension("khr_android_surface")])]),
..
}) => (),
})) => (),
_ => panic!(),
}
}

File diff suppressed because it is too large Load Diff

View File

@ -310,8 +310,12 @@ where
.map_err(|err| OutcomeErr::Full(err.into()))
}
SubmitAnyBuilder::QueuePresent(present_info) => {
let intermediary_result = if partially_flushed {
Ok(())
if partially_flushed {
queue
.with(|mut q| {
q.submit_unchecked([Default::default()], Some(new_fence.clone()))
})
.map_err(|err| OutcomeErr::Partial(err.into()))
} else {
// VUID-VkPresentIdKHR-presentIds-04999
for swapchain_info in &present_info.swapchain_infos {
@ -334,21 +338,24 @@ where
}
}
queue
let intermediary_result = queue
.with(|mut q| q.present_unchecked(present_info))?
.map(|r| r.map(|_| ()))
.fold(Ok(()), Result::and)
};
.fold(Ok(()), Result::and);
match intermediary_result {
Ok(()) => queue
.with(|mut q| {
q.submit_unchecked([Default::default()], Some(new_fence.clone()))
q.submit_unchecked(
[Default::default()],
Some(new_fence.clone()),
)
})
.map_err(|err| OutcomeErr::Partial(err.into())),
Err(err) => Err(OutcomeErr::Full(err.into())),
}
}
}
};
// Restore the state before returning.

View File

@ -597,6 +597,10 @@ pub enum FlushError {
/// for the same swapchain.
PresentIdLessThanOrEqual,
/// A new present mode was provided, but this mode was not one of the valid present modes
/// that the swapchain was created with.
PresentModeNotValid,
/// Access to a resource has been denied.
ResourceAccessError {
error: AccessError,
@ -615,9 +619,9 @@ pub enum FlushError {
impl Error for FlushError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
FlushError::AccessError(err) => Some(err),
FlushError::OomError(err) => Some(err),
FlushError::ResourceAccessError { error, .. } => Some(error),
Self::AccessError(err) => Some(err),
Self::OomError(err) => Some(err),
Self::ResourceAccessError { error, .. } => Some(error),
_ => None,
}
}
@ -629,27 +633,31 @@ impl Display for FlushError {
f,
"{}",
match self {
FlushError::AccessError(_) => "access to a resource has been denied",
FlushError::OomError(_) => "not enough memory",
FlushError::DeviceLost => "the connection to the device has been lost",
FlushError::SurfaceLost => "the surface of this swapchain is no longer valid",
FlushError::OutOfDate => "the swapchain needs to be recreated",
FlushError::FullScreenExclusiveModeLost => {
Self::AccessError(_) => "access to a resource has been denied",
Self::OomError(_) => "not enough memory",
Self::DeviceLost => "the connection to the device has been lost",
Self::SurfaceLost => "the surface of this swapchain is no longer valid",
Self::OutOfDate => "the swapchain needs to be recreated",
Self::FullScreenExclusiveModeLost => {
"the swapchain no longer has full screen exclusivity"
}
FlushError::Timeout => {
Self::Timeout => {
"the flush operation needed to block, but the timeout has elapsed"
}
FlushError::PresentIdLessThanOrEqual => {
Self::PresentIdLessThanOrEqual => {
"present id is less than or equal to previous"
}
FlushError::ResourceAccessError { .. } => "access to a resource has been denied",
FlushError::OneTimeSubmitAlreadySubmitted => {
Self::PresentModeNotValid => {
"a new present mode was provided, but this mode was not one of the valid \
present modes that the swapchain was created with"
}
Self::ResourceAccessError { .. } => "access to a resource has been denied",
Self::OneTimeSubmitAlreadySubmitted => {
"the command buffer or one of the secondary command buffers it executes was \
created with the \"one time submit\" flag, but has already been submitted in \
the past"
}
FlushError::ExclusiveAlreadyInUse => {
Self::ExclusiveAlreadyInUse => {
"the command buffer or one of the secondary command buffers it executes is \
already in use was not created with the \"concurrent\" flag"
}
@ -660,7 +668,7 @@ impl Display for FlushError {
impl From<AccessError> for FlushError {
fn from(err: AccessError) -> FlushError {
FlushError::AccessError(err)
Self::AccessError(err)
}
}
@ -682,9 +690,9 @@ impl From<RuntimeError> for FlushError {
impl From<FenceError> for FlushError {
fn from(err: FenceError) -> FlushError {
match err {
FenceError::OomError(err) => FlushError::OomError(err),
FenceError::Timeout => FlushError::Timeout,
FenceError::DeviceLost => FlushError::DeviceLost,
FenceError::OomError(err) => Self::OomError(err),
FenceError::Timeout => Self::Timeout,
FenceError::DeviceLost => Self::DeviceLost,
_ => unreachable!(),
}
}