ocornut / imgui

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

GLFW backend: Assertion "Monitor work bounds not setup properly" #7219

Open Artrender opened 7 months ago

Artrender commented 7 months ago

Version/Branch of Dear ImGui:

Version 1.90.1 WIP, Branch:docking

Back-ends:

imgui_impl_opengl3.cpp + imgui_impl_glfw.cpp

Compiler, OS:

Windows 11 Visual Studio 2022, Windows 10 Visual Studio 2019

Full config/build information:

No response

Details:

My Issue: Assertion failed! Error for some monitors 4k with a scale less than 150% on Windows 11 and on one monitor on Windows 10 with the latest GLFW library updated to v 3.3

At startup of the application it gives:

Microsoft Visual C++ Runtime Library

Assertion failed!

Program: ...m File: ...:...\imgui\imgui.cpp Line: 9880

Expression: ImRect(mon.MainPos, mon.MainPos + mon.MainSize).Contains(ImRect(mon.WorkPos, mon.WorkPos + mon.WorkSize)) && "Monitor work bounds not setup properly. If you don't have work area information, just copy MainPos/MainSize into them."

For information on how your program can cause an assertion failure, see the Visual C++ documentation on asserts

(Press Retry to debug the application - JIT must be enabled)

Abort Retry Ignore

Screenshots/Video:

imgui error

The error disappears if I downgrade to GLFW lib 3.2, but I loose many features that I need - like transparent GLFW and frameless.

ocornut commented 7 months ago

Can you report the contents of the platform_io.Monitors[] array, and find how/why that data is emitted from the GLFW platform callback?

ocornut commented 7 months ago

Also please report the return value of glfwGetMonitorContentScale().

Artrender commented 7 months ago

I used: //platform_io.Monitors[]

ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
for (int i = 0; i < platform_io.Monitors.Size; i++)
{
    const ImGuiPlatformMonitor& mon = platform_io.Monitors[i];
    // Print or log the monitor information
    printf("Monitor %d:\n", i);
    printf(" MainPos: (%.1f, %.1f)\n", mon.MainPos.x, mon.MainPos.y);
    printf(" MainSize: (%.1f, %.1f)\n", mon.MainSize.x, mon.MainSize.y);
    printf(" WorkPos: (%.1f, %.1f)\n", mon.WorkPos.x, mon.WorkPos.y);
    printf(" WorkSize: (%.1f, %.1f)\n", mon.WorkSize.x, mon.WorkSize.y);
    printf(" DpiScale: %.1f\n\n", mon.DpiScale);
}

//Get Monitor Content Scale
int monitorCount;
GLFWmonitor** monitors = glfwGetMonitors(&monitorCount);

for (int i = 0; i < monitorCount; ++i)
{
    float xscale, yscale;
    glfwGetMonitorContentScale(monitors[i], &xscale, &yscale);
    printf("Monitor %d content scale: x = %f, y = %f\n", i, xscale, yscale);
} 

Got: Monitor 0: MainPos: (0.0, 0.0) MainSize: (3840.0, 2160.0) WorkPos: (0.0, 0.0) WorkSize: (3840.0, 2088.0) DpiScale: 1.5

Monitor 1: MainPos: (-3840.0, 0.0) MainSize: (3840.0, 2160.0) WorkPos: (-4608.0, 0.0) WorkSize: (4608.0, 2520.0) DpiScale: 1.5

Monitor 0 content scale: x = 1.500000, y = 1.500000 Monitor 1 content scale: x = 1.500000, y = 1.500000 Assertion failed: ImRect(mon.MainPos, mon.MainPos + mon.MainSize).Contains(ImRect(mon.WorkPos, mon.WorkPos + mon.WorkSize)) && "Monitor work bounds not setup properly. If you don't have work area information, just copy MainPos/MainSize into them.", file H:\DigitalEdge\imgui-base-app\imgui\imgui.cpp, line 10048

But it looks that this is not accurate information from glfw, as the scale for Monitor 1 (in Windows it is 2) is 125%, not 150%

image
ocornut commented 7 months ago

This looks incorrect:

MainPos: (-3840.0, 0.0)
MainSize: (3840.0, 2160.0)
WorkPos: (-4608.0, 0.0)
WorkSize: (4608.0, 2520.0)

WorkPos/WorkSize doesn't fit in MainPos/MainSize.

Can you try examples/example_win32_directx11 and examples/example_sdl2_opengl3 ? See what is reported by those? You can visualize the Monitors information in Demo->Tools->Metrics->Viewport. Just check if the WorkPos/WorkSize looks correct with those. Depending on the result of this we can see where to investigate further.

But it looks that this is not accurate information from glfw, as the scale for Monitor 1 (in Windows it is 2) is 125%, not 150%

DPI feedback in Windows is a mess (depends on app manifest, process settings, etc.), so I wouldn't worry too much about that but indeed it is odd.

Artrender commented 7 months ago

Thank you, Omar, for your prompt responses. It seems that I have identified the potential cause of the issue.

The error occurs when I use the SetProcessDPIAware() function, and it only happens with certain monitors. Using this function might be affecting how the application handles DPI scaling, especially when interacting with monitors that have different DPI settings.

Should I refrain from using SetProcessDPIAware() in the future to avoid such issues? Is there a recommended approach to ensure DPI awareness across various monitors that you would suggest?

ocornut commented 6 months ago

It would be good if you compared with Win32 and SDL2 backends as requested.

Should I refrain from using SetProcessDPIAware() in the future to avoid such issues? Is there a recommended approach to ensure DPI awareness across various monitors that you would suggest?

I don't know. This may be a GLFW bug as well, without additional information I cannot tell.

RMilenkovic commented 5 months ago

Had the same issue. Resolved it by calling SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) instead of SetProcessDPIAware().

With SetProcessDPIAware() in ImGui_Impl_glfw.cpp :

#if GLFW_HAS_PER_MONITOR_DPI
        // Warning: the validity of monitor DPI information on Windows depends on the application DPI awareness settings, which generally needs to be set in the manifest or at runtime.
        float x_scale, y_scale; // <----- THESE VALUES END UP BEING 0.0f but only for one of my three monitors.
        glfwGetMonitorContentScale(glfw_monitors[n], &x_scale, &y_scale);
        if (x_scale == 0.0f || y_scale == 0.0f)
        {
            const char* err_desc = nullptr; //<------- Win32: Failed to query monitor DPI
            int error_code = glfwGetError(&err_desc); // <-------------- ERROR CODE 65544
        }
        monitor.DpiScale = x_scale;
#endif
...

SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) resolves this.