Skip to content
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

Another Power Saving Mode #5116

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

sergeyn
Copy link
Contributor

@sergeyn sergeyn commented Mar 18, 2022

This is a follow up to earlier request #3124 (which was auto-closed because I'm a git noob still)
The idea behind this pull request is to ONLY render a frame when there's either a change due to animation or mouse/keyboard event happened. You can still use it the old way (i.e. - render every frame as fast as possible), but for desktop-like application not rendering when nothing changed is a must-have feature, which is what this pull request implements. The reason I like this approach is that completely no rendering happens if there's no active animation or user input, compared to other approaches which simply reduce the framerate

Let me know if you find some dynamic feature which doesn't get handled properly by this update.

Features in this request (I've updated only dx12 backend):

  • frame is rendered only when it needs to render
  • reason for frame render is shown in console
  • fixed spurious mouse events causing needles updates
  • fixed dpi handling and added redraw on dpi change (and made dpi-enabled as default) (dx12 backend only)

@sergeyn sergeyn changed the title Key features: Another Power Saving Mode Mar 18, 2022
@sergeyn sergeyn force-pushed the another_power_saving_mode branch 2 times, most recently from 9ae268b to c180c7a Compare March 18, 2022 10:18
@sergeyn
Copy link
Contributor Author

sergeyn commented Mar 18, 2022

Linking other requests/discussions on the topic I could find:
#4133
#4076
#5023
#3124
#2749
#2268
#2901
#3220
#4284
#4133
#5140

@ForrestFeng
Copy link

Hi sergeyn,

I tried your code change and found one issue, the Plotting animation stops when the mouse moving is stopped. I donot think this is the expected result. Please check the original Plotting example.

IMOP, the power save mode should not break the animation or other dynamic UI changes.

image

@ocornut
Copy link
Owner

ocornut commented Mar 20, 2022 via email

@sergeyn
Copy link
Contributor Author

sergeyn commented Mar 20, 2022

@ForrestFeng - sure thing, thanks for reporting this. Fixed now.

@ocornut - Api function added ( ImGui::SetNextRefresh ) . But I'm sure you'll want to change things around whether you decide to get this in

 - added api function (ImGui::SetNextRefresh)
 - fixed windows not redrawing when closing via close button
@ForrestFeng
Copy link

ForrestFeng commented Mar 21, 2022

@sergeyn thanks for fixing it.

I have one question:
What's the best way to implement a battery and clock display with the current power-saving API.

The battery requires a much lower refresh frequency. The clock requires 1 refresh per minute. A clock with the second digit requires 1 refresh per second.

What's the best way to handle the different refresh frequency requirements with the API. Thanks.

Can we control how many frames to redraw with the API. For example, when the time changes from 7:22 to 7:23 I just want to redraw 2 or 3 frames, I do not want to waste the power to refresh the GUI all the time just for this clock.

image

@ForrestFeng
Copy link

@sergeyn one more defect found that the scroll bar is not synchronized with content changes in the window.

Steps to recreate:

  1. Open the Table Columns sample
  2. Move the mouse over the Open All button
  3. Left click (when click keep it in the same position)
  4. You can see the content is expanded
    Expect:
    The scroll bar becomes shorter immediately
    Actual:
    The scroll bar keeps in the old status unless you move the mouse.

image

Key features:
   - frame is rendered only when it needs to render
   - reason for frame render is shown in console
   - fixed spurious mouse events resulting in needles updates
   - fixed dpi handling (and made dpi-enabled as default)
   - fixed plot animations
   - added api function (ImGui::SetNextRefresh)
   - fixed windows not redrawing when closing via close button
   - fixed scrollbar resize when container window grows
@sergeyn
Copy link
Contributor Author

sergeyn commented Mar 21, 2022

@ForrestFeng - fixed scrollbar issue. thanks for reporting.

@ForrestFeng - as for your refresh question, you need to compute how much time should pass before you'd have a frame with a changed clock arrow (at any point in time) and shove it into SetNextRefresh

auto NextRefreshDelayInSeconds = NextTimeMyFancyClockShouldTick_TimePoint - (ImGui::GetTime()-LastTimeMyFancyClockTicked_TimePoint); ImGui::SetNextRefresh(float(NextRefreshDelayInSeconds), "My Fancy Clock Just Moved");

Note that you actually need to do this computation, it's not enough to just set refresh delay (first parameter to SetNextRefresh) to 1.0f (for 1 second) because this way another random refresh (due to mouse move for example) happening mid-way through your second (or minute) would always offset your re-render by 1 second, and this is not what you want

@ocornut - I had to compute final window size at the End() to know if scroll bar potentially going to change next update. Not an ideal solution as I'd like to have it to be completely zero cost. Do you happen to know a better approach of knowing if the scorllbar going to change ?

@ForrestFeng
Copy link

Note that you actually need to do this computation, it's not enough to just set refresh delay (first parameter to SetNextRefresh) to 1.0f (for 1 second) because this way another random refresh (due to mouse move for example) happening mid-way through your second (or minute) would always offset your re-render by 1 second, and this is not what you want

I do not quite understand the logic. Can you let me know how the delay/API works? Can we just complete the goal with a simple API like RequestRepaint() without any parameter?

Thanks.

@sergeyn
Copy link
Contributor Author

sergeyn commented Mar 21, 2022

Note that you actually need to do this computation, it's not enough to just set refresh delay (first parameter to SetNextRefresh) to 1.0f (for 1 second) because this way another random refresh (due to mouse move for example) happening mid-way through your second (or minute) would always offset your re-render by 1 second, and this is not what you want

I do not quite understand the logic. Can you let me know how the delay/API works? Can we just complete the goal with a simple API like RequestRepaint() without any parameter?

Thanks.

If you want RequestRepaint without any parameter, you simply pass 0.0f, ""

Api is quite simple: with the first parameter you specify the maximum amount of seconds you want next update to be delayed by. If you put 2.0f there, that means if no other repaint events happen, you'll get your repaint in 2 seconds.
The last parameter is a string for debugging purposes. It'll be shown in the console as the repaint reason.

@ForrestFeng
Copy link

@sergeyn and @ocornut

I create another PR for power save working mode based on the idea of sergeyn. It is compatible with the old no-blocking drawing mode while providing flexibility to have the power save feature.

Could you take a look at it?

Thanks

@sergeyn
Copy link
Contributor Author

sergeyn commented Mar 27, 2022

It is compatible with the old no-blocking drawing mode while providing flexibility to have the power save feature.

Hi! Plz correct me if I'm wrong. The mechanics you propose with RequestRedraw is exactly the same as mine when zero delay passed as an argument (i.e. SetNextRefresh(0.0) ). As I understand it, your approach doesn't handle blinking cursor type of animation, where you need to redraw once about every second, unless you make blinking cursor redraw all the time.

Regards.

@sergeyn
Copy link
Contributor Author

sergeyn commented Mar 27, 2022

One more repaint optimization I'm thinking about is to track the rectangle of the currently hovered over window. Then within this rectangle mouse move events can be ignored. Given that mouse move events are the repaint reason in 99% of the cases, this would drastically reduce amount of repaints happening when you actually work with an application.

@FanisDeligiannis
Copy link

Are there any plans of this being officially implemented, for other APIs and for docking branch?

@ocornut
Copy link
Owner

ocornut commented Jun 21, 2022 via email

@FanisDeligiannis
Copy link

Thank you! For now I've limited my UI to 10fps, which seems good enough, and that has reduced GPU usage to "good enough" levels.

ocornut added a commit that referenced this pull request May 7, 2024
…#7556, #5116 , #4076, #2749, #2268)

currently: ImGui::SetNextWindowRefreshPolicy(ImGuiWindowRefreshFlags_TryToAvoidRefresh);
- This is NOT meant to replace frame-wide/app-wide idle mode.
- This is another tool: the idea that a given window could avoid refresh and reuse last frame contents.
- I think it needs to be backed by a careful and smart design overall (refresh policy, load balancing, making it easy and obvious to user).
- It's not there yet, this is currently a toy for experimenting.
My other issues with this:
- It appears to be very simple, but skipping most of Begin() logic will inevitably lead to tricky/confusing bugs. Let's see how it goes.
- I don't like very much that this opens a door to varying inconsistencies
- I don't like very much that it can lead us to situation where the lazy refresh gets disabled in bulk due to some reason (e.g. resizing a dock space) and we get sucked in the temptation to update for idle rather than update for dynamism.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants