Add DPI-aware support
Closed this issue · 3 comments
In order to have the application be properly sized on a high DPI display, we need to set some platform-specific DPI-awareness values. Otherwise we might have cases where the game window only renders at something like 1440p on a 2160p monitor.
On Windows, this is done with a manifest. Apparently SDL_WINDOW_ALLOW_HIGHDPI
is optional and only affects querying/changing DPI at runtime. I googled around and wasn't able to find a clear solution to this in CMake besides the following rough idea:
IF (MSVC)
ADD_CUSTOM_COMMAND(
TARGET TESArena
POST_BUILD
COMMAND "mt.exe" -manifest \"${CMAKE_CURRENT_SOURCE_DIR}/../windows/dpi.manifest\" -outputresource:\"TESArena.exe\"\;\#1
)
ENDIF()
The DPI manifest is an XML document with some dpiAware
and dpiAwareness
elements. Not entirely sure what all is needed in it but the values should be ones that enable per-monitor DPI awareness, and can be verified in Visual Studio > Project Properties > Manifest Tool > Input and Output > DPI Awareness.
It looks like the equivalent on macOS is NSHighResolutionCapable
but it is not clear how we could do that in CMake.
I don't know how any of this applies to Linux.
To get basic DPI awareness, you only need the following in your manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
<dpiAware>True</dpiAware>
</windowsSettings>
</application>
</assembly>
This enables System level DPI awareness and Windows won't scale the window unless it's on a monitor with a different DPI to the system setting. The dpiAwareness
element was added in Win8 to advertise multi-monitor DPI support.
This document explains the values you can add to the manifest: https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/mt846517(v%3Dvs.85)
And this one has more info on what the various DPI modes do: https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-development-on-windows#dpi-awareness-mode
It goes without saying that you need to code this game to take advantage of higher DPI settings.
As far as I'm aware, Linux doesn't do any auto DPI scaling but relies on the programs to do this themselves.
Yes, those links are more or less what I found last night. The main blocker is knowing how to do this in CMake, because I tried multiple combinations of the example code in my first comment and none of them result in the Visual Studio project settings changing.
I think we want to support the per-monitor V2 mode, and that requires grabbing some low level info from the SDL window. I think it's SDL_SysWMInfo
, and then we get the window handle from that and then register a callback in the application, because SDL doesn't handle it itself.