From 3b9230bea26d222b9c9bc9149923acae734f5724 Mon Sep 17 00:00:00 2001 From: Ryan Andersen Date: Sat, 7 May 2022 14:28:34 -0700 Subject: [PATCH 1/2] Updating examples and SwapchainCreationError enum to resolve #1892 and related discussion --- examples/src/bin/buffer-pool.rs | 7 ++++++- examples/src/bin/clear_attachments.rs | 7 ++++++- examples/src/bin/deferred/main.rs | 7 ++++++- examples/src/bin/image-self-copy-blit/main.rs | 7 ++++++- examples/src/bin/image/main.rs | 7 ++++++- examples/src/bin/immutable-sampler/main.rs | 7 ++++++- examples/src/bin/indirect.rs | 7 ++++++- examples/src/bin/instancing.rs | 7 ++++++- examples/src/bin/interactive_fractal/main.rs | 10 ++++++++++ examples/src/bin/interactive_fractal/renderer.rs | 1 - examples/src/bin/multi-window.rs | 7 ++++++- .../src/bin/multi_window_game_of_life/main.rs | 9 +++++++++ examples/src/bin/occlusion-query.rs | 7 ++++++- examples/src/bin/push-descriptors/main.rs | 7 ++++++- examples/src/bin/runtime-shader/main.rs | 7 ++++++- examples/src/bin/runtime_array/main.rs | 7 ++++++- examples/src/bin/simple-particles.rs | 4 ++-- examples/src/bin/teapot/main.rs | 7 ++++++- examples/src/bin/tessellation.rs | 7 ++++++- examples/src/bin/texture_array/main.rs | 7 ++++++- examples/src/bin/triangle.rs | 11 +++++++++-- vulkano/src/swapchain/swapchain.rs | 15 ++++++++++++--- 22 files changed, 138 insertions(+), 24 deletions(-) diff --git a/examples/src/bin/buffer-pool.rs b/examples/src/bin/buffer-pool.rs index 5b3f1b7154..fbf648e706 100644 --- a/examples/src/bin/buffer-pool.rs +++ b/examples/src/bin/buffer-pool.rs @@ -234,12 +234,17 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/clear_attachments.rs b/examples/src/bin/clear_attachments.rs index 04760a0112..0a831e0ffd 100644 --- a/examples/src/bin/clear_attachments.rs +++ b/examples/src/bin/clear_attachments.rs @@ -195,11 +195,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/deferred/main.rs b/examples/src/bin/deferred/main.rs index 06c240e7a2..9a266e6170 100644 --- a/examples/src/bin/deferred/main.rs +++ b/examples/src/bin/deferred/main.rs @@ -163,11 +163,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/image-self-copy-blit/main.rs b/examples/src/bin/image-self-copy-blit/main.rs index d47e3c08c7..fb9ffc9b8b 100644 --- a/examples/src/bin/image-self-copy-blit/main.rs +++ b/examples/src/bin/image-self-copy-blit/main.rs @@ -346,11 +346,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/image/main.rs b/examples/src/bin/image/main.rs index db72caf77a..53b67b23c5 100644 --- a/examples/src/bin/image/main.rs +++ b/examples/src/bin/image/main.rs @@ -266,11 +266,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/immutable-sampler/main.rs b/examples/src/bin/immutable-sampler/main.rs index 07c148866d..3de94d6685 100644 --- a/examples/src/bin/immutable-sampler/main.rs +++ b/examples/src/bin/immutable-sampler/main.rs @@ -275,11 +275,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/indirect.rs b/examples/src/bin/indirect.rs index ba08a3d47d..5f7693b6b2 100644 --- a/examples/src/bin/indirect.rs +++ b/examples/src/bin/indirect.rs @@ -297,12 +297,17 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/instancing.rs b/examples/src/bin/instancing.rs index 7ef1be3e84..7d3600946c 100644 --- a/examples/src/bin/instancing.rs +++ b/examples/src/bin/instancing.rs @@ -293,12 +293,17 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/interactive_fractal/main.rs b/examples/src/bin/interactive_fractal/main.rs index eba71ae835..f7db58c2f5 100644 --- a/examples/src/bin/interactive_fractal/main.rs +++ b/examples/src/bin/interactive_fractal/main.rs @@ -63,6 +63,16 @@ fn main() { if !handle_events(&mut event_loop, &mut renderer, &mut app) { break; } + + match renderer.window_size() { + [w, h] => { + // Skip this frame when minimized + if w == 0 || h == 0 { + continue; + } + } + } + app.update_state_after_inputs(&mut renderer); compute_then_render(&mut renderer, &mut app, render_target_id); app.reset_input_state(); diff --git a/examples/src/bin/interactive_fractal/renderer.rs b/examples/src/bin/interactive_fractal/renderer.rs index 7f10c85eee..3cd576f457 100644 --- a/examples/src/bin/interactive_fractal/renderer.rs +++ b/examples/src/bin/interactive_fractal/renderer.rs @@ -271,7 +271,6 @@ impl Renderer { } /// Winit window size - #[allow(unused)] pub fn window_size(&self) -> [u32; 2] { let size = self.window().inner_size(); [size.width, size.height] diff --git a/examples/src/bin/multi-window.rs b/examples/src/bin/multi-window.rs index 4545722808..65fab73c74 100644 --- a/examples/src/bin/multi-window.rs +++ b/examples/src/bin/multi-window.rs @@ -352,11 +352,16 @@ fn main() { ref mut previous_frame_end, } = window_surfaces.get_mut(&window_id).unwrap(); + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if *recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/multi_window_game_of_life/main.rs b/examples/src/bin/multi_window_game_of_life/main.rs index f7353e9d78..29d18259f7 100644 --- a/examples/src/bin/multi_window_game_of_life/main.rs +++ b/examples/src/bin/multi_window_game_of_life/main.rs @@ -197,6 +197,15 @@ fn compute_then_render( life_color: [f32; 4], dead_color: [f32; 4], ) { + // Skip this window when minimized + match vulkano_window.window_size() { + [w, h] => { + if w == 0 || h == 0 { + return; + } + } + } + // Start frame let before_pipeline_future = match vulkano_window.start_frame() { Err(e) => { diff --git a/examples/src/bin/occlusion-query.rs b/examples/src/bin/occlusion-query.rs index c2cd2413ab..c1138205eb 100644 --- a/examples/src/bin/occlusion-query.rs +++ b/examples/src/bin/occlusion-query.rs @@ -312,11 +312,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/push-descriptors/main.rs b/examples/src/bin/push-descriptors/main.rs index 33f16a903a..c8bae54cc6 100644 --- a/examples/src/bin/push-descriptors/main.rs +++ b/examples/src/bin/push-descriptors/main.rs @@ -258,11 +258,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/runtime-shader/main.rs b/examples/src/bin/runtime-shader/main.rs index 1854b3aaf0..09a2d9474e 100644 --- a/examples/src/bin/runtime-shader/main.rs +++ b/examples/src/bin/runtime-shader/main.rs @@ -243,11 +243,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/runtime_array/main.rs b/examples/src/bin/runtime_array/main.rs index 7c286bdcb8..ce78372c04 100644 --- a/examples/src/bin/runtime_array/main.rs +++ b/examples/src/bin/runtime_array/main.rs @@ -395,11 +395,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/simple-particles.rs b/examples/src/bin/simple-particles.rs index 0ef3fc47b3..7922ab1bc3 100644 --- a/examples/src/bin/simple-particles.rs +++ b/examples/src/bin/simple-particles.rs @@ -412,8 +412,8 @@ fn main() { } Event::RedrawEventsCleared => { let dimensions = surface.window().inner_size(); - if dimensions.width == 0 && dimensions.height == 0 { - return; // On Windows, minimizing sets surface to 0x0. Do not draw frame. + if dimensions.width == 0 || dimensions.height == 0 { + return; } // Update per-frame variables. diff --git a/examples/src/bin/teapot/main.rs b/examples/src/bin/teapot/main.rs index 06f66741d0..448328ad8e 100644 --- a/examples/src/bin/teapot/main.rs +++ b/examples/src/bin/teapot/main.rs @@ -189,12 +189,17 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/tessellation.rs b/examples/src/bin/tessellation.rs index 9d31cbdf25..e5e8a49e61 100644 --- a/examples/src/bin/tessellation.rs +++ b/examples/src/bin/tessellation.rs @@ -349,11 +349,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/texture_array/main.rs b/examples/src/bin/texture_array/main.rs index 7a08a74855..e49bae0ff4 100644 --- a/examples/src/bin/texture_array/main.rs +++ b/examples/src/bin/texture_array/main.rs @@ -267,11 +267,16 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + previous_frame_end.as_mut().unwrap().cleanup_finished(); if recreate_swapchain { let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/examples/src/bin/triangle.rs b/examples/src/bin/triangle.rs index 591a3b5b57..9e365fcbb8 100644 --- a/examples/src/bin/triangle.rs +++ b/examples/src/bin/triangle.rs @@ -416,6 +416,13 @@ fn main() { recreate_swapchain = true; } Event::RedrawEventsCleared => { + // Do not draw frame when screen dimensions are zero. + // On Windows, this can occur from minimizing the application. + let dimensions = surface.window().inner_size(); + if dimensions.width == 0 || dimensions.height == 0 { + return; + } + // It is important to call this function from time to time, otherwise resources will keep // accumulating and you will eventually reach an out of memory error. // Calling this function polls various fences in order to determine what the GPU has @@ -425,11 +432,11 @@ fn main() { // Whenever the window resizes we need to recreate everything dependent on the window size. // In this example that includes the swapchain, the framebuffers and the dynamic state viewport. if recreate_swapchain { - // Get the new dimensions of the window. + // Use the new dimensions of the window. let (new_swapchain, new_images) = match swapchain.recreate(SwapchainCreateInfo { - image_extent: surface.window().inner_size().into(), + image_extent: dimensions.into(), ..swapchain.create_info() }) { Ok(r) => r, diff --git a/vulkano/src/swapchain/swapchain.rs b/vulkano/src/swapchain/swapchain.rs index afb43faa78..3136b54f7e 100644 --- a/vulkano/src/swapchain/swapchain.rs +++ b/vulkano/src/swapchain/swapchain.rs @@ -392,8 +392,8 @@ impl Swapchain { } // VUID-VkSwapchainCreateInfoKHR-imageExtent-01689 - // Shouldn't be possible with a properly behaving device - assert!(image_extent[0] != 0 || image_extent[1] != 0); + // On some platforms, dimensions of zero-length can occur by minimizing the surface. + if image_extent.contains(&0) { return Err(SwapchainCreationError::ImageExtentZeroLengthDimensions)} // VUID-VkSwapchainCreateInfoKHR-imageArrayLayers-01275 if image_array_layers == 0 @@ -1056,6 +1056,11 @@ pub enum SwapchainCreationError { max_supported: [u32; 2], }, + /// The provided `image_extent` contained at least one dimension of zero length. + /// This is prohibited by [VUID-VkSwapchainCreateInfoKHR-imageExtent-01689](https://khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSwapchainCreateInfoKHR.html#VUID-VkSwapchainCreateInfoKHR-imageExtent-01689) + /// which requires both the width and height be non-zero. + ImageExtentZeroLengthDimensions, + /// The provided image parameters are not supported as queried from `image_format_properties`. ImageFormatPropertiesNotSupported, @@ -1139,9 +1144,13 @@ impl fmt::Display for SwapchainCreationError { ), Self::ImageExtentNotSupported { provided, min_supported, max_supported } => write!( fmt, - "the provided `min_image_count` ({:?}) is not within the range (min: {:?}, max: {:?}) supported by the surface for this device", + "the provided `image_extent` ({:?}) is not within the range (min: {:?}, max: {:?}) supported by the surface for this device", provided, min_supported, max_supported, ), + Self::ImageExtentZeroLengthDimensions => write!( + fmt, + "the provided `image_extent` contained at least one dimension of zero length", + ), Self::ImageFormatPropertiesNotSupported => write!( fmt, "the provided image parameters are not supported as queried from `image_format_properties`", From 3951a8d4bc1565e75610e35fdd0f476bd75c6826 Mon Sep 17 00:00:00 2001 From: Ryan Andersen Date: Sat, 7 May 2022 14:48:23 -0700 Subject: [PATCH 2/2] Slightly better documentation --- vulkano/src/swapchain/swapchain.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/vulkano/src/swapchain/swapchain.rs b/vulkano/src/swapchain/swapchain.rs index 3136b54f7e..c2c03e514a 100644 --- a/vulkano/src/swapchain/swapchain.rs +++ b/vulkano/src/swapchain/swapchain.rs @@ -393,7 +393,9 @@ impl Swapchain { // VUID-VkSwapchainCreateInfoKHR-imageExtent-01689 // On some platforms, dimensions of zero-length can occur by minimizing the surface. - if image_extent.contains(&0) { return Err(SwapchainCreationError::ImageExtentZeroLengthDimensions)} + if image_extent.contains(&0) { + return Err(SwapchainCreationError::ImageExtentZeroLengthDimensions); + } // VUID-VkSwapchainCreateInfoKHR-imageArrayLayers-01275 if image_array_layers == 0 @@ -1059,7 +1061,10 @@ pub enum SwapchainCreationError { /// The provided `image_extent` contained at least one dimension of zero length. /// This is prohibited by [VUID-VkSwapchainCreateInfoKHR-imageExtent-01689](https://khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSwapchainCreateInfoKHR.html#VUID-VkSwapchainCreateInfoKHR-imageExtent-01689) /// which requires both the width and height be non-zero. - ImageExtentZeroLengthDimensions, + /// + /// This error is distinct from `ImageExtentNotSupported` because a surface's minimum supported + /// length may not enforce this rule. + ImageExtentZeroLengthDimensions, /// The provided image parameters are not supported as queried from `image_format_properties`. ImageFormatPropertiesNotSupported,