ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
57.79k stars 9.91k forks source link

High DPI, Retina Mac #3757

Open cmaughan opened 3 years ago

cmaughan commented 3 years ago

Version/Branch of Dear ImGui: Version: 1.80 Branch: docking

Back-ends: imgui_impl_opengl3.cpp + imgui_impl_sdl.cpp Operating System: Mac/Win

My Issue/Question:

On Windows, with a 4K display, using SDL + GL3 backends, I get a tiny view of ImGui. This is easily fixed by getting the DPI scale of the monitor (SDL_GetDisplayDPI(....) / 96.0f), and using this value to scale the font:

`io.Fonts->AddFontFromFileTTF(..., 16.0f * dpi_scale);`

Note that on Windows, you also need to add the manifest file to make sure that the app is DPI aware. Calling SDL_GetWindowSize with this configuration returns the same values as SDL_GetDrawableSize:

SDL_GetWindowSize = 100, 100
SDL_GetDrawableSize = 100, 100
DisplayFramebufferScale = 1

So, for example, a 100x100 window, will have a drawable of 100x100 and a window size on screen of 100x100, and although SDL_GetDisplayDPI returns 2, our DisplayFramebufferScale is now 1: everything is rendered at high DPI and we are happy, with 1:1 pixels on the screen.

Removing the manifest and using OS DPI scaling, our window is now visibly twice the size on screen, but our values for window size and drawable size are the same. Our DisplayFramebufferScale is still 1, but SDL_GetDisplayDPI scales 1, because the OS is lying to us and scaling everything up under the covers. Our fonts are blurry because we are technically scaling them up from a 100 to a 200 sized window. All good, as expected.

Here's the problem. On MacOS, with the same scenario, including a valid plist, and setting NSHighResolutionCapable, etc. the numbers that come back from SDL are different. This time, we get:

SDL_GetWindowSize = 100, 100
SDL_GetDrawableSize = 200, 200
Get_DisplayDPI / 96 = 2 (actually 2.5 on my MBP 16" system, but lets keep it simple...)
FrameBufferScale = 2
io.DisplaySize = 100, 100

And later in glViewport we set the size to io.DisplaySize. This is a problem because now, although we created a high DPI framebuffer, the viewport is rendering to 1/4 of it. And later we are zooming it up from 100x100 to 200x200 (the real size of the window). Blurry fonts.

Adding a hack to NewFrame to set DisplaySize = DrawableSize will fix the rendering, give me high resolution fonts as long as I scale the font size by DPI. But now something about the mouse logic is confused and I can't move viewports around/interact with the UI.

At this point, I'm stuck as to how to fix the mouse logic; and how to fix this in a universal way that makes sense. This behavior must have been seen before; I hope my explanation of what's going on here helps....

cmaughan commented 3 years ago

To be clear, the fundamental difference here is that SDL on Mac is returning the 'fake' window size, not the real window size in pixels when in high DPI mode. On Windows, we get the real window size when in high DPI - i.e the pixel dimensions.

ocornut commented 3 years ago

Hello Chris,

I'm not in the headspace to give a fully detailed answer, as you found out is a slightly wide and multi-headed topics. OSX does indeed report different window size from framebuffer size, Windows does not. I think the best action is we should aim eventually to make all examples DPi aware (at least for single viewport), maybe it'll be a nice target to tackle for ~1.82.

Note that on Windows, you also need to add the manifest file to make sure that the app is DPI aware.

There are other ways, namely in imgui_impl_win32 the ImGui_ImplWin32_EnableDpiAwareness() gives an equivalent result without requiring a manifest and without requiring SDK 10 at compile-time or Windows 7 at run-time. You can call ImGui_ImplWin32_EnableDpiAwareness() before initializing SDL/GLFW and it would work there too.

Maybe the https://github.com/ocornut/imgui/issues?q=+label%3Adpi+ tag can also be helpful.

cmaughan commented 3 years ago

Thanks, yup, this is a minefield alright, and requires a lot of test setup to go through the combinations. I don't mind the manifest/plist; but good to know about the other APIs.

It is the mouse interaction I'm stuck on. I might get some more time to delve into this tonight. It certainly isn't obvious at the moment!

ocornut commented 3 years ago

It's even more of a mess when you start digging in multi-viewports territory..... https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-how-should-i-handle-dpi-in-my-application

I think we need to focus on a simple path to get examples working. I'll try to let you a path.

For live DPI change, Backends should support texture update requests (we have done work on this side on a private repo, its surprisingly hairy if you include in-flight textures, the possibility of rewriting already used pixels) - all this work will be extremely useful not only for base DPI handling but for dynamic font atlas.

slajerek commented 3 years ago

Actually, I am struggling with the same problem, and some proper code example for SDL Backend would be good to have.

Temporarily I have this patch applied: https://github.com/ocornut/imgui/commit/a843af4306e0d786fec5394bba07fd5067384661

Especially this part of code seems to be enough:

//draw_data->FramebufferScale = ImGui::GetIO().DisplayFramebufferScale; // FIXME-VIEWPORT: This may vary on a per-monitor/viewport basis?
    if (g.ConfigFlagsCurrFrame & ImGuiConfigFlags_ViewportsEnable)
        draw_data->FramebufferScale = ImVec2(viewport->DpiScale, viewport->DpiScale);
    else
        draw_data->FramebufferScale = g.IO.DisplayFramebufferScale;

Note also, in some older SDL versions getting the DPI on macOS by SDL_GetDisplayDPI was broken and actually it is still not correctly fixed: https://bugzilla.libsdl.org/show_bug.cgi?id=4856

Which actually made it really hard to understand what is going on as we had to comply with two issues at once.

Anyway, the above works to some extent but as @cmaughan said the fonts are blurry. I've seen some code done in recent docking branch to include support for freetype library, I've added this but still, fonts are blurry because freetype currently does not support oversampling.

Anyway, having a proper, working example for HighDPI would be really awesome as the blurry fonts are unfortunately still there and my users are asking me why we can't simply have good looking fonts...

cmaughan commented 3 years ago

Hi @slajerek, @ocornut

As I mentioned above it is possible to get High DPI working with a couple of hacks on Mac. I recently did an experimental GUI for Sonic Pi, and it has the necessary fixes. These are just workarounds, but solved the problem for now.

This change gives you a high DPI frame buffer on Mac: FrameBuffer

These changes fix the mouse interaction: Mouse 1

Mouse 2

cmaughan commented 3 years ago

They are protected in the #if APPLE sections; and note that you also need the plist/manifest stuff to get things to work in the first place, along with the high DPI flag on window create in SDL.

krupkat commented 1 year ago

If anyone would like to use the fix from @cmaughan with a more recent version of ImGui, I have recently had success with that, using the latest docking branch. The fix is in 216f654.

Thank you @cmaughan for publishing your fix here!

cmaughan commented 1 year ago

You're welcome @krupkat - glad it works for you.

slajerek commented 1 year ago

@cmaughan I think there's a small bug in this code

            } else {
#if defined(__APPLE__)

shouldn't it be

#if defined(__APPLE__)
            } else {

?

I am integrating this. Wow, at first the outcome is that all is very small. So it works, that's what my users reported all the time for Windows platform, that default theme is very small :) check these both screenshots, looks OK, but indeed the theme needs to be updated:

Screenshot 2022-09-04 at 05 32 07 Screenshot 2022-09-04 at 06 45 34
Grieverheart commented 1 year ago

@cmaughan Thank you for your solution. I tried it out and was happy to see the fonts not being blurry. Now, when I tried the example, there where differences in positioning and sizing of the windows, as you can see below. Is this normal?

Screenshot 2023-01-11 at 14 46 48 Screenshot 2023-01-11 at 14 46 16

I don't have experience with Imgui yet, but I'd like to use it in my project. Sharp fonts are really important to me, though :) .

