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

Vsync no longer throttles rendering in v0.4.0 #1098

Closed
iwikal opened this issue Dec 20, 2020 · 21 comments
Closed

Vsync no longer throttles rendering in v0.4.0 #1098

iwikal opened this issue Dec 20, 2020 · 21 comments
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior

Comments

@iwikal
Copy link
Contributor

iwikal commented Dec 20, 2020

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.

@Moxinilian Moxinilian added C-Bug An unexpected or incorrect behavior A-Rendering Drawing game state to the screen labels Dec 20, 2020
@yuri91
Copy link

yuri91 commented Dec 26, 2020

I observed the same thing, on both X11 and Wayland.

I was wondering why a simple example was spinning my cpu at 100%, but then I saw that the app was running at ~1000fps

@yuri91
Copy link

yuri91 commented Dec 26, 2020

reverting this commit seems to fix the problem

@cart
Copy link
Member

cart commented Dec 26, 2020

What gpus / drivers do you all have?

@yuri91
Copy link

yuri91 commented Dec 26, 2020

Vendor: Intel (0x8086)
    Device: Mesa Intel(R) UHD Graphics (CML GT2) (0x9b41)

I use the standard i915 driver.

I don't know if it matters, but I am running the Sway Wayland compositor.

@cart
Copy link
Member

cart commented Dec 26, 2020

Interesting. Maybe mailbox vsync is broken on that setup? Normally if it was unsupported, wgpu would fall back to Fifo vsync (what we used before). Maybe the driver reports mailbox vsync as supported, but it's a broken impl?

@yuri91
Copy link

yuri91 commented Dec 26, 2020

mmh, with vulkaninfo I see these lines mentioning fifo and mailbox:

Present Modes: count = 4
		PRESENT_MODE_IMMEDIATE_KHR
		PRESENT_MODE_MAILBOX_KHR
		PRESENT_MODE_FIFO_KHR
		PRESENT_MODE_FIFO_RELAXED_KHR

So I guess that mailbox is at least advertised, but possibly broken?

@yuri91
Copy link

yuri91 commented Dec 26, 2020

I run vkcube with --present_mode set to 0 (immediate), 1 (mailbox) and 2 (fifo).

And for mailbox the cube is spinning as fast as in immediate, as opposed to fifo.

So I think that the driver is really broken.

At least for me, not sure about @iwikal setup

@iwikal
Copy link
Contributor Author

iwikal commented Dec 26, 2020

I won't have access to that computer until next year, but I have a similar setup on my laptop. I'll see if I can't reproduce the issue tonight.

For what it's worth, it was a SAPPHIRE Radeon RX5700 XT Nitro+, and I think I'm using the official Radeon drivers. Not sure if it's the open source or proprietary version though.

@yuri91
Copy link

yuri91 commented Dec 27, 2020

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:

pub enum PresentMode {
    /// The presentation engine does **not** wait for a vertical blanking period and
    /// the request is presented immediately. This is a low-latency presentation mode,
    /// but visible tearing may be observed. Will fallback to `Fifo` if unavailable on the
    /// selected  platform and backend. Not optimal for mobile.
    Immediate = 0,
    /// The presentation engine waits for the next vertical blanking period to update
    /// the current image, but frames may be submitted without delay. This is a low-latency
    /// presentation mode and visible tearing will **not** be observed. Will fallback to `Fifo`
    /// if unavailable on the selected platform and backend. Not optimal for mobile.
    Mailbox = 1,
    /// The presentation engine waits for the next vertical blanking period to update
    /// the current image. The framerate will be capped at the display refresh rate,
    /// corresponding to the `VSync`. Tearing cannot be observed. Optimal for mobile.
    Fifo = 2,
}

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 😅

@iwikal
Copy link
Contributor Author

iwikal commented Dec 27, 2020

Same behavior on my laptop which has Intel integrated graphics:

         apiVersion     = 4202641 (1.2.145)
         driverVersion  = 83898369 (0x5003001)
         vendorID       = 0x8086
         deviceID       = 0x5916
         deviceType     = PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
         deviceName     = Intel(R) HD Graphics 620 (KBL GT2)
       Present Modes: count = 4
                PRESENT_MODE_IMMEDIATE_KHR
                PRESENT_MODE_MAILBOX_KHR
                PRESENT_MODE_FIFO_KHR
                PRESENT_MODE_FIFO_RELAXED_KHR

