-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added IO::WantRender bool to facilitate lazy rendering support. #5599
base: master
Are you sure you want to change the base?
Conversation
That sounds very good, thank you! |
oh! great, do I well understand? imgui will (at least) have a powersaving mode?!?! really, this is THE missing feature that prevent using imGUI to design applications... |
I think people seem to misunderstand that you can achieve 98% of the many PR above with 10 lines of code in your main loop, by just updating on user inputs change... many users have been doing it for years. What the PR do are mostly fixing a few blind spots, standardizing an API for widgets to communicate requests, and standardizing interactions with a backend. All of those can be achieved by the user already (even peeking for blinking spot elapsed time). EDIT I don't disagree that the official standardized version is essential to move forward. We will add it. I'm just saying you don't need any of those PR to use a system like that. EDIT 2 All the PR have issues, which is why they are not merged, but there are good ideas in each of them. |
Checking However, it quickly becomes apparent that it is not enough. There are at least two problems that require deeper knowledge of what ImGui is doing.
My very out of place question here is how to properly handle the second problem? |
I think the essence of #4076 is to provide those. The "internal" answer to (2) may be to check if g.DimBgRatio is neither 0.0f neither 1.0f. While I assume integrating backend-side and example stuff is going to be trickier, I don't mind at least prioritizing the work on providing those "want refresh" values (in the form of both 1 timer and 1 frame count), so at least custom apps can take advantage of them. |
Two things that may be of use:
|
Yup, it works. Thanks.
This is updated in |
I meant: I believe the result from InputTrail after NewFrame() can be used for the next frame. As many backends will submit duplicate event (eg same mouse position).
|
Ctrl+Tab window switching has a delay that require special handling. Seems like checking for |
I have encountered a peculiarity with this approach. The glfw backend (?) is inserting MousePos events into the queue when the mouse is outside the application window. It does not need to be moved. The events are consumed (I see only one MousePos event in the queue per "frame") and the reported position accurately represents the cursor location, relative to the top-left of the application window, possibly with negative numbers. When the mouse is inside the window, there are no MousePos events generated for a stationary mouse position. I have seen this on Windows and Linux. |
Correct, when focused or hovered, but they should be flagged with It's not even easy for the backend to do a no-op check because comparing to There's filtering done in We could maintain a copy of expected value of fields at one given time, but it would unsync if any field is modified externally. I guess the safest is to do a replay of a given event type on add. Since all events are overwriting, a backward search can be used instead of a full replay. Assuming a non-clogged InputQueue it shouldn't be too bad. Currently UpdateInputEvents() does: if (e->Type == ImGuiInputEventType_MousePos)
{
ImVec2 event_pos(e->MousePos.PosX, e->MousePos.PosY);
if (IsMousePosValid(&event_pos))
event_pos = ImVec2(ImFloorSigned(event_pos.x), ImFloorSigned(event_pos.y)); // Apply same flooring as UpdateMouseInputs()
e->IgnoredAsSame = (io.MousePos.x == event_pos.x && io.MousePos.y == event_pos.y);
if (!e->IgnoredAsSame)
{
// Trickling Rule: Stop processing queued events if we already handled a mouse button change
if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted))
break;
io.MousePos = event_pos;
mouse_moved = true;
}
} Instead we would need to change |
Not well tested but the gist of that idea would be: static ImGuiInputEvent* FindLastInputEvent(ImGuiInputEventType type)
{
ImGuiContext& g = *GImGui;
for (int n = g.InputEventsQueue.Size - 1; n >= 0; n--)
if (g.InputEventsQueue[n].Type == type)
return &g.InputEventsQueue[n];
return NULL;
} Then add in // Filter duplicate
ImGuiInputEvent* last_event = FindLastInputEvent(ImGuiInputEventType_MousePos);
ImVec2 last_mouse_pos = last_event ? ImVec2(last_event->MousePos.PosX, last_event->MousePos.PosY) : g.IO.MousePos;
if (IsMousePosValid(&event_pos))
last_mouse_pos = ImVec2(ImFloorSigned(last_mouse_pos.x), ImFloorSigned(last_mouse_pos.y)); // Apply same flooring as UpdateMouseInputs()
if (last_mouse_pos.x == x && last_mouse_pos.y == y)
return; Or possibly still add the event but immediately mark it with EDIT added flooring. |
|
Right, it was added since. Anyhow, if you can test the AddMousePosEvent() idea locally and confirm it works, I can work on finishing the fuller thing. |
It seems to be working, i.e. no events are put into queue when the mouse is not moving either in or outside the application window. Shouldn't however the behavior be to report mouse position (and click, wheel, etc) events only inside the window? |
Clicks and wheel are only reported when hovered or captured (eg clicked and dragging). Pos is always reported IF FOCUSED or HOVERED (which also imply not captured elsewhere), there are variety of reasons eg positionning a tooltip. If you have a large tooltip or image following the mouse you don’t it to disappear or clamp as soon as you move.
|
…ill filter earlier in next commit. (#5599) Making it a separate commit as this leads to much indentation change.
Thanks! |
commit cc5058e Author: ocornut <[email protected]> Date: Thu Sep 29 21:59:32 2022 +0200 IO: Filter duplicate input events during the AddXXX() calls. (ocornut#5599, ocornut#4921) commit fac8295 Author: ocornut <[email protected]> Date: Thu Sep 29 21:31:36 2022 +0200 IO: remove ImGuiInputEvent::IgnoredAsSame (revert part of 839c310), will filter earlier in next commit. (ocornut#5599) Making it a separate commit as this leads to much indentation change. commit 9e7f460 Author: ocornut <[email protected]> Date: Thu Sep 29 20:42:45 2022 +0200 Fixed GetKeyName() for ImGuiMod_XXX values, made invalid MousePos display in log nicer. (ocornut#4921, ocornut#456) Amend fd408c9 commit 0749453 Author: ocornut <[email protected]> Date: Thu Sep 29 19:51:54 2022 +0200 Menus, Nav: Fixed not being able to close a menu with Left arrow when parent is not a popup. (ocornut#5730) commit 9f6aae3 Author: ocornut <[email protected]> Date: Thu Sep 29 19:48:27 2022 +0200 Nav: Fixed race condition pressing Esc during popup opening frame causing crash. commit bd2355a Author: ocornut <[email protected]> Date: Thu Sep 29 19:25:26 2022 +0200 Menus, Nav: Fixed using left/right navigation when appending to an existing menu (multiple BeginMenu() call with same names). (ocornut#1207) commit 3532ed1 Author: ocornut <[email protected]> Date: Thu Sep 29 18:07:35 2022 +0200 Menus, Nav: Fixed keyboard/gamepad navigation occasionally erroneously landing on menu-item in parent when the parent is not a popup. (ocornut#5730) Replace BeginMenu/MenuItem swapping g.NavWindow with a more adequate ImGuiItemFlags_NoWindowHoverableCheck. Expecting more subtle issues to stem from this. Note that NoWindowHoverableCheck is not supported by IsItemHovered() but then IsItemHovered() on BeginMenu() never worked: fix should be easy in BeginMenu() + add test is IsItemHovered(), will do later commit d5d7050 Author: ocornut <[email protected]> Date: Thu Sep 29 17:26:52 2022 +0200 Various comments As it turns out, functions like IsItemHovered() won't work on an open BeginMenu() because LastItemData is overriden by BeginPopup(). Probably an easy fix. commit e74a50f Author: Andrew D. Zonenberg <[email protected]> Date: Wed Sep 28 08:19:34 2022 -0700 Added GetGlyphRangesGreek() helper for Greek & Coptic glyph range. (ocornut#5676, ocornut#5727) commit d17627b Author: ocornut <[email protected]> Date: Wed Sep 28 17:38:41 2022 +0200 InputText: leave state->Flags uncleared for the purpose of backends emitting an on-screen keyboard for passwords. (ocornut#5724) commit 0a7054c Author: ocornut <[email protected]> Date: Wed Sep 28 17:00:45 2022 +0200 Backends: Win32: Convert WM_CHAR values with MultiByteToWideChar() when window class was registered as MBCS (not Unicode). (ocornut#5725, ocornut#1807, ocornut#471, ocornut#2815, ocornut#1060) commit a229a7f Author: ocornut <[email protected]> Date: Wed Sep 28 16:57:09 2022 +0200 Examples: Win32: Always use RegisterClassW() to ensure windows are Unicode. (ocornut#5725) commit e0330c1 Author: ocornut <[email protected]> Date: Wed Sep 28 14:54:38 2022 +0200 Fonts, Text: Fixed wrapped-text not doing a fast-forward on lines above the clipping region. (ocornut#5720) which would result in an abnormal number of vertices created. commit 4d4889b Author: ocornut <[email protected]> Date: Wed Sep 28 12:42:06 2022 +0200 Refactor CalcWordWrapPositionA() to take on the responsability of minimum character display. Add CalcWordWrapNextLineStartA(), simplify caller code. Should be no-op but incrementing IMGUI_VERSION_NUM just in case. Preparing for ocornut#5720 commit 5c4426c Author: ocornut <[email protected]> Date: Wed Sep 28 12:22:34 2022 +0200 Demo: Fixed Log & Console from losing scrolling position with Auto-Scroll when child is clipped. (ocornut#5721) commit 12c0246 Author: ocornut <[email protected]> Date: Wed Sep 28 12:07:43 2022 +0200 Removed support for 1.42-era IMGUI_DISABLE_INCLUDE_IMCONFIG_H / IMGUI_INCLUDE_IMCONFIG_H. (ocornut#255) commit 73efcec Author: ocornut <[email protected]> Date: Tue Sep 27 22:21:47 2022 +0200 Examples: disable GL related warnings on Mac + amend to ignore list. commit a725db1 Author: ocornut <[email protected]> Date: Tue Sep 27 18:47:20 2022 +0200 Comments for flags discoverability + add to debug log (ocornut#3795, ocornut#4559) commit 325299f Author: ocornut <[email protected]> Date: Wed Sep 14 15:46:27 2022 +0200 Backends: OpenGL: Add ability to #define IMGUI_IMPL_OPENGL_DEBUG. (ocornut#4468, ocornut#4825, ocornut#4832, ocornut#5127, ocornut#5655, ocornut#5709) commit 56c3eae Author: ocornut <[email protected]> Date: Tue Sep 27 14:24:21 2022 +0200 ImDrawList: asserting on incorrect value for CurveTessellationTol (ocornut#5713) commit 04316bd Author: ocornut <[email protected]> Date: Mon Sep 26 16:32:09 2022 +0200 ColorEdit3: fixed id collision leading to an assertion. (ocornut#5707) commit c261dac Author: ocornut <[email protected]> Date: Mon Sep 26 14:50:46 2022 +0200 Demo: moved ShowUserGuide() lower in the file, to make main demo entry point more visible + fix using IMGUI_DEBUG_LOG() macros in if/else. commit 51bbc70 Author: ocornut <[email protected]> Date: Mon Sep 26 14:44:26 2022 +0200 Backends: SDL: Disable SDL 2.0.22 new "auto capture" which prevents drag and drop across windows, and don't capture mouse when drag and dropping. (ocornut#5710) commit 7a9045d Author: ocornut <[email protected]> Date: Mon Sep 26 11:55:07 2022 +0200 Backends: WGPU: removed Emscripten version check (currently failing on CI, ensure why, and tbh its redundant/unnecessary with changes of wgpu api nowadays) commit 83a0030 Author: ocornut <[email protected]> Date: Mon Sep 26 10:33:44 2022 +0200 Added ImGuiMod_Shortcut which is ImGuiMod_Super on Mac and ImGuiMod_Ctrl otherwise. (ocornut#456) commit fd408c9 Author: ocornut <[email protected]> Date: Thu Sep 22 18:58:33 2022 +0200 Renamed and merged keyboard modifiers key enums and flags into a same set:. ImGuiKey_ModXXX -> ImGuiMod_XXX and ImGuiModFlags_XXX -> ImGuiMod_XXX. (ocornut#4921, ocornut#456) Changed signature of GetKeyChordName() to use ImGuiKeyChord. Additionally SetActiveIdUsingAllKeyboardKeys() doesn't set ImGuiKey_ModXXX but we never need/use those and the system will be changed in upcoming commits. # Conflicts: # imgui.cpp # imgui.h # imgui_demo.cpp
commit 5884219 Author: cfillion <[email protected]> Date: Wed Sep 28 23:37:39 2022 -0400 imgui_freetype: Assert if bitmap size exceed chunk size to avoid buffer overflow. (ocornut#5731) commit f2a522d Author: ocornut <[email protected]> Date: Fri Sep 30 15:43:27 2022 +0200 ImDrawList: Not using alloca() anymore, lift single polygon size limits. (ocornut#5704, ocornut#1811) commit cc5058e Author: ocornut <[email protected]> Date: Thu Sep 29 21:59:32 2022 +0200 IO: Filter duplicate input events during the AddXXX() calls. (ocornut#5599, ocornut#4921) commit fac8295 Author: ocornut <[email protected]> Date: Thu Sep 29 21:31:36 2022 +0200 IO: remove ImGuiInputEvent::IgnoredAsSame (revert part of 839c310), will filter earlier in next commit. (ocornut#5599) Making it a separate commit as this leads to much indentation change. commit 9e7f460 Author: ocornut <[email protected]> Date: Thu Sep 29 20:42:45 2022 +0200 Fixed GetKeyName() for ImGuiMod_XXX values, made invalid MousePos display in log nicer. (ocornut#4921, ocornut#456) Amend fd408c9 commit 0749453 Author: ocornut <[email protected]> Date: Thu Sep 29 19:51:54 2022 +0200 Menus, Nav: Fixed not being able to close a menu with Left arrow when parent is not a popup. (ocornut#5730) commit 9f6aae3 Author: ocornut <[email protected]> Date: Thu Sep 29 19:48:27 2022 +0200 Nav: Fixed race condition pressing Esc during popup opening frame causing crash. commit bd2355a Author: ocornut <[email protected]> Date: Thu Sep 29 19:25:26 2022 +0200 Menus, Nav: Fixed using left/right navigation when appending to an existing menu (multiple BeginMenu() call with same names). (ocornut#1207) commit 3532ed1 Author: ocornut <[email protected]> Date: Thu Sep 29 18:07:35 2022 +0200 Menus, Nav: Fixed keyboard/gamepad navigation occasionally erroneously landing on menu-item in parent when the parent is not a popup. (ocornut#5730) Replace BeginMenu/MenuItem swapping g.NavWindow with a more adequate ImGuiItemFlags_NoWindowHoverableCheck. Expecting more subtle issues to stem from this. Note that NoWindowHoverableCheck is not supported by IsItemHovered() but then IsItemHovered() on BeginMenu() never worked: fix should be easy in BeginMenu() + add test is IsItemHovered(), will do later commit d5d7050 Author: ocornut <[email protected]> Date: Thu Sep 29 17:26:52 2022 +0200 Various comments As it turns out, functions like IsItemHovered() won't work on an open BeginMenu() because LastItemData is overriden by BeginPopup(). Probably an easy fix. commit e74a50f Author: Andrew D. Zonenberg <[email protected]> Date: Wed Sep 28 08:19:34 2022 -0700 Added GetGlyphRangesGreek() helper for Greek & Coptic glyph range. (ocornut#5676, ocornut#5727) commit d17627b Author: ocornut <[email protected]> Date: Wed Sep 28 17:38:41 2022 +0200 InputText: leave state->Flags uncleared for the purpose of backends emitting an on-screen keyboard for passwords. (ocornut#5724) commit 0a7054c Author: ocornut <[email protected]> Date: Wed Sep 28 17:00:45 2022 +0200 Backends: Win32: Convert WM_CHAR values with MultiByteToWideChar() when window class was registered as MBCS (not Unicode). (ocornut#5725, ocornut#1807, ocornut#471, ocornut#2815, ocornut#1060) commit a229a7f Author: ocornut <[email protected]> Date: Wed Sep 28 16:57:09 2022 +0200 Examples: Win32: Always use RegisterClassW() to ensure windows are Unicode. (ocornut#5725) commit e0330c1 Author: ocornut <[email protected]> Date: Wed Sep 28 14:54:38 2022 +0200 Fonts, Text: Fixed wrapped-text not doing a fast-forward on lines above the clipping region. (ocornut#5720) which would result in an abnormal number of vertices created. commit 4d4889b Author: ocornut <[email protected]> Date: Wed Sep 28 12:42:06 2022 +0200 Refactor CalcWordWrapPositionA() to take on the responsability of minimum character display. Add CalcWordWrapNextLineStartA(), simplify caller code. Should be no-op but incrementing IMGUI_VERSION_NUM just in case. Preparing for ocornut#5720 commit 5c4426c Author: ocornut <[email protected]> Date: Wed Sep 28 12:22:34 2022 +0200 Demo: Fixed Log & Console from losing scrolling position with Auto-Scroll when child is clipped. (ocornut#5721) commit 12c0246 Author: ocornut <[email protected]> Date: Wed Sep 28 12:07:43 2022 +0200 Removed support for 1.42-era IMGUI_DISABLE_INCLUDE_IMCONFIG_H / IMGUI_INCLUDE_IMCONFIG_H. (ocornut#255) commit 73efcec Author: ocornut <[email protected]> Date: Tue Sep 27 22:21:47 2022 +0200 Examples: disable GL related warnings on Mac + amend to ignore list. commit a725db1 Author: ocornut <[email protected]> Date: Tue Sep 27 18:47:20 2022 +0200 Comments for flags discoverability + add to debug log (ocornut#3795, ocornut#4559) commit 325299f Author: ocornut <[email protected]> Date: Wed Sep 14 15:46:27 2022 +0200 Backends: OpenGL: Add ability to #define IMGUI_IMPL_OPENGL_DEBUG. (ocornut#4468, ocornut#4825, ocornut#4832, ocornut#5127, ocornut#5655, ocornut#5709) commit 56c3eae Author: ocornut <[email protected]> Date: Tue Sep 27 14:24:21 2022 +0200 ImDrawList: asserting on incorrect value for CurveTessellationTol (ocornut#5713) commit 04316bd Author: ocornut <[email protected]> Date: Mon Sep 26 16:32:09 2022 +0200 ColorEdit3: fixed id collision leading to an assertion. (ocornut#5707) commit c261dac Author: ocornut <[email protected]> Date: Mon Sep 26 14:50:46 2022 +0200 Demo: moved ShowUserGuide() lower in the file, to make main demo entry point more visible + fix using IMGUI_DEBUG_LOG() macros in if/else. commit 51bbc70 Author: ocornut <[email protected]> Date: Mon Sep 26 14:44:26 2022 +0200 Backends: SDL: Disable SDL 2.0.22 new "auto capture" which prevents drag and drop across windows, and don't capture mouse when drag and dropping. (ocornut#5710) commit 7a9045d Author: ocornut <[email protected]> Date: Mon Sep 26 11:55:07 2022 +0200 Backends: WGPU: removed Emscripten version check (currently failing on CI, ensure why, and tbh its redundant/unnecessary with changes of wgpu api nowadays) commit 83a0030 Author: ocornut <[email protected]> Date: Mon Sep 26 10:33:44 2022 +0200 Added ImGuiMod_Shortcut which is ImGuiMod_Super on Mac and ImGuiMod_Ctrl otherwise. (ocornut#456) commit fd408c9 Author: ocornut <[email protected]> Date: Thu Sep 22 18:58:33 2022 +0200 Renamed and merged keyboard modifiers key enums and flags into a same set:. ImGuiKey_ModXXX -> ImGuiMod_XXX and ImGuiModFlags_XXX -> ImGuiMod_XXX. (ocornut#4921, ocornut#456) Changed signature of GetKeyChordName() to use ImGuiKeyChord. Additionally SetActiveIdUsingAllKeyboardKeys() doesn't set ImGuiKey_ModXXX but we never need/use those and the system will be changed in upcoming commits. # Conflicts: # docs/CHANGELOG.txt # imgui.h # imgui_demo.cpp
…ill filter earlier in next commit. (ocornut#5599) Making it a separate commit as this leads to much indentation change.
There seems to be some discrepancy with how different types of key strokes are processed. When the focus is in a text input box, and a key is held down, repeated key events will be reported, producing e.g. "aaaaaaaaa" input. However, if one would want to remove the entered text and holds down backspace or delete keys, only the first input event is reported. If the mouse is moved (i.e. when screen redraw requests are being issued) whilst the backspace/delete key is pressed, the repeated key press events are reported as expected. (For example, open https://tracy.nereid.pl/, click on the "Find zone" button on top. Then press and hold any key to enter text. Then press backspace and observe only the first event is handled. Then move the mouse, while still holding backspace.) |
Character Input events repeats are submitted by the backend. (1) We could make some effort at making IsKeyPressed() with "repeat" automatically request refresh at a future expected "repeat" point of time when the key is down. However it would be problematic the same way just using if (IsKeyDown(ImGuiKey_Left))
scroll_x -= speed * io.Deltatime. From the backend point of view there's no changes. Since not all UI will animate and it is more reasonable to request animating user code to notify the system, I guess we could implement (1) and (2.A). They both boil down to the same thing: outputting one timer (in second) and one counter (in frames) which may be set to request refresh, which gets us back to #4076. (2.B) is the "lazy" workaround which will solve most cases automatically but at higher refresh cost. It has the advantage that you can use it today without any mod to core lib. Other solutions will need adding that counter/timer. If we ignore the backend+examples side of #4076 the core-imgui side boils down to a few dozens lines. EDIT IsKeyPressed()
{
if (key is down && repeat wanted)
{
calculate time to next "repeat" event
schedule a refresh (io.WantRenderRemainingTime = ImMin(io.WantRenderRemainingTime, time_to_next_repeat_event);
}
} |
In if (action != GLFW_PRESS && action != GLFW_RELEASE)
return; So I'm not sure I understand the solutions you propose.
It's just the backspace and delete keys that break things for some reason. |
This is system repeat rate which we don't use (vs we uses varying repeat rate, and app/user can use varying repeat rate too).
It happens with all KEYS (e.g. I see same problem holding left or right arrow). For CHARACTERS we always follow OS repeat which are sending events. Lazy solution: you keep refreshing if focused and any key is held. Correct solution Dear ImGui needs to output fields for this, e.g.
For example,
EDIT If you look at e.g. /pull/4076/files you'll find one possible implementation of that. (I don't think the PR has the adequate "final" API but should help the grok the idea, which is pretty simple). |
Hi, I made the following modifications :
in my opinion some setting function should wrap the WantRenderAfterTimeElapsed and looks like
this rise the issue of a widget that require rendering at special interval so imagine we have theses 3 widgets, that videoFrame asked for a refresh 1/30s later, and cursor want to update the refresh also, both can be out of sync... maybe a better solution is to use C++ timers like https://en.cppreference.com/w/cpp/thread/sleep_for one issue is that framework like glfwWaitEventsTimeout are second timeout based... so for a 1/30 video frame update, it can't be used.... one option could be not rely on underlying framework but re-implement a wrapper on top it, something like that (return True if redraw is required)
issues :
|
I'm thinking of a thing.... instead of a ImGui::GetIO().WantRender boolean the idea behind this is to move time related operations in main app at end of re-display, the ImGui::GetIO().NextUpdateTime now contain the time at which the re-display must occurs to be certain that the displayed content will be accurate now, back to the event handler part... it's up to the app programmer to create the logic to handle both event and re-display, for example GLFW allow timeout at second resolution, so you can't rely on timeout to return, you might require to start the event handling in a thread and have this thread wake up the GUI display thread... SDL allow ms timeout, so it might be used since at 60fps a re-display occurs each 16ms.... so, let's back after a re-display is started (either because an event occurred or because the app slept and woke at NextUpdateTime) each widget will look at current time, and the next time they need to update and recompute the NextUpdateTime.... you might want to add a jitters information, for example a blinking cursor don't require accurate wake-up... a jitters of 100ms won't be noticed by user, same for a plot widget.... but a video frame widget need accurate wake-up redisplay occurs then at XXXX-10ms and either the blinking choose to sync in advance, either it will ask for a new wakeup... I've no idea at which is best.... Don't know if we can rely on display VSync for timing and retrieve VSync Hz info... if yes, NextUpdateTime could be an int in 1/VSyncHz, and we can slimply skeep redisplay and just sleep current thread for 1/VSyncHz until an event occurs or NextUpdateTime-- == 0.... using this approach let the app designer choose how to perform the power saving mode... *** EDIT *** *** EDIT 2 *** |
I see your point with the NextUpdateTime. But what I don't see is how this negates the need for WantRender. WantRender is supposed to tell me if something in ImGui changed so we're in need of a new render. I think this is a separate thing from the NextUpdateTime used for e.g. animations etc. |
It negates the need because setting WantRender to true is same as setting NextUpdateTime to 0. There's no need for 2 things to control the same functionality. |
Okay, but as long as ImGui does not drive any kind of animations internally (correct me if I'm wrong), is this not more of an application thing the NextUpdateTime? We are running full on lazy, and am not updating anything before some kind of input occurs. Is not WantRender more in line with others in ImGui like WantMouseCapture etc.. just to keep ImGui as simple as possible just with a value telling when it needs update or other? All animations are driven by own update logic in the application. |
I understood the problem correctly only after implementing a custom backend that had to deal with keymaps. So, for the sake of future people encountering this issue: Text input is hard. You need to have two separate systems for handling keyboard events. The first system is simple and only represents the state of keys being pressed. So, for example, you have keys 'Q', 'W', or 'E'. There are no separate lowercase keys for 'q', 'w', or 'e', as the physical key can only be pressed or not, with no influence by the external state. The second system has to take into account all the possible key mappings. The most basic mapping would be key 'A' producing the character 'a'. However, the sequence of keys 'Shift' + 'A' would produce the character 'A'. Or 'Alt' + 'A' would result in 'ą' when the Polish keyboard layout is enabled. The composition engine is not limited to simultaneous key presses. For example, the sequence of separate key presses 'Shift' + '`' (~), and then 'a' also produces 'ą' on Windows. You can probably imagine this is even more complex with Arabic or Asian text. Or maybe there's no keyboard at all. What if text input is provided by machine recognition of handwriting? ImGui doesn't care about all these nuances and simply expects to receive Unicode characters. The original problem results from ImGui combining both systems to handle input box entry. The complex composition system supports key repeat. The simple key-pressed system, which is used for keys such as backspace, enter, or the navigation arrows, does not. It may be worth mentioning that keyboard layouts are a thing (e.g., QWERTY vs. AZERTY). I'm not sure on which layer the scancode translation would be done. The hardware doesn't care about what is printed on keycaps, keyboard layouts are an OS-level feature. Would the simple key-pressed-or-not system receive the 'Q' key when 'A' is pressed, because the layout is AZERTY? Does it depend on the underlying OS or backend implementation? What would be the scancode for the 'ą/ę' key, which is present in the layout mimicing the traditional Polish typewriter key arrangement? |
@wolfpld Currently away but replying on my mobile. Since 1.87 (i think) we clarified and finished aligning all backends so that they are responsible for submitting translated Keys. So when you press CTRL+A the A key should match your current keyboard layout. SDL differenciate scancodes (keyboard physical location) from keycodes (after translation) but I think it would be equally unable to handle a CTRL+ combination with any character. But otherwise if you exclude the specific case of mods being held, all systems are sending Characters (eg: ą/ę) that can be used for text inputs and will work with any languages. Win32 menu handling/accelerators systems are using low-level functions to obtains the right characrer even when a keyboard modifier is held. I am pretty sure we could do the same using Win32 api but its unlikely to be possible with SDL and GLFW. |
@ocornut I'm trying to do a draft proposal using time, and I notice that there is lot of time information in imGui
|
Thank you for the offer but please don’t draft more proposals. We don’t need more contents/PR we need higher-quality PRs. Between the work of Corentin and some of the discussion with Bartosz (with perhaps amends to come) I have enough good reference to use for an official version of it. I am just lacking bandwidth and support and need to prioritize work. I can see there’s increased pressure for this to be in mainline and I imagine we’ll do the work for it in 1.9x. |
ok, as you want.... I see now that DeltaTime is computed by SDL/GLFW.... I know that the STL isn't the most interesting C++ library (in particular string and unicode support is just BIIIIP), but not sure that SDL/GLFW/... are good approach also... they aren't consistent, don't give access to high precision clock... some libs are better than others and I would say that using the STL when the feature is available is better when the design is well done and provide good system portability... |
@ocornut I am also interested in this, am currently doing a normal workaround like this:
This works, but of course doesn't address the "blinking cursor issue" - that of visually changing events that traditionally require a full ImGui update every frame. Especially when my main content is not visible and I only update on events. First, I want to propose the idea that layout changes should always either be initiated by a user action, or a result of a process that the user expects (e.g. the code will explicitly request the UI to update). Here's a quick and dirty demo for a label that changes around 120 times a second that now is updated even when the UI stack only updates on user input events (typical GLFW loop checking for InputEventsQueue.empty()), else just renders existing draw data). The label: ImGui::AlignTextToFramePadding();
static OnDemandState frameLabel = AddOnDemandText("Frame 00000");
ImGui::GetWindowDrawList()->AddCallback([](const ImDrawList* dl, const ImDrawCmd* dc)
{
RenderOnDemandText(&GetUI().onDemandDrawList, frameLabel, "Frame %d", GetApp().frameNumber);
}, nullptr);
// Instead of:
//ImGui::Text("Frame %d", GetApp().frameNumber); Custom Text implementation (simplified for my use case): struct OnDemandState
{
ImVec2 pos;
ImVec2 clipMin, clipMax;
ImFont *font;
float fontSize;
};
OnDemandState AddOnDemandItem(ImGuiID id, const ImRect &bb)
{
OnDemandState state;
state.pos = bb.Min;
state.clipMin = bb.Min;
state.clipMax = bb.Max;
ImGui::ItemSize(bb, 0.0f);
ImGui::ItemAdd(bb, id);
return state;
}
OnDemandState AddOnDemandText(const char* maxText)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return {};
const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
const ImVec2 text_size = ImGui::CalcTextSize(maxText, NULL, true, 0.0f);
OnDemandState state = AddOnDemandItem(ImGui::GetID(maxText), ImRect(text_pos, text_pos + text_size));
state.font = ImGui::GetFont();
state.fontSize = ImGui::GetFontSize();
return state;
}
void RenderOnDemandText(ImDrawList *drawList, const OnDemandState &state, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
RenderOnDemandTextV(drawList, state, fmt, args);
va_end(args);
}
void RenderOnDemandTextV(ImDrawList *drawList, const OnDemandState &state, const char* fmt, va_list args)
{
const char* text, *text_end;
ImFormatStringToTempBufferV(&text, &text_end, fmt, args);
drawList->PushTextureID(state.font->ContainerAtlas->TexID);
drawList->AddText(state.font, state.fontSize, state.pos, ImGui::GetColorU32(ImGuiCol_Text), text, text_end);
drawList->PopTextureID();
} User rendering code: GetUI().onDemandDrawList._ResetForNewFrame();
GetUI().onDemandDrawList.PushClipRectFullScreen();
// Render 2D UI with callbacks at appropriate places for on-demand items
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
ImGuiViewport *viewport = ImGui::GetMainViewport();
const bool is_minimized = (viewport->Flags & ImGuiViewportFlags_IsMinimized) != 0;
ImDrawData draw_data = {};
draw_data.Valid = true;
draw_data.CmdListsCount = 0;
draw_data.TotalVtxCount = draw_data.TotalIdxCount = 0;
draw_data.DisplayPos = viewport->Pos;
draw_data.DisplaySize = is_minimized ? ImVec2(0.0f, 0.0f) : viewport->Size;
draw_data.FramebufferScale = ImGui::GetIO().DisplayFramebufferScale;
draw_data.OwnerViewport = viewport;
ImGui::AddDrawListToDrawDataEx(&draw_data, &draw_data.CmdLists, &GetUI().onDemandDrawList);
ImGui_ImplOpenGL3_RenderDrawData(&draw_data); Of course, this always renders the up-to-date data ontop, a proper implementation would actually render in-place in RenderOnDemand*, but then it would have to directly interface with the render backend - or you do it for your application manually (render-backend-specific) and then emit a ResetRenderState command right after. There's no way to modify the existing draw list with the vertex data already packed and uploaded to the GPU. Anyway, this is just a push to consider animations not part of the UI update, but as part of the rendering, and for animating UI code to be aware of that distinction. But my problem isn't actually the CPU, and this would only help CPU usage, which at 0.1-0.3% for just the GUI is really not a problem for me (I'm very happy with how ImGui performs on the CPU). The first proposition would still help anyway, with some animated updates now having screen coordinates associated with it, we could then consider to only render the area of the screen that the animation is part of. radeontop reports the bottleneck is still the "clip rectangle" stage of the graphics pipeline, but it dropped from 70% use to 30%. Most other pipelines (fragment based) dropped from 50% to 10%. So there's definitely a lot to gain, though it's still less than what I would have expected from rendering just a tiny part of the screen. Maybe the UI draw calls are batched so well that the CPU clipping doesn't do much, and the glScissors still has to clip and discard a ton of vertices, keeping that the main bottleneck. Now one final concern for me is that some events like mouse move would still trigger a full window re-render. Of course this is all a lot to consider and you might already have your idea on how to address this. Maybe this input will help you, maybe you already decided. Let me know if you want a full code example or anything. |
For me, I prefer to provide interfaces like IO.IsDirty and MarkDirty. I'm working on a game editor and have done some research using ImGui. Its API is similar to Unity's GUILayout. GUILayout::Button(GUIContent content, GUIStyle style, params GUILayoutOption[] options);
GUILayout::Label(GUIContent content, GUIStyle style, params GUILayoutOption[] options); I adopted Yoga as the layout engine. In each GUILayout::Func, I create a Yoga node, and after Yoga calculates the layout, I pass the position information to ImGui for rendering. It works pretty well and allows me to precisely control the position, size, and other aspects of UI elements. Based on this, it's easy to implement a stack layout. Currently, I'm troubled by performance issues because Yoga's layout calculation is very time-consuming. My approach is to accumulate the hash of all elements in the current frame and compare it with the previous frame to determine whether re-layout is needed (obviously, this could lead to bugs, such as cases where the hash doesn't change but the UI size does). If ImGui had an interface to indicate whether a redraw is needed, it would be perfect. I'm sorry that I can't provide the code at the moment, as my current backend uses Qt RHI, and as my research needs evolved, the code became quite messy. If anyone is interested, I will tidy it up when I have some time. |
In order to run more efficiently power-usage wise on browsers and mobile units where battery consumption is an issue we need a way to know when we need to update and render.
This solution have given high improvements when it comes to power consumption as we can check this variable in addition to the key/mouse flags for when we need to render.
It also gives a gain for desktops and other devices for cpu/gpu usage.