WIP - Windows high-DPI support


#1

Hi, I wanted to share my progress on implementing high-DPI support for Windows.

I’m hosting the code on github, and I imagine it’s going to need further development before it’s ready to be merged.


Here is the current patch: windows-highdpi-may25.diff (41.9 KB)

It’s (unfortunately) a fairly large and invasive patch, so I wanted to start a discussion and ask if anyone wants to help test.

Here is an overview:

  • The overall goal of the patch is to allow drawing at the monitor’s native resolution, while making SDL act the same as when it was DPI-unaware on a high-DPI monitor with Windows providing DPI virtualization. i.e. if you have a 640x480 window and drag it between a 100% scaled and 200% scaled monitors, the SDL window size stays 640x480, but when it’s on the 200% monitor, the SDL_GL_GetDrawableSize function will return 1280x960.

  • Instead of the SDL_WINDOW_ALLOW_HIGHDPI window flag, you need to use a new hint, SDL_HINT_VIDEO_HIGHDPI_ENABLED, because until recently, DPI awareness was a process-wide setting on Windows. If SDL only supported high DPI on Win 10 Anniversary Update and later, we could stick with the window flag. I adjusted the testcommon code so passing the --allow-highdpi flag enables the new hint instead of the window flag.

  • This should work on Vista and higher, although so far I’ve only been developing and testing on Windows 10 Creators Update. The major changes in Windows’s high DPI support were 8.1 getting per-monitor scaling support, and Windows 10 Anniversary Update getting the ability to change DPI awareness temporarily/per-window, which I’m not taking advantage of here.

  • To motivate some of the design, I did most of my testing with the following configuration:

    • On the left, the primary monitor, a 2880x1800 monitor with 200% scaling (what windows calls 192dpi) and a virtual size of 1440x900.
    • On the right, a 1920x1080 monitor with 100% scaling (96dpi). Windows considers this monitor’s origin to be at (2880, 0)

An important thing to note about Windows’s DPI virtualization is, in DPI unaware applications (e.g. SDL without this patch), windows on my right monitor have their X coordinates start at 2880. DPI unaware applications see the left monitor as extending from (0, 0) to (1440, 900), so this means there is a big gap in the coordinate system between the left (200% scaled) monitor and the right monitor.

My patch implements this same behaviour when you enable DPI awareness, so the monitor bounds reported by SDL remain the same whether DPI awareness is disabled / enabled, and SDL window positions/sizes should give you the same apparent position/size when DPI awareness is on/off. (try launching the SDL test applications with --info all)

That’s all that comes to mind for now; any feedback/questions are welcome :slight_smile:


#2

I won’t have time to look at this until the weekend, but I just wanted to quickly say - good job and thanks! Doing something like this has been on my TODO list for a while. I’m glad I was beaten to the punch. :slight_smile:

The DPI flag situation is a bit unfortunate (due to Microsoft’s API choices)…


#3

High DPI is also necessary to fix issues with window sizes when a user selects a Text/Scale option in newer versions of Windows that are greater than 100% (Ie setting 125% on a 1080p tv 32" tv so the text is actually legible in the OS from a distance)

This seems to be an issue with most id Tech and SDL based idTech games.


#4

This seems to be an issue with most id Tech and SDL based idTech games.

Yeah - in Quakespasm we force DPI awareness on, so the game’s window is tiny on high-dpi displays. The initial reason we did that was to workaround https://bugzilla.libsdl.org/show_bug.cgi?id=2713


#5

We also had that problem in another game using a totally different
engine (C4), not using SDL. (We fixed it by calling
SetProcessDPIAware(ness), similar to Erics snippet here:


)

Maybe the common denominator is OpenGL?

Cheers,
Daniel