Fix macOS wgpu live resize with low-latency surfaces - #8229
Conversation
|
Preview available at https://egui-pr-preview.github.io/pr/8229-codexmacos-wgpu-live-resize View snapshot changes at kitdiff |
|
Just submitted another winit PR that fixes another related resize issue: rust-windowing/winit#4589 It's not blocking this PR but something we'd probably want to wait for to be merged as well, so next egui release depends on winit version that fixes both issues. |
|
Thanks for the PR!
Should we still try to merge this egui PR now, or wait until there is a new winit release with your fix? |
|
@emilk Thanks for catching this. My dependency statement was incorrect. I validated both patches together and thought that the winit change was required. I just tested them independently and my egui app still resizes smoothly with I also retested the standalone winit/Metal demo in rust-windowing/winit#4588 which renders only from RedrawRequested. It does jitter without winit patch. So it's still useful but not required for this PR to be merged. |
|
Also heads-up: I still see occasional choppiness when increasing the window size in just released macOS 27 Developer Beta with this patch in. I haven't tested this on macOS 26 because I'm still on Sequoia. |
f480af1 to
f84b6c7
Compare
5ad0811 to
ca5f15a
Compare
|
What is |
f808fec to
6cee421
Compare
|
@lucasmerlin Ah, thanks for catching this! The PR branch accidentally picked up my later local experiment that depended on That was not meant to be part of this PR. I just cleaned it up and retested to confirm the fix still works. |
6cee421 to
866367d
Compare
lucasmerlin
left a comment
There was a problem hiding this comment.
Awesome, butter smooth now with no streaching or lag!
| [target.'cfg(target_os = "macos")'.dependencies] | ||
| wgpu = { workspace = true, features = ["metal"] } |
There was a problem hiding this comment.
It'd be great if we could keep metal optional, since some people might be using egui with vulkan or gl on macos.
I guess that was the original reason the feature flag was added.
| } else { | ||
| desired_maximum_frame_latency | ||
| }; | ||
|
|
There was a problem hiding this comment.
Nice, smart way to go about that!
Summary
This fixes macOS live-resize behavior for the
eframe/egui-wgpupath when using the low-latency wgpu surface configuration.The problem I was seeing is that native window resize can look visibly below the baseline expected from a desktop GUI: stale or stretched frames (manifesting as wobble/jitter), or severe lag while dragging a window edge.
The fix has three parts:
CAMetalLayer.presentsWithTransactionduring live resize to avoid stale/stretched framesdesired_maximum_frame_latency = 2while live resize is active, so transaction presentation does not stall when the app normally usesSurfaceConfig::LOW_LATENCYWindowEvent::Movedas part of the live-resize event stream, since resizing from the top or left edge changes the window originThis PR depends on the winit-side AppKit live-resize timing fix in rust-windowing/winit#4588
A renderer-only frame-latency change is not enough by itself. The temporary latency bump only solves the drawable starvation caused by combining
presentsWithTransactionwithSurfaceConfig::LOW_LATENCY. It does not change when winit emits resize/redraw events, whether redraws are delivered during AppKit's live-resize event-tracking loop, or whether the surface size is derived from the current backing rect.That is why the winit fix is needed first: it makes the windowing layer report the current AppKit backing size and request redraws from the live-resize/display callbacks. egui-wgpu still needs this PR on top because winit does not own the wgpu
Surfaceor the underlyingCAMetalLayerpresentation policy.In other words: winit fixes when the windowing layer reports resize/redraw work, while this PR fixes how egui-wgpu presents Metal-backed wgpu frames during that resize.
Why change the existing feature?
The existing
macos-window-resize-jitter-fixfeature addresses one symptom by enabling transaction presentation during resize, but it is not enough for the low-latency wgpu path.In particular,
presentsWithTransactionandSurfaceConfig::LOW_LATENCYinteract poorly during AppKit live resize. The old code avoids that by skipping transaction presentation when latency is1, but that means low-latency users get the resize jitter/wobble back.This PR keeps the low-latency path normally, but temporarily bumps frame latency only while live resize is active. That gives the resize path enough drawable slack without changing normal interaction latency.
I removed the
macos-window-resize-jitter-fixfeature because this seems like the behavior the macOS wgpu path should have by default, not a separate opt-in. If keeping the feature as a no-op compatibility alias is preferred, I can adjust the PR.Validation
I created a small demo app that somewhat resembles the layout of my actual app and highlights both horizontal and vertical resize jitter:
SurfaceConfig::LOW_LATENCYThe toolbar and list make stale or stretched frames easy to see during native resize. The jitter is visible even on the traffic light buttons.
Recordings:
Before 1: no transaction presentation, low latency
Shows jitter/wobble and stale/stretched frames during live resize.
before-1-jitter.mp4
Before 2: transaction presentation with low latency
Shows the other failure mode: live resize can become severely laggy when
transaction presentation is used while keeping
SurfaceConfig::LOW_LATENCY.before-2-lag.mp4
After: patched egui-wgpu + patched winit, low latency
No visible wobble/jitter and no severe live-resize lag.
after-fixed.mp4