diff --git a/crates/bevy_render/src/view/window/mod.rs b/crates/bevy_render/src/view/window/mod.rs index 72a23baea4f8f..762771a41edd5 100644 --- a/crates/bevy_render/src/view/window/mod.rs +++ b/crates/bevy_render/src/view/window/mod.rs @@ -15,6 +15,7 @@ use bevy_window::{ CompositeAlphaMode, PresentMode, PrimaryWindow, RawHandleWrapper, Window, WindowClosed, }; use std::{ + num::NonZeroU32, ops::{Deref, DerefMut}, sync::PoisonError, }; @@ -66,6 +67,7 @@ pub struct ExtractedWindow { pub physical_width: u32, pub physical_height: u32, pub present_mode: PresentMode, + pub desired_maximum_frame_latency: Option, /// Note: this will not always be the swap chain texture view. When taking a screenshot, /// this will point to an alternative texture instead to allow for copying the render result /// to CPU memory. @@ -136,6 +138,7 @@ fn extract_windows( physical_width: new_width, physical_height: new_height, present_mode: window.present_mode, + desired_maximum_frame_latency: window.desired_maximum_frame_latency, swap_chain_texture: None, swap_chain_texture_view: None, size_changed: false, @@ -429,6 +432,12 @@ pub fn need_surface_configuration( false } +// 2 is wgpu's default/what we've been using so far. +// 1 is the minimum, but may cause lower framerates due to the cpu waiting for the gpu to finish +// all work for the previous frame before starting work on the next frame, which then means the gpu +// has to wait for the cpu to finish to start on the next frame. +const DEFAULT_DESIRED_MAXIMUM_FRAME_LATENCY: u32 = 2; + /// Creates window surfaces. pub fn create_surfaces( // By accessing a NonSend resource, we tell the scheduler to put this system on the main thread, @@ -488,12 +497,10 @@ pub fn create_surfaces( PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync, PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync, }, - // TODO: Expose this as a setting somewhere - // 2 is wgpu's default/what we've been using so far. - // 1 is the minimum, but may cause lower framerates due to the cpu waiting for the gpu to finish - // all work for the previous frame before starting work on the next frame, which then means the gpu - // has to wait for the cpu to finish to start on the next frame. - desired_maximum_frame_latency: 2, + desired_maximum_frame_latency: window + .desired_maximum_frame_latency + .map(NonZeroU32::get) + .unwrap_or(DEFAULT_DESIRED_MAXIMUM_FRAME_LATENCY), alpha_mode: match window.alpha_mode { CompositeAlphaMode::Auto => wgpu::CompositeAlphaMode::Auto, CompositeAlphaMode::Opaque => wgpu::CompositeAlphaMode::Opaque, diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index 216dbf8abd446..d80f070a1657b 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -1,3 +1,5 @@ +use std::num::NonZeroU32; + use bevy_ecs::{ entity::{Entity, EntityMapper, MapEntities}, prelude::{Component, ReflectComponent}, @@ -270,6 +272,15 @@ pub struct Window { /// /// - Only supported on Windows. pub skip_taskbar: bool, + /// Optional hint given to the rendering API regarding the maximum number of queued frames admissible on the GPU. + /// + /// Given values are usually within the 1-3 range. If not provided, this will default to 2. + /// + /// See [`wgpu::SurfaceConfiguration::desired_maximum_frame_latency`]. + /// + /// [`wgpu::SurfaceConfiguration::desired_maximum_frame_latency`]: + /// https://docs.rs/wgpu/latest/wgpu/type.SurfaceConfiguration.html#structfield.desired_maximum_frame_latency + pub desired_maximum_frame_latency: Option, } impl Default for Window { @@ -299,6 +310,7 @@ impl Default for Window { window_theme: None, visible: true, skip_taskbar: false, + desired_maximum_frame_latency: None, } } }