2
votes

What's the correct way to deal with DPI scaling in an OpenGL application when the application is DPI monitor aware. aka:

SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);

I'm finding different behaviour on different devices - probably driver related, but some machines need to setup the viewport like this:

glViewport(0, 0, prc->right, prc->bottom)

while others need something like this:

glViewport(0, 0, (int)(prc->right * 96 / dpi), (int)(prc->bottom * 96 / dpi));

(where prc is the client rect and dpi is the current DPI of the window).

I've put together a simple demo program that shows the problem. The problems happen after changing the system scaling, but before signing out/back in.

Problems include:

  1. Rendering at the wrong scale (not sure which driver is wrong)
  2. Vertical shifting by what looks like the difference in the title bar height before changing the scaling vs after changing the scaling. (on macbook pro/bootcamp)

I've tried tearing down and recreating the wgl context on WM_DPICHANGED but to no avail and not sure what else to try.


Update: I've updated the sample program repo to include screen shots of what I'm seeing and I've included the .exe for the test program.

See here: https://bitbucket.org/toptensoftware/minimalopengl/overview


Update 2 - found a GPU that works as expected Radeon RX460. Updated screen shots in repo to show what's expected.


Update 3 - I'm now fairly confident this is caused by issues with the NVidia and Intel drivers and have logged bugs with both. I guess WHQL compliance doesn't cover OpenGL drivers.

Still... it'd be nice to have proper documentation or example program from Microsoft on how OpenGL and the per-monitor DPI support is supposed to work.

1
Where do you get prc->right and prc->bottom from?Nicol Bolas
As stated it's the window's client rect (ie: GetClientRect). See the referenced demo program for exact details.Brad Robinson

1 Answers

1
votes

Have the same problem on gtx 1050. I've noticed that this problem only appears with SetThreadDpiAwarenessContext function.

from msdn:

SetThreadDpiAwarenessContext function. Set the DPI awareness for the current thread to the provided value.

It means that if driver creates one or more additional threads to render OpenGL, each thread will have different dpi awareness level.

So there are three solutions:

  1. Use old SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) function from Windows 8.1 and call EnableNonClientDpiScaling(hWnd) in WM_NCCREATE message;
  2. Use new SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) from Creators Update;
  3. Set dpi awareness level in application manifest (will be applied to whole application).

Both functions set awareness level for whole process.