Optimize for macOS Performance and Fix Fullscreen Letterbox Issue in Unity Build
Recently, we have a performance issue on our macOS build. The game runs smoothly in low-end Windows laptops but laggy in a 2016 Macbook. Although the hardware of the Macbook is not even as good as the Windows laptop, we doubted the performance would be much different. In addition, it runs alright in Editor in Macbook but not in a build, so the hardware influence should be able to be ignored.
Spotting the Problem
After fighting the issue for a while, we’ve found that if we switch from the default fullscreen mode to the window mode, the window is very large (almost 4 times as the monitor size). This high resolution runs even in fullscreen, dragging down the performance and frame-rate of the game.
This may be because either we enabled Mac Retina Support, or we make the build in a high-resolution iMac and the default resolution is saved with the game build. I didn’t bother the figure out the reason but going straight into the solution.
Solution — Fixing the screen width
The first thing we do is manually setting the resolution with a script on game start:
int manualScreenWidth = 1920;
Screen.SetResolution(manualScreenWidth, Mathf.RoundToInt(1f * manualScreenWidth * Screen.currentResolution.height / Screen.currentResolution.width), Screen.fullScreen);
This set the screen width to 1920, and the height to proportional to the player’s monitor size (Screen.currentResolution). For example, in modern 16:9 monitors, it set resolution 1920×1080. This works pretty well in both full-screen mode and windows mode until the player changes the size of the windows manually…
Another problem — Letterbox
If the player set the window to be very narrow in Windows Mode, then entering Full-Screen mode will result a letter-box:
This is a very unwanted behaviour, we simply want the game to take all space when it goes into full-screen mode. This is actually the designed behaviour from Unity and Unity seems intend to keep the letterbox instead of stretching the resolution (I doubted if any developer prefers this). This has also been asked multiple times.
Solution for full-screen mode
After some search, I couldn’t find a very promising solution and decided to come up with my own one. I wrote a script that takes account for:
- Game is built-in default full-screen mode
- Use this script to:
- When changing from full-screen to window mode: set the width to 1920 and height proportional to monitor size (
Screen.currentResolution
), save both width and height inPlayerPrefs
. - When changing from window to full-screen mode: set the width to 1920 and height proportional to the saved width/height ratio.
The reason we need PlayerPrefs
to save the width and height is that, Unity cannot obtain the monitor size in full-screen mode. Screen.currentResolution
gives the current resolutions (the window size in window mode). There may be an even better solution using Windows.System.Display
, but using PlayerPrefs
is good enough, while the game is full-screen by default. Let me know if anyone knows another way to do it.
Window Mode | Full-screen Mode | |
Screen.width | Window width | Width in current resolution (Window width set before, or width set in Screen.SetResolution) |
Screen.height | Window height | Width in current resolution (Window height set before, or height set in Screen.SetResolution) |
Screen.currentResolution.width | Same as Screen.width | Same as Screen.width |
Screen.currentResolution.height | Same as Screen.height | Same as Screen.height |
Scripts:
Notes that I only set the manual screen width in Mac, and leaving the screen width in Windows to Screen.width
so it uses the maximum resolution.
7 COMMENTS
where is the script you describe?
Hi Jed,
Thank you for asking and I forgot to put the Gist links.
I just updated and you should be able to see them.
Hey there Richard. Great work! I took a look at some of the games Sweaty Chair created and they look fantastic. I’m also trying to create a game for MacOs and for some reason I get extreme fps drops for a simple 2d game. I’m trying to understand some of the coding you’re doing but there’s a few things that seem to have been left out. First, is SettingSettings supposed to be a singleton that you just create and is your ScriptableObjectSingleton object managing the singleton? Second, in SettingSettings, there’s a .current, I’m assuming that is being instantiated in ScriptableObjectSingleton as well? Finally, when and where are you calling SettingManager.SetResolution? I’d appreciate some help on getting the mac version of my game running, I’d be extremely grateful, thanks again.
Hi SincerelySleepy,
Yes, ScriptableObjectSingleton is basically a wrapper for ScriptableObject singleton and `SettingSettings.current` simply return the data in .asset file in the Resources. I didn’t spamming the scripts here but you can take a look at: https://github.com/Sweaty-Chair/SC-Essentials/tree/main/Assets/SweatyChair/Essentials/Singleton
`SettingManager.SetReolution` is called on Awake.
Thank you for that. I’m curious, what does a screenshot of your game look like AFTER you’ve applied your script on a mac? Say if the resolution is 2880 x 1800, won’t part of your screen still get cut off since 1920×1080 is a 16:9 aspect ratio and not a 16:10, or will you still have some letterboxing on top and sides?
I’d love to talk to you a bit about this issue as our game is riding on it. Are you open to chatting via email or IM? How can I reach you?
The height is calculated and proportional to Screen.height, so the letterbox won’t be happening.
You can add my Discord:
Richard – Sweaty Chair#5278
I can’t seem to add you, it’s saying the friend request failed.
I tried:
Richard – Sweaty Chair#5278
Sweaty Chair#5278
Mind adding me?
sincerelysleepy#0276