From 9a8ac5c95208a953efee2d72778badc88d164d2c Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 30 Jan 2022 11:36:38 -0500 Subject: [PATCH 1/8] Replace VSync with PresentMode Fixes #3807 --- crates/bevy_render/src/view/window.rs | 14 ++++----- crates/bevy_window/src/window.rs | 43 ++++++++++++++++++++------- crates/bevy_winit/src/lib.rs | 2 +- examples/ios/src/lib.rs | 8 +++-- examples/tools/bevymark.rs | 3 +- examples/ui/text_debug.rs | 3 +- examples/window/multiple_windows.rs | 4 +-- examples/window/window_settings.rs | 4 +-- 8 files changed, 54 insertions(+), 27 deletions(-) diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index 94bf8a21c0fdb..a120f44c8f822 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -7,7 +7,7 @@ use crate::{ use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; use bevy_utils::{tracing::debug, HashMap, HashSet}; -use bevy_window::{RawWindowHandleWrapper, WindowId, Windows}; +use bevy_window::{PresentMode, RawWindowHandleWrapper, WindowId, Windows}; use std::ops::{Deref, DerefMut}; use wgpu::TextureFormat; @@ -43,7 +43,7 @@ pub struct ExtractedWindow { pub handle: RawWindowHandleWrapper, pub physical_width: u32, pub physical_height: u32, - pub vsync: bool, + pub present_mode: PresentMode, pub swap_chain_texture: Option, pub size_changed: bool, } @@ -83,7 +83,7 @@ fn extract_windows(mut render_world: ResMut, windows: Res) handle: window.raw_window_handle(), physical_width: new_width, physical_height: new_height, - vsync: window.vsync(), + present_mode: window.present_mode(), swap_chain_texture: None, size_changed: false, }); @@ -138,10 +138,10 @@ pub fn prepare_windows( width: window.physical_width, height: window.physical_height, usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - present_mode: if window.vsync { - wgpu::PresentMode::Fifo - } else { - wgpu::PresentMode::Immediate + present_mode: match window.present_mode { + PresentMode::Fifo => wgpu::PresentMode::Fifo, + PresentMode::Mailbox => wgpu::PresentMode::Mailbox, + PresentMode::Immediate => wgpu::PresentMode::Immediate, }, }; diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 7381a32134ef7..65e3a60ee8e6c 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -5,6 +5,26 @@ use raw_window_handle::RawWindowHandle; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct WindowId(Uuid); +/// Behavior of the presentation engine based on frame rate. +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +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, +} + impl WindowId { pub fn new() -> Self { WindowId(Uuid::new_v4()) @@ -121,7 +141,7 @@ pub struct Window { scale_factor_override: Option, backend_scale_factor: f64, title: String, - vsync: bool, + present_mode: PresentMode, resizable: bool, decorations: bool, cursor_icon: CursorIcon, @@ -152,8 +172,8 @@ pub enum WindowCommand { logical_resolution: (f32, f32), scale_factor: f64, }, - SetVsync { - vsync: bool, + SetPresentMode { + present_mode: PresentMode, }, SetResizable { resizable: bool, @@ -222,7 +242,7 @@ impl Window { scale_factor_override: window_descriptor.scale_factor_override, backend_scale_factor: scale_factor, title: window_descriptor.title.clone(), - vsync: window_descriptor.vsync, + present_mode: window_descriptor.present_mode, resizable: window_descriptor.resizable, decorations: window_descriptor.decorations, cursor_visible: window_descriptor.cursor_visible, @@ -425,14 +445,15 @@ impl Window { } #[inline] - pub fn vsync(&self) -> bool { - self.vsync + pub fn present_mode(&self) -> PresentMode { + self.present_mode } #[inline] - pub fn set_vsync(&mut self, vsync: bool) { - self.vsync = vsync; - self.command_queue.push(WindowCommand::SetVsync { vsync }); + pub fn set_present_mode(&mut self, present_mode: PresentMode) { + self.present_mode = present_mode; + self.command_queue + .push(WindowCommand::SetPresentMode { present_mode }); } #[inline] @@ -557,7 +578,7 @@ pub struct WindowDescriptor { pub resize_constraints: WindowResizeConstraints, pub scale_factor_override: Option, pub title: String, - pub vsync: bool, + pub present_mode: PresentMode, pub resizable: bool, pub decorations: bool, pub cursor_visible: bool, @@ -584,7 +605,7 @@ impl Default for WindowDescriptor { position: None, resize_constraints: WindowResizeConstraints::default(), scale_factor_override: None, - vsync: true, + present_mode: PresentMode::Fifo, resizable: true, decorations: true, cursor_locked: false, diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index a833ecf44b57f..147f633f2ede1 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -94,7 +94,7 @@ fn change_window(world: &mut World) { .to_physical::(scale_factor), ); } - bevy_window::WindowCommand::SetVsync { .. } => (), + bevy_window::WindowCommand::SetPresentMode { .. } => (), bevy_window::WindowCommand::SetResizable { resizable } => { let window = winit_windows.get_window(id).unwrap(); window.set_resizable(resizable); diff --git a/examples/ios/src/lib.rs b/examples/ios/src/lib.rs index f79caa85d9625..c19a15933eb88 100644 --- a/examples/ios/src/lib.rs +++ b/examples/ios/src/lib.rs @@ -1,11 +1,15 @@ -use bevy::{input::touch::TouchPhase, prelude::*, window::WindowMode}; +use bevy::{ + input::touch::TouchPhase, + prelude::*, + window::{PresentMode, WindowMode}, +}; // the `bevy_main` proc_macro generates the required ios boilerplate #[bevy_main] fn main() { App::new() .insert_resource(WindowDescriptor { - vsync: true, + present_mode: PresentMode::Fifo, resizable: false, mode: WindowMode::BorderlessFullscreen, ..Default::default() diff --git a/examples/tools/bevymark.rs b/examples/tools/bevymark.rs index 290fdf42594aa..39701f4924e61 100644 --- a/examples/tools/bevymark.rs +++ b/examples/tools/bevymark.rs @@ -2,6 +2,7 @@ use bevy::{ core::FixedTimestep, diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, prelude::*, + window::PresentMode, }; use rand::random; @@ -28,7 +29,7 @@ fn main() { title: "BevyMark".to_string(), width: 800., height: 600., - vsync: false, + present_mode: PresentMode::Mailbox, resizable: true, ..Default::default() }) diff --git a/examples/ui/text_debug.rs b/examples/ui/text_debug.rs index 867a7aae382ea..b5c062b47d002 100644 --- a/examples/ui/text_debug.rs +++ b/examples/ui/text_debug.rs @@ -1,13 +1,14 @@ use bevy::{ diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin}, prelude::*, + window::PresentMode, }; /// This example is for debugging text layout fn main() { App::new() .insert_resource(WindowDescriptor { - vsync: false, + present_mode: PresentMode::Immediate, ..Default::default() }) .add_plugins(DefaultPlugins) diff --git a/examples/window/multiple_windows.rs b/examples/window/multiple_windows.rs index 6932460a20947..b84d3eaec7f37 100644 --- a/examples/window/multiple_windows.rs +++ b/examples/window/multiple_windows.rs @@ -8,7 +8,7 @@ use bevy::{ renderer::RenderContext, RenderApp, RenderStage, }, - window::{CreateWindow, WindowId}, + window::{CreateWindow, PresentMode, WindowId}, }; /// This example creates a second window and draws a mesh from two different cameras, one in each window @@ -57,7 +57,7 @@ fn create_new_window( descriptor: WindowDescriptor { width: 800., height: 600., - vsync: false, + present_mode: PresentMode::Immediate, title: "Second window".to_string(), ..Default::default() }, diff --git a/examples/window/window_settings.rs b/examples/window/window_settings.rs index e00ba07416809..9bb4cfff860a8 100644 --- a/examples/window/window_settings.rs +++ b/examples/window/window_settings.rs @@ -1,4 +1,4 @@ -use bevy::prelude::*; +use bevy::{prelude::*, window::PresentMode}; /// This example illustrates how to customize the default window settings fn main() { @@ -7,7 +7,7 @@ fn main() { title: "I am a window!".to_string(), width: 500., height: 300., - vsync: true, + present_mode: PresentMode::Fifo, ..Default::default() }) .add_plugins(DefaultPlugins) From f8061809d8e181f6dbb852096dd80c3f00196d2c Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 30 Jan 2022 12:14:28 -0500 Subject: [PATCH 2/8] Update PresentMode documentation --- crates/bevy_window/src/window.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 65e3a60ee8e6c..1574651f93119 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -5,7 +5,16 @@ use raw_window_handle::RawWindowHandle; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct WindowId(Uuid); -/// Behavior of the presentation engine based on frame rate. +/// Presentation mode for a window. +/// +/// The presentation mode specifies when a frame is presented to the window. The `Fifo` +/// option corresponds to a traditional `VSync`, where the framerate is capped by the +/// display refresh rate. Both `Immediate` and `Mailbox` are low-latency and are not +/// capped by the refresh rate, but may not be availalbe on all platforms. Tearing +/// may be observed with `Immediate` mode, but will not be observed with `Mailbox` or +/// `Fifo`. +/// +/// `Immediate` or `Mailbox` will gracefully fallback to `Fifo` when unavailable. #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum PresentMode { From a94351d7c2f18c51797fbf236402f9bbc0fc58b6 Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 30 Jan 2022 13:23:16 -0500 Subject: [PATCH 3/8] Add vsync alias to PresentMode and additional doc links --- crates/bevy_window/src/window.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 1574651f93119..d001603c82b14 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -15,8 +15,12 @@ pub struct WindowId(Uuid); /// `Fifo`. /// /// `Immediate` or `Mailbox` will gracefully fallback to `Fifo` when unavailable. +/// +/// The presentaion mode may be declared in the [`WindowDescriptor`](WindowDescriptor::present_mode) +/// or updated on a [`Window`](Window::set_present_mode). #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[doc(alias = "vsync")] 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, @@ -454,11 +458,13 @@ impl Window { } #[inline] + #[doc(alias = "vsync")] pub fn present_mode(&self) -> PresentMode { self.present_mode } #[inline] + #[doc(alias = "set_vsync")] pub fn set_present_mode(&mut self, present_mode: PresentMode) { self.present_mode = present_mode; self.command_queue @@ -587,6 +593,7 @@ pub struct WindowDescriptor { pub resize_constraints: WindowResizeConstraints, pub scale_factor_override: Option, pub title: String, + #[doc(alias = "vsync")] pub present_mode: PresentMode, pub resizable: bool, pub decorations: bool, From 30811cf0fe30d6e406d08ecf82ad76adb6096f1d Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 30 Jan 2022 14:41:34 -0500 Subject: [PATCH 4/8] Add a note regarding PresentMode oridinal values --- crates/bevy_window/src/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index d001603c82b14..356081428663f 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -35,7 +35,7 @@ pub enum PresentMode { /// 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, + Fifo = 2, // NOTE: The explicit ordinal values mirror wgpu and the vulkan spec. } impl WindowId { From e9b73d96d08103747f2d3e0648a25e1b7a2f5618 Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 30 Jan 2022 21:08:35 -0500 Subject: [PATCH 5/8] Remove present_mode from ios example --- examples/ios/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/ios/src/lib.rs b/examples/ios/src/lib.rs index c19a15933eb88..3da6a3629ebea 100644 --- a/examples/ios/src/lib.rs +++ b/examples/ios/src/lib.rs @@ -9,7 +9,6 @@ use bevy::{ fn main() { App::new() .insert_resource(WindowDescriptor { - present_mode: PresentMode::Fifo, resizable: false, mode: WindowMode::BorderlessFullscreen, ..Default::default() From f2a22b9b9412dc4fe2da83514f53941706731665 Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 30 Jan 2022 21:08:56 -0500 Subject: [PATCH 6/8] Remove extra space in PresentMode docs --- crates/bevy_window/src/window.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 356081428663f..d7bffe9be09bd 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -25,7 +25,7 @@ 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. + /// 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 From b8e8f82b56f16cdc39a25a010042df34b6dd14b1 Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Sun, 30 Jan 2022 21:23:25 -0500 Subject: [PATCH 7/8] Remove unused import in ios example --- examples/ios/src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/examples/ios/src/lib.rs b/examples/ios/src/lib.rs index 3da6a3629ebea..c4f687f57c941 100644 --- a/examples/ios/src/lib.rs +++ b/examples/ios/src/lib.rs @@ -1,8 +1,4 @@ -use bevy::{ - input::touch::TouchPhase, - prelude::*, - window::{PresentMode, WindowMode}, -}; +use bevy::{input::touch::TouchPhase, prelude::*, window::WindowMode}; // the `bevy_main` proc_macro generates the required ios boilerplate #[bevy_main] From 622099ef9004c651d9c303fd283657c50c81f82f Mon Sep 17 00:00:00 2001 From: Aaron Loucks Date: Thu, 3 Feb 2022 18:18:51 -0500 Subject: [PATCH 8/8] Fix typos in PresentMode docs --- crates/bevy_window/src/window.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index d7bffe9be09bd..94442c5e06e06 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -10,13 +10,13 @@ pub struct WindowId(Uuid); /// The presentation mode specifies when a frame is presented to the window. The `Fifo` /// option corresponds to a traditional `VSync`, where the framerate is capped by the /// display refresh rate. Both `Immediate` and `Mailbox` are low-latency and are not -/// capped by the refresh rate, but may not be availalbe on all platforms. Tearing +/// capped by the refresh rate, but may not be available on all platforms. Tearing /// may be observed with `Immediate` mode, but will not be observed with `Mailbox` or /// `Fifo`. /// /// `Immediate` or `Mailbox` will gracefully fallback to `Fifo` when unavailable. /// -/// The presentaion mode may be declared in the [`WindowDescriptor`](WindowDescriptor::present_mode) +/// The presentation mode may be declared in the [`WindowDescriptor`](WindowDescriptor::present_mode) /// or updated on a [`Window`](Window::set_present_mode). #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]