From 17d4bec08c15e4463ea9b4a8bc3eb9eb919aa0a0 Mon Sep 17 00:00:00 2001 From: Carter Anderson Date: Mon, 30 Mar 2020 19:21:12 -0700 Subject: [PATCH] rework surface and swap chain creation to support arbitrary number of surfaces/windows --- src/core/core_plugin.rs | 4 +- src/core/event.rs | 2 +- src/core/window/events.rs | 3 +- src/core/window/winit/mod.rs | 34 ++-- src/render/render_plugin.rs | 17 +- .../render_resource/resource_provider.rs | 9 - .../camera2d_resource_provider.rs | 99 +++++----- .../camera_resource_provider.rs | 106 ++++++----- .../frame_texture_resource_provider.rs | 49 +++-- src/render/renderer/renderer.rs | 1 - .../renderer/renderers/wgpu_renderer/mod.rs | 14 +- .../renderers/wgpu_renderer/wgpu_renderer.rs | 170 ++++++++++-------- .../renderers/wgpu_renderer/wgpu_resources.rs | 4 +- 13 files changed, 267 insertions(+), 245 deletions(-) diff --git a/src/core/core_plugin.rs b/src/core/core_plugin.rs index 66aeaf7202..c0e0076ec5 100644 --- a/src/core/core_plugin.rs +++ b/src/core/core_plugin.rs @@ -1,4 +1,4 @@ -use super::{CreateWindow, Time, WindowCreated, WindowResize, Windows, Event, WindowDescriptor}; +use super::{CreateWindow, Time, WindowCreated, WindowResized, Windows, Event, WindowDescriptor}; use crate::app::{plugin::AppPlugin, AppBuilder}; use bevy_transform::transform_system_bundle; @@ -20,7 +20,7 @@ impl AppPlugin for CorePlugin { app = app.add_system(transform_system); } - app = app.add_event::() + app = app.add_event::() .add_event::() .add_event::() .add_resource(Windows::default()) diff --git a/src/core/event.rs b/src/core/event.rs index b15becc917..f0ad901ad6 100644 --- a/src/core/event.rs +++ b/src/core/event.rs @@ -70,7 +70,7 @@ where self.event_count += 1; } - pub fn iter(&self, event_handle: &mut EventHandle) -> impl Iterator { + pub fn iter(&self, event_handle: &mut EventHandle) -> impl DoubleEndedIterator { let a_index = self.a_start_event_count - event_handle.last_event_count; let b_index = self.b_start_event_count - event_handle.last_event_count; event_handle.last_event_count = self.event_count; diff --git a/src/core/window/events.rs b/src/core/window/events.rs index 84c600083c..a5c2a3b785 100644 --- a/src/core/window/events.rs +++ b/src/core/window/events.rs @@ -1,10 +1,11 @@ use super::{WindowDescriptor, WindowId}; #[derive(Debug, Clone)] -pub struct WindowResize { +pub struct WindowResized { pub id: WindowId, pub width: u32, pub height: u32, + pub is_primary: bool, } #[derive(Debug, Clone)] diff --git a/src/core/window/winit/mod.rs b/src/core/window/winit/mod.rs index f659b0f6f3..88cae9f8b6 100644 --- a/src/core/window/winit/mod.rs +++ b/src/core/window/winit/mod.rs @@ -3,7 +3,7 @@ pub use winit_windows::*; use crate::prelude::*; -use super::{CreateWindow, Window, WindowCreated, WindowResize, Windows}; +use super::{CreateWindow, Window, WindowCreated, WindowResized, Windows}; use winit::{ event, event::WindowEvent, @@ -15,9 +15,8 @@ pub struct WinitPlugin; impl AppPlugin for WinitPlugin { fn build(&self, app: AppBuilder) -> AppBuilder { - app - .add_resource(WinitWindows::default()) - .set_runner(winit_runner) + app.add_resource(WinitWindows::default()) + .set_runner(winit_runner) } fn name(&self) -> &'static str { @@ -52,15 +51,20 @@ pub fn winit_runner(mut app: App) { let winit_windows = app.resources.get_mut::().unwrap(); let mut windows = app.resources.get_mut::().unwrap(); let window_id = winit_windows.get_window_id(winit_window_id).unwrap(); + let is_primary = windows + .get_primary() + .map(|primary_window| primary_window.id == window_id) + .unwrap_or(false); let mut window = windows.get_mut(window_id).unwrap(); window.width = size.width; window.height = size.height; - let mut resize_event = app.resources.get_mut::>().unwrap(); - resize_event.send(WindowResize { + let mut resize_event = app.resources.get_mut::>().unwrap(); + resize_event.send(WindowResized { id: window_id, height: window.height, width: window.width, + is_primary, }); } event::Event::WindowEvent { event, .. } => match event { @@ -102,22 +106,8 @@ fn handle_create_window_events( let mut window_created_events = resources.get_mut::>().unwrap(); for create_window_event in create_window_events.iter(create_window_event_handle) { let window = Window::new(&create_window_event.descriptor); - create_window( - &event_loop, - &mut window_created_events, - &mut winit_windows, - &window, - ); + winit_windows.create_window(event_loop, &window); + window_created_events.send(WindowCreated { id: window.id }); windows.add(window); } } - -pub fn create_window( - event_loop: &EventLoopWindowTarget<()>, - window_created_events: &mut Event, - winit_windows: &mut WinitWindows, - window: &Window, -) { - winit_windows.create_window(event_loop, &window); - window_created_events.send(WindowCreated { id: window.id }); -} diff --git a/src/render/render_plugin.rs b/src/render/render_plugin.rs index 739ab1a63f..1f35d41b46 100644 --- a/src/render/render_plugin.rs +++ b/src/render/render_plugin.rs @@ -14,14 +14,7 @@ use super::{ AssetBatchers, EntityRenderResourceAssignments, RenderResourceAssignments, }, }; -use crate::{ - app::{plugin::AppPlugin, AppBuilder}, - asset::AssetStorage, - prelude::{ - LocalToWorld, Mesh, PipelineDescriptor, Shader, StandardMaterial, Texture, - UniformResourceProvider, - }, -}; +use crate::{core::WindowResized, prelude::*}; #[derive(Default)] pub struct RenderPlugin; @@ -40,8 +33,12 @@ impl RenderPlugin { .add_draw_target(AssignedBatchesDrawTarget::default()) .add_draw_target(AssignedMeshesDrawTarget::default()) .add_draw_target(UiDrawTarget::default()) - .add_resource_provider(CameraResourceProvider::default()) - .add_resource_provider(Camera2dResourceProvider::default()) + .add_resource_provider(CameraResourceProvider::new( + app.resources.get_event_handle::(), + )) + .add_resource_provider(Camera2dResourceProvider::new( + app.resources.get_event_handle::(), + )) .add_resource_provider(LightResourceProvider::new(10)) .add_resource_provider(UiResourceProvider::new()) .add_resource_provider(MeshResourceProvider::new()) diff --git a/src/render/render_resource/resource_provider.rs b/src/render/render_resource/resource_provider.rs index 2e3bee4a84..9d17924586 100644 --- a/src/render/render_resource/resource_provider.rs +++ b/src/render/render_resource/resource_provider.rs @@ -18,13 +18,4 @@ pub trait ResourceProvider { _resources: &Resources, ) { } - fn resize( - &mut self, - _renderer: &mut dyn Renderer, - _world: &mut World, - _resources: &Resources, - _width: u32, - _height: u32, - ) { - } } diff --git a/src/render/render_resource/resource_providers/camera2d_resource_provider.rs b/src/render/render_resource/resource_providers/camera2d_resource_provider.rs index 84f6f54e4f..9074e8bc26 100644 --- a/src/render/render_resource/resource_providers/camera2d_resource_provider.rs +++ b/src/render/render_resource/resource_providers/camera2d_resource_provider.rs @@ -1,18 +1,29 @@ -use crate::render::{ - render_resource::{ - resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments, - ResourceProvider, +use crate::{ + core::WindowResized, + prelude::*, + render::{ + render_resource::{ + BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments, ResourceProvider, + }, + renderer::Renderer, }, - renderer::Renderer, - ActiveCamera2d, Camera, }; -use legion::prelude::*; use zerocopy::AsBytes; -#[derive(Default)] pub struct Camera2dResourceProvider { pub camera_buffer: Option, pub tmp_buffer: Option, + pub window_resized_event_handle: EventHandle, +} + +impl Camera2dResourceProvider { + pub fn new(window_resized_event_handle: EventHandle) -> Self { + Camera2dResourceProvider { + camera_buffer: None, + tmp_buffer: None, + window_resized_event_handle, + } + } } impl ResourceProvider for Camera2dResourceProvider { @@ -34,41 +45,47 @@ impl ResourceProvider for Camera2dResourceProvider { self.camera_buffer = Some(buffer); } - fn resize( - &mut self, - renderer: &mut dyn Renderer, - world: &mut World, - _resources: &Resources, - width: u32, - height: u32, - ) { - let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>(); - for (mut camera, _) in <(Write, Read)>::query().iter_mut(world) { - camera.update(width, height); - let camera_matrix: [[f32; 4]; 4] = camera.view_matrix.to_cols_array_2d(); + fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) { + let window_resized_events = resources.get::>().unwrap(); + let primary_window_resized_event = window_resized_events + .iter(&mut self.window_resized_event_handle) + .rev() + .filter(|event| event.is_primary) + .next(); - if let Some(old_tmp_buffer) = self.tmp_buffer { - renderer.remove_buffer(old_tmp_buffer); + if let Some(primary_window_resized_event) = primary_window_resized_event { + let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>(); + for (mut camera, _) in <(Write, Read)>::query().iter_mut(world) + { + camera.update( + primary_window_resized_event.width, + primary_window_resized_event.height, + ); + let camera_matrix: [[f32; 4]; 4] = camera.view_matrix.to_cols_array_2d(); + + if let Some(old_tmp_buffer) = self.tmp_buffer { + renderer.remove_buffer(old_tmp_buffer); + } + + self.tmp_buffer = Some(renderer.create_buffer_mapped( + BufferInfo { + size: matrix_size, + buffer_usage: BufferUsage::COPY_SRC, + ..Default::default() + }, + &mut |data, _renderer| { + data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); + }, + )); + + renderer.copy_buffer_to_buffer( + self.tmp_buffer.unwrap(), + 0, + self.camera_buffer.unwrap(), + 0, + matrix_size as u64, + ); } - - self.tmp_buffer = Some(renderer.create_buffer_mapped( - BufferInfo { - size: matrix_size, - buffer_usage: BufferUsage::COPY_SRC, - ..Default::default() - }, - &mut |data, _renderer| { - data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); - }, - )); - - renderer.copy_buffer_to_buffer( - self.tmp_buffer.unwrap(), - 0, - self.camera_buffer.unwrap(), - 0, - matrix_size as u64, - ); } } } diff --git a/src/render/render_resource/resource_providers/camera_resource_provider.rs b/src/render/render_resource/resource_providers/camera_resource_provider.rs index 0f0ba7f168..a66c877f5d 100644 --- a/src/render/render_resource/resource_providers/camera_resource_provider.rs +++ b/src/render/render_resource/resource_providers/camera_resource_provider.rs @@ -1,19 +1,31 @@ -use crate::render::{ - render_resource::{ - resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments, - ResourceProvider, +use crate::{ + core::WindowResized, + prelude::*, + render::{ + render_resource::{ + resource_name, BufferInfo, BufferUsage, RenderResource, RenderResourceAssignments, + ResourceProvider, + }, + renderer::Renderer, + ActiveCamera, Camera, }, - renderer::Renderer, - ActiveCamera, Camera, }; -use bevy_transform::prelude::LocalToWorld; -use legion::prelude::*; use zerocopy::AsBytes; -#[derive(Default)] pub struct CameraResourceProvider { pub camera_buffer: Option, pub tmp_buffer: Option, + pub window_resized_event_handle: EventHandle, +} + +impl CameraResourceProvider { + pub fn new(window_resized_event_handle: EventHandle) -> Self { + CameraResourceProvider { + camera_buffer: None, + tmp_buffer: None, + window_resized_event_handle, + } + } } impl ResourceProvider for CameraResourceProvider { @@ -35,44 +47,48 @@ impl ResourceProvider for CameraResourceProvider { self.camera_buffer = Some(buffer); } - fn resize( - &mut self, - renderer: &mut dyn Renderer, - world: &mut World, - _resources: &Resources, - width: u32, - height: u32, - ) { - let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>(); - for (mut camera, local_to_world, _) in - <(Write, Read, Read)>::query().iter_mut(world) - { - camera.update(width, height); - let camera_matrix: [[f32; 4]; 4] = - (camera.view_matrix * local_to_world.0).to_cols_array_2d(); + fn update(&mut self, renderer: &mut dyn Renderer, world: &mut World, resources: &Resources) { + let window_resized_events = resources.get::>().unwrap(); + let primary_window_resized_event = window_resized_events + .iter(&mut self.window_resized_event_handle) + .rev() + .filter(|event| event.is_primary) + .next(); + if let Some(primary_window_resized_event) = primary_window_resized_event { + let matrix_size = std::mem::size_of::<[[f32; 4]; 4]>(); + for (mut camera, local_to_world, _) in + <(Write, Read, Read)>::query().iter_mut(world) + { + camera.update( + primary_window_resized_event.width, + primary_window_resized_event.height, + ); + let camera_matrix: [[f32; 4]; 4] = + (camera.view_matrix * local_to_world.0).to_cols_array_2d(); - if let Some(old_tmp_buffer) = self.tmp_buffer { - renderer.remove_buffer(old_tmp_buffer); + if let Some(old_tmp_buffer) = self.tmp_buffer { + renderer.remove_buffer(old_tmp_buffer); + } + + self.tmp_buffer = Some(renderer.create_buffer_mapped( + BufferInfo { + size: matrix_size, + buffer_usage: BufferUsage::COPY_SRC, + ..Default::default() + }, + &mut |data, _renderer| { + data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); + }, + )); + + renderer.copy_buffer_to_buffer( + self.tmp_buffer.unwrap(), + 0, + self.camera_buffer.unwrap(), + 0, + matrix_size as u64, + ); } - - self.tmp_buffer = Some(renderer.create_buffer_mapped( - BufferInfo { - size: matrix_size, - buffer_usage: BufferUsage::COPY_SRC, - ..Default::default() - }, - &mut |data, _renderer| { - data[0..matrix_size].copy_from_slice(camera_matrix.as_bytes()); - }, - )); - - renderer.copy_buffer_to_buffer( - self.tmp_buffer.unwrap(), - 0, - self.camera_buffer.unwrap(), - 0, - matrix_size as u64, - ); } } } diff --git a/src/render/render_resource/resource_providers/frame_texture_resource_provider.rs b/src/render/render_resource/resource_providers/frame_texture_resource_provider.rs index 4de958b653..4a3719ce42 100644 --- a/src/render/render_resource/resource_providers/frame_texture_resource_provider.rs +++ b/src/render/render_resource/resource_providers/frame_texture_resource_provider.rs @@ -12,6 +12,8 @@ use legion::prelude::Resources; pub struct FrameTextureResourceProvider { pub name: String, pub descriptor: TextureDescriptor, + pub width: u32, + pub height: u32, } impl FrameTextureResourceProvider { @@ -19,44 +21,35 @@ impl FrameTextureResourceProvider { FrameTextureResourceProvider { name: name.to_string(), descriptor, + width: 0, + height: 0, } } - pub fn update(&mut self, renderer: &mut dyn Renderer, _world: &World, resources: &Resources) { + pub fn update(&mut self, renderer: &mut dyn Renderer, resources: &Resources) { let windows = resources.get::().unwrap(); let window = windows.get_primary().unwrap(); - self.descriptor.size.width = window.width; - self.descriptor.size.height = window.height; - let mut render_resource_assignments = - resources.get_mut::().unwrap(); - if let Some(old_resource) = render_resource_assignments.get(&self.name) { - renderer.remove_texture(old_resource); + if self.descriptor.size.width != window.width + || self.descriptor.size.height != window.height + { + self.descriptor.size.width = window.width; + self.descriptor.size.height = window.height; + + let mut render_resource_assignments = + resources.get_mut::().unwrap(); + if let Some(old_resource) = render_resource_assignments.get(&self.name) { + renderer.remove_texture(old_resource); + } + + let texture_resource = renderer.create_texture(&self.descriptor, None); + render_resource_assignments.set(&self.name, texture_resource); } - - let texture_resource = renderer.create_texture(&self.descriptor, None); - render_resource_assignments.set(&self.name, texture_resource); } } impl ResourceProvider for FrameTextureResourceProvider { - fn initialize( - &mut self, - renderer: &mut dyn Renderer, - world: &mut World, - resources: &Resources, - ) { - self.update(renderer, world, resources); - } - - fn resize( - &mut self, - renderer: &mut dyn Renderer, - world: &mut World, - resources: &Resources, - _width: u32, - _height: u32, - ) { - self.update(renderer, world, resources); + fn update(&mut self, renderer: &mut dyn Renderer, _world: &mut World, resources: &Resources) { + self.update(renderer, resources) } } diff --git a/src/render/renderer/renderer.rs b/src/render/renderer/renderer.rs index 44d73f41ca..0e35e86592 100644 --- a/src/render/renderer/renderer.rs +++ b/src/render/renderer/renderer.rs @@ -11,7 +11,6 @@ use crate::{ use std::ops::Range; pub trait Renderer { - fn resize(&mut self, world: &mut World, resources: &mut Resources); fn update(&mut self, world: &mut World, resources: &mut Resources); fn create_buffer_with_data(&mut self, buffer_info: BufferInfo, data: &[u8]) -> RenderResource; fn create_sampler(&mut self, sampler_descriptor: &SamplerDescriptor) -> RenderResource; diff --git a/src/render/renderer/renderers/wgpu_renderer/mod.rs b/src/render/renderer/renderers/wgpu_renderer/mod.rs index 5a1788cd60..fc2839a19c 100644 --- a/src/render/renderer/renderers/wgpu_renderer/mod.rs +++ b/src/render/renderer/renderers/wgpu_renderer/mod.rs @@ -8,8 +8,8 @@ pub use wgpu_renderer::*; pub use wgpu_resources::*; use crate::{ - app::{plugin::AppPlugin, AppBuilder, system_stage}, - core::{Event, WindowResize}, + app::{plugin::AppPlugin, system_stage, AppBuilder}, + core::{Event, WindowCreated, WindowResized}, render::renderer::Renderer, }; @@ -29,9 +29,13 @@ impl AppPlugin for WgpuRendererPlugin { } pub fn wgpu_render_system(resources: &Resources) -> impl FnMut(&mut World, &mut Resources) { - let window_resize_event = resources.get::>().unwrap(); - let mut wgpu_renderer = futures::executor::block_on(WgpuRenderer::new(window_resize_event.get_handle())); + let window_resized_event = resources.get::>().unwrap(); + let window_created_event = resources.get::>().unwrap(); + let mut wgpu_renderer = futures::executor::block_on(WgpuRenderer::new( + window_resized_event.get_handle(), + window_created_event.get_handle(), + )); move |world, resources| { wgpu_renderer.update(world, resources); } -} \ No newline at end of file +} diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs index 3f0c7f8c78..7000d458df 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_renderer.rs @@ -1,7 +1,7 @@ use super::{wgpu_type_converter::OwnedWgpuVertexBufferDescriptor, WgpuRenderPass, WgpuResources}; use crate::{ asset::{AssetStorage, Handle}, - core::{Event, EventHandle, WindowResize, winit::WinitWindows, Windows}, + core::{winit::WinitWindows, Event, EventHandle, WindowCreated, WindowResized, Windows, Window}, legion::prelude::*, render::{ pass::{ @@ -19,21 +19,29 @@ use crate::{ texture::{SamplerDescriptor, TextureDescriptor}, }, }; -use std::{cell::RefCell, collections::HashMap, ops::Deref, rc::Rc}; +use std::{ + cell::RefCell, + collections::{HashMap, HashSet}, + ops::Deref, + rc::Rc, +}; pub struct WgpuRenderer { pub device: Rc>, pub queue: wgpu::Queue, - pub surface: Option, pub encoder: Option, pub render_pipelines: HashMap, wgpu::RenderPipeline>, pub wgpu_resources: WgpuResources, - pub window_resize_handle: EventHandle, + pub window_resized_event_handle: EventHandle, + pub window_created_event_handle: EventHandle, pub intialized: bool, } impl WgpuRenderer { - pub async fn new(window_resize_event: EventHandle) -> Self { + pub async fn new( + window_resized_event_handle: EventHandle, + window_created_event_handle: EventHandle, + ) -> Self { let adapter = wgpu::Adapter::request( &wgpu::RequestAdapterOptions { power_preference: wgpu::PowerPreference::Default, @@ -43,19 +51,21 @@ impl WgpuRenderer { .await .unwrap(); - let (device, queue) = adapter.request_device(&wgpu::DeviceDescriptor { - extensions: wgpu::Extensions { - anisotropic_filtering: false, - }, - limits: wgpu::Limits::default(), - }).await; + let (device, queue) = adapter + .request_device(&wgpu::DeviceDescriptor { + extensions: wgpu::Extensions { + anisotropic_filtering: false, + }, + limits: wgpu::Limits::default(), + }) + .await; WgpuRenderer { device: Rc::new(RefCell::new(device)), queue, - surface: None, encoder: None, - window_resize_handle: window_resize_event, + window_resized_event_handle: window_resized_event_handle, + window_created_event_handle, intialized: false, wgpu_resources: WgpuResources::default(), render_pipelines: HashMap::new(), @@ -67,10 +77,7 @@ impl WgpuRenderer { return; } - self.create_surface(resources); self.initialize_resource_providers(world, resources); - self.resize(world, resources); - self.intialized = true; } @@ -342,75 +349,76 @@ impl WgpuRenderer { } } - pub fn create_surface(&mut self, resources: &Resources) { - #[cfg(feature = "winit")] + pub fn handle_window_resized_events(&mut self, resources: &mut Resources) { + let windows = resources.get::().unwrap(); + let window_resized_events = resources.get::>().unwrap(); + let mut handled_windows = HashSet::new(); + // iterate in reverse order so we can handle the latest window resize event first for each window. + // we skip earlier events for the same window because it results in redundant work + for window_resized_event in window_resized_events + .iter(&mut self.window_resized_event_handle) + .rev() { - let winit_windows = resources.get::().unwrap(); - let windows = resources.get::().unwrap(); - let primary_window = windows.get_primary().unwrap(); - let primary_winit_window = winit_windows.get_window(primary_window.id).unwrap(); - let surface = wgpu::Surface::create(primary_winit_window.deref()); - self.surface = Some(surface); + if handled_windows.contains(&window_resized_event.id) { + continue; + } + + let window = windows + .get(window_resized_event.id) + .expect("Received window resized event for non-existent window"); + + self.setup_swap_chain(window); + + handled_windows.insert(window_resized_event.id); } } + + pub fn handle_window_created_events(&mut self, resources: &mut Resources) { + let windows = resources.get::().unwrap(); + let winit_windows = resources.get::().unwrap(); + let window_created_events = resources.get::>().unwrap(); + for window_created_event in + window_created_events.iter(&mut self.window_created_event_handle) + { + let window = windows + .get(window_created_event.id) + .expect("Received window created event for non-existent window"); + #[cfg(feature = "winit")] + { + let primary_winit_window = winit_windows.get_window(window.id).unwrap(); + let surface = wgpu::Surface::create(primary_winit_window.deref()); + self.wgpu_resources + .window_surfaces + .insert(window.id, surface); + self.setup_swap_chain(window); + } + } + } + + fn setup_swap_chain(&mut self, window: &Window) { + let surface = self + .wgpu_resources + .window_surfaces + .get(&window.id) + .expect("Received window resized event for window without a wgpu surface"); + + let swap_chain_descriptor: wgpu::SwapChainDescriptor = window.into(); + let swap_chain = self + .device + .borrow() + .create_swap_chain(surface, &swap_chain_descriptor); + self.wgpu_resources + .window_swap_chains + .insert(window.id, swap_chain); + } } impl Renderer for WgpuRenderer { - fn resize(&mut self, world: &mut World, resources: &mut Resources) { - if let Some(surface) = self.surface.as_ref() { - self.encoder = Some( - self.device - .borrow() - .create_command_encoder(&wgpu::CommandEncoderDescriptor { todo: 0 }), - ); - let swap_chain_descriptor: wgpu::SwapChainDescriptor = { - let windows = resources.get::().unwrap(); - let window = windows.get_primary().unwrap(); - window.into() - }; - - let swap_chain = self - .device - .borrow() - .create_swap_chain(surface, &swap_chain_descriptor); - - // WgpuRenderer can't own swap_chain without creating lifetime ergonomics issues, so lets just store it in World. - resources.insert(swap_chain); - let mut render_graph = resources.get_mut::().unwrap(); - for resource_provider in render_graph.resource_providers.iter_mut() { - resource_provider.resize( - self, - world, - resources, - swap_chain_descriptor.width, - swap_chain_descriptor.height, - ); - } - - // consume current encoder - let command_buffer = self.encoder.take().unwrap().finish(); - self.queue.submit(&[command_buffer]); - } else { - // TODO: remove this warning if this case is not a problem - println!("warning: attempted to resize renderer before surface was ready"); - } - } - fn update(&mut self, world: &mut World, resources: &mut Resources) { self.initialize(world, resources); + self.handle_window_created_events(resources); + self.handle_window_resized_events(resources); - let resized = - resources - .get::>() - .unwrap() - .iter(&mut self.window_resize_handle) - .last() - .map(|_| ()) - .is_some(); - - if resized { - self.resize(world, resources); - } // TODO: this self.encoder handoff is a bit gross, but its here to give resource providers access to buffer copies without // exposing the wgpu renderer internals to ResourceProvider traits. if this can be made cleaner that would be pretty cool. self.encoder = Some( @@ -425,13 +433,17 @@ impl Renderer for WgpuRenderer { let mut encoder = self.encoder.take().unwrap(); - let mut swap_chain = resources.get_mut::().unwrap(); + // TODO: create swap chain outputs for every swap chain + let swap_chain = self + .wgpu_resources + .window_swap_chains + .values_mut() + .next() + .unwrap(); let frame = swap_chain .get_next_texture() .expect("Timeout when acquiring next swap chain texture"); - // self.setup_dynamic_entity_shader_uniforms(world, render_graph, &mut encoder); - // setup, pipelines, bind groups, and resources let mut pipeline_storage = resources .get_mut::>() diff --git a/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs b/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs index e673ee7bce..0ee5812e11 100644 --- a/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs +++ b/src/render/renderer/renderers/wgpu_renderer/wgpu_resources.rs @@ -10,7 +10,7 @@ use crate::{ }, renderer::Renderer, texture::{SamplerDescriptor, TextureDescriptor}, - }, + }, core::WindowId, }; use std::collections::HashMap; @@ -22,6 +22,8 @@ pub struct WgpuBindGroupInfo { #[derive(Default)] pub struct WgpuResources { pub render_resources: RenderResources, + pub window_surfaces: HashMap, + pub window_swap_chains: HashMap, pub buffers: HashMap, pub textures: HashMap, pub samplers: HashMap,