Skip to content

Fix jittering during window resize on MacOS for WGPU/Metal#1551

Open
noelgbl wants to merge 10 commits intolinebender:mainfrom
noelgbl:macos-window-resize-jitter-fix
Open

Fix jittering during window resize on MacOS for WGPU/Metal#1551
noelgbl wants to merge 10 commits intolinebender:mainfrom
noelgbl:macos-window-resize-jitter-fix

Conversation

@noelgbl
Copy link

@noelgbl noelgbl commented Jan 3, 2026

This update fixes a widely known jitter issue on Metal/MacOS #1521 that occurs during window resizing. It introduces a new resized_window field in MasonryState to track the state of window resizing. The on_window_resize_state_change method in RenderContext is added to handle the resizing behavior for surfaces.

…text`

This update introduces a new `resized_window` field in `MasonryState` to track the state of window resizing. The `on_window_resize_state_change` method in `RenderContext` is added to handle the resizing behavior for surfaces, particularly for macOS/Metal to avoid rendering artifacts during interactive resizing. This change enhances the rendering pipeline's responsiveness to window size changes.
Copy link
Contributor

@PoignardAzur PoignardAzur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fine? I don't have a Mac on hand to test this on, so I'd appreciate if someone could test this.

@noelgbl noelgbl marked this pull request as ready for review January 27, 2026 09:11
@noelgbl
Copy link
Author

noelgbl commented Jan 27, 2026

I would need HAL features from Vello's wgpu namespace, so this might become a bigger change. For now, it works like expected on MacOS.

@noelgbl
Copy link
Author

noelgbl commented Jan 27, 2026

Any idea on doing this without touching Vello or completely disabling Vello's default features and using WGPU directly?

@PoignardAzur
Copy link
Contributor

@DJMcNab ?

Copy link
Contributor

@jaredoconnell jaredoconnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I won't approve since CI isn't passing and there is unsafe code, but I can confirm that this fixes the jitter.

Comment on lines 180 to 186
#[allow(unsafe_code, reason = "We only mutate a backend-specific flag on the Metal HAL surface when the runtime backend matches Metal")]
unsafe {
if let Some(hal_surface) = surface.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;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked more into that unsafe block and looked up the wgpu side to see how safe this was, and even if it works in practice, I'm not convinced this isn't undefined behavior, though I could be wrong.

Aside from that, I don't think this change is forward-compatible. In the current head commit of wgpu, wgpu::hal::metal::Surface does not publicly expose present_with_transaction. Ordinarily, I wouldn't block a PR on a future dependency, but combined with the unclear safety, it's giving me pause.

@noelgbl
Copy link
Author

noelgbl commented Feb 7, 2026

#8716 simply exposes a different API for setting this flag, which is also part of v28. Unfortunately, this issue cannot be solved without setting this flag, and therefore, unsafe code. Leaving the required change here for WGPU 28 and for future reference.

unsafe {
    if let Some(hal_surface) = surface.surface.as_hal::<wgpu::hal::api::Metal>() {
        let guard = hal_surface.render_layer().lock();
        guard.set_presents_with_transaction(resizing);
    }
}

@noelgbl noelgbl changed the title Add window resizing state management to MasonryState and `RenderCon… Fix jittering during window resize on MacOS for WGPU/Metal Feb 7, 2026
@PoignardAzur
Copy link
Contributor

(Unrelatedly, wow, googling "cargo metal crate rust" does not give me the results I want.)

@PoignardAzur
Copy link
Contributor

Unfortunately, this issue cannot be solved without setting this flag, and therefore, unsafe code.

The problem isn't unsafe code, it's undefined behavior. Taking a shared reference to a struct, transmuting it to a pointer then a mutable reference, then using it to mutating a field, is (I believe) undefined behavior unless the reference is to an internally mutable type. The compiler might optimize the mutation away in some cases, etc.

I'm more comfortable with the guard.set_presents_with_transaction(true); solution, which AFAICT uses objc's message-sending API.

However, it seems we can't use that API until we switch to wgpu 28, so...

I don't know. Ideologically, there are strong arguments for saying "Undefined behavior: not even once". In this particular case, the unsoundness would be temporary, only affect a single platform, there's no other way to get the feature/bugfix we want, it works on multiple people's computers, and while I know we're not supposed to speculate about the possible blast radius of undefined behavior, realistically I think the worst case behavior is that the bool doesn't get updated and we're back to square one.

I'd appreciate a second opinion on this.

Comment on lines +37 to +43
[target.'cfg(target_os = "macos")'.dependencies]
# Enables masonry_core/default -> vello -> wgpu -> wgpu_hal -> metal,
# which we need to interact with CoreAnimation during window resizing.
# This is not a very elegant fix and also enables all other HAL's.
# Remove this once a feature gating solution is found.
# See: https://github.com/linebender/xilem/pull/1551
masonry_core = { workspace = true, features = ["default"] }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we just enable the metal feature directly?

Suggested change
[target.'cfg(target_os = "macos")'.dependencies]
# Enables masonry_core/default -> vello -> wgpu -> wgpu_hal -> metal,
# which we need to interact with CoreAnimation during window resizing.
# This is not a very elegant fix and also enables all other HAL's.
# Remove this once a feature gating solution is found.
# See: https://github.com/linebender/xilem/pull/1551
masonry_core = { workspace = true, features = ["default"] }
[target.'cfg(target_os = "macos")'.dependencies]
# We need Metal to interact with CoreAnimation during window resizing.
wgpu = { version = "27.0.1", default-features = false, features = ["metal"] }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also thought of this, but wanted to avoid having to sync the version with Vello. But you probably know better than me if that's the way to go.

@xStrom
Copy link
Member

xStrom commented Feb 9, 2026

Avoiding undefined behavior seems like a great goal to me. Frankly I'm surprised that Vello isn't on wgpu 28 already, given that 29 is around the corner. We should see if we could get a Vello release with 28 out.

@noelgbl
Copy link
Author

noelgbl commented Feb 9, 2026

Then let's just wait for v28 if you feel more comfortable with it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants