Skip to content

Commit

Permalink
Ignore Timeout errors on Linux AMD & Intel (bevyengine#5957)
Browse files Browse the repository at this point in the history
# Objective

- Fix bevyengine#3606
- Fix bevyengine#4579
- Fix bevyengine#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: <https://github.com/gfx-rs/wgpu/blob/94ce76391b560a66e36df1300bd684321e57511a/wgpu/examples/framework.rs#L362-L370>

Veloren [handles the Timeout error the way this PR proposes to handle it](gfx-rs/wgpu#1218 (comment)).

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>
  • Loading branch information
2 people authored and ItsDoot committed Feb 1, 2023
1 parent cc2c6cd commit ea30f2b
Showing 1 changed file with 43 additions and 19 deletions.
62 changes: 43 additions & 19 deletions crates/bevy_render/src/view/window.rs
Expand Up @@ -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
// 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")
})
};

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")
.expect("Error configuring surface");
window.swap_chain_texture = Some(TextureView::from(frame));
} else {
match surface_data.surface.get_current_texture() {
Ok(swap_chain_frame) => swap_chain_frame,
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 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}");
}
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);
}
}

0 comments on commit ea30f2b

Please sign in to comment.