bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
34.7k stars 3.39k forks source link

UI nodes don't resize when toggling fullscreen #14277

Closed benfrankel closed 1 week ago

benfrankel commented 1 month ago

Bevy version

0.14.0

Relevant system information

Linux with i3wm (tiling window manager).

AdapterInfo { name: "AMD Radeon RX 570 Series (RADV POLARIS10)", vendor: 4098, device: 26591, device_type: DiscreteGpu, driver: "radv", driver_info: "Mesa 24.0.6-arch1.2", backend: Vulkan }

What you did

Toggle fullscreen while looking at my title screen UI.

What went wrong

This is how my UI normally looks:

2024-07-11_1720684551_1215x728

This is how my UI sometimes looks after toggling from fullscreen to windowed:

2024-07-11_1720684545_1215x728

I checked, and the buttons in this case are the same size as they were while in fullscreen.

This issue can happen in reverse as well, with the fullscreen buttons being as small as they were while windowed.

Resizing the window slightly after the bug occurs will snap the buttons back to the correct size.

ickshonpe commented 1 month ago

It seems like the single UI layout update after the window resize isn't enough. You could try a system something like this to force it to reupdate again for few frames after the window resizes:

fn force_ui_reupdate_on_window_resized(
    mut counter: Local<u8>,
    mut window_resized_events: EventReader<WindowResized>,
    mut ui_scale: ResMut<UiScale>,
    mut ui_node_query: Query<(&mut Style, Option<&mut Text>)>,
) {
    if 0 < *counter {
        ui_scale.set_changed();
        for (mut style, maybe_text) in ui_node_query.iter_mut() {
            style.set_changed();
            if let Some(mut text) = maybe_text {
                text.set_changed();
            }
        }
    }   

    *counter = counter.saturating_sub(1);
    if !window_resized_events.is_empty() {
        window_resized_events.clear();
        *counter = 2;
    }
}

I just typed this out quickly, it's not tested but I think it should work. The query might be overkill, maybe it'll correct itself just with setting UiScale to changed the frame directly after the window resize.

alice-i-cecile commented 1 month ago

Duplicate of #14255.

UkoeHB commented 1 month ago

@alice-i-cecile not a duplicate, this is about toggling to fullscreen and #14255 is about resizing the window itself. They seem related though.

benfrankel commented 2 weeks ago

I'm seeing this bug occasionally in the itch.io release of my jam game as well. This is much more severe than the related bug, because the size difference between windowed and fullscreen makes the UI completely broken instead of "slightly jittery / delayed", and toggling back to windowed -> back to fullscreen -> ... does not fix it for the user.

benfrankel commented 2 weeks ago

This appears to be a system ordering bug. I ran the same app 30 times without recompiling and saw the bug 10/30 times. Whenever the bug was present, it happened 100% consistently on every fullscreen toggle.

Also, manually mutating the Style component of a bugged UI node (via inspector) snaps it back to the correct size, but it doesn't fix any of the other bugged nodes' sizes. That's as expected, I suppose.

benfrankel commented 2 weeks ago

I suspect that this is a system ordering bug between CameraUpdateSystem and UiSystem::Layout, which both run in PostUpdate with no ordering specified between them. The former contains a system that updates the Camera's viewport size if the window has been resized, while the latter has a system that reads the Camera's viewport size if the window has been resized, and uses that to calculate UI node sizes.

This is probably also causing https://github.com/bevyengine/bevy/issues/14255.

I could test this out but I haven't been able to reproduce the bug in a bevy example yet.

benfrankel commented 2 weeks ago

Well. I wasn't able to reproduce the bug in a minimal example with unmodified Bevy 0.14.0, but when I explicitly ordered CameraUpdateSystem after UiSystem::Layout, it triggered the exact buggy behavior I've been seeing -- and when I ordered it before, it didn't cause a crash, which demonstrates that the system sets are ambiguous.

IDK if system order randomization doesn't apply to cargo run --example or if I got supremely unlucky... but that should be enough to prove that that's the cause of the issue, or at least one way it can be caused.

UkoeHB commented 2 weeks ago

I suspect that this is a system ordering bug between CameraUpdateSystem and UiSystem::Layout, which both run in PostUpdate with no ordering specified between them.

It makes sense to me this would be the issue. Can you open a PR?

benfrankel commented 2 weeks ago

Opened PR :)