-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Enable creating "virtual" windows without corresponding OS window #6256
Conversation
eee987b
to
bad1a8a
Compare
Oh, I missed #6114, which seems to make almost the same changes with mainly different intention / language around them. It also adds a test example and changes the I'd suggest rebasing @targrub's changes on my implementation. My pull request seems to be more minimal and be more open to different use cases. #6114 for example says /// During normal use, this can be safely unwrapped; the value should only be [`None`] when synthetically constructed for tests.
which rules out the use cases I am suggesting. Of course we should probably mention the use of "virtual windows" for testing and @targrub's test example is also a good addition. I'm not sure how #6147 fits in. The windows created there do seem to always have a enum AbstractWindowHandle {
Raw(RawWindowHandleWrapper),
Virtual,
Canvas(Canvas),
} instead. |
Sounds good; I'm on board with that course of action. |
I rewrote my code to use an enum instead of |
I've updated my PR to use your enum instead. |
I've fixed that behavior in a subsequent commit.
I'm not familiar with that phrasing; what does that mean, "rebasing @targrub's changes on my implementation"?
That comment was written by @alice-i-cecile . :) |
It just means that my PR gets merged first. Your PR would then show a message say something about "conflicts" because we are editing the same lines in the same file. You would then merge the (then) current main branch from bevy into your branch solving these conflicts (or alternatively, run All in all the commit history should then look like
You can also do that work before my PR gets merged, but that requires some git magic. |
I'm going to merge targrub's PR first to spare them the git pain :) I also think it's less complex / controversial than this change. |
Gee, thanks! |
It's causing a lot of trouble for my side to not have the Wouldn't it be a good idea to include |
Unfortunately I don't think this is possible. As I understand the main purpose of For your PR it would make sense though to add the canvas as a field of |
There are many types called “Window” in bevy. The Window created by CreateWindow is the one used by winit to link the actual OS window to the engine. It's possible that it already exists when this event is called, I think the OS window is just created lazily when it doesn't exist yet. However, I didn't write that code and it's entirely undocumented, so I'm mostly guessing here based on the snippets I've read through in the course of creating my PR. Anyways, the problem is that there's no way get the canvas to the winit initializer at the moment without having a web-only API, which I don't want to force. |
Couldn't there just be a |
That was my previous solution, but that complicates things in combination with this PR, making a few things redundant. I'll have to take a look if I can get that working again in the new architecture. |
da84b1f
to
460c467
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very clean, and the use cases are good. Can you add a full example to examples/window
demonstrating how to use this in practice? The "render a texture to it" makes a lot of sense, but will be hard for users to piece together.
460c467
to
fef8f2a
Compare
Sure, good idea. I'm gonna try to come up with something simple. |
@anlumo, can I get a review from you on this since you've been touching related code and working off this PR? |
So, sorry for taking so long. I already knew the code itself while adapting my PR to it, and now I've also checked out the documentation and the example. All of that seems fine to me. |
@MDeiml can you rebase this? |
Virtual windows will by default not have a surface texture associated to them, but implementors can set the texture in `ExtractedWindow` manually. This is intended to be used when embedding games into other appications like editors or for running games headless.
7e2ec5d
to
0c6caff
Compare
crates/bevy_render/src/lib.rs
Outdated
instance.create_surface(&handle) | ||
let surface = { | ||
let windows = app.world.resource_mut::<bevy_window::Windows>(); | ||
let raw_handle = windows.get_primary().and_then(|window| unsafe { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a SAFETY comment :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that's true. The file was missing the SAFETY comment before the change, but I'll add one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually looking at it now it seems to me that this was never safe. In particular this comment
bevy/crates/bevy_window/src/raw_handle.rs
Lines 36 to 40 in 02fbf16
// SAFETY: [`RawHandleWrapper`] is just a normal "raw pointer", which doesn't impl Send/Sync. However the pointer is only | |
// exposed via an unsafe method that forces the user to make a call for a given platform. (ex: some platforms don't | |
// support doing window operations off of the main thread). | |
// A recommendation for this pattern (and more context) is available here: | |
// https://github.com/rust-windowing/raw-window-handle/issues/59 |
is wrong. The raw window and display handle are directly exposed as the attributes are
pub
and there are pub
methods to access them.
Even without this problem, for my particular case to ensure safety, all windows in Windows
have to be created through the main thread, but new windows can be created and added from any thread using Windows::add.
Same goes for
bevy/crates/bevy_render/src/view/window.rs
Lines 186 to 187 in 02fbf16
.or_insert_with(|| unsafe { | |
// NOTE: On some OSes this MUST be called from the main thread. |
If I understand this situation correctly this could be made safe by:
- Making the attributes of
RawHandleWrapper
private and removing the methods to access them - Making
Window::add
unsafe and specifying that it has to be called from the main thread. Maybe add a comment that it is better to useCreateWindow
anyways. - Making
prepare_windows
an exclusive system which if I remember correctly would make it run on the main thread
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making prepare_windows an exclusive system which if I remember correctly would make it run on the main thread
Ideally we would add a NonSend
system parameter here, which forces main thread access without blocking parallelism fully.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, it seems like changing the methods of Windows
to ensure safety is unpractical, as there are also methods which expose mutable references, which also would need to be unsafe. So I'll make creating RawHandleWrapper
unsafe instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Making prepare_windows an exclusive system which if I remember correctly would make it run on the main thread
Ideally we would add a
NonSend
system parameter here, which forces main thread access without blocking parallelism fully.
The marker was already there, I just missed it.
}); | ||
|
||
let window_id = WindowId::new(); | ||
windows.add(Window::new_virtual( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This bit needs more comments; it's the point of the example.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some small feedback, but I'm liking the direction. I'd also be interested in seeing a headless rendering + virtual window example, but won't require it to be part of this PR. I suspect that it will be a very useful method for testing UI code without a GPU.
0c6caff
to
e4bb697
Compare
e4bb697
to
4290e3b
Compare
Closed per rationale in #8278. |
Objective
Solution
raw_window_handle
attribute anOption
raw_window_handle
ofNone
inprepare_windows
ExtractedWindow
Changelog
new_virtual
method toWindow
, which does not take aRawWindowHandleWrapper
Window::raw_window_handle
to returnNone
if it was created usingnew_virtual
prepare_windows
to ignore windows that were created usingnew_virtual