From f9ae8d7b410643b91af1f53090c1412d6b1b71a8 Mon Sep 17 00:00:00 2001 From: Nicola Papale Date: Mon, 12 Sep 2022 14:06:38 +0200 Subject: [PATCH 1/6] Ignore `Timeout` errors on Linux AMD Alternative: An alternative solution found in the `wgpu` examples is: ```rust let frame = surface .get_current_texture() .or_else(|_| { render_device.configure_surface(surface, &swap_chain_descriptor); surface.get_current_texture() }) .expect("Error reconfiguring surface"); window.swap_chain_texture = Some(TextureView::from(frame)); ``` See: The reason I went with this PR's solution is that `configure_surface` seems to be quite an expensive operation, and it would run every frame with the wgpu framework solution, despite the fact it works perfectly fine without `configure_surface`. I know this looks super hacky with the linux-specific line and the AMD check, but my understanding is that the `Timeout` occurence is specific to a quirk of some AMD drivers on linux, and if otherwise met should be considered a bug. --- crates/bevy_render/src/view/window.rs | 56 +++++++++++++++++---------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index 627c96e8c9de8..aae2cde29391c 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -10,7 +10,7 @@ use bevy_window::{ CompositeAlphaMode, PresentMode, RawHandleWrapper, WindowClosed, WindowId, Windows, }; use std::ops::{Deref, DerefMut}; -use wgpu::TextureFormat; +use wgpu::{Backends, TextureFormat}; /// Token to ensure a system runs on the main thread. #[derive(Resource, Default)] @@ -220,32 +220,46 @@ pub fn prepare_windows( }, }; - // Do the initial surface configuration if it hasn't been configured yet. Or if size or - // present mode changed. - let frame = if window_surfaces.configured_windows.insert(window.id) - || window.size_changed - || window.present_mode_changed - { - render_device.configure_surface(&surface_data.surface, &surface_configuration); - surface_data - .surface - .get_current_texture() - .expect("Error configuring surface") + #[cfg(target_os = "linux")] + let is_amd = || { + render_instance + .enumerate_adapters(Backends::VULKAN) + .any(|adapter| adapter.get_info().name.starts_with("AMD")) + }; + + let not_already_configured = window_surfaces.configured_windows.insert(window.id); + + if not_already_configured || window.size_changed || window.present_mode_changed { + let no_new_surface_message = "Error reconfiguring surface"; + let surface = &surface_data.surface; + render_device.configure_surface(surface, &surface_configuration); + let frame = surface.get_current_texture().expect(no_new_surface_message); + window.swap_chain_texture = Some(TextureView::from(frame)); } else { - match surface_data.surface.get_current_texture() { - Ok(swap_chain_frame) => swap_chain_frame, + let surface = &surface_data.surface; + match surface.get_current_texture() { + Ok(frame) => { + window.swap_chain_texture = Some(TextureView::from(frame)); + } Err(wgpu::SurfaceError::Outdated) => { - render_device.configure_surface(&surface_data.surface, &surface_configuration); - surface_data - .surface + render_device.configure_surface(surface, &surface_configuration); + let frame = surface .get_current_texture() - .expect("Error reconfiguring surface") + .expect("Error reconfiguring surface"); + window.swap_chain_texture = Some(TextureView::from(frame)); + } + #[cfg(target_os = "linux")] + Err(wgpu::SurfaceError::Timeout) if is_amd() => { + debug!( + "Couldn't get swap chain texture. This is probably a quirk \ + of your Linux AMD GPU driver, so it can be safely ignored." + ); + } + Err(err) => { + panic!("Couldn't get swap chain texture, operation unrecoverable: {err}"); } - err => err.expect("Failed to acquire next swap chain texture!"), } }; - - window.swap_chain_texture = Some(TextureView::from(frame)); window.swap_chain_texture_format = Some(surface_data.format); } } From 69572e02d7590a7d8aca22e750fc1d1117bf846a Mon Sep 17 00:00:00 2001 From: Nicola Papale Date: Mon, 12 Sep 2022 14:26:06 +0200 Subject: [PATCH 2/6] Document quirky behavior --- crates/bevy_render/src/view/window.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index aae2cde29391c..7cdf649e779e5 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -10,7 +10,7 @@ use bevy_window::{ CompositeAlphaMode, PresentMode, RawHandleWrapper, WindowClosed, WindowId, Windows, }; use std::ops::{Deref, DerefMut}; -use wgpu::{Backends, TextureFormat}; +use wgpu::TextureFormat; /// Token to ensure a system runs on the main thread. #[derive(Resource, Default)] @@ -220,10 +220,16 @@ pub fn prepare_windows( }, }; + // A recurring issue is hitting `wgpu::SurfaceError::Timeout` on certain Linux + // AMD drivers. This seems to be a quirk of the driver. + // We'd rather keep panicking when not on Linux AMD, because in those case, + // the `Timeout` is still probably the symptom of a degraded unrecoverable + // application state. + // see https://github.com/bevyengine/bevy/pull/5957 #[cfg(target_os = "linux")] let is_amd = || { render_instance - .enumerate_adapters(Backends::VULKAN) + .enumerate_adapters(wgpu::Backends::VULKAN) .any(|adapter| adapter.get_info().name.starts_with("AMD")) }; From 5b3b4544a182099032626c429d8f1dabb5ca2954 Mon Sep 17 00:00:00 2001 From: Nicola Papale Date: Mon, 26 Sep 2022 13:56:34 +0200 Subject: [PATCH 3/6] Workaround timeout bug on intel devices as well --- crates/bevy_render/src/view/window.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index 7cdf649e779e5..7bec5cccd4877 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -221,16 +221,20 @@ pub fn prepare_windows( }; // A recurring issue is hitting `wgpu::SurfaceError::Timeout` on certain Linux - // AMD drivers. This seems to be a quirk of the driver. - // We'd rather keep panicking when not on Linux AMD, because in those case, + // mesa driver implementations. This seems to be a quirk of some drivers. + // We'd rather keep panicking when not on Linux mesa, because in those case, // the `Timeout` is still probably the symptom of a degraded unrecoverable // application state. // see https://github.com/bevyengine/bevy/pull/5957 + // and https://github.com/gfx-rs/wgpu/issues/1218 #[cfg(target_os = "linux")] - let is_amd = || { + let may_erroneously_timeout = || { render_instance .enumerate_adapters(wgpu::Backends::VULKAN) - .any(|adapter| adapter.get_info().name.starts_with("AMD")) + .any(|adapter| { + let name = adapter.get_info().name; + name.starts_with("AMD") || name.starts_with("Intel") + }) }; let not_already_configured = window_surfaces.configured_windows.insert(window.id); @@ -255,10 +259,10 @@ pub fn prepare_windows( window.swap_chain_texture = Some(TextureView::from(frame)); } #[cfg(target_os = "linux")] - Err(wgpu::SurfaceError::Timeout) if is_amd() => { + Err(wgpu::SurfaceError::Timeout) if may_erroneously_timeout() => { debug!( "Couldn't get swap chain texture. This is probably a quirk \ - of your Linux AMD GPU driver, so it can be safely ignored." + of your Linux GPU driver, so it can be safely ignored." ); } Err(err) => { From fb04948494ac282c3b48d58e0d7307ca4f5c8d5d Mon Sep 17 00:00:00 2001 From: Nicola Papale Date: Tue, 1 Nov 2022 12:58:11 +0100 Subject: [PATCH 4/6] Add different error message for configuration --- crates/bevy_render/src/view/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index 7bec5cccd4877..c7f8b0fca950e 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -240,7 +240,7 @@ pub fn prepare_windows( let not_already_configured = window_surfaces.configured_windows.insert(window.id); if not_already_configured || window.size_changed || window.present_mode_changed { - let no_new_surface_message = "Error reconfiguring surface"; + let no_new_surface_message = "Error configuring surface"; let surface = &surface_data.surface; render_device.configure_surface(surface, &surface_configuration); let frame = surface.get_current_texture().expect(no_new_surface_message); From 587b33fad193b17be5c4270f695c93c2244af4ce Mon Sep 17 00:00:00 2001 From: Nicola Papale Date: Tue, 1 Nov 2022 15:04:31 +0100 Subject: [PATCH 5/6] Make error message a trace --- crates/bevy_render/src/view/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index c7f8b0fca950e..286c085db75a7 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -260,7 +260,7 @@ pub fn prepare_windows( } #[cfg(target_os = "linux")] Err(wgpu::SurfaceError::Timeout) if may_erroneously_timeout() => { - debug!( + bevy_utils::tracing::trace!( "Couldn't get swap chain texture. This is probably a quirk \ of your Linux GPU driver, so it can be safely ignored." ); From a988909628fbda85c7d1ac80eaa089d1590c023c Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Sat, 12 Nov 2022 00:05:03 -0800 Subject: [PATCH 6/6] improve variables --- crates/bevy_render/src/view/window.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index 286c085db75a7..8e6f82c66c911 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -239,14 +239,14 @@ pub fn prepare_windows( let not_already_configured = window_surfaces.configured_windows.insert(window.id); + let surface = &surface_data.surface; if not_already_configured || window.size_changed || window.present_mode_changed { - let no_new_surface_message = "Error configuring surface"; - let surface = &surface_data.surface; render_device.configure_surface(surface, &surface_configuration); - let frame = surface.get_current_texture().expect(no_new_surface_message); + let frame = surface + .get_current_texture() + .expect("Error configuring surface"); window.swap_chain_texture = Some(TextureView::from(frame)); } else { - let surface = &surface_data.surface; match surface.get_current_texture() { Ok(frame) => { window.swap_chain_texture = Some(TextureView::from(frame));