From 460c467cd2a4df734593263a773807676fc654e1 Mon Sep 17 00:00:00 2001 From: MDeiml Date: Fri, 14 Oct 2022 16:59:04 +0200 Subject: [PATCH] Introduce `AbstractWindowHandle` enum --- crates/bevy_render/src/lib.rs | 20 +++--- crates/bevy_render/src/view/window.rs | 97 +++++++++++++------------- crates/bevy_window/src/window.rs | 44 +++++++----- crates/bevy_winit/src/winit_windows.rs | 2 +- 4 files changed, 84 insertions(+), 79 deletions(-) diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index 1d289fe13eab80..5913b59bc68dd1 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -21,6 +21,7 @@ pub mod view; use bevy_core::FrameCount; use bevy_hierarchy::ValidParentCheckPlugin; +use bevy_window::AbstractWindowHandle; pub use extract_param::Extract; pub mod prelude { @@ -144,21 +145,18 @@ impl Plugin for RenderPlugin { .register_type::(); if let Some(backends) = options.backends { - let windows = app.world.resource_mut::(); let instance = wgpu::Instance::new(backends); let surface = { - if let Some(window) = windows.get_primary() { - if let Some(raw_window_handle) = window.raw_window_handle() { - unsafe { - let handle = raw_window_handle.get_handle(); - Some(instance.create_surface(&handle)) + let windows = app.world.resource_mut::(); + let raw_handle = windows.get_primary().and_then(|window| unsafe { + match window.window_handle() { + AbstractWindowHandle::RawWindowHandle(handle) => { + Some(instance.create_surface(&handle.get_handle())) } - } else { - None + AbstractWindowHandle::Virtual => None, } - } else { - None - } + }); + raw_handle }; let request_adapter_options = wgpu::RequestAdapterOptions { power_preference: options.power_preference, diff --git a/crates/bevy_render/src/view/window.rs b/crates/bevy_render/src/view/window.rs index 05632cf5b50ebb..f8f8a3254e8f43 100644 --- a/crates/bevy_render/src/view/window.rs +++ b/crates/bevy_render/src/view/window.rs @@ -6,7 +6,7 @@ use crate::{ use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; use bevy_utils::{tracing::debug, HashMap, HashSet}; -use bevy_window::{PresentMode, RawWindowHandleWrapper, WindowClosed, WindowId, Windows}; +use bevy_window::{AbstractWindowHandle, PresentMode, WindowClosed, WindowId, Windows}; use std::ops::{Deref, DerefMut}; /// Token to ensure a system runs on the main thread. @@ -38,7 +38,7 @@ impl Plugin for WindowRenderPlugin { pub struct ExtractedWindow { pub id: WindowId, - pub raw_window_handle: Option, + pub handle: AbstractWindowHandle, pub physical_width: u32, pub physical_height: u32, pub present_mode: PresentMode, @@ -83,7 +83,7 @@ fn extract_windows( .entry(window.id()) .or_insert(ExtractedWindow { id: window.id(), - raw_window_handle: window.raw_window_handle(), + handle: window.window_handle(), physical_width: new_width, physical_height: new_height, present_mode: window.present_mode(), @@ -132,7 +132,7 @@ pub struct WindowSurfaces { /// Creates and (re)configures window surfaces, and obtains a swapchain texture for rendering. /// -/// This will not handle [virtual windows](bevy_window::Window::new_virtual). +/// This will not handle [virtual windows](bevy_window::AbstractWindowHandle::Virtual). /// /// NOTE: `get_current_texture` in `prepare_windows` can take a long time if the GPU workload is /// the performance bottleneck. This can be seen in profiles as multiple prepare-stage systems all @@ -165,58 +165,59 @@ pub fn prepare_windows( ) { let window_surfaces = window_surfaces.deref_mut(); for window in windows.windows.values_mut() { - if let Some(handle) = &window.handle { - let surface = window_surfaces + let surface = match &window.handle { + AbstractWindowHandle::RawWindowHandle(handle) => window_surfaces .surfaces .entry(window.id) .or_insert_with(|| unsafe { // NOTE: On some OSes this MUST be called from the main thread. render_instance.create_surface(&handle.get_handle()) - }); + }), + AbstractWindowHandle::Virtual => continue, + }; + + let swap_chain_descriptor = wgpu::SurfaceConfiguration { + format: *surface + .get_supported_formats(&render_adapter) + .get(0) + .unwrap_or_else(|| { + panic!( + "No supported formats found for surface {:?} on adapter {:?}", + surface, render_adapter + ) + }), + width: window.physical_width, + height: window.physical_height, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT, + present_mode: match window.present_mode { + PresentMode::Fifo => wgpu::PresentMode::Fifo, + PresentMode::Mailbox => wgpu::PresentMode::Mailbox, + PresentMode::Immediate => wgpu::PresentMode::Immediate, + PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync, + PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync, + }, + }; + + // Do the initial surface configuration if it hasn't been configured yet. Or if size or + // present mode changed. + if window_surfaces.configured_windows.insert(window.id) + || window.size_changed + || window.present_mode_changed + { + render_device.configure_surface(surface, &swap_chain_descriptor); + } - let swap_chain_descriptor = wgpu::SurfaceConfiguration { - format: *surface - .get_supported_formats(&render_adapter) - .get(0) - .unwrap_or_else(|| { - panic!( - "No supported formats found for surface {:?} on adapter {:?}", - surface, render_adapter - ) - }), - width: window.physical_width, - height: window.physical_height, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT, - present_mode: match window.present_mode { - PresentMode::Fifo => wgpu::PresentMode::Fifo, - PresentMode::Mailbox => wgpu::PresentMode::Mailbox, - PresentMode::Immediate => wgpu::PresentMode::Immediate, - PresentMode::AutoVsync => wgpu::PresentMode::AutoVsync, - PresentMode::AutoNoVsync => wgpu::PresentMode::AutoNoVsync, - }, - }; - - // Do the initial surface configuration if it hasn't been configured yet. Or if size or - // present mode changed. - if window_surfaces.configured_windows.insert(window.id) - || window.size_changed - || window.present_mode_changed - { + let frame = match surface.get_current_texture() { + Ok(swap_chain_frame) => swap_chain_frame, + Err(wgpu::SurfaceError::Outdated) => { render_device.configure_surface(surface, &swap_chain_descriptor); + surface + .get_current_texture() + .expect("Error reconfiguring surface") } + err => err.expect("Failed to acquire next swap chain texture!"), + }; - let frame = match surface.get_current_texture() { - Ok(swap_chain_frame) => swap_chain_frame, - Err(wgpu::SurfaceError::Outdated) => { - render_device.configure_surface(surface, &swap_chain_descriptor); - surface - .get_current_texture() - .expect("Error reconfiguring surface") - } - err => err.expect("Failed to acquire next swap chain texture!"), - }; - - window.swap_chain_texture = Some(TextureView::from(frame)); - } + window.swap_chain_texture = Some(TextureView::from(frame)); } } diff --git a/crates/bevy_window/src/window.rs b/crates/bevy_window/src/window.rs index ab5afc7f0185df..b882eb0d735986 100644 --- a/crates/bevy_window/src/window.rs +++ b/crates/bevy_window/src/window.rs @@ -151,6 +151,21 @@ impl WindowResizeConstraints { } } +/// Handle used for creating surfaces in the render plugin +/// +/// Either a raw handle to an OS window or `Virtual` to signify that there is no corresponding OS window. +#[derive(Clone, Debug)] +pub enum AbstractWindowHandle { + /// The window corresponds to an operator system window. + RawWindowHandle(RawWindowHandleWrapper), + /// The window does not to correspond to an operator system window. + /// + /// It differs from a non-virtual window, in that the caller is responsible + /// for creating and presenting surface textures and inserting them into + /// [`ExtractedWindow`](https://docs.rs/bevy/*/bevy/render/view/struct.ExtractedWindow.html). + Virtual, +} + /// An operating system or virtual window that can present content and receive user input. /// /// To create a window, use a [`EventWriter`](`crate::CreateWindow`). @@ -259,7 +274,7 @@ pub struct Window { cursor_visible: bool, cursor_locked: bool, physical_cursor_position: Option, - raw_window_handle: Option, + window_handle: AbstractWindowHandle, focused: bool, mode: WindowMode, canvas: Option, @@ -368,7 +383,7 @@ impl Window { physical_height: u32, scale_factor: f64, position: Option, - raw_window_handle: Option, + raw_window_handle: RawWindowHandle, ) -> Self { Window { id, @@ -388,7 +403,9 @@ impl Window { cursor_locked: window_descriptor.cursor_locked, cursor_icon: CursorIcon::Default, physical_cursor_position: None, - raw_window_handle: Some(RawWindowHandleWrapper::new(raw_window_handle)), + window_handle: AbstractWindowHandle::RawWindowHandle(RawWindowHandleWrapper::new( + raw_window_handle, + )), focused: true, mode: window_descriptor.mode, canvas: window_descriptor.canvas.clone(), @@ -399,11 +416,7 @@ impl Window { /// Creates a new virtual [`Window`]. /// - /// This window does not have to correspond to an operator system window. - /// - /// It differs from a non-virtual window, in that the caller is responsible - /// for creating and presenting surface textures and inserting them into - /// [`ExtractedWindow`](https://docs.rs/bevy/*/bevy/render/view/struct.ExtractedWindow.html). + /// See [`AbstractWindowHandle::Virtual`]. pub fn new_virtual( id: WindowId, window_descriptor: &WindowDescriptor, @@ -430,7 +443,7 @@ impl Window { cursor_locked: window_descriptor.cursor_locked, cursor_icon: CursorIcon::Default, physical_cursor_position: None, - raw_window_handle: None, + window_handle: AbstractWindowHandle::Virtual, focused: true, mode: window_descriptor.mode, canvas: window_descriptor.canvas.clone(), @@ -816,16 +829,9 @@ impl Window { self.focused } - /// Get the [`RawWindowHandleWrapper`] corresponding to this window. - /// - /// A return value of `None` signifies that this is a virtual window and does not - /// correspond to an OS window. The creator of the window is responsible - /// for creating and presenting surface textures and inserting them into - /// [`ExtractedWindow`](https://docs.rs/bevy/*/bevy/render/view/struct.ExtractedWindow.html). - /// - /// See [`Self::new_virtual`]. - pub fn raw_window_handle(&self) -> Option { - self.raw_window_handle.clone() + /// Get the [`AbstractWindowHandle`] corresponding to this window. + pub fn window_handle(&self) -> AbstractWindowHandle { + self.window_handle.clone() } /// The "html canvas" element selector. diff --git a/crates/bevy_winit/src/winit_windows.rs b/crates/bevy_winit/src/winit_windows.rs index 47423957cfbc5d..4467574874c611 100644 --- a/crates/bevy_winit/src/winit_windows.rs +++ b/crates/bevy_winit/src/winit_windows.rs @@ -201,7 +201,7 @@ impl WinitWindows { inner_size.height, scale_factor, position, - Some(raw_window_handle), + raw_window_handle, ) }