diff --git a/bevy_render/src/lib.rs b/bevy_render/src/lib.rs index 5a6487c381..fe7aee0f2a 100644 --- a/bevy_render/src/lib.rs +++ b/bevy_render/src/lib.rs @@ -40,21 +40,22 @@ use self::{ render_graph::RenderGraph, render_resource::{ entity_render_resource_assignments_system, - resource_providers::{ - LightResourceProvider, - UniformResourceProvider, - }, + resource_providers::{LightResourceProvider, UniformResourceProvider}, AssetBatchers, EntityRenderResourceAssignments, RenderResourceAssignments, }, shader::{uniforms::StandardMaterial, Shader}, texture::Texture, }; -use bevy_app::{stage, AppBuilder, AppPlugin}; +use bevy_app::{stage, AppBuilder, AppPlugin, GetEventReader}; use bevy_asset::AssetStorage; use bevy_transform::prelude::LocalToWorld; -use render_resource::resource_providers::{mesh_resource_provider_system}; -use render_graph_2::{nodes::{Camera2dNode, CameraNode}, RenderGraph2}; +use bevy_window::{WindowCreated, WindowResized}; +use render_graph_2::{ + nodes::{Camera2dNode, CameraNode, SwapChainWindowSource, WindowSwapChainNode}, + RenderGraph2, +}; +use render_resource::resource_providers::mesh_resource_provider_system; pub static RENDER_RESOURCE_STAGE: &str = "render_resource"; pub static RENDER_STAGE: &str = "render"; @@ -88,8 +89,14 @@ impl RenderPlugin { impl AppPlugin for RenderPlugin { fn build(&self, app: &mut AppBuilder) { let mut render_graph = RenderGraph2::default(); - render_graph.add_system_node(CameraNode::default(), app.resources_mut()); - render_graph.add_system_node(Camera2dNode::default(), app.resources_mut()); + let resources = app.resources_mut(); + render_graph.add_system_node(CameraNode::default(), resources); + render_graph.add_system_node(Camera2dNode::default(), resources); + render_graph.add_node(WindowSwapChainNode::new( + SwapChainWindowSource::Primary, + resources.get_event_reader::(), + resources.get_event_reader::(), + )); let mut asset_batchers = AssetBatchers::default(); asset_batchers.batch_types2::(); app.add_stage_after(stage::POST_UPDATE, RENDER_RESOURCE_STAGE) @@ -111,10 +118,7 @@ impl AppPlugin for RenderPlugin { // core systems .add_system(entity_render_resource_assignments_system()) .add_system_to_stage_init(stage::POST_UPDATE, camera::camera_update_system) - .add_system_to_stage( - stage::POST_UPDATE, - mesh::mesh_specializer_system(), - ) + .add_system_to_stage(stage::POST_UPDATE, mesh::mesh_specializer_system()) .add_system_to_stage(stage::POST_UPDATE, mesh::mesh_batcher_system()) .add_system_to_stage( stage::POST_UPDATE, diff --git a/bevy_render/src/render_graph_2/nodes/window_swapchain_node.rs b/bevy_render/src/render_graph_2/nodes/window_swapchain_node.rs index 53c5c581bf..641b4ae4f6 100644 --- a/bevy_render/src/render_graph_2/nodes/window_swapchain_node.rs +++ b/bevy_render/src/render_graph_2/nodes/window_swapchain_node.rs @@ -1,19 +1,41 @@ use crate::{ render_graph_2::{Node, ResourceBindings, ResourceSlot}, - render_resource::{RenderResource, ResourceInfo}, + render_resource::ResourceInfo, renderer_2::RenderContext, - texture::TextureDescriptor, }; use bevy_app::{EventReader, Events}; use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; use legion::prelude::*; +pub enum SwapChainWindowSource { + Primary, + Id(WindowId), +} + +impl Default for SwapChainWindowSource { + fn default() -> Self { + SwapChainWindowSource::Primary + } +} + pub struct WindowSwapChainNode { - window_id: WindowId, - use_primary_window: bool, - window_resized_event_reader: EventReader, + source_window: SwapChainWindowSource, window_created_event_reader: EventReader, - swap_chain_resource: Option, + window_resized_event_reader: EventReader, +} + +impl WindowSwapChainNode { + pub fn new( + source_window: SwapChainWindowSource, + window_created_event_reader: EventReader, + window_resized_event_reader: EventReader, + ) -> Self { + WindowSwapChainNode { + source_window, + window_created_event_reader, + window_resized_event_reader, + } + } } impl Node for WindowSwapChainNode { @@ -39,32 +61,30 @@ impl Node for WindowSwapChainNode { let windows = resources.get::().unwrap(); let render_resources = render_context.resources_mut(); - let window = if self.use_primary_window { - windows.get_primary().expect("No primary window exists") - } else { - windows - .get(self.window_id) - .expect("Received window resized event for non-existent window") + let window = match self.source_window { + SwapChainWindowSource::Primary => { + windows.get_primary().expect("No primary window exists") + } + SwapChainWindowSource::Id(id) => windows + .get(id) + .expect("Received window resized event for non-existent window"), }; // create window swapchain if let Some(_) = window_created_events - .find_latest(&mut self.window_created_event_reader, |e| { - e.id == window.id - }) + .find_latest(&mut self.window_created_event_reader, |e| e.id == window.id) { render_resources.create_swap_chain(window); } // resize window swapchain if let Some(_) = window_resized_events - .find_latest(&mut self.window_resized_event_reader, |e| { - e.id == window.id - }) + .find_latest(&mut self.window_resized_event_reader, |e| e.id == window.id) { render_resources.create_swap_chain(window); } - output.set(WINDOW_TEXTURE, self.swap_chain_resource.unwrap()); + let swap_chain_texture = render_resources.next_swap_chain_texture(window.id); + output.set(WINDOW_TEXTURE, swap_chain_texture); } } diff --git a/bevy_render/src/renderer_2/render_resource_context.rs b/bevy_render/src/renderer_2/render_resource_context.rs index cd527fc433..5021d1712e 100644 --- a/bevy_render/src/renderer_2/render_resource_context.rs +++ b/bevy_render/src/renderer_2/render_resource_context.rs @@ -24,8 +24,9 @@ impl GlobalRenderResourceContext { pub trait RenderResourceContext: Downcast + Send + Sync + 'static { fn create_swap_chain(&self, window: &Window); - fn next_swap_chain_texture(&self, window_id: WindowId); - fn drop_swap_chain_texture(&self, window_id: WindowId); + fn next_swap_chain_texture(&self, window_id: WindowId) -> RenderResource; + fn drop_swap_chain_texture(&self, render_resource: RenderResource); + fn drop_all_swap_chain_textures(&self); fn create_sampler(&self, sampler_descriptor: &SamplerDescriptor) -> RenderResource; fn create_texture(&self, texture_descriptor: &TextureDescriptor) -> RenderResource; fn create_buffer(&self, buffer_info: BufferInfo) -> RenderResource; diff --git a/bevy_wgpu/src/renderer_2/wgpu_render_context.rs b/bevy_wgpu/src/renderer_2/wgpu_render_context.rs index 7470dfd646..d028a209a5 100644 --- a/bevy_wgpu/src/renderer_2/wgpu_render_context.rs +++ b/bevy_wgpu/src/renderer_2/wgpu_render_context.rs @@ -426,7 +426,6 @@ impl RenderContext for WgpuRenderContext { let mut encoder = self.command_encoder.take().unwrap(); { let render_pass = create_render_pass( - self, pass_descriptor, render_resource_assignments, &refs, @@ -447,7 +446,6 @@ impl RenderContext for WgpuRenderContext { } pub fn create_render_pass<'a, 'b>( - render_context: &'a WgpuRenderContext, pass_descriptor: &PassDescriptor, global_render_resource_assignments: &'b RenderResourceAssignments, refs: &WgpuResourceRefs<'a>, @@ -459,7 +457,6 @@ pub fn create_render_pass<'a, 'b>( .iter() .map(|c| { create_wgpu_color_attachment_descriptor( - render_context, global_render_resource_assignments, refs, c, @@ -468,7 +465,6 @@ pub fn create_render_pass<'a, 'b>( .collect::>(), depth_stencil_attachment: pass_descriptor.depth_stencil_attachment.as_ref().map(|d| { create_wgpu_depth_stencil_attachment_descriptor( - render_context, global_render_resource_assignments, refs, d, @@ -478,7 +474,6 @@ pub fn create_render_pass<'a, 'b>( } fn get_texture_view<'a>( - render_context: &'a WgpuRenderContext, global_render_resource_assignments: &RenderResourceAssignments, refs: &WgpuResourceRefs<'a>, name: &str, @@ -487,10 +482,10 @@ fn get_texture_view<'a>( resource_name::texture::SWAP_CHAIN => { if let Some(primary_swap_chain) = refs .swap_chain_outputs - .get(render_context.primary_window.as_ref().unwrap()) - .map(|output| &output.view) + .values() + .next() { - primary_swap_chain + &primary_swap_chain.view } else { panic!("No primary swap chain found for color attachment"); } @@ -509,13 +504,11 @@ fn get_texture_view<'a>( } fn create_wgpu_color_attachment_descriptor<'a>( - render_context: &'a WgpuRenderContext, global_render_resource_assignments: &RenderResourceAssignments, refs: &WgpuResourceRefs<'a>, color_attachment_descriptor: &RenderPassColorAttachmentDescriptor, ) -> wgpu::RenderPassColorAttachmentDescriptor<'a> { let attachment = get_texture_view( - render_context, global_render_resource_assignments, refs, color_attachment_descriptor.attachment.as_str(), @@ -526,7 +519,6 @@ fn create_wgpu_color_attachment_descriptor<'a>( .as_ref() .map(|target| { get_texture_view( - render_context, global_render_resource_assignments, refs, target.as_str(), @@ -543,13 +535,11 @@ fn create_wgpu_color_attachment_descriptor<'a>( } fn create_wgpu_depth_stencil_attachment_descriptor<'a>( - render_context: &'a WgpuRenderContext, global_render_resource_assignments: &RenderResourceAssignments, refs: &WgpuResourceRefs<'a>, depth_stencil_attachment_descriptor: &RenderPassDepthStencilAttachmentDescriptor, ) -> wgpu::RenderPassDepthStencilAttachmentDescriptor<'a> { let attachment = get_texture_view( - render_context, global_render_resource_assignments, refs, depth_stencil_attachment_descriptor.attachment.as_str(), diff --git a/bevy_wgpu/src/renderer_2/wgpu_render_resource_context.rs b/bevy_wgpu/src/renderer_2/wgpu_render_resource_context.rs index 2b3a5dde39..5da028c0d2 100644 --- a/bevy_wgpu/src/renderer_2/wgpu_render_resource_context.rs +++ b/bevy_wgpu/src/renderer_2/wgpu_render_resource_context.rs @@ -7,7 +7,7 @@ use bevy_render::{ shader::Shader, texture::{SamplerDescriptor, TextureDescriptor}, }; -use bevy_window::{Window, WindowId}; +use bevy_window::Window; use std::sync::Arc; #[derive(Clone)] @@ -99,11 +99,15 @@ impl RenderResourceContext for WgpuRenderResourceContext { self.wgpu_resources .create_window_swap_chain(&self.device, window) } - fn next_swap_chain_texture(&self, window_id: bevy_window::WindowId) { - self.wgpu_resources.next_swap_chain_texture(window_id); + fn next_swap_chain_texture(&self, window_id: bevy_window::WindowId) -> RenderResource { + self.wgpu_resources.next_swap_chain_texture(window_id) } - fn drop_swap_chain_texture(&self, window_id: WindowId) { - self.wgpu_resources.remove_swap_chain_texture(window_id); + fn drop_swap_chain_texture(&self, render_resource: RenderResource) { + self.wgpu_resources + .remove_swap_chain_texture(render_resource); + } + fn drop_all_swap_chain_textures(&self) { + self.wgpu_resources.remove_all_swap_chain_textures(); } fn set_asset_resource_untyped( &self, diff --git a/bevy_wgpu/src/wgpu_renderer.rs b/bevy_wgpu/src/wgpu_renderer.rs index 4d59ae72a7..b173570549 100644 --- a/bevy_wgpu/src/wgpu_renderer.rs +++ b/bevy_wgpu/src/wgpu_renderer.rs @@ -12,7 +12,7 @@ use bevy_render::{ }; use bevy_window::{WindowCreated, WindowResized, Windows}; use legion::prelude::*; -use std::{collections::HashSet, ops::Deref, sync::Arc}; +use std::{ops::Deref, sync::Arc}; pub struct WgpuRenderer { pub device: Arc, pub queue: wgpu::Queue, @@ -171,35 +171,6 @@ impl WgpuRenderer { } } - pub fn handle_window_resized_events( - &mut self, - resources: &Resources, - global_render_resources: &dyn RenderResourceContext, - ) { - 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_reader) - .rev() - { - 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"); - - // TODO: consider making this a WgpuRenderContext method - global_render_resources.create_swap_chain(window); - - handled_windows.insert(window_resized_event.id); - } - } - pub fn handle_window_created_events( &mut self, resources: &Resources, @@ -216,12 +187,11 @@ impl WgpuRenderer { #[cfg(feature = "bevy_winit")] { let winit_windows = resources.get::().unwrap(); - let primary_winit_window = winit_windows.get_window(window.id).unwrap(); - let surface = wgpu::Surface::create(primary_winit_window.deref()); + let winit_window = winit_windows.get_window(window.id).unwrap(); + let surface = wgpu::Surface::create(winit_window.deref()); global_render_resource_context .wgpu_resources .set_window_surface(window.id, surface); - global_render_resource_context.create_swap_chain(window); } } } @@ -251,8 +221,14 @@ impl WgpuRenderer { for mut stage in linear_scheduler.get_stages(&mut render_graph) { for job in stage.iter_mut() { for node_state in job.iter_mut() { - node_state.node.update(world, resources, &mut render_context, &node_state.input, &mut node_state.output); - } + node_state.node.update( + world, + resources, + &mut render_context, + &node_state.input, + &mut node_state.output, + ); + } } } @@ -263,7 +239,6 @@ impl WgpuRenderer { } pub fn update(&mut self, world: &mut World, resources: &mut Resources) { - self.run_graph(world, resources); let mut encoder = { let mut global_context = resources.get_mut::().unwrap(); let render_resource_context = global_context @@ -273,7 +248,6 @@ impl WgpuRenderer { self.handle_window_created_events(resources, render_resource_context); - self.handle_window_resized_events(resources, render_resource_context); let mut render_context = WgpuRenderContext::new(self.device.clone(), render_resource_context.clone()); if !self.intialized { @@ -292,6 +266,7 @@ impl WgpuRenderer { render_context.command_encoder.take() }; + self.run_graph(world, resources); // TODO: add to POST_UPDATE and remove redundant global_context render_resource_sets_system().run(world, resources); let mut global_context = resources.get_mut::().unwrap(); @@ -317,9 +292,6 @@ impl WgpuRenderer { .get_primary() .map(|window| window.id); if let Some(primary_window_id) = primary_window_id { - render_context - .render_resources - .next_swap_chain_texture(primary_window_id); render_context.primary_window = Some(primary_window_id); } @@ -371,11 +343,9 @@ impl WgpuRenderer { self.queue.submit(&[command_buffer]); } - // clear primary swap chain texture - if let Some(primary_window_id) = primary_window_id { - render_context - .render_resources - .drop_swap_chain_texture(primary_window_id); - } + // clear swap chain textures + render_context + .render_resources + .drop_all_swap_chain_textures(); } } diff --git a/bevy_wgpu/src/wgpu_resources.rs b/bevy_wgpu/src/wgpu_resources.rs index b9749ad670..3d1e3aa686 100644 --- a/bevy_wgpu/src/wgpu_resources.rs +++ b/bevy_wgpu/src/wgpu_resources.rs @@ -43,7 +43,7 @@ pub struct WgpuBindGroupInfo { pub struct WgpuResourcesReadLock<'a> { pub buffers: RwLockReadGuard<'a, HashMap>, pub textures: RwLockReadGuard<'a, HashMap>, - pub swap_chain_outputs: RwLockReadGuard<'a, HashMap>, + pub swap_chain_outputs: RwLockReadGuard<'a, HashMap>, pub render_pipelines: RwLockReadGuard<'a, HashMap, wgpu::RenderPipeline>>, pub bind_groups: RwLockReadGuard<'a, HashMap>, @@ -65,7 +65,7 @@ impl<'a> WgpuResourcesReadLock<'a> { pub struct WgpuResourceRefs<'a> { pub buffers: &'a HashMap, pub textures: &'a HashMap, - pub swap_chain_outputs: &'a HashMap, + pub swap_chain_outputs: &'a HashMap, pub render_pipelines: &'a HashMap, wgpu::RenderPipeline>, pub bind_groups: &'a HashMap, } @@ -75,7 +75,7 @@ pub struct WgpuResources { // TODO: remove this from WgpuResources. it doesn't need to be here pub window_surfaces: Arc>>, pub window_swap_chains: Arc>>, - pub swap_chain_outputs: Arc>>, + pub swap_chain_outputs: Arc>>, pub buffers: Arc>>, pub textures: Arc>>, pub samplers: Arc>>, @@ -105,18 +105,21 @@ impl WgpuResources { .insert(window_id, surface); } - pub fn next_swap_chain_texture(&self, window_id: WindowId) { + pub fn next_swap_chain_texture(&self, window_id: WindowId) -> RenderResource { let mut swap_chain_outputs = self.window_swap_chains.write().unwrap(); let swap_chain_output = swap_chain_outputs.get_mut(&window_id).unwrap(); let next_texture = swap_chain_output.get_next_texture().unwrap(); + let render_resource = RenderResource::new(); + // TODO: Add ResourceInfo self.swap_chain_outputs .write() .unwrap() - .insert(window_id, next_texture); + .insert(render_resource, next_texture); + render_resource } - pub fn remove_swap_chain_texture(&self, window_id: WindowId) { - self.swap_chain_outputs.write().unwrap().remove(&window_id); + pub fn remove_swap_chain_texture(&self, render_resource: RenderResource) { + self.swap_chain_outputs.write().unwrap().remove(&render_resource); } pub fn remove_all_swap_chain_textures(&self) {