Hello,
I tried to add Hi-DPI / Retina support to the new SDLGameWindow but it turns out it is way more complicated than just adding the Sdl.Window.State.AllowHiDpi creation flag to the window.
I lack the OS X understanding and unlimited access to a Retina, and I don't get what OS X is expecting when it comes to backbuffer, window and viewport size. Their virtual DPI system is totally different from other systems and the documentation didn't quite helped me. There are some design decisions to take as well, because setting a 2880x1800 resolution may end up to a 1440x900 viewport, which is misleading compared to what XNA users are used to and specific to OS X. Do we want this? Do we need some virtualisation?
Right now, GraphicsDeviceManager.HardwareModeSwitch = true renders a black screen on any Retina displays, while the borderless mode displays games only on 1/4th of the screen (on the lower left). This means that it is a regression compared to OpenTK (which was supporting Hi-DPI, but only correctly working with the desktop resolution, or borderless).
I wouldn't mind some help on this front, or any hints on how OS X works with Hi-DPI, OpenGL and SDL2. ( @tomspilman mind adding the "help wanted" tag?)
Note that on Windows, enabling Hi-DPI is as simple as adding a manifest to enable it. No other action is required and it works as expected. I'll push a PR to add this to the DesktopGL template.
@dellis1972 Did you have any issues with Retina on the latest SDL changes?
Current situation, with Hi-DPI disabled:
graphics.HardwareModeSwitch = true; doesn't work at all on Retina displays and Windows with 4k displays. It results in either a black screen or cropped viewport depending on the resolution begin under or above the desktop virtual resolution.
graphics.HardwareModeSwitch = false; works, but doesn't expose the selected resolution, it forces games to use the DPI scaled desktop resolution (i.e. if DPI are x2 and the desktop resolution 1920x1080, viewport and backbuffer will be 960x540 no matter the PreferedBackBuffer). This is a loss of quality if selected resolution is above desktop, and a loss of performance if under desktop. That's how SDL2 works in borderless mode and there's nothing to do about this.
With Hi-DPI enabled, nothing works on any OS on Retina / Windows4K.
I've been tinkering with this lately.
OS X:
Windows:
Which means that there is only a manifest to add to the template and this issue is solved.
We should probably update the templates in NewSDL branch.
@mrhelmut can you give an sample of the Info.plist bits to add/remove?
an sample
*a sample #gramarnazi
Make sure that both NSHighResolutionCapable and NSHighResolutionMagnifyAllowed are absent.
Make sure that both NSHighResolutionCapable and NSHighResolutionMagnifyAllowed are absent.
I'm guessing if you don't give those options than system is responsible for handling the size.
I've always thought that without these options, OS X would not give you a high resolution backbuffer (and basically just a black screen), but as far as I have tested, it just overrides retina settings and gives you what you asked for at base DPI.
This, or OS X cached some old info.plist and I would still be as much puzzled. ^^
I know this thread hasn't been updated in a long time...is there yet any resolution for this issue?
I have a cross-platform game. On Windows it renders at the desired resolution, but on Mac everything is rendering at half of the requested X/Y resolution (example: 320x240 instead of 640x480).
Neither NSHighResolutionCapable nor NSHighResolutionMagnifyAllowed are present in the info.plist.
If anyone knows a workaround I'd be interested. Thanks!
MacOS can be picky at times. info.plist are handled with some sort of metadata caching, which means that if you previously ran an application with different metadata, sometimes MacOS won't refresh the metadata correctly/immediately. Also, .plist are read by MacOS only if they are packaged within a .app bundle (as far as I know).
I still have to look into this for a proper fix (if there is any).
OK, I'll eagerly await it =) Thanks very much!
How do I enable/disable HiDPI using Visual Studio 2017 for Mac which does not seem to easily use .plist files? I have a still-unfixable issue #6308.
I do MonoGame Mac development directly Visual Studio 2017 for Mac (which works with MonoGame 3.7) so the workflow is different.
As noted above:
Also, .plist are read by MacOS only if they are packaged within a .app bundle
As far as I know, you can't debug HiDPI without bundling a .app (I'm not proficient with VS for Mac, so there may or may not be a way to do that).
With the latest develop branch and a .plist with HiDPI disabled, all of our games behave normally on Retina displays.
I haven't figured a clean way to support HiDPI on Mac, but most games disable it anyway (it's a safer, more compatible way to go). I'd suggest HardwareSwitchMode = false;, HiDPI disabled, and working with a virtual resolution within your game (i.e. rendering to a render target at a the desired resolution and stretching it to whatever the fullscreen mode really is).
I have been bashing my head against the wall over this issue on and off for months now. I really would like to ship my game but I want it to render at full resolution first!
Like mdrejhon above, I am using Visual Studio Community 2017 for Mac, and just as he is experiencing, my game is rendering at exactly half the horizontal and half the vertical resolution desired. For instance, if I try to run fullscreen on my 2560x1600 MacBook Pro, I get 1280x800 scaled up to fullscreen. If I try to run at 640x480, it renders at 320x240 and then blows it up to the size it would have been at 640x480.
I have read the above notes regarding Info.plist. The good news is that you can edit Info.plist directly within Visual Studio. The bad news is that following the above advice doesn't seem to have the desired effect. What's bizarre is that there is an effect of some sort!
If I leave both NSHighResolutionCapable and NSHighResolutionMagnifyAllowed out, build the app, then highlight it and press Command+I to "Get Info," the "Open In Low Resolution" checkbox is present and clickable in the Info box. However, the game launches in the above state whether or not that box is actually checked.
If I put both NSHighResolutionCapable and NSHighResolutionMagnifyAllowed into the Info.plist file, but set their values to NO, and then rebuild, the "Open In Low Resolution" checkbox is present in the Info box, but it's both checked and greyed out, meaning that you can't uncheck it. The game launches in the above state anyway.
If I put both NSHighResolutionCapable and NSHighResolutionMagnifyAllowed into the Info.plist file, but set their values to YES, and then rebuild, the behavior is the same as if the values aren't present.
If I set NSHighResolutionCapable to YES but NSHighResolutionMagnifyAllowed to NO, then rebuild, the "Open in Low Resolution" checkbox is present, but it's unchecked and greyed out, meaning that you can't check it. The game still launches in the above state.
If I set NSHighResolutionCapable to NO but NSHighResolutionMagnifyAllowed to YES, then rebuild, the behavior is the same as if both values were set to NO.
So I've tried every possible combination, and it seems based on these results that MacOS is reading this data properly, but something in MonoGame (or an underlying framework) is ignoring the options, and is always magnifying instead. Does this info help at all? Is there any chance that this issue can be fixed and/or a workaround can be identified? Any help would be greatly appreciated...thanks!
For now, HighDPI is not possible on Mac OS and for MonoGame to work properly you have to remove it from the Info.plist. The limitation being the behavior you're mentioning: the backbuffer size will correspond to the current scaling that Mac OS applies for your monitor. There's no way around it.
Mac OS has an annoying way of handling high DPI (and is basically the only system doing things differently from the other). We know what the problem is but fixing it requires some time and a Mac that I don't own.
The main issue being that Mac OS doesn't give you back a backbuffer of the size you are asking (with or without high DPI enabled), and that's a problem on its own. Getting the rendering right isn't quite a problem, but then Mac OS does something that no other OS do: the window size will be scaled, but not the backbuffer, which means that Viewport and Window.Size aren't the same. And that's a major issue because MonoGame (and XNA back in its days) has not been designed for this to ever happen.
This doesn't sound complicated but there are some cascading effects within MonoGame that need to be dealt with in order to have a rock solid High DPI support for Mac OS. More specifically, the inner working of the Viewport would require some heavy rework across all platforms so that the window and the viewport can be different while preserving the API consistency (and there are other side effects, like the need to scale mouse coordinates on Mac OS).
Even if we do get it right, there will not be a 100% chance that the resolution that Mac OS gives you back will be the one you asked.
If anyone is willing to tackle this issue, here are a few hints regarding where to start:
SDL_WINDOW_ALLOW_HIGHDPI (this will require NSHighResolutionCapable)SDL_GetWindowSize() by SDL_GL_GetDrawableSize() to get the unscaled backbuffer resolutionViewport to the asked resolution but instead query what Mac OS returnedSDL_GL_GetDrawableSize() / SDL_GetWindowSize() scaling ratio and figure out how this can be managed so that the viewport and the window size can be different and preserve the expected renderingRenderTarget and Viewport systemsThank you for that very quick, descriptive and informative (yet unfortunate) answer.
The fact that I've got a 3-month-old at home means that I won't have the time to dig under the hood, but I hope someone else is able to address this enormous undertaking in the future. (to whoever might wind up being that person: please contact me so I can at least buy you a beer)
Is there a compromise such as an interim simpler undertaking?
Such as this alternative: Is there a way to make scaling discovery easier? A new scaling-factor property, perhaps? That's always 1.0 on all platforms except on Retina Macs (and similar) whereupon it can be used to easily compensate scaling math. Right now, I've had tons of difficulties detecting or calculating the scaling value necessary to easily make mouse coordinates correct during .HardwareModeSwitch = false
I don't care as much about getting the correct resolution -- as I do care about reliably calculating the correct scaling factors & correct mouse coordinates during .HardwareModeSwitch = false (which has better 3D performance on my MacBook Pro than .HardwareModeSwitch = true).
So maybe this problem can be simplified as as two-stage fix:
(1) Improved discovery of scaling.
Before fixing it more completely:
(2) Improved ability to get the resolution requested.
@mdrejhon Exposing a scaling factor shouldn't be complicated (SDL_GL_GetDrawableSize() / SDL_GetWindowSize() should do the trick and return 1.0 on systems other than Mac OS), but it doesn't solve the problem since the discrepancy between the size of the viewport and the window on Mac OS may make the rendering wrong (e.g. part of the screen cropped or zoomed out ; this should be very visible when using RenderTargets or full screen shaders).
And your comment reminds me that there is another problem with HighDPI on Mac OS: its behavior is not the same depending on the HardwareModeSwitch switch...
Any help here would be very welcome. :)
I've encountered the issue that my game is only rendered to the bottom-left quarter of the screen as soon as I begin using custom rendertargets.
I've not set any of the fancy AllowHiDpi stuff you were talking about.
Is there some way around this?
If you disable Retina support in the plist, it should work properly (the properties to remove are mentioned earlier in the thread; note that they must be _removed_ and not just set the false).
Also, to update this thread: with all the fuss around macOS security lately, we (the company I'm in, not MonoGame) shifted our focus away from macOS. Hence I'll likely not look into a real Retina support myself (especially since disabling it seems to just do the trick).
As I already mentioned, I did not add anything to my plist at all.
This is my plist file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleIdentifier</key>
<string>project.MonoGame.Project.MacOS</string>
<key>CFBundleName</key>
<string>Project.MacOS</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>10.9</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
</dict>
</plist>
@mrhelmut thank you very much for your efforts on this.
I am currently on catalina (regretting that update...) and I am also experiencing these problems. Could you share an example PLIST file where the retina support is disabled? I tried researching for the values I need to set, but it seems I am still missing something. Thank you in advance!
It currently looks like htis:
<dict>
<key>CFBundleIdentifier</key>
<string>project.MonoGame.Basher.MacOS</string>
<key>CFBundleName</key>
<string>Basher.MacOS</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>10.9</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSMainNibFile</key>
<string>MainMenu</string>
</dict>
Sure thing, here's one that is working for us (inc. on Catalina):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>Launch.sh</string>
<key>CFBundleIconFile</key>
<string>ScourgeBringer</string>
<key>CFBundleIdentifier</key>
<string>com.flyingoak.ScourgeBringer</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>ScourgeBringer</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>FONV</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>LSMinimumSystemVersion</key>
<string>10.13</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright 漏 2015-2020 Flying Oak Games. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
</dict>
</plist>
Thank you for the quick response!
I tried your version of the plist file, but the problem remains: It keeps the rendering in just the lower left corner.
I am on the release version 3.7.1.
Is it mandatory to use the development branch for this?
For me those things also didn't work. The only thing I found so far is the dirty hack I posted here: https://github.com/MonoGame/MonoGame/issues/6936
It is recommended to be on the development branch and making sure that the SDL native library is not outdated (we recommend SDL 2.0.10, which should be the one that ships with the current development branch).
Also, when dealing with DPI scaling on any systems, it is best to render games based on what GraphicsDevice.Viewport gives back after setting the backbuffer, and not assume that the backbuffer size you set is going to be the expected size (as a rule of thumb, never trust PreferredBackBufferWidth and PreferredBackBufferHeight).
Also, when dealing with DPI scaling on any systems, it is best to render games based on what GraphicsDevice.Viewport gives back after setting the backbuffer, and not assume that the backbuffer size you set is going to be the expected size (as a rule of thumb, never trust PreferredBackBufferWidth and PreferredBackBufferHeight).
it's what I am doing and the root of the problem looks as if the Viewport is the one having the wrong values ( as you can see in the example code of #6936 as well).
I have seen occurrences of #6936 only when Retina isn't properly disabled with a plist (but of course that needs more testing). Would you mind making sure that you are packaging your app in a proper .app bundle when testing this?
Unfortunately I haven't figure out a way to properly disable Retina while debugging (even though a plist is provided by Visual Studio). macOS seems to require a release bundle for Retina properties to be applied (and I've also noticed that macOS is caching plist infos, so make sure you also bump the CFBundleShortVersionString every time otherwise properties might not be updated).
The root cause of #6936 is that MonoGame doesn't support Retina scaling and requires Retina to be disabled in the plist for the Viewport to be correct (and unscaled, which is what you'd expect from a game).
I am not and have never used any HiDPI tags like NSHighResolutionCapable or NSHighResolutionMagnifyAllowed in the info.plist
However when running a compiled .app version (Release) of my game on a retina screen, I am getting the bottom left quarter display issue.
EDIT:
I found that this worked for dealing with the bottom-left quarter of the window bug:
<key>NSHighResolutionCapable</key>
<false/>
<key>NSHighResolutionMagnifyAllowed</key>
<false/>
I found that by putting these tags in, and setting them to false, I was able to build a package that did indeed set the "Use Low Resolution" / "Open in Low Resolution" flag on the .App file when it was installed (and greyed it out so it couldn't be changed accidentally). And that when this flag was set the retina screen issue (ie. "the bottom-left quarter of the window bug") went away.
Perhaps there have been some updates to the OS and/or the frameworks since these tags were found not to work? (and so now they do work).
SUMMARY:
(1) I put:
<key>NSHighResolutionCapable</key>
<false/>
<key>NSHighResolutionMagnifyAllowed</key>
<false/>
into the info.plist (despite being told not to)
(2) I updated both of the build number strings, so as to avoid having cached plist tags interfering in the outcome
(3) I built a series of .pkg files and then ran them to see if the .app file delivered into the Applications folder had it's "Use low resolution" flag set or not. The first time I did this, it appeared not to have worked, but the second time it appeared that it had worked, so I uploaded and submitted it along with a comment asking Apple to check whether the flag had been set if the build failed again (cos I thought that would at least tell us if that route was hopeless). But as it happens Apple approved the build.
In conclusion I'm not 100% sure I have fixed the problem, but I'm happy that I've either fixed it enough to get the build passed, or else I just got lucky.
I also had success using the above method of specifying the keys and setting them to false on Catalina.
These keys (set to false) are needed now for Macs, at least for version 3.7. Some customers of mine ran into problems also (screen showing a quarter size) without them.
Every macOS is a new surprise in regard to how the system is working with OpenGL contexts and Retina... To be honest, macOS has become such a mess with every update behaving differently that I am likely to give up on it and stop working on its support (not to mention that Apple dropped OpenGL with the new ARM based macs which don't support it anymore).
Future efforts in supporting macOS will likely be toward the upcoming Vulkan backend.