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

Implement support for seamless display scaling on Windows and Linux (for multi-monitor setups with different DPI) #56341

Open
Tracked by #2998
hhyyrylainen opened this issue Dec 30, 2021 · 9 comments

Comments

@hhyyrylainen
Copy link

Godot version

v4.0.dev.custom_build.91b97dac0

System information

Linux (Fedora 35), Wayland, Vulkan API 1.2.189 - Using Vulkan Device #0: AMD - AMD RADV SIENNA_CICHLID (6900 XT)

Issue description

When moving a Godot editor window from my 4K screen to my smaller screen, the GUI scaling stays the same, meaning that all the GUI elements take up a much larger proportion of the Godot window than they probably should. At least I can see much less content in the file and node trees, also the placeholder text is even cut off on the search bar. Instead Godot should scale down the GUI when moved to a monitor with a different DPI / resolution.

Here's how the really large scaling looks in 4.0:
Kuvakaappaus - 2021-12-30 10-13-58

And for reference here's 3.4 (showing a different project) where I can actually see much more useful content:
Kuvakaappaus - 2021-12-30 10-19-13

Steps to reproduce

  • Checkout the latest master code
  • Compile with scons target=release_debug -j 30 tools=yes
  • Run editor from terminal: bin/godot.linuxbsd.opt.tools.64
  • Observe how the project manager window is well scaled on the 4K monitor it opens on, but when I move it over to my primary monitor that is 2560x1440 all the GUI elements are very large
  • Open any project and observe again, when moved to the 2560x1440 monitor (I opened a separate issue about things opening on the wrong monitor: Godot 4.0 editor opens on wrong monitor (DisplayServer regression) #56340), how the Godot editor GUI elements are scaled too big, with the usability being pretty severely impacted as very little content can fit on screen.

Minimal reproduction project

problem is with the Godot editor itself, a new project / any project can be opened to see more of the issue

@Calinou
Copy link
Member

Calinou commented Dec 30, 2021

Run-time editor scale changes would need to be supported to allow for this, but this would require a lot of work. #52170 might make this easier, but it's still far from trivial. See also godotengine/godot-proposals#6.

#40084 implemented seamless display scaling on macOS, but the same approach can't be used on Windows and Linux. Linux in particular has a longstanding tradition of issues with hiDPI, especially on multi-monitor setups with different DPI – some of those issues can only be fixed in Wayland. Not all hiDPI support is created equal… :slightly_smiling_face:

As a workaround, you can force a specific editor scale to be used in the Editor Settings (Interface > Editor > Display Scale). You most likely want to use 100% in your case.

@Calinou Calinou changed the title Godot 4.0 editor GUI scaling doesn't react to moving window to different monitor Implement support for seamless display scaling on Windows and Linux (for multi-monitor setups with different DPI) Dec 30, 2021
@alvinhochun
Copy link
Contributor

Thanks @Calinou for kindly pointing me to this issue from IRC, and because of that I thought I'd put my two cents here...

To clarify, on Windows the Godot editor already seamlessly scales to different displays (at least on Windows 10) because it declares itself as "system DPI aware". Godot is aware of and renders in the scaling of the primary monitor, but being "system DPI aware" means that it doesn't know about the different scaling on non-primary monitors. Windows being "helpful", it automatically bitmap-up/downscale the Godot window when moved to another monitor with a different scaling, making everything into a blurry mess. It's worse when you have monitors using a non-integer scaling, because then you can have cases like windows rendered at 175% being bitmap-scaled to 100%.

For this reason, when I use the editor I choose to override the per-application DPI setting (right-click properties from Explorer) to "application" to cause Windows to not apply the bitmap scaling, and then manually set the scaling I want in the Godot editor. I prefer the application to not seamlessly adjust the scaling if that means doing bitmap scaling of the whole window, especially when it comes to text-heavy applications.

(The seamless display scaling on macOS seems to be the same deal achieved using bitmap scaling, so it suffers from similar issues. The difference is that macOS only has native x1 and x2 and any other scales are always bitmap-scaled from x2.)


I agree that the Godot editor needs to support changing the UI scale during run-time for this. In the case of Windows, after this is supported, we can change Godot to use "per-monitor v2" DPI awareness (with "per-monitor aware" and then "system aware" as fallbacks) and use WM_DPICHANGED to trigger dynamic change of scaling.

There is this old PR #28771, I wonder if it's still the right approach to aim for? I kind of want to look into this for a bit, but since I'm new to the Godot codebase I'll need to spend some time to explore.

@Calinou
Copy link
Member

Calinou commented Jan 4, 2022

There is this old PR #28771, I wonder if it's still the right approach to aim for? I kind of want to look into this for a bit, but since I'm new to the Godot codebase I'll need to spend some time to explore.

Now that #52170 was merged, we can use it for run-time scaling on the editor. The downside of using this new scale factor instead of the current editor scaling code is that it will not cause editor icons to be regenerated at higher/lower resolutions. Nonetheless, for run-time scale changes to support multiple monitors with different DPI, I believe it's good enough. We can use the monitor with the highest DPI as a basis for the editor scale, and scale down on other monitors based on that (to ensure icons remain fairly crisp on all monitors).

For instance, if you have 3 monitors with the following automatically determined scale factors1:

  • 125%
  • 200%
  • 100%

The editor scale will be set to 200% automatically. The run-time editor scale is set to the following value on each monitor:

  • 62.5%
  • 100%
  • 50%

Footnotes

  1. Godot does not support reading the OS-provided scale factor yet: https://github.com/godotengine/godot-proposals/issues/2661

@alvinhochun
Copy link
Contributor

Now that #52170 was merged, we can use it for run-time scaling on the editor. The downside of using this new scale factor instead of the current editor scaling code is that it will not cause editor icons to be regenerated at higher/lower resolutions. Nonetheless, for run-time scale changes to support multiple monitors with different DPI, I believe it's good enough. We can use the monitor with the highest DPI as a basis for the editor scale, and scale down on other monitors based on that (to ensure icons remain fairly crisp on all monitors).

I'm not sure about this. The reason I want to look into implementing per-monitor scaling is to get crisp text and UI rendering in the editor seamlessly. I fear that this approach may end up with a lot of things being blurry, which will only be marginally better than the current situation (at least on Windows).

@Calinou
Copy link
Member

Calinou commented Jan 4, 2022

I'm not sure about this. The reason I want to look into implementing per-monitor scaling is to get crisp text and UI rendering in the editor seamlessly. I fear that this approach may end up with a lot of things being blurry, which will only be marginally better than the current situation (at least on Windows).

The 2D scale factor I mentioned does keep things crisp – it's not just bitmap scaling of the entire window. Fonts will be re-rendered to match the final 2D scale, so they will remain crisp.

@alvinhochun
Copy link
Contributor

How can I go about testing the 2D scale factor with a hardcoded scale? I tried adding:

diff --git a/main/main.cpp b/main/main.cpp
index c9a846155b..da12139f57 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1998,6 +1998,7 @@ bool Main::start() {
 			ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/aspect", PropertyInfo(Variant::STRING, "display/window/stretch/aspect", PROPERTY_HINT_ENUM, "ignore,keep,keep_width,keep_height,expand"));
 			GLOBAL_DEF("display/window/stretch/shrink", 1.0);
 			ProjectSettings::get_singleton()->set_custom_property_info("display/window/stretch/shrink", PropertyInfo(Variant::REAL, "display/window/stretch/shrink", PROPERTY_HINT_RANGE, "0.1,8,0.01,or_greater"));
+			sml->set_screen_stretch(SceneTree::STRETCH_MODE_DISABLED, SceneTree::STRETCH_ASPECT_IGNORE, Size2i(0, 0), 1.5);
 			sml->set_auto_accept_quit(GLOBAL_DEF("application/config/auto_accept_quit", true));
 			sml->set_quit_on_go_back(GLOBAL_DEF("application/config/quit_on_go_back", true));
 			GLOBAL_DEF("gui/common/snap_controls_to_pixels", true);

on the 3.x branch, but the text are blurry (I assume the bitmaps being blurry is normal because editor scale is 100%).
圖片

@Calinou
Copy link
Member

Calinou commented Apr 29, 2023

on the 3.x branch, but the text are blurry (I assume the bitmaps being blurry is normal because editor scale is 100%).

The editor or project manager doesn't have font oversampling enabled, as it didn't make use of font oversampling before your change. To resolve this, call sml->set_use_font_oversampling(true); just below the line you added. (This can be done in both master and 3.x.)

If we make use of built-in scaling options, font oversampling should always be enabled for the project manager and editor. The use of MSDF fonts could also be considered (with an opt-in editor setting).

@alvinhochun
Copy link
Contributor

alvinhochun commented Nov 28, 2023

Disregarding the editor for now, I wonder if Godot can just add an extra option to enable per-monitor DPI by changing this call to pass PROCESS_PER_MONITOR_DPI_AWARE instead?

if (OS::get_singleton()->is_hidpi_allowed()) {
HMODULE Shcore = LoadLibraryW(L"Shcore.dll");
if (Shcore != nullptr) {
typedef HRESULT(WINAPI * SetProcessDpiAwareness_t)(SHC_PROCESS_DPI_AWARENESS);
SetProcessDpiAwareness_t SetProcessDpiAwareness = (SetProcessDpiAwareness_t)GetProcAddress(Shcore, "SetProcessDpiAwareness");
if (SetProcessDpiAwareness) {
SetProcessDpiAwareness(SHC_PROCESS_SYSTEM_DPI_AWARE);
}
}
}

Games don't really need to handle WM_DPICHANGED when a lot of them just scale the viewport without needing to care about the DPI. The current mode of PROCESS_SYSTEM_DPI_AWARE really messes up the scaling on secondary monitors, especially for pixel games. Seeing that Godot 4.2 adds an integer scaling option, it's quite a bummer for it to be ruined by the system DPI scaling.

Though now is probably too late to add such an option to Godot 4.2 :(

@Calinou
Copy link
Member

Calinou commented Dec 7, 2023

Though now is probably too late to add such an option to Godot 4.2 :(

Now that 4.2 is released, feel free to open a PR against master so we can look into this for 4.3 🙂

Remember that we still aim Godot to be able to run on Windows 7-8.1 (on a best-effort basis), so compatibility must be checked first before attempting to use APIs only present on Windows 10/11.

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

3 participants