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

Incorrect mouse event position y precision in maximized window with content_scale_factor #94780

Open
lostminds opened this issue Jul 26, 2024 · 5 comments

Comments

@lostminds
Copy link

Tested versions

Reproducible in 4.3bX and 4.3rc1

System information

Windows 10, macOS 14.5

Issue description

In a Window with content_scale_factor 2 (for HiDPI purposes) mouse event positions are expected to be even or half pixel units, which is also the case if the window is in windowed mode or fullscreen.

However, if you instead maximize the window the y coordinate of mouse events global_position start getting additional seemingly random decimals added as you can see in the example below.

windows_precision_bug.mp4

This happen on Windows, but only in Maximized window mode. It might also happen on linux in the same mode, but I've been unable to test it myself. Can't reproduce it on macOS, but this might be because there's no maximized window mode in the same sense there.

Steps to reproduce

  • Create a new project
  • Add a single control main scene with a script that handles the gui_input signal and on mouse button events prints out the event global position in some way (like via a label).
  • Set the window scale in project settings to 2
  • Run this project and try clicking in the window, observe the expected mouse coordinate precision.
  • Maximize the window and try clicking again, observe the y coordinate having unexpected decimals added.

Minimal reproduction project (MRP)

mouse-precision-test.zip

@snokaru
Copy link

snokaru commented Jul 26, 2024

Hello, new contributor here!

I've looked into this for a bit, I was able to also reproduce this on Linux (Ubuntu 23.10), it seems like the issue is not actually due to full-screen, but it is due to uneven screen resolutions.

Whenever the size of the window is changed, Window (main/window.cpp) updates the viewport size via _update_viewport_size. In this method, a 2D override size (2d_override_size) is computed based on the content_scale_factor and the actual window resolution (size). Due to the scaling of 2, the 2D override size is basically half of the original window size.

Once this size is computed, the window sets it on the Viewport (main/viewport.cpp) through _set_size. Here, a new scale is recomputed (stretch_transform.scale) by dividing size and 2d_override_size, this time for the stretch transform. This calculation is done on real numbers, resulting in something very close to 2 but not exactly 2 if the actual resolution is uneven on any axis.

I would be happy to work on a fix if I can get some guidance on what the expected behavior is. At the moment, I can see two ways it could go:

  • Does the Viewport actually need to recompute the same scale that Window already uses for calculations? Perhaps we can just provide the scaling factor as well?
  • Should the stretch_transform of the viewport ever have real values? Maybe we can just compute it based on integers. I can see code in Window specifically to make sure that the scale factor is an integer bigger than or equal to one, but I lack the knowledge of how stretch transforms work and if this may be acceptable.

@lostminds
Copy link
Author

I would be happy to work on a fix if I can get some guidance on what the expected behavior is.

That's great to hear! I assume you mean uneven viewport sizes? In my case the issue only manifested in maximized windows mode. But this could I guess result in an uneven height viewport area of the window in case the height of the windows title bar is uneven (which is a little unexpected)? And it could be that in windowed mode the size will never be uneven since when resizing it at 2x scale each pixel resize step will always result in an even window size.

If it's just a precision error of Vector2 I'd however expect that to result in additional decimals, but more like 128.000076 instead of things like 128.8772. But perhaps the precision error are compounded by multiple multiplications?

Regarding the transforms I think they will need to at least support non-integer scales as the content_scale_factor on windows can be any scale value theoretically. It's set as a float, so it's unexpected to hear it's validated to be an integer > 1 like you write above? And even if you base the scale on system dpi-scaling it might at least be values like 1.5 and 1.75 and not just 1 or 2.

@snokaru
Copy link

snokaru commented Jul 26, 2024

And it could be that in windowed mode the size will never be uneven since when resizing it at 2x scale each pixel resize step will always result in an even window size.

I was also able to get the issue in windowed mode on my end (Linux) by slightly resizing the window, however I'm not sure about Windows. Also, I can get both axes to manifest the issue by resizing in both directions, not just the Y axis.
image

If it's just a precision error of Vector2 I'd however expect that to result in additional decimals, but more like 128.000076 instead of things like 128.8772. But perhaps the precision error are compounded by multiple multiplications?

Yes, that is what I noticed, the value goes into multiple multiplications before ending up as the displayed globalPosition.

Regarding the transforms I think they will need to at least support non-integer scales as the content_scale_factor on windows can be any scale value theoretically. It's set as a float, so it's unexpected to hear it's validated to be an integer > 1 like you write above? And even if you base the scale on system dpi-scaling it might at least be values like 1.5 and 1.75 and not just 1 or 2.

After checking this further, it was a mistake on my part, the logic I was mentioning is only executed when the setting display/window/stretch/stretch_mode is set to integer, but the default is fractional.

Then the only solution I can see currently is to not recompute the scale based on current and override resolutions, as you can't avoid possible precision errors otherwise.

@lostminds
Copy link
Author

lostminds commented Jul 26, 2024

Then the only solution I can see currently is to not recompute the scale based on current and override resolutions, as you can't avoid possible precision errors otherwise.

Indeed. Why is this even done? As stretch_transform.scale should be the same as content_scale_factor, why recalculate it back and forth via 2d_override_size and introduce compounding precision errors? Why not set it to content_scale_factor directly in this case?

@alvinhochun
Copy link
Contributor

This may be tangentially related to #93796

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

No branches or pull requests

4 participants