From a89ae8e9d99c1f9187ab947616d8eb0b38dc5ca1 Mon Sep 17 00:00:00 2001 From: "Shoyu Vanilla (Flint)" Date: Wed, 9 Oct 2024 07:52:19 +0900 Subject: [PATCH] fix: Skip some rendering logics when the viewport width or height is zero (#15654) # Objective - Fixes #15285 ## Solution `winit` sends resized to zero events when the window is minimized only on Windows OS(rust-windowing/winit#2015). This makes updating window viewport size to `(0, 0)` and panicking when calculating aspect ratio. ~~So, just skip these kinds of events - resizing to (0, 0) when the window is minimized - on Windows OS~~ Idially, the camera extraction excludes the cameras whose target size width or height is zero here; https://github.com/bevyengine/bevy/blob/25bfa80e60e886031dd6eb1a3fe2ea548fc0a6c6/crates/bevy_render/src/camera/camera.rs#L1060-L1074 but it seems that winit event loop sends resize events after extraction and before post update schedule, so they might panics before the extraction filters them out. Alternatively, it might be possible to change event loop evaluating order or defer them to the right schedule but I'm afraid that it might cause some breaking changes, so just skip rendering logics for such windows and they will be all filtered out by the extractions on the next frame and thereafter. ## Testing Running the example in the original issue and minimizing causes panic, or just running `tests/window/minimising.rs` with `cargo run --example minimising` panics without this PR and doesn't panics with this PR. I think that we should run it in CI on Windows OS btw --- crates/bevy_core_pipeline/src/bloom/settings.rs | 4 +++- crates/bevy_pbr/src/cluster/assign.rs | 9 ++++++--- crates/bevy_render/src/camera/camera.rs | 12 ++++++++---- crates/bevy_render/src/camera/camera_driver_node.rs | 8 ++++++-- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/crates/bevy_core_pipeline/src/bloom/settings.rs b/crates/bevy_core_pipeline/src/bloom/settings.rs index 3fc35dc4d5105..effa135677f3b 100644 --- a/crates/bevy_core_pipeline/src/bloom/settings.rs +++ b/crates/bevy_core_pipeline/src/bloom/settings.rs @@ -226,7 +226,9 @@ impl ExtractComponent for Bloom { camera.is_active, camera.hdr, ) { - (Some(URect { min: origin, .. }), Some(size), Some(target_size), true, true) => { + (Some(URect { min: origin, .. }), Some(size), Some(target_size), true, true) + if size.x != 0 && size.y != 0 => + { let threshold = bloom.prefilter.threshold; let threshold_softness = bloom.prefilter.threshold_softness; let knee = threshold * threshold_softness.clamp(0.0, 1.0); diff --git a/crates/bevy_pbr/src/cluster/assign.rs b/crates/bevy_pbr/src/cluster/assign.rs index 046011cb097b7..4c3e22febed65 100644 --- a/crates/bevy_pbr/src/cluster/assign.rs +++ b/crates/bevy_pbr/src/cluster/assign.rs @@ -218,9 +218,12 @@ pub(crate) fn assign_objects_to_clusters( continue; } - let Some(screen_size) = camera.physical_viewport_size() else { - clusters.clear(); - continue; + let screen_size = match camera.physical_viewport_size() { + Some(screen_size) if screen_size.x != 0 && screen_size.y != 0 => screen_size, + _ => { + clusters.clear(); + continue; + } }; let mut requested_cluster_dimensions = config.dimensions_for_screen_size(screen_size); diff --git a/crates/bevy_render/src/camera/camera.rs b/crates/bevy_render/src/camera/camera.rs index a272df4e6c167..3aded842ea665 100644 --- a/crates/bevy_render/src/camera/camera.rs +++ b/crates/bevy_render/src/camera/camera.rs @@ -965,10 +965,14 @@ pub fn camera_system( } camera.computed.target_info = new_computed_target_info; if let Some(size) = camera.logical_viewport_size() { - camera_projection.update(size.x, size.y); - camera.computed.clip_from_view = match &camera.sub_camera_view { - Some(sub_view) => camera_projection.get_clip_from_view_for_sub(sub_view), - None => camera_projection.get_clip_from_view(), + if size.x != 0.0 && size.y != 0.0 { + camera_projection.update(size.x, size.y); + camera.computed.clip_from_view = match &camera.sub_camera_view { + Some(sub_view) => { + camera_projection.get_clip_from_view_for_sub(sub_view) + } + None => camera_projection.get_clip_from_view(), + } } } } diff --git a/crates/bevy_render/src/camera/camera_driver_node.rs b/crates/bevy_render/src/camera/camera_driver_node.rs index 2548c416ce185..f01d781478783 100644 --- a/crates/bevy_render/src/camera/camera_driver_node.rs +++ b/crates/bevy_render/src/camera/camera_driver_node.rs @@ -41,10 +41,14 @@ impl Node for CameraDriverNode { let mut run_graph = true; if let Some(NormalizedRenderTarget::Window(window_ref)) = camera.target { let window_entity = window_ref.entity(); - if windows.windows.get(&window_entity).is_some() { + if windows + .windows + .get(&window_entity) + .is_some_and(|w| w.physical_width > 0 && w.physical_height > 0) + { camera_windows.insert(window_entity); } else { - // The window doesn't exist anymore so we don't need to run the graph + // The window doesn't exist anymore or zero-sized so we don't need to run the graph run_graph = false; } }