Open DLLarson opened 3 years ago
I've discovered that when using the high DPI compatibility workaround the XOR-ed tracking rects are far away from the proper screen coordinates.
Another strong reason to make the program high DPI aware!
-Dale
High DPI programming...
MFC. Although we’ve added per-monitor DPI scaling support to Win32, WPF and WinForms, MFC does not natively support this functionality:
User information...
-Dale
Greetings I want to add to this problem as well. I am running a 4K monitor (27" inch).
This first screen shot is from the CBDesigner and the second screen shot is from CB 3.50 after open up the map you can see the differences between the two
CB 3.10
CB 3.50
It would be very nice if the 4k correction could be implemented so that CB does not display so tiny and unreadable.
The expected behavior would be more in line with CB 3.10.
Note that when I change the properties as noted above (DPI settings) on the exe it works fine.
After changing both exe's properties (DPI settings for compatible mode) both are satisfactory:
Hi Don,
Thanks for the feedback!
The program needs to be changed such that it recognizes the situation and automatically provides the behavior that tweaking the compatibility does.
Did you see any problems with drag-and-drop behavior or resizing a pane (for example)?
-Dale
(Adding more links for future reference...)
Newer information on how to handle DPI awareness:
Win32 docs for DPI awareness API's:
https://learn.microsoft.com/en-us/windows/win32/api/_hidpi/
https://learn.microsoft.com/en-us/windows/win32/learnwin32/dpi-and-device-independent-pixels
Some info about MFC support:
https://devblogs.microsoft.com/cppblog/mfc-applications-now-default-to-being-dpi-aware/
https://stackoverflow.com/questions/62188168/dpi-scaling-a-complete-dialog-box-from-resource
These links describe an application's Compatibility high DPI settings dialog:
Some tips on implementing support for DPI awareness:
https://mariusbancila.ro/blog/2021/05/19/how-to-build-high-dpi-aware-native-desktop-applications/
https://learn.microsoft.com/en-us/troubleshoot/windows/win32/mix-gdi-and-gdi-plus-drawing
Problems with Windows version detection:
https://github.com/glfw/glfw/issues/1294
-Dale
I've learned that the CB applications behave pretty well with High DPI (except for the color palette control in CBDesign) using MFC's built-in support for DPI awareness. Note that it's important to make sure the program's DPI awareness compatibility property settings are left to their defaults. In my case I had to delete subkey values at registry key AppCompatFlags
for the CB*.exe
applications because I was testing behavior and some got stuck with an applied setting and was greyed out so it couldn't be restored. Other people reported seeing this greyed item issue but I could find no solution. Hence the use of the Regedit-or. The key here is not to mess with the compatibility settings in the first place.
CBDesign's color palette window scaling is fixable. It just needs to compute its layout rather than use hardcoded values that assume the 96dpi Windows "standard". Pretty simple.
A different problem has to do with the client areas that display the playing boards and the tray palette lists that show tiles, markers and playing pieces. The issue is whether or not we should scale those views/controls. GameBox designers work in pixel space for boards and bitmap images that underlie Tiles. So in the case of CBDesign we probably wouldn't want to scale the views in those tools.
However, when playing a game using CBPlay this isn't so clear cut. I can see where scaling would make sense for the views of maps, Trays, etc... so they aren't too tiny to see. Maps frequently contain text that may not be very legible even in the full zoom level.
-Dale
Again, I have no knowledge of HiDIPI, and no hardware that would allow me to experiment. With those caveats, I have a couple of comments...
A different problem has to do with the client areas that display the playing boards and the tray palette lists that show tiles, markers and playing pieces. The issue is whether or not we should scale those views/controls. GameBox designers work in pixel space for boards and bitmap images that underlie Tiles. So in the case of CBDesign we probably wouldn't want to scale the views in those tools.
I would expect that the bitmap editor squares would suffer the same too-small problem as the color choice squares in the color picker. Are you sure we wouldn't want to scale the bitmap editor view? Or is there some difference between these windows that I'm not recognizing?
However, when playing a game using CBPlay this isn't so clear cut. I can see where scaling would make sense for the views of maps, Trays, etc... so they aren't too tiny to see. Maps frequently contain text that may not be very legible even in the full zoom level.
Would such scaling always be by simple integer multiplies, or does proper scaling require slower operations?
I would expect that the bitmap editor squares would suffer the same too-small problem as the color choice squares in the color picker.
Yep. It would.
Are you sure we wouldn't want to scale the bitmap editor view?
I'm actually not sure what to do yet. I haven't pinned down what support GDI offers yet. If they can do it automatically then it should be cake to implement. I did notice that VS2019's bitmap editor (I used it to modify the do-not-drop cursor) doesn't scale and it's tough to use. So I just need some more information to make a smarter decision.
I would prefer to scale everything so it behaves more like an app that doesn't offer DPI awareness and you see the fuzzy version (with proper DPI support it wouldn't be fuzzy.) It's fuzzy because windows renders the app on a 96dpi GDI off screen bitmap surface and inflates that for the desktop. See the older CB app to experience the results of system scaling. You should be able to test on your own non-4k screen if you can just change your screen scaling from 100%.
Would such scaling always be by simple integer multiplies, or does proper scaling require slower operations?
I'll let you know when I learn more about GDI DPI awareness support.
-Dale
Would such scaling always be by simple integer multiplies,...
Nope. Not usually. However when the Desktop Window Manager is used (pretty much always) it will first render at a simple multiple of the application and then scale it down to the target scaling.
This link describes how windows supports DPI awareness for the various levels of application support:
https://learn.microsoft.com/en-us/windows/win32/learnwin32/dpi-and-device-independent-pixels
or does proper scaling require slower operations?
Sure. As a minimum we would use StretchBlt. But this overhead is insignificant on today's platforms. Even in the old timey days it wasn't that bad.
-Dale
Would such scaling always be by simple integer multiplies,...
Nope. Not usually. However when the Desktop Window Manager is used (pretty much always) it will first render at a simple multiple of the application and then scale it down to the target scaling.
Sure. As a minimum we would use StretchBlt. But this overhead is insignificant on today's platforms. Even in the old timey days it wasn't that bad.
-Dale
Even if modern graphics hardware can perform scaling relatively quickly, won't doing anything other than an integer multiply result in blurry bitmaps? Since so much of CB map and piece display usually involves bitmaps, I would be afraid many .gbx
es would end up blurry. I assume the automatic anti-aliasing mechanisms are specifically tailored for fonts.
Even if modern graphics hardware can perform scaling relatively quickly, won't doing anything other than an integer multiply result in blurry bitmaps?
Absolutely! But like most things in this world, you can't always get what you want. In fact I think most of the directly supported scaling values in Win10's display properties are not integer multiples of the "standard" 96 dpi resolution that classic Windows used.
When it comes to our situation we can render all fonts and vector graphics with no compromises in a view. The exception are the various bitmaps. So I think we can get pretty good results with only bitmaps getting scaled.
Perhaps there are other API's than StretchBlt that yield better bitmap scaling results. I'm still looking around for that. I'm loathe to have to require including some 3rd party library to get a better result since they seem to come and go (do you know of any that have lasted the test of time?). The solution should use Windows provided technologies that have a history of support (like GDI has.) One might be GDI+ which I'm going to look at next. Then there's Direct2D. That involves a new level of complexity due to the use of COM for it's API's. Of course all these complicate cross-platform support. What to do?
In the good old days we simply rendered or provided bitmaps at each integer multiple so each zoom level was directly supported. Now with High resolution monitors this is no longer true. Hence my original concern for CBDesign's unique board design problems. I chose the fixed zoom level approach for image quality and runtime performance. CB didn't have to StretchBlt because of fixed zoom levels. This is no longer true.
We could also ditch the current Zoom model altogether and use the currently defined bitmaps as "suggestions" that are selected as close enough for the current view's dynamic zoom level. That would be a big job.
Another approach is to simply defeat all the MFC DPI support and just allow Windows to do GDI scaling and live with the resulting fuzziness as Windows does for legacy CB. dlazov
(Don) who posted earlier in this issue was happy with the Windows fuzzy solution. I personally would rather have the application look like it belongs in current version of Windows.
So we need an approach that is good enough while balancing all the concerns.
I'm open to hearing alternate approaches but as you can see even Microsoft had to do some tricky stuff (that usually leads to fuzziness) to provide application compatibility for programs that don't support DPI scaling.
-Dale
When it comes to our situation we can render all fonts and vector graphics with no compromises in a view. The exception are the various bitmaps. So I think we can get pretty good results with only bitmaps getting scaled.
While I agree that "only" bitmaps are going to be fuzzy, I expect a large fraction of .gbx
es to involve a lot of bitmaps.
Perhaps there are other API's than StretchBlt that yield better bitmap scaling results. I'm still looking around for that. I'm loathe to have to require including some 3rd party library to get a better result since they seem to come and go (do you know of any that have lasted the test of time?). The solution should use Windows provided technologies that have a history of support (like GDI has.) One might be GDI+ which I'm going to look at next. Then there's Direct2D. That involves a new level of complexity due to the use of COM for it's API's. Of course all these complicate cross-platform support. What to do?
I don't know anything about any graphics libraries other than the Win32 GDI API. I have done some work with wxWidgets, but only using wxDC, which wraps GDI. I have never used wxGraphicsContext, which wraps GDI+.
I'm open to hearing alternate approaches but as you can see even Microsoft had to do some tricky stuff (that usually leads to fuzziness) to provide application compatibility for programs that don't support DPI scaling.
Could we just not scale bitmaps at all, or are they too difficult to read at native size? If they are too small, could we let the user choose what integral multiplier to apply to the bitmaps?
Using vector graphics instead of bitmaps would solve scaling problems, but I don't know how practical it is. In my work life, I have a coworker who has done some work with SVG files, but I never have. My understanding of them is that there is no good C/C++ library support for them; the library my coworker was using is written in Rust, and so is the GNOME one. I'm pretty sure wxWidgets wraps the nanoSVG library, but the discussions suggest it has a number of limitations. And adding SVG support doesn't fix existing bitmap-based .gbx
es, nor is it clear to me how easy it is to make future .gbx
es using SVG editors.
I've had a chance to investigate the GDI+ stuff and it may be perfect for working this problem. It's interesting that you found that wxWidgets provides a wrapper for it. I wonder what they used for the backend for this class on a non-Windows platform.
Could we just not scale bitmaps at all, or are they too difficult to read at native size?
Consider a 4K panel on a laptop with a 15inch screen. It would be definitely be really tiny to see (especially for older folks like myself.) A 15 inch screen has about 282 pixels per inch. A 25x25 pixel counter would be really small on a laptop.
For a point of comparison. On my 4K monitor at natural bit size this is what counters from Paths of Glory and my Tactics 2 game look like:
My display is set to 175% scaling (168dpi) so that's what MSPaint is scaled to. But the counters are shown at their natural pixel size.
As another comparison, here's Tactic 2's full 4K screen capture with the windows scaling set to 100% or 96dpi (classic WIndows scaling):
Pretty bad (at least for my aging eyes.) Now imagine shrinking this image down to a laptop screen.
If they are too small, could we let the user choose what integral multiplier to apply to the bitmaps?
This is an interesting idea. Perhaps we could automatically select a "floor" integer multiple that is nearest to the current multiple of screen DPI/96dpi and render the tiles at that level. So for my screen the ratio is set at 1.75 (175%). So round up to 2 and use that as the base scaling for the board and tool views. In fact, I think the low level rendering would be the same regardless of using either integer multiples or exact scaling so we could try both.
An added benefit of GDI+ is that is supports rotating bitmaps. I'll bet it produces a much better rotated counter image than the raster scanned approach I used to rotate images.
I think I'm going to hack up the code some so I can experiment with GDI+ to see how we can fit it into the existing graphics support. This is some pretty meaty work. I expect it to take a while.
-Dale
I've had a chance to investigate the GDI+ stuff and it may be perfect for working this problem. It's interesting that you found that wxWidgets provides a wrapper for it. I wonder what they used for the backend for this class on a non-Windows platform.
Judging by https://docs.wxwidgets.org/3.1.3/classwx_graphics_renderer.html#afba6de5b8d2415167cfe5a1d6c179003, Cairo and OS X Core Graphics.
Could we just not scale bitmaps at all, or are they too difficult to read at native size?
Yes, it looks like some of those pieces aren't much taller than the ribbon tabs. Too small indeed.
Judging by https://docs.wxwidgets.org/3.1.3/classwx_graphics_renderer.html#afba6de5b8d2415167cfe5a1d6c179003, Cairo and OS X Core Graphics.
Excellent info. Thanks!
-Dale
Here's some info on High DPI support built into wxWidgets...
https://docs.wxwidgets.org/3.2/overview_high_dpi.html
It looks like we need to include a predefined .rc file for Windows to ensure the manifest has the proper High DPI settings:
The behaviour of the application when running on a high-DPI display depends on the values in
its [manifest](https://docs.microsoft.com/en-us/windows/win32/sbscs/application-manifests).
You may either use your own manifest, in which case you need to define the dpiAware (for
compatibility with older OS versions) and dpiAwareness (for proper per-monitor DPI support) in
it, or simply include wx/msw/wx.rc from your resource file to use the manifest provided by
wxWidgets and predefine wxUSE_DPI_AWARE_MANIFEST to opt-in into [high DPI support]
(https://docs.microsoft.com/en-us/windows/win32/hidpi/high-dpi-desktop-application-
development-on-windows): define it as 1 for minimal DPI awareness and 2 for full, per-monitor
DPI awareness supported by Windows 10 version 1703 or later.
-Dale
Here's some info on High DPI support built into wxWidgets...
I don't have any way to test this, so I will leave this to you.
or simply include wx/msw/wx.rc from your resource file to use the manifest provided by wxWidgets and predefine wxUSE_DPI_AWARE_MANIFEST
I don't have any way to test this, so I will leave this to you.
Can you tell me what existing file I would include the wx/msw/wx.rc
file. It looks like the RC's were replaced by .xrc
's.
Also, in what file should I predefine wxUSE_DPI_AWARE_MANIFEST
in the wxWidgets world?
-Dale
Can you tell me what existing file I would include the
wx/msw/wx.rc
file. It looks like the RC's were replaced by.xrc
's.Also, in what file should I predefine
wxUSE_DPI_AWARE_MANIFEST
in the wxWidgets world?
From https://docs.wxwidgets.org/3.2/page_multiplatform.html, I think we will always need .rc
files in Windows; they just won't have as much in them as they used to.
From looking at .../build/cmake/functions.cmake
, it looks to me like we should add set(wxUSE_DPI_AWARE_MANIFEST "value")
to our topmost CMakeLists.txt
(where value
is either system
or per-monitor
). I'm guessing, until we do more work to handle per-monitor
, we should use system
.
Ok... I'll give it a whirl.
-Dale
CBDesign and CBPlay have some visual elements rendered very small on a 4K display.
The workaround is to set application compatibility like so:
Unfortunately this makes the app "fuzzy":
It would be best if the program could properly adapt to high DPI displays automatically.