Version/Branch of Dear ImGui:
1.93.1 WIP, branch docking
Back-ends:
imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp (GLFW 3.3.10)
Compiler, OS:
g++ 13.3, Linux Mint 22.3 (kernel 6.8), X11, Xfce 4.18 / xfwm4 with compositing, Mesa Intel HD 630, single 1920x1080 60 Hz monitor
Full config/build information:
Dear ImGui 1.93.1 WIP (19301)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=201103
define: __linux__
define: __GNUC__=13
define: IMGUI_HAS_VIEWPORT
define: IMGUI_HAS_DOCK
IM_ASSERT: runs expression: OK. expand size: OK
--------------------------------
io.BackendPlatformName: imgui_impl_glfw (3310)
io.BackendRendererName: imgui_impl_opengl3
io.ConfigFlags: 0x00000483
NavEnableKeyboard
NavEnableGamepad
DockingEnable
ViewportsEnable
io.ConfigDpiScaleFonts
io.ConfigDpiScaleViewports
io.ConfigViewportsNoDecoration
io.ConfigViewportsNoDefaultParent
io.ConfigNavCaptureKeyboard
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x00001C1E
HasMouseCursors
HasSetMousePos
PlatformHasViewports
HasMouseHoveredViewport
RendererHasVtxOffset
RendererHasTextures
RendererHasViewports
--------------------------------
io.Fonts: 1 fonts, Flags: 0x00000000, TexSize: 512,128
io.Fonts->FontLoaderName: stb_truetype
io.DisplaySize: 1280.00,800.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------
style.WindowPadding: 8.00,8.00
style.WindowBorderSize: 1.00
style.FramePadding: 4.00,3.00
style.FrameRounding: 3.00
style.FrameBorderSize: 0.00
style.ItemSpacing: 8.00,4.00
style.ItemInnerSpacing: 4.00,4.00Details:
When I drag ImGui window out of the main viewport it jiggles and stutters. Drag "Hello, world!" window out of the main viewport and back, then drag it around the desktop for 10–20 seconds. It will lag the cursor by a varying amount. Combine with left click releases when inside the viewport.
Seems to be related to #2117.
Disclaimer: Code work done by Claude and reviewed by me. I intentionally did not open PR due to LLM / AI contribution policy. Nevertheless I wanted to share this with others and upstream authors can take the idea and implement the fix on their own if they like.
Code with changes: https://github.com/hinxx/imgui/tree/viewport-drag-latency
Two issues were observed:
- One slow frame when draggin ImGui window out of main viewport
Today UpdatePlatformWindows() creates the platform window at the moment the window no longer fits the
host viewport; in the middle of the draging it out. At 60Hz vsync I get a frame that takes about ~100 ms and it is noticable as a glitch in movement.
- window position is updated once per frame, so it wobbles when dragged
After trying out several things like turning the xfce4 compositor off, which did help, but not completely the issue iss that ImGui samples the mouse once per frame (for me 16 ms with 60hz refresh rate). This makes ImGui position and WM position out of sync and results in wobbles or jitter in window posisiton. Brute force solution is not using vsync (refresh at > 300 frames/s) but then CPU cycles are wasted.
Three changes that fix the above:
- have a pool of hidden platform windows instead of destroying them. this is created at init and reduces first slow frame time when draggin window out by factotr of ~2.
io.ConfigViewportsOwnViewportOnMove(new, default off): set own viewport when the drag starts and not when the window starts leaving the viewport.- "Late mouse pos latching" in app main loop does extra mouse poll just before the next vblank at high rate (~500 time a asec).
With 2+3 the stutter is gone for me as far as I was able to test.
Questions
Is having a window pool acceptable?
Is a core flag like ConfigViewportsOwnViewportOnMove OK?
Where would late mouse pos latching belong (maybe it is apps bussiness and not a concern for imgui)?
Screenshots/Video:
Before fix the wobble is noticeable as is the glitch when window leaves the main viewport: IMGUI_GLFW_WINDOW_POOL=0 ./example_glfw_opengl3:
https://github.com/user-attachments/assets/c71dad07-f7d4-4e09-822e-f25988b26b6f
Fixed: IMGUI_OWNVP=1 IMGUI_LATELATCH=500 ./example_glfw_opengl3
https://github.com/user-attachments/assets/e780645b-f4b7-487a-ac01-b028ab3d83f1
It might a bit hard to tell what the improvement is on the video, but one telling sign is the mouse pointer being glued to the window titlebar on move for the fixed vs. the wobbly where it visibly looks "detached".
Minimal, Complete and Verifiable Example code:
The code fixes in my branch can be selectively enabled or disabled to observe the improvement.
Observed behavior before fix (stock code) with lots of debug for analysis with scripts/llm:
IMGUI_DIAG=1 IMGUI_GLFW_WINDOW_POOL=0 ./example_glfw_opengl3Fixes applied, no more stutter on move out and not wobble outside the main viewport:
IMGUI_OWNVP=1 IMGUI_LATELATCH=500 ./example_glfw_opengl3See the code for some other env variables that you play arond with, but these 2 IMGUI_OWNVP=1 IMGUI_LATELATCH=500 do th etrick for me..
See misc/debug/viewport_drag/ for scripts that were used for analysis (need xdotool) and some notes on automated tests done by Claude. I tested the behavior manually to confirm that the wobble is gone.
Activity
5
- Why does dragging a non-main window out of the main window—when using independent viewports—cause lag? Based on my recent experiments with multi-threading in Dear ImGui, it appears that once a non-main window’s bounding rectangle extends beyond the boundaries of the main window, the underlying ImGui implementation creates a separate, full-fledged window (a complete GLFW window). This is likely the source of the lag.
Yes, the GLFW window creation is one the problem, and I measured it using the scripts in my fork: glfwCreateWindow ~60 ms, first glfwMakeContextCurrent ~20 ms, glfwShowWindow ~15 ms. The whole pull-out frame is ~100 ms.
- Conversely, dragging that window back into the main window area triggers the destruction of that separate GLFW window. This behavior is baked into the core of ImGui; I’m skeptical that a "window pool" approach would be effective here (though that’s just my personal take).
ImGui still calls Platform_CreateWindow and Platform_DestroyWindow exactly as before; the GLFW backend just serves them from hidden windows created at init instead of creating them when the window boundary is crossed. I saw Platform_CreateWindow droped to ~ 1 ms and the pull-out frame to ~ 35 ms. So yes, the pool does not ocmpletely eliminate the stutter, but it becomes noticeably smaller. and only happens the first time the window leaves the main viewport. I did not notice any lag on window destroy once dropped inside the main viewport..
You can observe the behavior of ImGui sub-windows as they enter or leave the main window when multi-viewport support is enabled. When a sub-window enters the main window, the corresponding system-level window is destroyed; conversely, when it leaves, a new system-level window is created. By "system-level window," I am referring to an actual OS-level window—distinct from the "pure" ImGui windows that exist solely within the main window (which is the case when io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable is not set). With this configuration enabled, system-level windows are dynamically created or destroyed as needed. You can actually observe this creation and destruction process taking place in Task Manager. This is based on my testing on Windows using version 1.92.
Hello, PR would be easier to track and discuss. Attaching a copy of the commits for now until I can read/review. imgui-76dab9b-9a7e3f9.patch
(PS: @denggold68-eng Hiding your comment. You are describing Multi-Viewports, @hinxx and I understand them. Please read the Glossary before making further posts about that topic, thank you 🙏 )
//
I think there are two completely unrelated topics discussed here and they should be discussed separately. As those backend dependent issues are extremely tricky to move forward with, bundling two issues in one is likely to hinder progress. Please create a separate topic if you want to discuss late latching?
1. Initial Window Creation
This is hugely driver-dependent. As a side note, drivers makers should be kept pressured to fix their code so it doesn't take 100 ms.
Your two first commits (pools and pre-creating windows) are two solutions for a same problem. I am not ruling out that both would be desirable but at minimum they should be measured and compared. Intuitively if we use the pool you should not need to pre-create windows on move (and to a lesser degree vice-versa).
If would be also interesting to consider if more of the pooling logic could be handled by the core lib (assuming it simplify things- i don't know yet).
2. Late latching
This itself is a large open-ended topic. It could apply to imgui windows as well as viewport/platform windows separately. It's going to be difficult to find one solution that satisfies everyone but we should still try and discuss our experiments. Please open an issue and paste explanation/patches for your approach.
I presume it may be possible to come up with an API designed for late latching. At core it is simply an io.AddMousePosEvent() call or equivalent which may or not need tagging for late latching. If called before RenderDrawData() it could potentially be used to offset a given window draw list? And it could also potentially be used to offset platform windows. Most of that code could be potentially kept in core, with app taking responsibility for the more opinionated decisions (e.g. time racing to end of frame).
Why does dragging a non-main window out of the main window—when using independent viewports—cause lag? Based on my recent experiments with multi-threading in Dear ImGui, it appears that once a non-main window’s bounding rectangle extends beyond the boundaries of the main window, the underlying ImGui implementation creates a separate, full-fledged window (a complete GLFW window). This is likely the source of the lag. Conversely, dragging that window back into the main window area triggers the destruction of that separate GLFW window. This behavior is baked into the core of ImGui; I’m skeptical that a "window pool" approach would be effective here (though that’s just my personal take). Where would late mouse pos latching belong (maybe it is apps bussiness and not a concern for imgui)? If you want to introduce a delay to the mouse position, you would likely need to modify the code yourself; the standard, official example code doesn't provide a built-in way to handle this—you would need to implement a hook.