mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 13:20:05 -04:00
Fix random hangs by improving wgpu::Surface lifecycle handling (#8171)
### Related * Closes #8134. * Related to #5136. Possibly fixes: * #8123 * #5145 ### What We did not properly handle the variants of [`CurrentSurfaceTexture`](https://docs.rs/wgpu/latest/wgpu/enum.CurrentSurfaceTexture.html) and always returned `SkipFrame`. Because of this `egui` could end up in a state where frames are always skipped after observing `Outdated`, without the chance to recover (unless an event arrives from the outside). > [!NOTE] > This is not Wayland-specific, but could happen on all platforms. It just happens frequently for Wayland compositors that directly resize a window after creation (such as tiling/scrolling compositors like `hyprland` and `niri`). This PR improves this by separating the code paths for `Outdated` and `Lost`, to help recover from those events.
This commit is contained in:
@@ -313,7 +313,17 @@ pub enum SurfaceErrorAction {
|
||||
/// Do nothing and skip the current frame.
|
||||
SkipFrame,
|
||||
|
||||
/// Instructs egui to recreate the surface, then skip the current frame.
|
||||
/// Reconfigure the existing surface, then skip the current frame.
|
||||
///
|
||||
/// Calls [`wgpu::Surface::configure`] on the current surface object.
|
||||
/// Use for [`wgpu::CurrentSurfaceTexture::Outdated`].
|
||||
Reconfigure,
|
||||
|
||||
/// Drop the surface, create a new one via [`wgpu::Instance::create_surface`], configure it,
|
||||
/// then skip the current frame.
|
||||
///
|
||||
/// Use for [`wgpu::CurrentSurfaceTexture::Lost`], where reconfiguring the same surface
|
||||
/// object cannot recover.
|
||||
RecreateSurface,
|
||||
}
|
||||
|
||||
@@ -376,23 +386,28 @@ impl Default for WgpuConfiguration {
|
||||
// No display handle available at this point — callers should replace this with
|
||||
// `WgpuSetup::from_display_handle(...)` before creating the instance if one is available.
|
||||
wgpu_setup: WgpuSetup::without_display_handle(),
|
||||
on_surface_status: Arc::new(|status| {
|
||||
match status {
|
||||
wgpu::CurrentSurfaceTexture::Outdated => {
|
||||
// This error occurs when the app is minimized on Windows.
|
||||
// Silently return here to prevent spamming the console with:
|
||||
// "The underlying surface has changed, and therefore the swap chain must be updated"
|
||||
}
|
||||
wgpu::CurrentSurfaceTexture::Occluded => {
|
||||
// This error occurs when the application is occluded (e.g. minimized or behind another window).
|
||||
log::debug!("Dropped frame with error: {status:?}");
|
||||
}
|
||||
_ => {
|
||||
log::warn!("Dropped frame with error: {status:?}");
|
||||
}
|
||||
on_surface_status: Arc::new(|status| match status {
|
||||
wgpu::CurrentSurfaceTexture::Outdated => {
|
||||
// The compositor changed the surface (resize, scale, output, …). wgpu
|
||||
// requires us to reconfigure before the next acquire. Skipping would mean
|
||||
// we are stuck in `Outdated` forever.
|
||||
log::trace!("Dropped frame with error: {status:?}");
|
||||
SurfaceErrorAction::Reconfigure
|
||||
}
|
||||
wgpu::CurrentSurfaceTexture::Lost => {
|
||||
// The underlying surface is gone and we need a fresh one from the `wgpu::Instance`.
|
||||
log::debug!("Dropped frame with error: {status:?}");
|
||||
SurfaceErrorAction::RecreateSurface
|
||||
}
|
||||
wgpu::CurrentSurfaceTexture::Occluded => {
|
||||
// App is hidden (minimized / behind another window). Skip silently.
|
||||
log::trace!("Skipping frame due to occlusion.");
|
||||
SurfaceErrorAction::SkipFrame
|
||||
}
|
||||
_ => {
|
||||
log::warn!("Dropped frame with error: {status:?}");
|
||||
SurfaceErrorAction::SkipFrame
|
||||
}
|
||||
|
||||
SurfaceErrorAction::SkipFrame
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user