From a89359007bb754efbc644c31eb1f192012905914 Mon Sep 17 00:00:00 2001 From: Ryan Andersen Date: Mon, 9 May 2022 05:25:26 -0700 Subject: [PATCH] Image extent zero length (#1893) * Updating examples and SwapchainCreationError enum to resolve #1892 and related discussion * Slightly better documentation --- 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 ++++++++++ .../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 | 20 ++++++++++++++++--- 22 files changed, 143 insertions(+), 24 deletions(-) diff --git a/examples/src/bin/buffer-pool.rs b/examples/src/bin/buffer-pool.rs index 5b3f1b71..fbf648e7 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 04760a01..0a831e0f 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 06c240e7..9a266e61 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 d47e3c08..fb9ffc9b 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 db72caf7..53b67b23 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 07c14886..3de94d66 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 ba08a3d4..5f7693b6 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 7ef1be3e..7d360094 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 eba71ae8..f7db58c2 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 7f10c85e..3cd576f4 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 45457228..65fab73c 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 f7353e9d..29d18259 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 c2cd2413..c1138205 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 33f16a90..c8bae54c 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 1854b3aa..09a2d947 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 7c286bdc..ce78372c 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 0ef3fc47..7922ab1b 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 06f66741..448328ad 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 9d31cbdf..e5e8a49e 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 7a08a748..e49bae0f 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 591a3b5b..9e365fcb 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 afb43faa..c2c03e51 100644 --- a/vulkano/src/swapchain/swapchain.rs +++ b/vulkano/src/swapchain/swapchain.rs @@ -392,8 +392,10 @@ 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 +1058,14 @@ 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. + /// + /// 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, @@ -1139,9 +1149,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`",