-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Frame rate limiting #1343
Comments
In this discussion, I think it's important to clearly distinguish between "frame rate" (how often your screen draws), "system tick rate" (how often a given system runs) and "game tick rate" (how often the main game loop runs). I think these are all important to be able to control and limit ergonomically, but the details are a bit distinct. Currently, as I understand it, there are three ways to tackle this sort of functionality:
(Chime in if my understanding is wrong; I haven't poked at this much myself.) |
This is not relevant to this issue. That's something to be discussed with Run Criteria (as you point out). Here we are talking about the global refresh rate. "game tick rate" is coupled with rendering frame rate, by design, so they are practically synonymous.
VSync is orthogonal. There needs to be a frame rate limiter independent of vsync. VSync is about presenting the frames with the correct timing (synchronized to the monitor), not about framerate. It is to ensure the frames are displayed correctly on the screen, without visual artifacts (tearing). Vsync can (and preferably should, when supported; we are already doing this in bevy) be implemented in a way that does not limit frame rate. See "mailbox vsync". Also the various vendor/driver provided solutions that go by various names like "adaptive sync", "fast sync", whatever. As for GUI applications, you don't want to refresh at all if there is nothing to do. Unlike games, they are mostly idle. Therefore, for proper power savings for GUI apps, there needs to be more flexible and aggressive throttle control, to only refresh when there are things to do: handle external events / input, ongoing animations, any change that needs to update the UI / screen. |
I don't think this is a particularly good design, merely a convenient one. If we're discussing ways in which users can control and limit the performance of their game, I think that drawing this distinction and working towards the decoupling of the concepts is an important part of the puzzle. For example, relevant to your point on non-game applications: we may want to allow the main logic loop to proceed unimpeded, while the rendering is paused completely until there is something new to draw (or the window is focused). |
Yeah I think the next step forward here is decoupling rendering from "game updates", which we have discussed a bit here: #1098 (comment) This opens up the door to "frame rate limiting", "pipelined rendering", disabling rendering when minimized / unfocused, etc. |
the mailbox option doesn't do framelimiting on some devices. we need to rely on vsync for framelimiting until bevy supports framelimiting internally. bevyengine#1343
the mailbox option doesn't do framelimiting on some devices. we need to rely on vsync for framelimiting until bevy supports framelimiting internally. #1343
the mailbox option doesn't do framelimiting on some devices. we need to rely on vsync for framelimiting until bevy supports framelimiting internally. bevyengine#1343
I'm assuming that by "decoupling rendering" you are referring to a separate render thread. Please note that rendering in a separate thread (or in many cases, decoupling rendering in general) from game updates will inherently introduce a degree of latency: Objects move in systems -> wait some time -> picked up by the renderer and frame is rendered with that data. I think anything that adds latency is important to consider carefully. Personally, I feel that decoupling rendering may be over-engineering here and serves mostly to confuse users with another layer to think about. I understand that there are advantages as well, so it may be worthwhile, but so far I don't see huge benefit. |
One significant benefit is that if you can run non-rendering systems at a much higher framerate, it reduces the chance of ignored inputs. This is already an issue in Bevy, even when running at a full 60fps, and the lower the framerate is the worse it will become. Maybe there are other better ways to fix this (some way of guaranteeing that that the .pressed and .just_pressed checks return true whenever the key was pressed at any point since the previous update cycle, even if it was released before the current?), but being able to run update cycles at for example 120fps instead of 60, while still rendering at 60, would mean keypresses are checked more frequently, making the problem less noticeable and annoying to the player. |
Input is definitely an interesting case here, and I agree that there should be a way to poll input at a faster rate than the framerate. I'm still unconvinced that decoupled rendering is the answer here though. To me it feels like more of a specific problem which should be solved independently. |
I created a prototype framerate limiter here #3317 (comment) with the goal of reducing input latency. |
This is the (janky) solution I've used for my project so far, just a nothing system that sleeps to hold up the frame for a set period of time. This is my temp fix until something better comes along (the change to fifo present mode doesn't seem to work on my laptop) fn frame_limiter_system() {
use std::{thread, time};
thread::sleep(time::Duration::from_millis(10));
} |
Shameless plug for https://github.com/aevyrie/bevy_framepace, since my last post. I've done quite a bit of experimentation in this area for the work we are doing at Foresight with desktop applications. The nice thing about frame pacing combined with framerate limiting, is that it has much better latency than Fifo vsync alone, latency as good as Immediate, with no frame tearing, and much less CPU/GPU use than any of Fifo/Mailbox/Immediate. |
The quoted part of the issue is solved by #3974. |
Can we define some thing like such as |
I would like a way to globally cap the rate at which the main schedule runs similar to FixedUpdate (or lock it in sync with FixedUpdate). My use case is: I have a headless server running I'm mostly reporting this here because the |
@siler does this not work for you? MinimalPlugins.set(ScheduleRunnerPlugin::run_loop(
std::time::Duration::from_secs_f64(1.0 / UPDATES_PER_SECOND),
)) |
@JMS55, does that mean this will go into 0.15? |
There's no set date I can give you. At the start of a release cycle I typically add tasks I think would be good to do to the milestone. As we get towards the end of a cycle, I remove the ones that won't realistically be completed in time or aren't even started. No one's taken up frame limiting, so I've removed it from the milestone. |
…4155) # Objective - Fixes #14135 ## Solution - If no windows are visible, app updates will run regardless of redraw call result. This a relatively dirty fix, a more robust solution is desired in the long run: #1343 (comment) https://discord.com/channels/691052431525675048/1253771396832821270/1258805997011730472 The solution would disconnect rendering from app updates. ## Testing - `window_settings` now works ## Other platforms Not a problem on Linux: https://discord.com/channels/691052431525675048/692572690833473578/1259526650622640160 Not a problem on MacOS: https://discord.com/channels/691052431525675048/692572690833473578/1259563986148659272
…4155) # Objective - Fixes #14135 ## Solution - If no windows are visible, app updates will run regardless of redraw call result. This a relatively dirty fix, a more robust solution is desired in the long run: #1343 (comment) https://discord.com/channels/691052431525675048/1253771396832821270/1258805997011730472 The solution would disconnect rendering from app updates. ## Testing - `window_settings` now works ## Other platforms Not a problem on Linux: https://discord.com/channels/691052431525675048/692572690833473578/1259526650622640160 Not a problem on MacOS: https://discord.com/channels/691052431525675048/692572690833473578/1259563986148659272
Add a way to limit the frame rate.
Ideally, allow for more flexible control over updates, to support non-game gui applications that should sleep when idle.
The text was updated successfully, but these errors were encountered: