-
Notifications
You must be signed in to change notification settings - Fork 0
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
Explanation gap for dealing with high refresh rate displays #1
Comments
For FPS < TPS, we have the following cases:
None of these are really a problem. For FPS > TPS, we have the following cases:
In some of these cases, redrawing each time is wasteful and there's nothing to interpolate to make the game look better. In others, redrawing each time will normally result in the same image unless you are interpolating element positions. Interpolating introduces lag so it's not always so great. |
Some more thoughts... The new Also, I'm starting to believe that real-time position interpolation is ok for high refresh rate displays, but only because the extra frame delay is much smaller than on regular 60Hz displays. On 60Hz displays it really hurts latency. At 120Hz, latency is ok because you are at a very similar place as with 60Hz without interpolation, but then one might also be polling input events more often, which can help make the system more responsive. And at those rates, prediction failures (if using that) will be less noticeable. So... best support requires using different strategies for different refresh rates. Is that correct? |
No, not fully correct: on a fixed-timestep loop, input polling will be delayed one tick anyway, no matter the display refresh rate. |
I have another solution that seems better than anything else I've previously thought of:
This system remains simple to use (tick based), easy to test with only 3 main levels, but supporting higher refresh rates and input responsivity for the computers that can handle that. This seems like a decent compromise. The main downside is that we may break determinism in some cases if we are not careful, so that's one extra thing to keep in mind when relevant. Another downside is that then we can't use TPS for turbo/slow modes so freely. That was always kind of a hacky way to implement such things, though, so it's not a big deal. You can still set TPS to 480 anyway, but then you will need yet a few more hacks to compensate the main usage of TPS. A more thorough model for implementing turbo modes / slowdowns that doesn't impact input responsivity should be explored. It's fairly clear, though, that it should be applied in its own logical layer. To be seen: whether to configure the TPS manually or automatically based on empirical FPS measures. |
In non-pixel-art games, smooth interpolation of game elements at >60Hz (e.g: 144Hz and 240Hz displays) is not uncommon. The current explanation doesn't really explain how to deal with this, and kinda brushes it away as if saying "just stick to 60 ticks per second and draw accordingly".
Adjusting TPS based on the screen's refresh rate is not a good idea, you are basically just doing
Draw
logic insideUpdate
but with an extra artificial split, and you can no longer use fixed delta values inUpdate
. Additionally, Ebitengine API doesn't provide any function to get the display's maximum refresh rate.On practical solutions:
Draw
based on time. This is the safest way to go, but it introduces a 1 tick delay, which can become a real issue for fast-paced games.Update
and does all the work onDraw
. This is not even incorrect, but it does kinda go against the ethos of Ebitengine.I don't think Ebitengine has an "official" or recommended way to deal with these situations (TPS != FPS without lag or vsync off being the causes) or acknowledges it as a significant concern. Otherwise I believe at least a
DisplayRefreshRate
function would most likely exist.There are also optimization concerns. When handling consecutive draws on pixel-art games, in many cases (when not using time-dependent shaders or similar effects) you can use
SetScreenClearedEveryFrame(false)
and ignore the draws, as nothing has changed. Otherwise high refresh rate displays can start burning quite a lot of processing time for no good reason. We also have no function to limit the FPS and let Ebitengine do this internally for us.Summarizing, there's definitely a gap in the documentation around this issue, but the situation is unclear for Ebitengine itself too. But now at least anyone interested in this will know about some practical options or can start bothering Hajime Hoshi on my behalf.
The text was updated successfully, but these errors were encountered: