bevy: Vsync no longer throttles rendering in v0.4.0
Bevy version v0.4.0
Operating system & version
Arch Linux 5.9.11
What you did
use bevy::prelude::*;
fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_plugin(bevy::diagnostic::FrameTimeDiagnosticsPlugin)
.add_plugin(bevy::diagnostic::PrintDiagnosticsPlugin::default())
.run();
}
What you expected to happen
Using Bevy v0.3.0:
❯ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.07s
Running `target/debug/bevy_vsync`
Diagnostics:
---------------------------------------------------------------------------------------------
frame_count : 64.000000 (avg 64.000000)
frame_time : 0.016700 (avg 0.016689)
fps : 59.950072 (avg 59.930779)
What actually happened
Using Bevy v0.4.0:
❯ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.08s
Running `target/debug/bevy_vsync`
Diagnostics:
---------------------------------------------------------------------------------------------
frame_count : 332.000000 (avg 332.000000)
frame_time : 0.002922 (avg 0.003053)
fps : 328.634749 (avg 328.075462)
Additional information
This was observed under X11.
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 21 (10 by maintainers)
If the GUI has draggable elements, you will notice the lag between the cursor moving and the draggable element moving. Even if it is just a single frame.
There is a reason VR headsets use framerates >60Hz. Even if it doesn’t impact desktop gaming much, as far as I know it is noticable when you move your head in a VR headset. (Don’t own one, so can’t try to check for myself.)
Short term I think the fix should be to revert to FIFO as the cost of no frame limiting is pretty high and the “fix” is easy. Medium term we should bake in some frame limiting (which will be slightly involved due to the issues mentioned above). Then we can flip back to “mailbox with fifo fallback”.
Same behavior on my laptop which has Intel integrated graphics:
I was looking through the source of vkcube and found this: https://github.com/KhronosGroup/Vulkan-Tools/blob/1f550ddec2f3519f3ee7fd9cb1941b5642796ae2/cube/cube.c#L1234-L1263
So like @yuri91 is saying, it sounds like the high framerate is to be expected and is in fact just mailbox working as intended. And if we wanted to cap rendering to 60 fps we need to either use FIFO, or wait manually. I’m curious, why did we switch to mailbox? @cart
Edit: I think the “not optimal for mobile” disclaimer is not only true for smartphones, but any device that runs on battery power, such as laptops. Battery is also not the only reason why unthrottled rendering might be undesirable, especially if Bevy is meant to be used for non-game applications. If we make a Bevy GUI editor in Bevy, I’d like it to not max out my CPU.
Considering that:
Considering all these factors, then I really think the kind of vsync used should be a configurable parameter.
We switched to mailbox because it cut input latency, which in retrospect is probably just by nature of not blocking on vsync framerates.
wgpu examples use mailbox by default, and they do have built in frame limiting: https://github.com/gfx-rs/wgpu-rs/blob/4c518912790ee011cebcd75e9879647554e3261c/examples/framework.rs#L235
We should probably do the same, but the “request redraw” approach they use will require some changes on our end (ex: breaking rendering out from the main schedule so it can be executed separately on-demand). There might be some nuance there because the current system was built under the assumption that rendering runs immediately after game logic. And the LAST stage runs after rendering. We’d need to decide how to handle that. These changes could either be very easy or very hard 😄
I don’t know much about Vulkan, but I was curious about this issue so I read some stuff about presentation modes.
As far as I understand, the mailbox mode does not guarantee a capped frame rate. Even in the wgpu definition of the enum the comments seem to imply so:
I also read the following articles about it:
As far as I understand, with the mailbox presentation mode there is a capped 60fps frame rate only if the swap chain has only two available images. Otherwise the application is free to present a new image in the mailbox without having to wait for vsync.
Is this correct? and if so, is it the case that there are only two images used by bevy? I am not sure where to look in the code to check.
EDIT: I think that wgpu uses 3 images by default (see https://github.com/gfx-rs/wgpu/blob/7e3965bb5a6f8da0692237fb1fd63fe03434b405/wgpu-core/src/swap_chain.rs#L52), but uses less if the maximum number of available images is lower (https://github.com/gfx-rs/wgpu/blob/2287ae3f8a7246e8b47b73a1de6fe2410c42b8c8/wgpu-core/src/device/mod.rs#L3922).
Is it possible that on my platform I get 3, while other platforms get 2 and so get capped to 60fps?(EDIT: I tried changing it, and it didn’t make a difference)Sorry if all of this makes no sense 😅
@alice-i-cecile it seems like we can close this, no? Vsync is now configureable.
I changed the title, since vsync seems to actually still prevent tearing which is its main purpose.