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

Fullscreen not working in Godot 4 when passed to DisplayServer create function #54065

Closed
AndreaTerenz opened this issue Oct 21, 2021 · 23 comments · Fixed by #64969
Closed

Fullscreen not working in Godot 4 when passed to DisplayServer create function #54065

AndreaTerenz opened this issue Oct 21, 2021 · 23 comments · Fixed by #64969

Comments

@AndreaTerenz
Copy link

AndreaTerenz commented Oct 21, 2021

Godot version

4.0.dev

System information

Issue verified on:

  • Manjaro Linux 5.13, Ryzen 5 3600, Radeon RX 580 with Vulkan 1.2
  • Windows 11, Intel i5-8250U, Nvidia MX 110 also with Vulkan 1.2

Issue description

I am trying to port my game from Godot 3 to Godot 4. Somehow, even fullscreen isn't working, even though it is turned on in the settings:
image
image
I know the resolution is 1024x600, the Godot default, but on Godot 3 that isn't a problem and the window simply gets scaled to completely fill my 1080p screen. From an answer I received on reddit, from a user also having this issue, it seems to happen regardless of GPU brand and regardless of how Godot 4 is "acquired" (manual build or download from the pre-alpha releases) and of whether the project is run from the editor or as an executable.

Steps to reproduce

  1. Make a new Godot 4 project
  2. Setup any kind of sample scene
  3. Check "Fullscreen" in the project's Window settings

Minimal reproduction project

No response

@AndreaTerenz
Copy link
Author

I'm not so sure about the porting label: the issue arose while I was porting a game, but it is reproducible in a completely new Godot 4 project

@akien-mga
Copy link
Member

porting means related to platform ports.

@AndreaTerenz
Copy link
Author

@akien-mga ok then all the more reason to not use it for this issure lol
@Chaosus

@AndreaTerenz
Copy link
Author

Also, I just verified that this issue is also present on Windows (Win11, Intel i5-8250U, Nvidia MX 110), so it shouldn't be OS specific

@akien-mga
Copy link
Member

@akien-mga ok then all the more reason to not use it for this issure lol

The implementation of fullscreen is part of DisplayServer, which is a component which has to be implemented specifically for each platform port. So yes, this is related to porting. Labels are intended for our contributors, please let us specify them as we see best fit with our knowledge of the engine internals.

@follower
Copy link
Contributor

For the sake of completeness, here is the Reddit thread mentioned: https://old.reddit.com/r/godot/comments/qclznk/fullscreen_not_working_in_godot_4/

@AndreaTerenz
Copy link
Author

AndreaTerenz commented Oct 21, 2021

@akien-mga

Labels are intended for our contributors, please let us specify them as we see best fit with our knowledge of the engine internals.

I'm sorry, I thought you were indeed criticizing the use of the label

@follower
Copy link
Contributor

Have you tried with the --fullscreen command line flag to see if it has the same behaviour?

(I just tried --fullscreen with the project manager and it did display fullscreen ok. Although, perhaps ironically, the project manager does lack a way to exit fullscreen though. :) )

This was on Linux (elementary OS 5.1) with:

Godot Engine v4.0.dev.20211015.official.f113dc986 - https://godotengine.org
Vulkan API 1.2.182 - Using Vulkan Device #0: Intel - Intel(R) HD Graphics 4400 (HSW GT2)

@akien-mga
Copy link
Member

akien-mga commented Oct 21, 2021

I can confirm the issue on Linux (Mageia 9), didn't test other platforms yet.

On the other hand it works fine for the editor itself (one can toggle fullscreen with Shift+F11).

Running the project with --fullscreen also doesn't work.

@AndreaTerenz
Copy link
Author

I also tested this (on Windows) with the latest three builds of Godot 4 (15/10, 04/10 and 29/09) and it is still present

@akien-mga
Copy link
Member

This seems to be caused by this chunk of code:

godot/main/main.cpp

Lines 1271 to 1302 in 9c9ec63

if (use_custom_res) {
if (!force_res) {
window_size.width = GLOBAL_GET("display/window/size/width");
window_size.height = GLOBAL_GET("display/window/size/height");
if (globals->has_setting("display/window/size/test_width") &&
globals->has_setting("display/window/size/test_height")) {
int tw = globals->get("display/window/size/test_width");
if (tw > 0) {
window_size.width = tw;
}
int th = globals->get("display/window/size/test_height");
if (th > 0) {
window_size.height = th;
}
}
}
if (!bool(GLOBAL_GET("display/window/size/resizable"))) {
window_flags |= DisplayServer::WINDOW_FLAG_RESIZE_DISABLED_BIT;
}
if (bool(GLOBAL_GET("display/window/size/borderless"))) {
window_flags |= DisplayServer::WINDOW_FLAG_BORDERLESS_BIT;
}
if (bool(GLOBAL_GET("display/window/size/fullscreen"))) {
window_mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
}
if (bool(GLOBAL_GET("display/window/size/always_on_top"))) {
window_flags |= DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP_BIT;
}
}

use_custom_res is false for the editor and project manager, where fullscreen works. If I disable this code then fullscreen also works for the project when specified on the command line (but project settings are not respected anymore).

@akien-mga akien-mga self-assigned this Oct 21, 2021
@follower
Copy link
Contributor

FWIW a project with:

  • Project settings full-screen enabled and no --fullscreen: doesn't work.
  • Project settings full-screen enabled and with --fullscreen: doesn't work.
  • Project settings full-screen not enabled and with --fullscreen: does work.

@akien-mga
Copy link
Member

the DisplayServer::WINDOW_MODE_FULLSCREEN flag isn't OR'ed with window_mode, insted it is directly assigned to it - unlike the other three flags in that piece of code. E.g.:

That's not the issue, window_mode isn't a bitmask, unlike window_flags.


The problem seems to be that when the DisplayServer is created with window_mode == WINDOW_MODE_FULLSCREEN, it might be too early to actually set the fullscreen mode in the DisplayServer.

display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err);

Then even if --fullscreen is passed, which should force resetting the window mode for the main window, the value is bypassed because the main window was already created as fullscreen, so there's nothing to change (in theory).

godot/main/main.cpp

Lines 1616 to 1618 in 9c9ec63

} else if (init_fullscreen) {
DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_FULLSCREEN);
}

In practice when window_set_mode() is called the first time as part of the DisplayServerX11 constructor it doesn't seem to actually succeed making the window fullscreen.

window_set_mode(p_mode, id);

That's from looking at the DisplayServerX11, the issue is likely similar with DisplayServerWindows. The bug might not happen on macOS, needs testing (CC @bruvzg).

@AndreaTerenz
Copy link
Author

That's not the issue, window_mode isn't a bitmask, unlike window_flags.

Yes sorry I noticed that it was window_mode and not window_flags as soon as I posted the comment and deleted it - I thought it wouldn't have been noticed ops

@akien-mga akien-mga changed the title Fullscreen not working in Godot 4 Fullscreen not working in Godot 4 when passed to DisplayServer create function Oct 21, 2021
@follower
Copy link
Contributor

Note that via the CLI init_fullscreen gets set to true but window_mode does not get set:

godot/main/main.cpp

Lines 740 to 748 in 9c9ec63

} else if (I->get() == "-f" || I->get() == "--fullscreen") { // force fullscreen
init_fullscreen = true;
} else if (I->get() == "-m" || I->get() == "--maximized") { // force maximized window
init_maximized = true;
window_mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
} else if (I->get() == "-w" || I->get() == "--windowed") { // force windowed window

Note that via project settings window_mode gets set but init_fullscreen does not get set to true:

godot/main/main.cpp

Lines 1295 to 1297 in 9c9ec63

if (bool(GLOBAL_GET("display/window/size/fullscreen"))) {
window_mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
}

Both window_mode & window_flags get supplied to the display server creation function, but none of the init_* values get supplied:

godot/main/main.cpp

Lines 1509 to 1516 in 9c9ec63

display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err);
if (err != OK || display_server == nullptr) {
//ok i guess we can't use this display server, try other ones
for (int i = 0; i < DisplayServer::get_create_function_count(); i++) {
if (i == display_driver_idx) {
continue; //don't try the same twice
}
display_server = DisplayServer::create(i, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err);

The init_* values get used here:

godot/main/main.cpp

Lines 1609 to 1625 in 9c9ec63

if (init_screen != -1) {
DisplayServer::get_singleton()->window_set_current_screen(init_screen);
}
if (init_windowed) {
//do none..
} else if (init_maximized) {
DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_MAXIMIZED);
} else if (init_fullscreen) {
DisplayServer::get_singleton()->window_set_mode(DisplayServer::WINDOW_MODE_FULLSCREEN);
}
if (init_always_on_top) {
DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_ALWAYS_ON_TOP, true);
}
if (allow_focus_steal_pid) {
DisplayServer::get_singleton()->enable_for_stealing_focus(allow_focus_steal_pid);
}

