ocornut / imgui

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

Screen resolution change cannot be handled correctly on windows 11 platform #6556

Closed cliche9 closed 1 year ago

cliche9 commented 1 year ago

Thanks for creating such an amazing GUI framework, it's really great!

Here is my issue:

Version/Branch of Dear ImGui:

Version: 1.89.6 Branch: docking

Back-end/Renderer/Compiler/OS/Dependencies

Back-ends: GLFW Renderer: OpenGL Compiler: MSVC 2022 Operating System: Windows 11 Dependencies: imgui-node-editor and GLFW&OpenGL related(glm, glad, etc.)

My Issue/Question:

  1. When I set the screen resolution scale to 100%, the program works fine. 1

  2. When the program is running, I scale the screen resolution to 125%, the program goes black. 2

  3. When my screen resolution is set to 125%, the program goes wired. The mouse cannot operate correctly, as if a single mouse position occupies multiple pixels, making it impossible to perform proper positioning and selection operations. 3

It seems like the screen's dpi change cannot be handled correctly. I don't know how to address this problem.

ocornut commented 1 year ago
  1. When the program is running, I scale the screen resolution to 125%, the program goes black.

This doesn't seem to happen in our example. Can you test the example_glfw_opengl3 example to compare?

  1. When my screen resolution is set to 125%, the program goes wired. The mouse cannot operate correctly,

I can think of many variants of this, which is generally confusing for users/developers, but only on other backends and platforms. But GLFW in particular enable DPI awareness and there are no known problem on GLFW+OpenGL+Windows. Likewise can you check example_glfw_opengl3 ?

Use Tools->Metrics and Tools->DebugLog inputs to try to inspect things.

(PS: You can drag or paste images/gifs into messages without needing to host them elsewhere.)

cliche9 commented 1 year ago
  1. When the program is running, I scale the screen resolution to 125%, the program goes black.

This doesn't seem to happen in our example. Can you test the example_glfw_opengl3 example to compare?

  1. When my screen resolution is set to 125%, the program goes wired. The mouse cannot operate correctly,

I can think of many variants of this, which is generally confusing for users/developers, but only on other backends and platforms. But GLFW in particular enable DPI awareness and there are no known problem on GLFW+OpenGL+Windows. Likewise can you check example_glfw_opengl3 ?

Use Tools->Metrics and Tools->DebugLog inputs to try to inspect things.

(PS: You can drag or paste images/gifs into messages without needing to host them elsewhere.)

example_glfw_opengl3 works fine on any conditions, I just checked my code, it has a very similar main loop like example_glfw_opengl3, maybe I should check imgui-node-editor. Anyway, thanks for your answer

cliche9 commented 1 year ago

I've checked my code. Finally I found that when I recreateFontAtlas when the program is running, the program went black. Is it illegal to rebuild Dear ImGui Font Style? Here is my recreateFontAtlas code:

void Application::recreateFontAtlas() {
    printf("Recreate font triggered\n");
    ImGuiIO& io = ImGui::GetIO();

    IM_DELETE(io.Fonts);

    io.Fonts = IM_NEW(ImFontAtlas);

    ImFontConfig config;
    config.OversampleH = 4;
    config.OversampleV = 4;
    config.PixelSnapH = false;

    defaultFont = io.Fonts->AddFontFromFileTTF("../assets/font/Play-Regular.ttf", 18.0f, &config);
    headerFont  = io.Fonts->AddFontFromFileTTF("../assets/font/Cuprum-Bold.ttf",  20.0f, &config);

    io.Fonts->Build();
}
ocornut commented 1 year ago

Wow wow you should not delete and reaffect io.Fonts. You can call its clear function, load new functions and then call the backend function to destroy/recreate fonts.

cliche9 commented 1 year ago

Wow wow you should not delete and reaffect io.Fonts. You can call its clear function, load new functions and then call the backend function to destroy/recreate fonts.

Would you please explain more about how to reload io.Fonts or is there a FAQ mentioned this question?

ocornut commented 1 year ago

Replace your delete/new sequence by calls to the clear function + call the destroy/create function declared in imgui_impl_opengl3.h

This will be streamlined and made simpler with future work.