I was looking through the source of vkcube and found this:
https://github.com/KhronosGroup/Vulkan-Tools/blob/1f550ddec2f3519f3ee7fd9cb1941b5642796ae2/cube/cube.c#L1234-L1263

    // The FIFO present mode is guaranteed by the spec to be supported
    // and to have no tearing.  It's a great default present mode to use.
    VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;

    //  There are times when you may wish to use another present mode.  The
    //  following code shows how to select them, and the comments provide some
    //  reasons you may wish to use them.
    //
    // It should be noted that Vulkan 1.0 doesn't provide a method for
    // synchronizing rendering with the presentation engine's display.  There
    // is a method provided for throttling rendering with the display, but
    // there are some presentation engines for which this method will not work.
    // If an application doesn't throttle its rendering, and if it renders much
    // faster than the refresh rate of the display, this can waste power on
    // mobile devices.  That is because power is being spent rendering images
    // that may never be seen.

    // VK_PRESENT_MODE_IMMEDIATE_KHR is for applications that don't care about
    // tearing, or have some way of synchronizing their rendering with the
    // display.
    // VK_PRESENT_MODE_MAILBOX_KHR may be useful for applications that
    // generally render a new presentable image every refresh cycle, but are
    // occasionally early.  In this case, the application wants the new image
    // to be displayed instead of the previously-queued-for-presentation image
    // that has not yet been displayed.
    // VK_PRESENT_MODE_FIFO_RELAXED_KHR is for applications that generally
    // render a new presentable image every refresh cycle, but are occasionally
    // late.  In this case (perhaps because of stuttering/latency concerns),
    // the application wants the late image to be immediately displayed, even
    // though that may mean some tearing.

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.

@sim82
Copy link

sim82 commented Dec 28, 2020

I can confirm that mailbox vsync causes weird effects on my dell xps13 running fedora on X11. Maybe also relevant: I'm not running any kind of compositing (plain i3 window manager), so maybe Mailbox vsync is hitting some less-well supported codepath in the driver.
Symptom: reported fps is fluctuating between 60-100fps but motion is quite jerky (in my own project https://github.com/sim82/crystal_planes). It is hard to describe but it seems to skip frames frequently. Hardcoding vsync to fifo fixes the jerkyness and the fps is stable at 60. If it helps I can do some more analysis, e.g. run with compositing or get more timing information from the mainloop.

GPU0:
VkPhysicalDeviceProperties:

    apiVersion     = 4202627 (1.2.131)
    driverVersion  = 83890184 (0x5001008)
    vendorID       = 0x8086
    deviceID       = 0x5916
    deviceType     = PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU
    deviceName     = Intel(R) HD Graphics 620 (KBL GT2)

@iwikal iwikal changed the title Vsync broken in v0.4.0 Vsync no longer throttles rendering in v0.4.0 Jan 12, 2021
@iwikal
Copy link
Contributor Author

iwikal commented Jan 12, 2021

I changed the title, since vsync seems to actually still prevent tearing which is its main purpose.

@cart
Copy link
Member

cart commented Jan 12, 2021

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 😄

@smokku
Copy link
Member

smokku commented Jan 17, 2021

I am observing this issue on Windows 10 with nVidia GeForce card.

@zeh
Copy link

zeh commented Jan 19, 2021

Same. Not sure I'm doing something wrong (I'm new to Bevy), but...

image

I have a NVidia GeForce RTX 2080. I guess it's a good card, and I use a 144Hz monitor, but 1600fps is a bit too high so I'd like to have that fixed to vsync instead. 😅

@cart
Copy link
Member

cart commented Jan 19, 2021

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".

@maddiemort
Copy link

maddiemort commented Mar 28, 2021

I'm also having this problem. Is there any kind of workaround or short term fix I can apply before the changes you mentioned have been made?

Edit: I am on 0.4, I just realised I should probably try upgrading to bevy main before complaining about this, and see if the problem is still there. I'll update this once I've managed to upgrade.

@lvella
Copy link

lvella commented May 9, 2021

Considering that:

  • 1/60 of a second is not a latency that impacts every game type (not at all for GUI applications);
  • Not every device can afford the extra power draw of mailbox;
  • Not every device is limited by 60Hz, and 1/144 second latency might be acceptable where 1/60 wasn't;
  • If updates occur at fixed timesteps (as recommended by many game dev source) then mailbox doesn't improve latency when compared with fifo;
  • The nonscientific nature of the claims that <10 ms can be humanly perceived and affect your gameplay.

Considering all these factors, then I really think the kind of vsync used should be a configurable parameter.

@bjorn3
Copy link
Contributor

bjorn3 commented May 9, 2021

1/60 of a second is not a latency that impacts every game type (not at all for GUI applications);

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.

The nonscientific nature of the claims that <10 ms can be humanly perceived and affect your gameplay.

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.)

@lvella
Copy link

lvella commented May 9, 2021

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.)

As I understand, it is not for latency, but for smoothness. Whether vsync is fifo or mailbox doesn't matter for VR.

@aevyrie
Copy link
Member

aevyrie commented Apr 22, 2022

@alice-i-cecile it seems like we can close this, no? Vsync is now configureable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Bug An unexpected or incorrect behavior
Projects
None yet
Development

No branches or pull requests