cmaughan commented 1 year ago

@cmaughan Thank you for your solution. I tried it out and was happy to see the fonts not being blurry. Now, when I tried the example, there where differences in positioning and sizing of the windows, as you can see below. Is this normal? Screenshot 2023-01-11 at 14 46 48 Screenshot 2023-01-11 at 14 46 16 I don't have experience with Imgui yet, but I'd like to use it in my project. Sharp fonts are really important to me, though :) .

Not sure; maybe you reloaded a saved layout and it wasn't remapped to the new DPI?

bhundt commented 1 year ago

Hi everybody,I know that this topic has been discussed a lot and I a read and googled a bunch but unfortunately I am stuck with the following problem:

I am using ImGui docking branch (commit bf87fbc), ImplSDL2 and ImplOpenGL3. SDL2 is installed with version 2.26.4 and I am working on a M1 Macbook with Ventura 13.2.1. When I enable docking and viewports and I switch SDL2 to high dpi mode I was able to use the fix by @krupkat for successful rendering. BUT my mouse interaction is still broken. In the following screenshot you see where my mouse is pointing (approximated with the red arrow) and you see the mouse position identified by ImGui by the highlighted item in the ImGui Demo Window.

image

I addition when I am dragging a window out of my main window, all ImGui windows get very large AND the mouse interaction works correctly:

Screenshot 2023-03-27 at 08 20 33

vs.

Screenshot 2023-03-27 at 08 21 22

I am scaling the fonts globally and I call ScaleAllSizes().

I played around a lot in imgui_impl_sdl2.cpp to try to rescale multiple values of mouse positions, window positions and so on but I was utterly unable to come close to something which seemed right...any help is greatly appreciated!

cmaughan commented 1 year ago

I'm not in front of it at the moment, but you might want to check that @krupkat got all of my changes in their update. Assuming they did, I've seen your problem before, and IIRC there are more places to apply my mouse scaling fixes in the docking branch than the regular one. Unfortunately I'm not setup on Mac, so that's all I can offer for now. I will update when I get chance to try it. It is certainly past due for a proper fix in ImGui core; I imagine everyone hits this problem these days.

krupkat commented 1 year ago

You can check out this version from my fork: https://github.com/krupkat/imgui/releases/tag/docking_v1.89.4_wip It is quite recent with the official docking branch.

The changes from the official branch are the one you linked: https://github.com/krupkat/imgui/commit/216f654c323761fdd2b86318117494a735446f00 and one more where I simplified it a bit and fixed similar issues on Linux: https://github.com/krupkat/imgui/commit/80be499ed31f71459c8b253b80f283dbf2fd65c2

I have previously tested on Mac and was successful, but didn't try multiviewport, maybe you can try without that feature.

bhundt commented 1 year ago

You can check out this version from my fork: https://github.com/krupkat/imgui/releases/tag/docking_v1.89.4_wip It is quite recent with the official docking branch.

The changes from the official branch are the one you linked: krupkat@216f654 and one more where I simplified it a bit and fixed similar issues on Linux: krupkat@80be499

I have previously tested on Mac and was successful, but didn't try multiviewport, maybe you can try without that feature.

Thanks for your feedback and also thanks @cmaughan. I just tried the branch you (@krupkat) mentioned and without Multi-Viewport mouse input works as expected.

Still the issue remains when using multiviewport. I tried to scale mouse and window positions in impl_sdl2.cpp where the code branches out depending on ImGuiConfigFlags_ViewportsEnable but the issue persists. So I guess the problem needs to be related to obtaining the mouse position in relation to the main window...