Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Arc WinitWindow and extract to render world #12524

Closed
wants to merge 15 commits into from

Conversation

s-puig
Copy link
Contributor

@s-puig s-puig commented Mar 16, 2024

Objective

Fixes #11236
(likely) Fixes #11150
(likely) Fixes #11734

Problem

Window crashes when using pipelined rendering under GPU-bound scenarios.

It is not exclusive to XWayland and is based on a race condition with pipelined rendering.

Winit windows might be deleted on app world while the window is still alive in render world, if the render world window tries to access a winit resource (i.e. a surface or raw handle) it panics because the winit window no longer exists.
All those crashes go away by disabling pipelined rendering.

Solution

  • Arc<WinitWindow> and extract it when using pipelined rendering.

Alternative solutions

  • Delay deleting WinitWindow by a frame.

@Friz64
Copy link
Contributor

Friz64 commented Mar 16, 2024

I can confirm this fixes #11150 / #11734 for me in its current state.

Copy link
Member

@james7132 james7132 left a comment

Choose a reason for hiding this comment

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

Would it be possible to put this behind a feature flag that is enabled when "pipelined_rendering" is enabled on the top level Bevy crate? Or is this an issue when pipelined_rendering is disabled?

@james7132 james7132 requested a review from hymm March 17, 2024 01:46
@james7132 james7132 added C-Bug An unexpected or incorrect behavior A-Windowing Platform-agnostic interface layer to run your app in C-Crash A sudden unexpected crash labels Mar 17, 2024
Copy link
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

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

@james7132 I don't agree with feature-flagging this :)

It looks like it should always work, even when pipelined rendering is off, and maintaining compile-gated code like this is substantially harder.

That said, I don't feel strongly enough to block on this point: the cost is small and the fix is important.

@s-puig
Copy link
Contributor Author

s-puig commented Mar 17, 2024

@james7132 I don't agree with feature-flagging this :)

It looks like it should always work, even when pipelined rendering is off, and maintaining compile-gated code like this is substantially harder.

That said, I don't feel strongly enough to block on this point: the cost is small and the fix is important.

I don't really feel either way, but i should add that this fix forcefully skips the last frame of window events since it doesn't have a Window component anymore. This is irrelevant in pipelined because it already does (needs it's own issue) either unintentionally or crashing.

Forcing this fix upon non-pipelined also makes it so they skip this last frame of window events even though this bug can't happen.

Personally, I would keep it feature-flagged until a definite fix can be found rather than adding a "bug" to non-pipelined.

@JMS55
Copy link
Contributor

JMS55 commented Mar 17, 2024

Maybe we can wrap the window in an Arc or something?

@james7132
Copy link
Member

james7132 commented Mar 17, 2024

My biggest concern here is that the extra frame that we're now running potentially has extra user or plugin logic running through it, which may run contrary to the expectations that closing the window will immediately send an AppExit event.

With that said, this problem persists even with the cfg block, which comes with more complexity. I'm fine with this as is for now, but @JMS55's suggestion to internally wrap it in an Arc may be the right strategy here.

@alice-i-cecile alice-i-cecile added this to the 0.14 milestone Mar 17, 2024
Copy link
Contributor

You added a new example but didn't add metadata for it. Please update the root Cargo.toml file.

@s-puig
Copy link
Contributor Author

s-puig commented Mar 26, 2024

Unsure what's up with CI and the bot but fix should be ready for review.

@s-puig s-puig changed the title Fix window panic on close Arc WinitWindow and extract to render world Mar 28, 2024
} else {
bevy_utils::tracing::warn!("Winit feature was enabled but couldn't detect WinitPlugin. Are you sure you loaded this after WinitPlugin?");
}
}
Copy link
Member

Choose a reason for hiding this comment

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

This potentially hard-couples bevy_render and bevy_winit. I'm not sure if we want to do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm open to alternatives, but i don't see a way around it if we want to properly fix it. There is always the option of using a hack (delaying the winit window removal in app world).

Copy link
Contributor

@Friz64 Friz64 Apr 15, 2024

Choose a reason for hiding this comment

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

@s-puig Take a look at this: Friz64@0561754

It also works as a fix, and avoids the hard-coupling to bevy_winit. I'm not convinced that dynamic dispatch is the most elegant solution here.

github-merge-queue bot pushed a commit that referenced this pull request Apr 30, 2024
… using pipelined rendering (#12978)

# Objective

A `RawWindowHandle` is only valid as long as the window it was retrieved
from is alive. Extend the lifetime of the window, so that the
`RawWindowHandle` doesn't outlive it, and bevy doesn't crash when
closing a window a pipelined renderer is drawing to.

- Fix #11236
- Fix #11150
- Fix #11734
- Alternative to / Closes #12524

## Solution

Introduce a `WindowWrapper` that takes ownership of the window. Require
it to be used when constructing a `RawHandleWrapper`. This forces
windowing backends to store their window in this wrapper.

The `WindowWrapper` is implemented by storing the window in an `Arc<dyn
Any + Send + Sync>`.

We use dynamic dispatch here because we later want the
`RawHandleWrapper` to be able dynamically hold a reference to any
windowing backend's window.

But alas, the `WindowWrapper` itself is still practically invisible to
windowing backends, because it implements `Deref` to the underlying
window, by storing its type in a `PhantomData`.

---

## Changelog

### Added

- Added `WindowWrapper`, which windowing backends are now required to
use to store their underlying window.

### Fixed

- Fixed a safety problem which caused crashes when closing bevy windows
when using pipelined rendering.

## Migration Guide

- Windowing backends now need to store their window in the new
`WindowWrapper`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Windowing Platform-agnostic interface layer to run your app in C-Bug An unexpected or incorrect behavior C-Crash A sudden unexpected crash
Projects
None yet
5 participants