mirror of
https://github.com/bevyengine/bevy
synced 2024-09-21 06:52:04 +00:00
Ignore Timeout
errors on Linux AMD & Intel (#5957)
# Objective
- Fix #3606
- Fix #4579
- Fix #3380
## Solution
When running on a Linux machine with some AMD or Intel device, when calling
`surface.get_current_texture()`, ignore `wgpu::SurfaceError::Timeout` errors.
## 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: <94ce76391b/wgpu/examples/framework.rs (L362-L370)
>
Veloren [handles the Timeout error the way this PR proposes to handle it](https://github.com/gfx-rs/wgpu/issues/1218#issuecomment-1092056971).
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` occurrence is specific to a quirk of some AMD drivers on linux, and if otherwise met should be considered a bug.
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
7ced5336e6
commit
ffa489a846
1 changed files with 48 additions and 24 deletions
|
@ -220,32 +220,56 @@ 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")
|
||||
} else {
|
||||
match surface_data.surface.get_current_texture() {
|
||||
Ok(swap_chain_frame) => swap_chain_frame,
|
||||
Err(wgpu::SurfaceError::Outdated) => {
|
||||
render_device.configure_surface(&surface_data.surface, &surface_configuration);
|
||||
surface_data
|
||||
.surface
|
||||
.get_current_texture()
|
||||
.expect("Error reconfiguring surface")
|
||||
}
|
||||
err => err.expect("Failed to acquire next swap chain texture!"),
|
||||
}
|
||||
// A recurring issue is hitting `wgpu::SurfaceError::Timeout` on certain Linux
|
||||
// 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 may_erroneously_timeout = || {
|
||||
render_instance
|
||||
.enumerate_adapters(wgpu::Backends::VULKAN)
|
||||
.any(|adapter| {
|
||||
let name = adapter.get_info().name;
|
||||
name.starts_with("AMD") || name.starts_with("Intel")
|
||||
})
|
||||
};
|
||||
|
||||
window.swap_chain_texture = Some(TextureView::from(frame));
|
||||
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 {
|
||||
render_device.configure_surface(surface, &surface_configuration);
|
||||
let frame = surface
|
||||
.get_current_texture()
|
||||
.expect("Error configuring surface");
|
||||
window.swap_chain_texture = Some(TextureView::from(frame));
|
||||
} else {
|
||||
match surface.get_current_texture() {
|
||||
Ok(frame) => {
|
||||
window.swap_chain_texture = Some(TextureView::from(frame));
|
||||
}
|
||||
Err(wgpu::SurfaceError::Outdated) => {
|
||||
render_device.configure_surface(surface, &surface_configuration);
|
||||
let frame = surface
|
||||
.get_current_texture()
|
||||
.expect("Error reconfiguring surface");
|
||||
window.swap_chain_texture = Some(TextureView::from(frame));
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
Err(wgpu::SurfaceError::Timeout) if may_erroneously_timeout() => {
|
||||
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."
|
||||
);
|
||||
}
|
||||
Err(err) => {
|
||||
panic!("Couldn't get swap chain texture, operation unrecoverable: {err}");
|
||||
}
|
||||
}
|
||||
};
|
||||
window.swap_chain_texture_format = Some(surface_data.format);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue