Skip to content

Fix handling of WindowResolution change#24746

Open
B0ryskart0n wants to merge 12 commits into
bevyengine:mainfrom
B0ryskart0n:window-res-fix
Open

Fix handling of WindowResolution change#24746
B0ryskart0n wants to merge 12 commits into
bevyengine:mainfrom
B0ryskart0n:window-res-fix

Conversation

@B0ryskart0n

@B0ryskart0n B0ryskart0n commented Jun 24, 2026

Copy link
Copy Markdown

Objective

Fixes two issues I've identified with changing window resolution (and scaling).
See #24724.

Solution (outdated, see the later comments)

  1. When determining the requested window resolution (and scaling) uses the current WindowResolution properties, not the cached ones.
  2. Sends the WindowResized Message not only if the physical resolution has changed but additionally if the scaling has changed.

Testing

  • I've tested this using the simple app attached below. I encourage anyone to also try that and verify that now this behaviour is correct.
  • I've tested this on CachyOS KDE (Wayland), but I've checked the code surrounding this and I don't think there is any platform-dependency.

Showcase

Click to view showcase
use bevy::input::common_conditions::input_just_pressed;
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, startup)
        .add_systems(
            Update,
            (
                update_resolution_text,
                reset_window.run_if(input_just_pressed(KeyCode::Digit0)),
                change_base_scale.run_if(input_just_pressed(KeyCode::Digit1)),
                change_scale_override.run_if(input_just_pressed(KeyCode::Digit2)),
            ),
        )
        .run();
}

fn startup(mut commands: Commands) {
    commands.spawn(Camera2d);
    commands.spawn(Text::default());
    // Visual check of the actual logical resolution.
    // In 640x360 this text should be at the lower boundary of the window, barely visible.
    commands.spawn((
        Text2d::new("I'm at [0, -180]"),
        Transform::from_translation(vec3(0.0, -180.0, 0.0)),
    ));
}
fn reset_window(mut q_window: Query<&mut Window>) {
    let mut bevy_window = q_window.single_mut().unwrap();
    bevy_window.resolution.set_scale_factor(1.0);
    bevy_window.resolution.set_scale_factor_override(None);
    bevy_window.resolution.set_physical_resolution(1280, 720);
}
fn change_base_scale(mut q_window: Query<&mut Window>) {
    let mut bevy_window = q_window.single_mut().unwrap();
    bevy_window.resolution.set_scale_factor(2.0);
    bevy_window.resolution.set_physical_resolution(1280, 720);
}
fn change_scale_override(mut q_window: Query<&mut Window>) {
    let mut bevy_window = q_window.single_mut().unwrap();
    bevy_window.resolution.set_scale_factor_override(Some(2.0));
    bevy_window.resolution.set_physical_resolution(1280, 720);
}
/// Only for informative purposes, to display the current window state.
fn update_resolution_text(mut q_text: Query<&mut Text>, q_window: Query<&Window>) {
    let res = q_window.single().unwrap().resolution.clone();

    q_text.single_mut().unwrap().0 = format!(
        "Logical size: {}\nPhysical size: {}\nBase scale: {}\nScale override: {:?}",
        res.size(),
        res.physical_size(),
        res.base_scale_factor(),
        res.scale_factor_override()
    );
}

@github-actions

Copy link
Copy Markdown
Contributor

Welcome, new contributor!

Please make sure you've read our contributing guide, as well as our policy regarding AI usage, and we look forward to reviewing your pull request shortly ✨

@alice-i-cecile alice-i-cecile added this to the 0.20 milestone Jun 24, 2026
@alice-i-cecile alice-i-cecile added C-Bug An unexpected or incorrect behavior A-Windowing Platform-agnostic interface layer to run your app in X-Uncontroversial This work is generally agreed upon D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jun 24, 2026
@kfc35

kfc35 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Video of what the showcase example looks like with this PR for Mac:
https://github.com/user-attachments/assets/73c07593-4b7c-4487-afe2-49a5cdc8fa99

My opinion: the showcase behaves better than it does on main (double pressing between 0 and 2 doesn’t change the window multiple times), but I find it strange that the content doesn’t update until the window is manually resized (however, maybe that’s outside the scope of this PR? Is that what you’re referencing in “additional info” in the issue?). I also find it strange that the initial window is still double in physical size at 2560x1440.

I assume this PR would have also changed what the initial window looks like? It isn’t clear from the PR description what the behavior of the showcase is before the change and after; I’m just going from what the reported bug was in the issue. Like, I would think that the initializing of the window would start with the 1280 x 720 resolution, and then pressing “1” would not change anything since nothing changes with the resolution (base scale stays at 2, physical resolution would stay the same).

@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jun 25, 2026
@B0ryskart0n

Copy link
Copy Markdown
Author

Huge thanks for testing!

One remark up front: My OS's scale factor is 1.0. This is also the assumption that I made with reset_resolution function.
I'm going to perform more testing on what happens with a different OS scale factor later.


I didn't touch the initial window settings (not directly at least). By default Bevy creates a window with 1280x720 with base_scale_factor=1.0. However, this 1.0 can get overriden instantly based on winit's (OS's) scale factor here.

Could you please confirm that the initial window size has not changed relative to main? If my PR does changes the initial window then that's unexpected and I'll address that.

In the beginning of the video, you start manually resizing and then a sudden change in resolution happens. Is that triggered by a keyboard input, or not?


The content not updating until a manual resize is exactly what I referred to in the Additional Information part. This is caused by the condition in the Changed<WindowResolution> function logic. It sends the Message (that triggers a redraw) only if the physical resolution has changed, but a change in scale_factor should also send that Message.


I'm aware that this doesn't address all your remarks. I'm going to investigate this further later today/tomorrow and come back with some commits or comments.

@kfc35

kfc35 commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

I didn't touch the initial window settings (not directly at least). By default Bevy creates a window with 1280x720 with base_scale_factor=1.0. However, this 1.0 can get overriden instantly based on winit's (OS's) scale factor here.

Could you please confirm that the initial window size has not changed relative to main? If my PR does changes the initial window then that's unexpected and I'll address that.

I can confirm that the initial window size on main for me has not changed with this PR (Logical size [1280, 720], Physical size [2560, 1440], Base scale: 2, Scale override: None)

In the beginning of the video, you start manually resizing and then a sudden change in resolution happens. Is that triggered by a keyboard input, or not?

Yep, it was triggered by me pressing “0” specifically. I should’ve said what I did exactly 😅 but after manually resizing and then pressing 0, I cycle through pressing “0” “1” and “2”, then I press “0” and then “2”, then some frantic combo of “0” “1” and “2” (hah), and then I manually resize with a scale factor of 2.0 without a scale override to show the content updating upon resize. Then I press “0” and then “2” to show the content updating upon resize again.

I'm aware that this doesn't address all your remarks. I'm going to investigate this further later today/tomorrow and come back with some commits or comments.

Let me know when you’d like me to test again on my Mac, happy to help

@B0ryskart0n

Copy link
Copy Markdown
Author

Thanks for clarifying the video.
Now I understand the problem you encountered, and yes, it's the one I mentioned as Additional information.
What I've identified there is that: if the physical resolution has not changed, then the resize events will not be sent.
However, the event also needs to be sent if the scale factor changes, because this event propagates the redraw of the window content.

I thought I had already solved that and for me it worked, but it appears that Mac treats something differently.

In the recent commits I've added some clarification comments for future developers.
Also I've simplified the logic to send the resize event regardless of which WindowResolution property has changed: if the WindowResolution has changed at all then we send the event, which I think is the right approach.

Could you please verify how this works now?

My guess is that the scale changes are not going to work (I expect you'll need to resize it manually for it to scale properly, just as you've shown in the video) but I have an idea of what might be behind it, and it's in a slightly different part of the code.

@kfc35

kfc35 commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

With the updated changes, the example behaves the same as when I tested previously. This time I was more intentional with the sequence of number inputs and it should be clear in the video what was pressed and how things change.

Screen.Recording.2026-06-25.at.8.30.58.PM.mov

I did notice something though (if it helps, although this mightve been deducible previously). If I manually resize the window at given scale, and then change the scale factor via pressing one of the number keys, the content does update in. size (i.e. going at base scale 1, manually resizing window, then going to base scale 2 OR overriding the scale to 2 does update the content size.)

BTW if the scale changes are a different thing that you’d rather tackle in a follow up PR, that’s fine with me since I think this is already an improvement from main.

If anyone’s curious what this example is like on main:
https://github.com/user-attachments/assets/6f3c6d88-a2c5-49d4-a60f-4502c1811865
The last few moments are of me pressing “2" twice in a row, and of me pressing “0” twice in a row. That is strange resizing behavior that doesn’t exist after this PR

@B0ryskart0n

Copy link
Copy Markdown
Author

The last two commits introduce a mechanism of writing a WindowScaleFactorChanged when the scale factor changes. Also I've added some temporary logging, which should help me with debugging the Mac specific situation.

BTW if the scale changes are a different thing that you’d rather tackle in a follow up PR, that’s fine with me since I think this is already an improvement from main.

I considered that, but I think this logic is coupled in such a way that it's better to fix this together.

Please let me know @kfc35 how is it now.
What I'm most interested in is if the manual resize is required for the scaled factor to take effect.

@kfc35

kfc35 commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Just tested it out, and the manual resize is no longer required for the content to re-scale! Nice!!

I think after you take out the warn!’s and the #[tracing::instrument(skip_all)] (assuming those aren’t necessary), I would approve this

@kfc35

kfc35 commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

@kfc35 kfc35 added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Jun 26, 2026
@B0ryskart0n

Copy link
Copy Markdown
Author

Could someone please force a rerun of the checks, or should I force it with a blank commit?
The build failed with a connection issue.

@B0ryskart0n

Copy link
Copy Markdown
Author

Summarizing the development:

The handling of WindowResolution has been changed so that now it sends the resize request to winit using the requested resolution (instead of the cached one).
Additionally, apart from sending the WindowResized Message, it also sends the WindowScaleFactorChanged Message which triggers a rendering redraw.


Hi @alice-i-cecile, as you're assigned, would you be able to find some time to review this, or should I try to find someone else?

@alice-i-cecile

Copy link
Copy Markdown
Member

I'll review this today :)

@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jun 30, 2026
@alice-i-cecile alice-i-cecile modified the milestones: 0.20, 0.19.1 Jun 30, 2026
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 D-Straightforward Simple bug fixes and API improvements, docs, test and examples S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Uncontroversial This work is generally agreed upon

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants