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

Unable to change fullscreen resolution? #14542

Closed
TheSHEEEP opened this issue Dec 11, 2017 · 50 comments · Fixed by godotengine/godot-docs#4038
Closed

Unable to change fullscreen resolution? #14542

TheSHEEEP opened this issue Dec 11, 2017 · 50 comments · Fixed by godotengine/godot-docs#4038

Comments

@TheSHEEEP
Copy link

Operating system or device, Godot version, GPU Model and driver (if graphics related):
Windows 64bit & NVIDIA GeForce GTX 970
Linux 64bit & NVIDIA GeForce GTX 1060
Godot 2.1.4

Issue description:
This is the bug report belonging to this question. Since I had no answers or comments in more than three days, I assume I have hit a bug? Or a missing feature?
Either way, I am logging this as a bug - though please correct me if I'm just doing this wrong or this is actually a missing feature.

Steps to reproduce:
Set your application to fullscreen via OS.set_window_fullscreen(true). Then, change the size of the window via OS.set_window_size().
It will mess up the rendering on Windows and on Linux it will mess up the rendering for one frame before returning the resolution to the previous one.

Link to minimal example project:
Just use the Window Management demo (best on Windows, but also "messes up" in Linux for me). Activate fullscreen, then click resize. You'll see. If you don't and it happens only for me, I can provide screenshots.

@MrJustreborn
Copy link

Duplicate of #14446 ?

@akien-mga
Copy link
Member

Duplicate of #14446 ?

Doesn't sound like it, no.

@TheSHEEEP
Copy link
Author

TheSHEEEP commented Dec 11, 2017

This one comment on #14446 does sound important, though:
"Godot currently does not support non-native fullscreen resolutions on any platforms."

So I guess my problem is just the result of this "does not support", so this is actually a feature request?

@RayKoopa
Copy link
Contributor

Yeah, and I wish it would be supported some time soon™️

@TheSHEEEP
Copy link
Author

Agreed. A game released on PC that does not offer a resolution selection in fullscreen mode will earn a lot of weird looks at the fact ;)

@TheSHEEEP
Copy link
Author

As I just found out, you also cannot switch the current screen while in true fullscreen mode. You have to work around it by going into a different mode (windowed "or" borderless fullscreen) first, change target monitor, then apply fullscreen again.
Should I open a new issue for this?

@Calinou
Copy link
Member

Calinou commented Dec 13, 2017

@TheSHEEEP Yes, multi-monitor support is a separate issue from non-native fullscreen, so a new issue should be opened for that.

@reduz
Copy link
Member

reduz commented Jun 18, 2018

I think there is a misunderstanding here, this is not a bug, probably should be fixed with documentation.

Godot does not understand fullscreen video modes. It is kind of silly to support that nowadays, given that monitors all have fixed pixel densities.

The right way to do what you want to do is using viewport resizing and just change viewport size while keeping the regular fullscreen mode.

@TheSHEEEP
Copy link
Author

TheSHEEEP commented Jun 19, 2018

That would lead to strange windowing programming, though.
If the user wants to have his application in windowed mode, you'll have to set the actual window resolution.
If the user wants to have his window in fullscreen (either borderless windowed or "true" fullscreen), you'll have to adjust the viewport size instead.
Or do you have to always treat the viewport and window size as two completely different things that will not affect each other directly and change both in the case of windowed mode?

What you say makes sense, of course, but what I'm used to from other engines is to have only one setting for this. When I last used Ogre or Urho3D, for example, you could set the resolution to 640x480 and fullscreen to true and that would do exactly what you want - give you a fullscreen window at 640x480 resolution.

I'm not sure splitting these into window size and viewport size is really helping anyone.

Either way, as long as resolution change at fullscreen is possible - and leading to increased/decreased performance, as it should - how exactly that is done is a minor usability concern.

@RayKoopa
Copy link
Contributor

You forget that mouse movement also feels different in a lower resolution than it would in upscaled games. This may sound neglectible and "fix your game", but my specific use case was to rebuild a very old game which runs natively at 640x480 as exactly as possible. I can simulate it by scaling the mouse coordinates from 640x480 to the desktop resolution though, I guess.

@reduz
Copy link
Member

reduz commented Jun 19, 2018

@TheSHEEEP Yes, you can have completely independent viewport size than Window size in Godot. There is a very flexible API for this in Viewport.

I can understand that some engines may still support this, but it's really pointless nowadays. Screen pixels and resolutions are nowadays completely fixed. Dealing with fullscreen modes is also a hassle because you have to obtain a list of the supportes ones so, if your game is not designed to handle this you have to work it around. Using the Viewport API, all this is handled transparently and nicely for you.

@lukaskotik
Copy link

Almost every (not only AAA) desktop game offers possibility to somehow change fullscreen resolution for performance-wise reasons. So at least good explanation in Docs or detailed tutorial on this topic could be very helpful.

@TheSHEEEP
Copy link
Author

I'd also add a log message of some kind if the window resolution is changed when in fullscreen mode. I'm fairly sure I'm not the only one who was surprised by it not working - knowing that you instead have to change the viewport size isn't really self-explanatory.

@bengtsts
Copy link
Contributor

After some testing on X11 and Android builds this is what I found:
OS.set_window_size() is for setting the size of the window not the resolution of the rendered image in the window. For use when not in full screen.
Setting the window size lower than the view port size appears to cause artifacts. Either set a minimal window size to match your view port or update your view port to fit within the window.

To solve the problem in the original post I used the following:

extends Node

# My fps output
#onready var fps = get_node("UI/FPS")

func _ready():
    # Wait for window resize event before changing resolution upon going full screen or
    # resolution update won't work as expected with a single button press
    get_viewport().connect("size_changed", self, "on_window_resize")
    set_process(true)

func _process(delta):
    # I Use OS.get_frames_per_second() on a Label to watch for performance changes
    #fps.set_text(str(OS.get_frames_per_second()))
    pass

func _on_Button_pressed():
    OS.set_window_fullscreen(true)
    # On Android setting full screen isn't useful thus window resizing events aren't
    # called so get_viewport().set_rect() should be called here

func on_window_resize():
    # Change resolution to 640x360 pixels
    get_viewport().set_rect(Rect2(0, 0, 640, 360))

Special note for full resolution of full screen windows.
Godot 2.1 doesn't use my full screen resolution when in full screen mode on my PC and phone.
My 1920x1080 PC monitor and 1280x720 phone both render at 1066x600 in the view port.
This is inconsistent with windowed mode where the default resolution matches with window size.
It is however easily fixed with:

func on_window_resize():
    var screen_size = OS.get_window_size()
    get_viewport().set_rect(Rect2(Vector2(0, 0), screen_size))

I personally like having control over view port size independent of window size. Its useful for making low res pixel games where a high res view port on a large window serves no purpose except to lower performance and drain batteries -- not accounting for style. I hope this feature doesn't go away even if simpler commands are implemented.

Hopefully this is helpful to someone.

@sporeservant
Copy link

For anyone viewing this in the future, replace set_rect with set_attach_to_screen_rect.

I noticed this was necessary when I had a nested viewport w/ an additional camera (2D) - even when you select Full Screen startup, a resize on the primary viewport is occurring. However, the sub viewport was not resizing, and had to be updated manually. Failure to do so resulted in all sorts of incorrect local mouse coordinates, etc.

func on_window_resize():
	print("SCREEN RESIZED")
	var screen_size = OS.get_window_size()
	var screen_rect = Rect2(Vector2(0, 0), screen_size)
        # set primary viewport - it isn't clear to me if this is actually necessary
	get_viewport().set_attach_to_screen_rect(screen_rect)
         # set child viewport - this is necessary
	nested_viewport_container.get_viewport().set_attach_to_screen_rect(screen_rect)

@Calinou
Copy link
Member

Calinou commented May 28, 2020

By the way, there is now a demo showcasing the use of a secondary viewport for 3D render scaling independently of 2D elements: https://github.com/godotengine/godot-demo-projects/tree/master/viewport/3d_scaling

Feel free to open pull requests to add a 2D example scene or support for mouse coordinate conversion.

@Tobi-La
Copy link

Tobi-La commented May 28, 2020

I'm still struggling to change the fullscreen resolution. For windowed mode it works fine with OS.set_window_size(resolution). When fullscreen is active I tried
get_viewport().set_rect(resolution), which says that the set_rect method doesn't exist.
When using get_viewport().set_attach_to_screen_rect(resolution) like @sporeservant suggested, the game rendered at the lower resolution I selected, but not scaled up. I have instead some weird artifacts on the part that should be covered by the scaled-up viewport.
grafik

@Calinou
Copy link
Member

Calinou commented May 28, 2020

@Tobi-La Try using the Viewport set_stretch_override methods instead (I don't remember the exact name). Or was it in SceneTree?

@Tobi-La
Copy link

Tobi-La commented May 28, 2020

@Calinou Thanks. I tried set_size_override of viewport, but it scales down my ui and repositions it. Just like if my games base resolution was turned up. Activating set_size_override_stretch didn't change anything.

@Calinou
Copy link
Member

Calinou commented May 28, 2020

@Tobi-La Are you using two Viewport nodes (one for the 3D viewport, one for the 2D nodes)? Note that you only need to create one Viewport node, as there's already an implicit root Viewport.

You need to do this to scale the 2D and 3D views separately.

@Tobi-La
Copy link

Tobi-La commented May 30, 2020

@Calinou Thanks, trying to adapt that. Could you tell me what the difference between size and content_scale_size in the code is?

@Tobi-La
Copy link

Tobi-La commented May 30, 2020

Thanks, @Calinou . I think I managed to get my scale factor by using this formula:

	var ratioFactorOrig = 1280.0/720
	var currentRatio = float(viewportSize.x) / viewportSize.y
	
	if currentRatio > ratioFactorOrig:
		internalScale = 720.0 / viewportSize.y 
	else:
		internalScale = 1280.0 / viewportSize.x

1280 x 720 is my base resolution

However, I noticed that the performance is worse than before, my fps drops noticeably in comparison to using only the root viewport. Is this expected? I could do some benchmarks if this helps.

@Calinou
Copy link
Member

Calinou commented May 30, 2020

However, I noticed that the performance is worse than before, my fps drops noticeably in comparison to using only the root viewport. Is this expected? I could do some benchmarks if this helps.

Yes, using two viewports will unfortunately be slower than only using one viewport, not to mention the additional cost required by the TextureRect displaying the ViewportTexture. I'm not sure if anything can be done about this.

The cheapest way to render a viewport is to attach it directly to the screen, but this prevents screen-reading shaders from working and is only available in GLES2. (This is what games in the 90s/2000s did before the norm was to split the HUD from 3D world rendering.)

@clayjohn Is it possible to use multiple viewports with set_attach_to_screen_rect?

@clayjohn
Copy link
Member

@Calinou yep. You can use as many as you like. You will have to disable the root Viewport though as it draws last and will cover the entire screen.

@Tobi-La
Copy link

Tobi-La commented May 31, 2020

Thanks again @Calinou
I have noticed two more issues though:

  1. Particle effects in my 3d viewport are not rendered on GLES2 (works fine on GLES3).
  2. I have weird looking artefacts on lower resolution scales on mobile.

100% res:
Screenshot_20200531-174503_2 BER Bausimulator
50% res:
Screenshot_20200531-174456_2 BER Bausimulator

Any idea where that could be coming from?

@Calinou
Copy link
Member

Calinou commented May 31, 2020

Particle effects in my 3d viewport are not rendered on GLES2 (works fine on GLES3).

Are these Particles or CPUParticles nodes? Only CPUParticles are supposed when using GLES2.

@Tobi-La
Copy link

Tobi-La commented May 31, 2020

Yes, of course. I just moved the nodes to the new viewport, everything worked fine before when I only had the root viewport.

@vitorbalbio
Copy link

vitorbalbio commented Sep 18, 2020

Hi! First i want to say that deliver a 3D Game for PC without fullscreen resolution setting is unconceivable nowadays. The current "oficial" workarounds using viewports are overcomplicated and far to be good. Also they impact your game architecture and workflow. (#20619, godotengine/godot-proposals#1465)

A proper easy and build-in solution for it can be found in all other general purpose Game Engines as a simple setting and it seems wrongly ignored in Godot. But everything is not lost if you use C# in Windows.

One easy solution that anyone can implement in your game is just change the user display resolution using the OS Calls. It can be done with C# and the user32.dll and probably also with GDNative (But i know too little about GDNative to make sure)
You can find a lot of tutorials in internet about it like:
https://www.codeproject.com/Articles/6810/Dynamic-Screen-Resolution
https://www.codeproject.com/Articles/36664/Changing-Display-Settings-Programmatically

That way you can make a game that just works and it will run in the native user display that you can set by code.

Notice though that it's very dangerous if done wrongly since you're handling the user system settings!
If you broke something probably the user will need to recover the system to make their display work again or if they have the luck to have another monitor (as i did) they will need to remove some register keys.
https://answers.microsoft.com/en-us/windows/forum/windows_10-hardware/windows-10-reset-external-monitors-settings/b3a53cef-e54f-4410-b09e-6846fa297a3f

You need to absolutely guarantee that in any case you will set the monitor settings to the original setup if not in game. If something done wrong during the set of some resolution it also need to automatically get back to some safe config.

Also even if the user do ALT+TAB or rage quit with Alt + F4 you need to guarantee that everything get back to normal.

For all this Godot is gorgeous since it provide notifications when the application loses focus or quit an by what i see it works nicelly.
https://docs.godotengine.org/pt_BR/stable/getting_started/workflow/best_practices/godot_notifications.html

I did implemented this solution in my game and by now it's working as should (after i did break my system some times testing).
In future i want to check about Exclusive Mode too. But it's off Topic.

I would like to see this handled in a more streamlined and integrated way inside the engine but for now it's the best option i found. So if you're struggling on it also consider this solution.

@Calinou
Copy link
Member

Calinou commented Sep 18, 2020

The modern way to handle screen resolution changes is fully supported in Godot, and there's a demo that showcases it. If you look around, it's what a lot of AAA games do now 🙂

I don't think we need to go out of our way to provide modesetting, which provides a very bad experience to macOS and Linux players (especially when the game crashes, since the native resolution won't be set back).

@vitorbalbio
Copy link

vitorbalbio commented Sep 18, 2020

The modern way to handle screen resolution changes is fully supported in Godot, and there's a demo that showcases it. If you look around, it's what a lot of AAA games do now 🙂

I don't think we need to go out of our way to provide modesetting, which provides a very bad experience to macOS and Linux players (especially when the game crashes, since the native resolution won't be set back).

