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

Fix jittering during window resize on MacOS for WGPU/Metal (#7641)

Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
ASPCartman
2025-11-01 14:55:56 +03:00
committed by GitHub
parent e861c8ec79
commit c5347f28e4
3 changed files with 88 additions and 10 deletions

View File

@@ -25,7 +25,7 @@ all-features = true
rustdoc-args = ["--generate-link-to-definition"]
[features]
default = ["fragile-send-sync-non-atomic-wasm", "wgpu/default"]
default = ["fragile-send-sync-non-atomic-wasm", "macos-window-resize-jitter-fix", "wgpu/default"]
## Enable [`winit`](https://docs.rs/winit) integration. On Linux, requires either `wayland` or `x11`
winit = ["dep:winit", "winit/rwh_06"]
@@ -43,6 +43,9 @@ x11 = ["winit?/x11"]
## Thus that usage is guarded against with compiler errors in wgpu.
fragile-send-sync-non-atomic-wasm = ["wgpu/fragile-send-sync-non-atomic-wasm"]
## Enables `present_with_transaction` surface flag temporary during window resize on MacOS.
macos-window-resize-jitter-fix = ["wgpu/metal"]
[dependencies]
egui = { workspace = true, default-features = false }
epaint = { workspace = true, default-features = false, features = ["bytemuck"] }

View File

@@ -14,6 +14,7 @@ struct SurfaceState {
alpha_mode: wgpu::CompositeAlphaMode,
width: u32,
height: u32,
resizing: bool,
}
/// Everything you need to paint egui with [`wgpu`] on [`winit`].
@@ -230,6 +231,7 @@ impl Painter {
width: size.width,
height: size.height,
alpha_mode,
resizing: false,
},
);
let Some(width) = NonZeroU32::new(size.width) else {
@@ -326,6 +328,59 @@ impl Painter {
}
}
/// Handles changes of the resizing state.
///
/// Should be called prior to the first [`Painter::on_window_resized`] call and after the last in
/// the chain. Used to apply platform-specific logic, e.g. OSX Metal window resize jitter fix.
pub fn on_window_resize_state_change(&mut self, viewport_id: ViewportId, resizing: bool) {
profiling::function_scope!();
let Some(state) = self.surfaces.get_mut(&viewport_id) else {
return;
};
if state.resizing == resizing {
if resizing {
log::debug!(
"Painter::on_window_resize_state_change() redundant call while resizing"
);
} else {
log::debug!(
"Painter::on_window_resize_state_change() redundant call after resizing"
);
}
return;
}
// Resizing is a bit tricky on macOS.
// It requires enabling ["present_with_transaction"](https://developer.apple.com/documentation/quartzcore/cametallayer/presentswithtransaction)
// flag to avoid jittering during the resize. Even though resize jittering on macOS
// is common across rendering backends, the solution for wgpu/metal is known.
//
// See https://github.com/emilk/egui/issues/903
#[cfg(all(target_os = "macos", feature = "macos-window-resize-jitter-fix"))]
{
// SAFETY: The cast is checked with if condition. If the used backend is not metal
// it gracefully fails. The pointer casts are valid as it's 1-to-1 type mapping.
// This is how wgpu currently exposes this backend-specific flag.
unsafe {
if let Some(hal_surface) = state.surface.as_hal::<wgpu::hal::api::Metal>() {
let raw =
std::ptr::from_ref::<wgpu::hal::metal::Surface>(&*hal_surface).cast_mut();
(*raw).present_with_transaction = resizing;
Self::configure_surface(
state,
self.render_state.as_ref().unwrap(),
&self.configuration,
);
}
}
}
state.resizing = resizing;
}
pub fn on_window_resized(
&mut self,
viewport_id: ViewportId,