use std::ops::{Deref, DerefMut}; use crate::{ render_resource::TextureView, renderer::{RenderDevice, RenderInstance}, texture::BevyDefault, RenderStage, }; use bevy_app::{App, Plugin}; use bevy_ecs::prelude::*; use bevy_utils::HashMap; use bevy_window::{RawWindowHandleWrapper, WindowId, Windows}; use wgpu::{SwapChainFrame, TextureFormat}; pub struct WindowRenderPlugin; impl Plugin for WindowRenderPlugin { fn build(&self, app: &mut App) { let render_app = app.sub_app_mut(0); render_app .init_resource::() .add_system_to_stage(RenderStage::Extract, extract_windows.system()) .add_system_to_stage(RenderStage::Prepare, prepare_windows.system()); } } pub struct ExtractedWindow { pub id: WindowId, pub handle: RawWindowHandleWrapper, pub physical_width: u32, pub physical_height: u32, pub vsync: bool, pub swap_chain_frame: Option, } #[derive(Default)] pub struct ExtractedWindows { pub windows: HashMap, } impl Deref for ExtractedWindows { type Target = HashMap; fn deref(&self) -> &Self::Target { &self.windows } } impl DerefMut for ExtractedWindows { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.windows } } fn extract_windows(mut commands: Commands, windows: Res) { let mut extracted_windows = ExtractedWindows::default(); for window in windows.iter() { extracted_windows.insert( window.id(), ExtractedWindow { id: window.id(), handle: window.raw_window_handle(), physical_width: window.physical_width(), physical_height: window.physical_height(), vsync: window.vsync(), swap_chain_frame: None, }, ); } commands.insert_resource(extracted_windows); } #[derive(Default)] pub struct WindowSurfaces { surfaces: HashMap, swap_chains: HashMap, } pub struct WindowSwapChain { value: TextureView, } pub fn prepare_windows( mut windows: ResMut, mut window_surfaces: ResMut, render_device: Res, render_instance: Res, ) { let window_surfaces = window_surfaces.deref_mut(); for window in windows.windows.values_mut() { let surface = window_surfaces .surfaces .entry(window.id) .or_insert_with(|| unsafe { render_instance.create_surface(&window.handle.get_handle()) }); let swap_chain_descriptor = wgpu::SwapChainDescriptor { format: TextureFormat::bevy_default(), width: window.physical_width, height: window.physical_height, usage: wgpu::TextureUsage::RENDER_ATTACHMENT, present_mode: if window.vsync { wgpu::PresentMode::Fifo } else { wgpu::PresentMode::Immediate }, }; let swap_chain = window_surfaces .swap_chains .entry(window.id) .or_insert_with(|| render_device.create_swap_chain(surface, &swap_chain_descriptor)); let frame = if let Ok(swap_chain_frame) = swap_chain.get_current_frame() { swap_chain_frame } else { let swap_chain = window_surfaces .swap_chains .entry(window.id) .or_insert_with(|| { render_device.create_swap_chain(surface, &swap_chain_descriptor) }); swap_chain .get_current_frame() .expect("Failed to acquire next swap chain texture!") }; window.swap_chain_frame = Some(TextureView::from(frame)); } }