1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-30 21:30:03 -04:00

Address review comments

This commit is contained in:
lucasmerlin
2026-03-23 15:34:39 +01:00
parent a9e828fa5b
commit 4ac5916ee8
7 changed files with 35 additions and 153 deletions

View File

@@ -276,58 +276,7 @@ fn describe_adapters(adapters: &[wgpu::Adapter]) -> String {
}
}
/// Describes a surface error when acquiring a texture for rendering.
///
/// These correspond to the error variants of [`wgpu::CurrentSurfaceTexture`] — everything
/// except `Success` and `Suboptimal`, which contain usable frames. This enum is passed to the
/// [`WgpuConfiguration::on_surface_error`] callback so you can decide how to respond.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SurfaceStatus {
/// Timed out waiting for the next frame.
///
/// This is usually transient. Skip the current frame and try again next frame.
Timeout,
/// The surface configuration no longer matches the underlying display surface.
///
/// The surface should be reconfigured (egui will do this automatically if you return
/// [`SurfaceErrorAction::RecreateSurface`]). This commonly happens after a window resize
/// or display settings change.
Outdated,
/// The surface has been lost and must be recreated from scratch.
///
/// This is more severe than [`Self::Outdated`] — the entire surface is invalid. Return
/// [`SurfaceErrorAction::RecreateSurface`] to recover.
Lost,
/// The window is not visible (e.g. minimized or fully behind another window).
///
/// Skip the current frame. There is nothing to render to.
Occluded,
/// A GPU validation error occurred.
///
/// This should not be reachable under normal circumstances, unless
/// you wrap the [`winit::Painter::paint_and_update_textures`] in a wgpu
/// error scope, and there is a validation error in the
/// [`wgpu::Surface::get_current_texture`] call.
Validation,
}
impl std::fmt::Display for SurfaceStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Timeout => write!(f, "Surface timed out"),
Self::Outdated => write!(f, "Surface outdated"),
Self::Lost => write!(f, "Surface lost"),
Self::Occluded => write!(f, "Surface occluded"),
Self::Validation => write!(f, "Surface validation error"),
}
}
}
/// Specifies which action should be taken as consequence of a [`SurfaceStatus`]
/// Specifies which action should be taken as consequence of a surface error.
pub enum SurfaceErrorAction {
/// Do nothing and skip the current frame.
SkipFrame,
@@ -354,8 +303,13 @@ pub struct WgpuConfiguration {
/// How to create the wgpu adapter & device
pub wgpu_setup: WgpuSetup,
/// Callback for surface errors.
pub on_surface_error: Arc<dyn Fn(SurfaceStatus) -> SurfaceErrorAction + Send + Sync>,
/// Callback for surface status changes.
///
/// Called with the [`wgpu::CurrentSurfaceTexture`] result whenever acquiring a frame
/// does not return [`wgpu::CurrentSurfaceTexture::Success`]. For
/// [`wgpu::CurrentSurfaceTexture::Suboptimal`], egui automatically reconfigures the
/// surface and uses the frame — the callback is not invoked in that case.
pub on_surface_status: Arc<dyn Fn(&wgpu::CurrentSurfaceTexture) -> SurfaceErrorAction + Send + Sync>,
}
#[test]
@@ -370,7 +324,7 @@ impl std::fmt::Debug for WgpuConfiguration {
present_mode,
desired_maximum_frame_latency,
wgpu_setup,
on_surface_error: _,
on_surface_status: _,
} = self;
f.debug_struct("WgpuConfiguration")
.field("present_mode", &present_mode)
@@ -391,13 +345,13 @@ 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_error: Arc::new(|err| {
if err == SurfaceStatus::Outdated {
on_surface_status: Arc::new(|status| {
if matches!(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"
} else {
log::warn!("Dropped frame with error: {err}");
log::warn!("Dropped frame with error: {status:?}");
}
SurfaceErrorAction::SkipFrame
}),

View File

@@ -132,16 +132,13 @@ impl WgpuSetup {
log::debug!("Creating wgpu instance with backends {backends:?}");
let desc = &create_new.instance_descriptor;
let mut descriptor = wgpu::InstanceDescriptor {
let descriptor = wgpu::InstanceDescriptor {
backends: desc.backends,
flags: desc.flags,
backend_options: desc.backend_options.clone(),
memory_budget_thresholds: desc.memory_budget_thresholds,
display: None,
display: create_new.display_handle.as_ref().map(|handle| handle.clone_for_wgpu()),
};
if let Some(handle) = &create_new.display_handle {
descriptor.display = Some(handle.clone_for_wgpu());
}
wgpu::util::new_instance_with_webgpu_detection(descriptor).await
}
Self::Existing(existing) => existing.instance.clone(),

View File

@@ -3,7 +3,7 @@
#![expect(clippy::unwrap_used)] // TODO(emilk): avoid unwraps
#![expect(unsafe_code)]
use crate::{RenderState, SurfaceErrorAction, SurfaceStatus, WgpuConfiguration, renderer};
use crate::{RenderState, SurfaceErrorAction, WgpuConfiguration, renderer};
use crate::{
RendererOptions,
capture::{CaptureReceiver, CaptureSender, CaptureState, capture_channel},
@@ -501,46 +501,13 @@ impl Painter {
};
let output_frame = match output_frame {
wgpu::CurrentSurfaceTexture::Success(frame)
| wgpu::CurrentSurfaceTexture::Suboptimal(frame) => frame,
wgpu::CurrentSurfaceTexture::Timeout => {
match (*self.configuration.on_surface_error)(SurfaceStatus::Timeout) {
SurfaceErrorAction::RecreateSurface => {
Self::configure_surface(surface_state, render_state, &self.configuration);
}
SurfaceErrorAction::SkipFrame => {}
}
return vsync_sec;
wgpu::CurrentSurfaceTexture::Success(frame) => frame,
wgpu::CurrentSurfaceTexture::Suboptimal(frame) => {
Self::configure_surface(surface_state, render_state, &self.configuration);
frame
}
wgpu::CurrentSurfaceTexture::Outdated => {
match (*self.configuration.on_surface_error)(SurfaceStatus::Outdated) {
SurfaceErrorAction::RecreateSurface => {
Self::configure_surface(surface_state, render_state, &self.configuration);
}
SurfaceErrorAction::SkipFrame => {}
}
return vsync_sec;
}
wgpu::CurrentSurfaceTexture::Lost => {
match (*self.configuration.on_surface_error)(SurfaceStatus::Lost) {
SurfaceErrorAction::RecreateSurface => {
Self::configure_surface(surface_state, render_state, &self.configuration);
}
SurfaceErrorAction::SkipFrame => {}
}
return vsync_sec;
}
wgpu::CurrentSurfaceTexture::Occluded => {
match (*self.configuration.on_surface_error)(SurfaceStatus::Occluded) {
SurfaceErrorAction::RecreateSurface => {
Self::configure_surface(surface_state, render_state, &self.configuration);
}
SurfaceErrorAction::SkipFrame => {}
}
return vsync_sec;
}
wgpu::CurrentSurfaceTexture::Validation => {
match (*self.configuration.on_surface_error)(SurfaceStatus::Validation) {
ref other => {
match (*self.configuration.on_surface_status)(other) {
SurfaceErrorAction::RecreateSurface => {
Self::configure_surface(surface_state, render_state, &self.configuration);
}