diff --git a/crates/bevy_render/src/view/window/mod.rs b/crates/bevy_render/src/view/window/mod.rs index ae5389e906820..48686af01db01 100644 --- a/crates/bevy_render/src/view/window/mod.rs +++ b/crates/bevy_render/src/view/window/mod.rs @@ -15,7 +15,7 @@ use core::{ num::NonZero, ops::{Deref, DerefMut}, }; -use tracing::{debug, warn}; +use tracing::{debug, info, warn}; use wgpu::{ SurfaceConfiguration, SurfaceTargetUnsafe, TextureFormat, TextureUsages, TextureViewDescriptor, }; @@ -348,6 +348,7 @@ pub fn create_surfaces( .expect("Failed to create wgpu surface") }; let caps = surface.get_capabilities(&render_adapter); + let present_mode = present_mode(window, &caps); let formats = caps.formats; // For future HDR output support, we'll need to request a format that supports HDR, // but as of wgpu 0.15 that is not yet supported. @@ -368,14 +369,7 @@ pub fn create_surfaces( width: window.physical_width, height: window.physical_height, usage: TextureUsages::RENDER_ATTACHMENT, - present_mode: match window.present_mode { - PresentMode::Fifo => wgpu::PresentMode::Fifo, - PresentMode::FifoRelaxed => wgpu::PresentMode::FifoRelaxed, - PresentMode::Mailbox => wgpu::PresentMode::Mailbox, - PresentMode::Immediate => wgpu::PresentMode::Immediate, - PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync, - PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync, - }, + present_mode, desired_maximum_frame_latency: window .desired_maximum_frame_latency .map(NonZero::::get) @@ -413,17 +407,57 @@ pub fn create_surfaces( data.configuration.width = window.physical_width; data.configuration.height = window.physical_height; - data.configuration.present_mode = match window.present_mode { - PresentMode::Fifo => wgpu::PresentMode::Fifo, - PresentMode::FifoRelaxed => wgpu::PresentMode::FifoRelaxed, - PresentMode::Mailbox => wgpu::PresentMode::Mailbox, - PresentMode::Immediate => wgpu::PresentMode::Immediate, - PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync, - PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync, - }; + let caps = data.surface.get_capabilities(&render_adapter); + data.configuration.present_mode = present_mode(window, &caps); render_device.configure_surface(&data.surface, &data.configuration); } window_surfaces.configured_windows.insert(window.entity); } } + +fn present_mode( + window: &mut ExtractedWindow, + caps: &wgpu::SurfaceCapabilities, +) -> wgpu::PresentMode { + let present_mode = match window.present_mode { + PresentMode::Fifo => wgpu::PresentMode::Fifo, + PresentMode::FifoRelaxed => wgpu::PresentMode::FifoRelaxed, + PresentMode::Mailbox => wgpu::PresentMode::Mailbox, + PresentMode::Immediate => wgpu::PresentMode::Immediate, + PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync, + PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync, + }; + let fallbacks = match present_mode { + wgpu::PresentMode::AutoVsync => { + &[wgpu::PresentMode::FifoRelaxed, wgpu::PresentMode::Fifo][..] + } + wgpu::PresentMode::AutoNoVsync => &[ + wgpu::PresentMode::Immediate, + wgpu::PresentMode::Mailbox, + wgpu::PresentMode::Fifo, + ][..], + wgpu::PresentMode::Mailbox => &[ + wgpu::PresentMode::Mailbox, + wgpu::PresentMode::Immediate, + wgpu::PresentMode::Fifo, + ][..], + // Always end in FIFO to make sure it's always supported + x => &[x, wgpu::PresentMode::Fifo][..], + }; + let new_present_mode = fallbacks + .iter() + .copied() + .find(|fallback| caps.present_modes.contains(fallback)) + .unwrap_or_else(|| { + unreachable!( + "Fallback system failed to choose present mode. \ + This is a bug. Mode: {:?}, Options: {:?}", + window.present_mode, &caps.present_modes + ); + }); + if new_present_mode != present_mode && fallbacks.contains(&present_mode) { + info!("PresentMode {present_mode:?} requested but not available. Falling back to {new_present_mode:?}"); + } + new_present_mode +}