I'm not really against this approach but it need to be better integrated to be considered a "feature of the engine". Currently it's more like a handy workaround.

First you need to make your game around this workflow. That means that in every single 3D scene you will need a viewport container, viewport and attach a script to control resolution. Or you need a Master Scene that will handle all 3D scenes on it.
It only gets a bit better in Godot 4 since you can set Linear Filtering directly in the ViewportContainer but in Godot 3x you yet need to band-aid it with a TextureRect. 😞

I really don't think decouple UI and 3D is a bad idea. It can indeed be great. But if it's a "engine feature" or "engine design" it need to be much better integrated on the engine itself and stop rely on multiple node setups to work. So it would be great if we have a proper "Viewport Screen Resolution" setting decoupled from the base window size that handle all viewports. The best approach to this i can think is to have this setting internally the ViewportContainers and allow us to overwrite if needed, or something like that. The root node in Godot 4 is also one of those already right? I can fill a more detailed proposal for this if you think it worth. 😉

That should handle all this in a elegant way in all viewports. It probably yet would need a proper way to get all available screen sizes (Which also can be done by now with user32.dll) but only this would be already a much better solution than any currently available (and probably better then mine also).

This seams feasible?

@starry-abyss
Copy link
Contributor

Also "elegant Godot way" (suggested in several different issue tickets on various resolution-related topics) to do things with a combination of several viewports has a limitation, which makes the suggestion a hell to use: #20619

@vitorbalbio
Copy link

vitorbalbio commented Sep 19, 2020

Also "elegant Godot way" (suggested in several different issue tickets on various resolution-related topics) to do things with a combination of several viewports has a limitation, which makes the suggestion a hell to use: #20619

Yep! I posted a proposal to this some days ago. By the time i was not aware it was already a bug reported but i already think it could be because it's a hard limitation or flaw design of how editor handles viewports.
godotengine/godot-proposals#1465

@TheSHEEEP
Copy link
Author

TheSHEEEP commented Sep 19, 2020