cliche9 commented 1 year ago

Replace your delete/new sequence by calls to the clear function + call the destroy/create function declared in imgui_impl_opengl3.h

This will be streamlined and made simpler with future work.

Thanks! I solved the black screen problem by the replacement.

  1. When my screen resolution is set to 125%, the program goes wired. The mouse cannot operate correctly, as if a single mouse position occupies multiple pixels, making it impossible to perform proper positioning and selection operations.

Additionally, about question 3, I remove all the code about changing io.DisplaySize, io.DisplayFramebufferScale and io.MousePos in my newFrame function, now it works fine!

ocornut commented 1 year ago

Closing this.

Note that your approach will have some issues on Mac by default. We're working on standardizing a few things to make things works for everyone neatly.

wangzihe commented 1 year ago

@ocornut I am trying to use the above code to reload fonts when there is a change in DPI scale. However, I kept running into the following assert:

Assertion failed: cfg.DstFont && (!cfg.DstFont->IsLoaded() || cfg.DstFont->ContainerAtlas == atlas), file imgui_draw.cpp, line 2370

The assertion is really with io_ref.Fonts->Build. I don't know what this assertion is checking. Could you share some light on this? The assertation only happens when I tried to clear old fonts and then reload the font. It works okay when I first loaded the font.

Here is the system configuration:

Dear ImGui 1.89.4 (18940)
--------------------------------

sizeof(size_t): 4, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=199711
define: _WIN32
define: _MSC_VER=1934
define: _MSVC_LANG=201402
define: IMGUI_HAS_VIEWPORT
define: IMGUI_HAS_DOCK
--------------------------------

io.BackendPlatformName: imgui_impl_glfw
io.BackendRendererName: imgui_impl_opengl3

Here is the snippet of code I used to load/reload fonts when DPI scale changes.


    int dpi_scale_int = round(dpi_scale);
    ImFont* font = io_ref.Fonts->AddFontFromFileTTF(
        "./src/fonts/NotoSansSC-Light.otf",
        19.0f * dpi_scale, NULL,
        io_ref.Fonts->GetGlyphRangesChineseFull());
    if (font == NULL) {
        LOG(ERROR) << "Failed to load font file";
    }

    // merge in icons from Font Awesome
    ImFontConfig icons_config;
    icons_config.MergeMode = true;
    icons_config.PixelSnapH = true;
    io_ref.Fonts->AddFontFromFileTTF("./src/external/fa-solid-900.ttf",
        15.0f * dpi_scale, &icons_config, icons_ranges);

    io_ref.Fonts->Build();
    ImGuiIO& io_ref = ImGui::GetIO();
    if (io_ref.Fonts->Fonts.size()) {
        io_ref.Fonts->ClearFonts();
    }
    ImGui_ImplOpenGL3_DestroyFontsTexture();
    ImGui_ImplOpenGL3_CreateFontsTexture();
pengqiyu commented 9 months ago

aboute question 3, you can modify imgui_impl_win32.cpp -> ImGui_ImplWin32_WndProcHandler function, event WM_NCMOUSEMOVE, ''' io.AddMouseSourceEvent(mouse_source); float dpiScale = ImGui_ImplWin32_GetDpiScaleForHwnd(hwnd); int titleBarHeight = GetSystemMetrics(SM_CYCAPTION); RECT rect; GetWindowRect(hwnd, &rect); io.AddMousePosEvent((float)(mouse_pos.x - rect.left) / dpiScale + rect.left, (float)(mouse_pos.y - rect.top - titleBarHeight) / dpiScale + rect.top + titleBarHeight); '''

KarlHedlund commented 6 months ago

Just want to chime in that if you ended up in this thread while trying to solve DPI scaling and you've still got a black window, don't call io.Fonts->Build();

Here's what worked for me, calling it outside of NewFrame:

        io.Fonts->Clear();
        auto font1 = io.Fonts->AddFontFromFileTTF("C:/Windows/Fonts/Arial.ttf", 16);
        ImGui_ImplOpenGL3_DestroyFontsTexture();
        IM_ASSERT(ImGui_ImplOpenGL3_CreateFontsTexture());