ocornut / imgui

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

SDL3 HIDPI Handling #7273

Open tokyovigilante opened 9 months ago

tokyovigilante commented 9 months ago

Version/Branch of Dear ImGui:

master

Back-ends:

imgui_impl_sdl3.cpp + imgui_impl_opengl3.cpp

Compiler, OS:

Fedora 40 + Wayland

Full config/build information:

Dear ImGui 1.90.2 WIP (19013)
--------------------------------

sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=201103
define: __linux__
define: __GNUC__=4
define: __clang_version__=17.0.6 (Fedora 17.0.6-4.fc40)
--------------------------------

io.BackendPlatformName: imgui_impl_sdl3
io.BackendRendererName: imgui_impl_opengl3
io.ConfigFlags: 0x00000003
 NavEnableKeyboard
 NavEnableGamepad
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x00000006
 HasMouseCursors
 HasSetMousePos
--------------------------------

io.Fonts: 2 fonts, Flags: 0x00000000, TexSize: 512,256
io.DisplaySize: 2880.00,1800.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------

style.WindowPadding: 16.00,16.00
style.WindowBorderSize: 1.00
style.FramePadding: 8.00,6.00
style.FrameRounding: 0.00
style.FrameBorderSize: 0.00
style.ItemSpacing: 16.00,8.00
style.ItemInnerSpacing: 8.00,8.00

Details:

This is half-bug, half-exploration, but I have been experimenting with SDL3 HIDPI scaling, and note that the approach in SDL3 (compared to SDL2) is that all metrics are computed based on a "logical" (ie apparent or window) resolution, with the backing store (ie pixel) resolution supplied as a drawable, and the difference between representing a scale factor.

https://github.com/libsdl-org/SDL/blob/main/docs/README-highdpi.md

The current SDL3 implementation in Dear IMGUI doesn't seem to respect this, and when an SDL3 window is created using the SDL_WINDOW_HIGH_PIXEL_DENSITY flag, this is the result:

screenshot

Not beautiful. However, overriding the detected scale and setting a window scale of 1.0 and the drawable size to the window pixel size as follows:

    int display_w, display_h;
    SDL_GetWindowSizeInPixels(bd->Window, &display_w, &display_h);
    io.DisplaySize = ImVec2((float)display_w, (float)display_h);
    io.DisplayFramebufferScale = ImVec2(1.0, 1.0);

and then scaling fonts and the style scale to the scale factor:

float windowScale = SDL_GetWindowDisplayScale(bd->Window);
ImGui.GetStyle().ScaleAll(windowScale);

screenshot

Beautiful. The only other change needed seems to be scaling mouse events.

            ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();
            float windowScale = SDL_GetWindowDisplayScale(bd->Window);
            io.AddMousePosEvent(mouse_pos.x * windowScale, mouse_pos.y * windowScale);

Acknowledging there are many ways to skin the DPI cat, SDL3's approach has unified the platform differences (i.e represents Mac/Linux and (presumably) Windows HIDPI windows the same way, and is a sensible approach which doesn't need over-rendering for fractional scaling (ie rendering at 2.0x and downscaling to 1.5x to display). It is also non-breaking for LODPI, ie 1.0x scale factor just renders at 1.0.

I would humbly propose that this is a good and pragmatic model for IMGUI in general, ie working in logical display units, then scaling by a factor up to pixel size when rendering.

(Examples using Source Sans / Source Sans Bold @ 16pt and Freetype)

daironxuan commented 9 months ago
// Windows DPI scaling
float GetScreenScale()
{
    const HDC screen = GetDC(nullptr);
    const int dpiX = GetDeviceCaps(screen, LOGPIXELSX);
    ReleaseDC(nullptr, screen);
    return static_cast<float>(dpiX) / 96.0f;
}
屏幕截图 2024-02-13 105802

io.Fonts->AddFontFromFileTTF("Add your fonts", 16.0f * GetScreenScale());

Currently under Windows, the display is normal

Linux can use X11 to get the DPI scaling of the system

bhundt commented 3 months ago

EDIT: just found https://github.com/ocornut/imgui/issues/6065#issuecomment-1410485983 and it works now correctly on my macOS machine!

Unfortunately the idea here seems to not work on my macOS machine. The result ist the following strangely garbled output:

Screenshot 2024-08-01 at 20 36 50

Code here: https://gist.github.com/bhundt/a142d3dc4368c55ba1e707e6e34120fa