The modern way to handle screen resolution changes is fully supported in Godot, and there's a demo that showcases it. If you look around, it's what a lot of AAA games do now

Just to re-iterate: That incurs a hefty performance cost as was said some replies above (due to using another viewport in addition to the root one), as well as kinda nightmarish editor handling.

The other way is setting the window to fullscreen and the root viewport to whatever resolution you want (e.g. lower than whatever the fullscreen resolution is for performance or style reasons) and stretching set to "viewport".

So users can basically decide if they want:
Non-stretched UI + negative performance impact + editor issues
vs
Stretched UI + best performance + best editor handling

Is that correct?

@Calinou
Copy link
Member

Calinou commented Sep 19, 2020

@TheSHEEEP Yes, more or less. That said, when you use the root viewport approach, keep in mind you can't enable filtering yet (this is implemented by #30039). Therefore, you want to enforce an integer scaling ratio to avoid scaling artifacts (1/2, 1/3, 1/4, …).

As for the editor handling issue, I believe you could figure out a way to automatically add your game scene to the viewport (for 2D projects). Maybe you can use an autoload for this?

For 3D projects, it shouldn't be an issue if you're already using the root viewport for your GUI elements.

@jamie-pate
Copy link
Contributor

I think there is a misunderstanding here, this is not a bug, probably should be fixed with documentation.

Godot does not understand fullscreen video modes. It is kind of silly to support that nowadays, given that monitors all have fixed pixel densities.

The right way to do what you want to do is using viewport resizing and just change viewport size while keeping the regular fullscreen mode.

With laptop manufacturers producing laptops with Intel 620 gpus that want to power 4k screens it's more important than ever!

@Calinou
Copy link
Member

Calinou commented Oct 9, 2020

@jamie-pate I think the best solution is still to manually decrease the resolution to 1080p or lower in this case. I have a 4K laptop with integrated graphics, and it's what I ended up doing after realizing not even the desktop was able to update smoothly at 60 FPS.

@jamie-pate
Copy link
Contributor

jamie-pate commented Oct 10, 2020

Yes, after thinking about it I agree, just having a stressful time getting things working well on these trash tier laptops which are the most common platform of my demographic 😭

I already scan dxdiag output so maybe I can just put up a warning on the title screen

Another thing that 4.0 will hopefully bring that will make my life that much easier 😆

@jamie-pate
Copy link
Contributor

With 4k being a huge performance suck, I wonder if there would be a way to just switch to normal dpi resolutions on any high dpi monitor on the system for the duration of the game, and switch back on exit 🤔 that would make a sweet plugin

@vitorbalbio
Copy link

vitorbalbio commented Nov 22, 2020

Hi Jamie.
That's exactly what I'm doing. But it only works in C# and Windows builds since you need to access and setup the user32.dll. check this out: https://www.codeproject.com/Articles/6810/Dynamic-Screen-Resolution.
Someone should notice that even if this was "closed" it's clearly that it's yet a requirement for many real users. I'm quite disappointed that it is considered solved by putting a close tag and a line in documentation saying that it will not be done while so many people yet ask for a proper solution or at least a best workflow to the current design.

@Calinou
Copy link
Member

Calinou commented Nov 24, 2021

Note that in the master branch, you can now change the 3D resolution scaling (with any float value) without using a separate viewport. It won't affect 2D/GUI rendering, so your HUD will remain crisp.

FidelityFX FSR 1.0 was also merged to optionally improve scaling quality.

@nonchip
Copy link

nonchip commented Dec 22, 2021

@Calinou sadly also in the master branch, all of Viewport's members set_rect,set_attach_to_screen_rect,set_size_override,set_size_override_stretch seem to be gone (while some of them are still documented), and size, while writable, does not affect the viewport in any way.
do you happen to know if/how it's still possible to "downscale"/"undersample"/... the 2D/GUI rendering in that way? because setting the window size in the project settings and then enabling stretch mode still works as expected, but i'd need to set that size dynamically. (i'm explicitly trying to change the resolution the whole fullscreen is rendered at, not "just" downsample the 3d part, because i'm doing this for style reasons too instead of pure performance)

EDIT: apparently there's a Window.content_scale_size now, which does what I want, and SubViewport.size_2d_override still exists, so i guess that would be how to change them now?

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

Successfully merging a pull request may close this issue.