Although I assume there's a distinction between initialization & mode setting, it does seem a little odd to have what appears to be duplication. Is this actually intentional; or, a side effect of search/replace on an older implementation; or, a "belt and suspenders" backup?

If intentional, it seems wise to maybe only use window_mode & then (if necessary) do the initialisation based on testing window_mode & DisplayServer::WINDOW_MODE_FULLSCREEN?

@follower
Copy link
Contributor

This is the commit where the initial change was made: f8a79a9#diff-18b7c19417a461e4793bb2157831659d96ede991391e10ee5bc51f19453b7685L1186

And from a quick glance it seems like the lack of init_fullscreen is probably unintentional & the duplication might be unintentional?

@follower
Copy link
Contributor

Okay, after running it under gdb (with breakpoint on DisplayServerX11::window_set_mode()) I think there's ~two bugs which are interacting:

  • The reason --fullscreen on its own works is because first DisplayServerX11::window_set_mode() is called with p_mode=DisplayServer::WINDOW_MODE_WINDOWED, then called a second time (because init_fullscreen is set, I assume) with p_mode=DisplayServer::WINDOW_MODE_FULLSCREEN--which gets actioned because the old mode doesn't match the new one.
  • When only the fullscreen project setting is set, DisplayServerX11::window_set_mode() is called (only once due to no init_fullscreen) with p_mode=DisplayServer::WINDOW_MODE_FULLSCREEN but it seems it doesn't take effect.
  • When the fullscreen project setting is set it's possible to set a breakpoint on Main::setup2() & manually set the init_fullscreen with print init_fullscreen=1--which results in two calls to DisplayServerX11::window_set_mode() with p_mode=DisplayServer::WINDOW_MODE_FULLSCREEN; first which fails & the second one doesn't get actioned because the old mode equals the new mode.
  • When the fullscreen project setting is set it's possible to set a breakpoint on Main::setup2() & set the init_fullscreen with print init_fullscreen=1--which results in two calls to DisplayServerX11::window_set_mode() with p_mode=DisplayServer::WINDOW_MODE_FULLSCREEN first which fails & if we manually step through & then jump to the line after the return statement then the project gets shown as fullscreen.

@bruvzg
Copy link
Member

bruvzg commented Oct 21, 2021

The bug might not happen on macOS, needs testing

On macOS, fullscreen (set in the Project settings or with --fullscreen command line flag) is working fine.

@follower
Copy link
Contributor

via xprop it seems that when the window is not fullscreen we get:

_NET_WM_STATE(ATOM) =

but when it is fullscreen we get:

_NET_WM_STATE(ATOM) = _NET_WM_STATE_FULLSCREEN

(As set by:

// Using EWMH -- Extended Window Manager Hints
XEvent xev;
Atom wm_state = XInternAtom(x11_display, "_NET_WM_STATE", False);
Atom wm_fullscreen = XInternAtom(x11_display, "_NET_WM_STATE_FULLSCREEN", False);
)

So, at least for X11 it seems we need to check at some point whether or not the fullscreen has taken effect--before we assume it has.

(And there does seem to be some other "double-checking" code already, e.g.:

if (p_enabled && window_is_maximize_allowed(p_window)) {
// Wait for effective resizing (so the GLX context is too).
// Give up after 0.5s, it's not going to happen on this WM.
// https://github.com/godotengine/godot/issues/19978
for (int attempt = 0; window_get_mode(p_window) != WINDOW_MODE_MAXIMIZED && attempt < 50; attempt++) {
usleep(10000);
}
}
)

@follower
Copy link
Contributor

As a workaround, this worked for me on Linux in a script attached to the main scene:

func _ready() -> void:
    DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
    DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)

@archerallstars
Copy link

archerallstars commented Feb 15, 2022

For Visual Script users, you can use this as a workaround:

Screenshot 2022-02-15 020823

How to setup a window_set_mode() node:

  1. Add a function call node.
  2. Set call mode to Singleton.
  3. Set singleton to DisplayServer.
  4. Set function to window_set_mode().

You can see all the available int values for window_set_mode() here.

@akien-mga
Copy link
Member

Still reproducible as of 4.0 alpha 12.

@akien-mga
Copy link
Member

Fixed for Windows with #63914, but still pending a different fix for Linux.

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

Successfully merging a pull request may close this issue.

6 participants