RenderGraph2: Finish graph executor, fix window textures
This commit is contained in:
		
							parent
							
								
									8326a1a3c2
								
							
						
					
					
						commit
						5780bf4025
					
				| @ -50,14 +50,15 @@ use self::{ | |||||||
| use bevy_app::{stage, AppBuilder, AppPlugin, GetEventReader}; | use bevy_app::{stage, AppBuilder, AppPlugin, GetEventReader}; | ||||||
| use bevy_asset::AssetStorage; | use bevy_asset::AssetStorage; | ||||||
| use bevy_transform::prelude::LocalToWorld; | use bevy_transform::prelude::LocalToWorld; | ||||||
| use bevy_window::{WindowCreated, WindowResized}; | use bevy_window::{WindowCreated, WindowReference, WindowResized}; | ||||||
| use pass::PassDescriptor; | use pass::PassDescriptor; | ||||||
| use pipeline::pipelines::build_forward_pipeline; | use pipeline::pipelines::build_forward_pipeline; | ||||||
| use render_graph_2::{ | use render_graph_2::{ | ||||||
|     nodes::{Camera2dNode, CameraNode, PassNode, SwapChainWindowSource, WindowSwapChainNode}, |     nodes::{Camera2dNode, CameraNode, PassNode, WindowSwapChainNode, WindowTextureNode}, | ||||||
|     RenderGraph2, |     RenderGraph2, | ||||||
| }; | }; | ||||||
| use render_resource::resource_providers::mesh_resource_provider_system; | use render_resource::resource_providers::mesh_resource_provider_system; | ||||||
|  | use texture::{Extent3d, TextureDescriptor, TextureDimension, TextureFormat, TextureUsage}; | ||||||
| 
 | 
 | ||||||
| pub static RENDER_RESOURCE_STAGE: &str = "render_resource"; | pub static RENDER_RESOURCE_STAGE: &str = "render_resource"; | ||||||
| pub static RENDER_STAGE: &str = "render"; | pub static RENDER_STAGE: &str = "render"; | ||||||
| @ -126,7 +127,28 @@ impl AppPlugin for RenderPlugin { | |||||||
|             render_graph.add_node_named( |             render_graph.add_node_named( | ||||||
|                 "swapchain", |                 "swapchain", | ||||||
|                 WindowSwapChainNode::new( |                 WindowSwapChainNode::new( | ||||||
|                     SwapChainWindowSource::Primary, |                     WindowReference::Primary, | ||||||
|  |                     resources.get_event_reader::<WindowCreated>(), | ||||||
|  |                     resources.get_event_reader::<WindowResized>(), | ||||||
|  |                 ), | ||||||
|  |             ); | ||||||
|  |             render_graph.add_node_named( | ||||||
|  |                 "main_pass_depth_texture", | ||||||
|  |                 WindowTextureNode::new( | ||||||
|  |                     WindowReference::Primary, | ||||||
|  |                     TextureDescriptor { | ||||||
|  |                         size: Extent3d { | ||||||
|  |                             depth: 1, | ||||||
|  |                             width: 1, | ||||||
|  |                             height: 1, | ||||||
|  |                         }, | ||||||
|  |                         array_layer_count: 1, | ||||||
|  |                         mip_level_count: 1, | ||||||
|  |                         sample_count: 1, | ||||||
|  |                         dimension: TextureDimension::D2, | ||||||
|  |                         format: TextureFormat::Depth32Float, // PERF: vulkan recommends using 24 bit depth for better performance
 | ||||||
|  |                         usage: TextureUsage::OUTPUT_ATTACHMENT, | ||||||
|  |                     }, | ||||||
|                     resources.get_event_reader::<WindowCreated>(), |                     resources.get_event_reader::<WindowCreated>(), | ||||||
|                     resources.get_event_reader::<WindowResized>(), |                     resources.get_event_reader::<WindowResized>(), | ||||||
|                 ), |                 ), | ||||||
| @ -164,7 +186,20 @@ impl AppPlugin for RenderPlugin { | |||||||
|             render_graph.add_node_edge("camera", "main_pass").unwrap(); |             render_graph.add_node_edge("camera", "main_pass").unwrap(); | ||||||
|             render_graph.add_node_edge("camera2d", "main_pass").unwrap(); |             render_graph.add_node_edge("camera2d", "main_pass").unwrap(); | ||||||
|             render_graph |             render_graph | ||||||
|                 .add_slot_edge("swapchain", WindowSwapChainNode::OUT_TEXTURE, "main_pass", "color") |                 .add_slot_edge( | ||||||
|  |                     "swapchain", | ||||||
|  |                     WindowSwapChainNode::OUT_TEXTURE, | ||||||
|  |                     "main_pass", | ||||||
|  |                     "color", | ||||||
|  |                 ) | ||||||
|  |                 .unwrap(); | ||||||
|  |             render_graph | ||||||
|  |                 .add_slot_edge( | ||||||
|  |                     "main_pass_depth_texture", | ||||||
|  |                     WindowTextureNode::OUT_TEXTURE, | ||||||
|  |                     "main_pass", | ||||||
|  |                     "depth", | ||||||
|  |                 ) | ||||||
|                 .unwrap(); |                 .unwrap(); | ||||||
|         } |         } | ||||||
|         app.add_resource(render_graph); |         app.add_resource(render_graph); | ||||||
|  | |||||||
| @ -131,10 +131,10 @@ impl RenderGraph2 { | |||||||
| 
 | 
 | ||||||
|         { |         { | ||||||
|             let output_node = self.get_node_state_mut(output_node_id)?; |             let output_node = self.get_node_state_mut(output_node_id)?; | ||||||
|             output_node.add_output_edge(edge.clone())?; |             output_node.edges.add_output_edge(edge.clone())?; | ||||||
|         } |         } | ||||||
|         let input_node = self.get_node_state_mut(input_node_id)?; |         let input_node = self.get_node_state_mut(input_node_id)?; | ||||||
|         input_node.add_input_edge(edge)?; |         input_node.edges.add_input_edge(edge)?; | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| @ -156,10 +156,10 @@ impl RenderGraph2 { | |||||||
| 
 | 
 | ||||||
|         { |         { | ||||||
|             let output_node = self.get_node_state_mut(output_node_id)?; |             let output_node = self.get_node_state_mut(output_node_id)?; | ||||||
|             output_node.add_output_edge(edge.clone())?; |             output_node.edges.add_output_edge(edge.clone())?; | ||||||
|         } |         } | ||||||
|         let input_node = self.get_node_state_mut(input_node_id)?; |         let input_node = self.get_node_state_mut(input_node_id)?; | ||||||
|         input_node.add_input_edge(edge)?; |         input_node.edges.add_input_edge(edge)?; | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
| @ -185,7 +185,7 @@ impl RenderGraph2 { | |||||||
|                 if let Some(Edge::SlotEdge { |                 if let Some(Edge::SlotEdge { | ||||||
|                     output_node: current_output_node, |                     output_node: current_output_node, | ||||||
|                     .. |                     .. | ||||||
|                 }) = input_node_state.input_edges.iter().find(|e| { |                 }) = input_node_state.edges.input_edges.iter().find(|e| { | ||||||
|                     if let Edge::SlotEdge { |                     if let Edge::SlotEdge { | ||||||
|                         input_index: current_input_index, |                         input_index: current_input_index, | ||||||
|                         .. |                         .. | ||||||
| @ -222,9 +222,9 @@ impl RenderGraph2 { | |||||||
|         let output_node_state = self.get_node_state(edge.get_output_node()); |         let output_node_state = self.get_node_state(edge.get_output_node()); | ||||||
|         let input_node_state = self.get_node_state(edge.get_input_node()); |         let input_node_state = self.get_node_state(edge.get_input_node()); | ||||||
|         if let Ok(output_node_state) = output_node_state { |         if let Ok(output_node_state) = output_node_state { | ||||||
|             if output_node_state.output_edges.contains(edge) { |             if output_node_state.edges.output_edges.contains(edge) { | ||||||
|                 if let Ok(input_node_state) = input_node_state { |                 if let Ok(input_node_state) = input_node_state { | ||||||
|                     if input_node_state.input_edges.contains(edge) { |                     if input_node_state.edges.input_edges.contains(edge) { | ||||||
|                         return true; |                         return true; | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -270,6 +270,7 @@ impl RenderGraph2 { | |||||||
|     ) -> Result<impl Iterator<Item = (&Edge, &NodeState)>, RenderGraphError> { |     ) -> Result<impl Iterator<Item = (&Edge, &NodeState)>, RenderGraphError> { | ||||||
|         let node = self.get_node_state(label)?; |         let node = self.get_node_state(label)?; | ||||||
|         Ok(node |         Ok(node | ||||||
|  |             .edges | ||||||
|             .input_edges |             .input_edges | ||||||
|             .iter() |             .iter() | ||||||
|             .map(|edge| (edge, edge.get_output_node())) |             .map(|edge| (edge, edge.get_output_node())) | ||||||
| @ -284,6 +285,7 @@ impl RenderGraph2 { | |||||||
|     ) -> Result<impl Iterator<Item = (&Edge, &NodeState)>, RenderGraphError> { |     ) -> Result<impl Iterator<Item = (&Edge, &NodeState)>, RenderGraphError> { | ||||||
|         let node = self.get_node_state(label)?; |         let node = self.get_node_state(label)?; | ||||||
|         Ok(node |         Ok(node | ||||||
|  |             .edges | ||||||
|             .output_edges |             .output_edges | ||||||
|             .iter() |             .iter() | ||||||
|             .map(|edge| (edge, edge.get_input_node())) |             .map(|edge| (edge, edge.get_input_node())) | ||||||
|  | |||||||
| @ -39,56 +39,13 @@ pub trait SystemNode: Node { | |||||||
|     fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable>; |     fn get_system(&self, resources: &mut Resources) -> Box<dyn Schedulable>; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct NodeState { | pub struct Edges { | ||||||
|     pub id: NodeId, |     pub id: NodeId, | ||||||
|     pub name: Option<Cow<'static, str>>, |  | ||||||
|     pub node: Box<dyn Node>, |  | ||||||
|     pub input_slots: ResourceSlots, |  | ||||||
|     pub output_slots: ResourceSlots, |  | ||||||
|     pub input_edges: Vec<Edge>, |     pub input_edges: Vec<Edge>, | ||||||
|     pub output_edges: Vec<Edge>, |     pub output_edges: Vec<Edge>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Debug for NodeState { | impl Edges { | ||||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |  | ||||||
|         writeln!(f, "{:?} ({:?})", self.id, self.name) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl NodeState { |  | ||||||
|     pub fn new<T>(id: NodeId, node: T) -> Self |  | ||||||
|     where |  | ||||||
|         T: Node, |  | ||||||
|     { |  | ||||||
|         NodeState { |  | ||||||
|             id, |  | ||||||
|             name: None, |  | ||||||
|             input_slots: ResourceSlots::from(node.input()), |  | ||||||
|             output_slots: ResourceSlots::from(node.output()), |  | ||||||
|             node: Box::new(node), |  | ||||||
|             input_edges: Vec::new(), |  | ||||||
|             output_edges: Vec::new(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn node<T>(&self) -> Result<&T, RenderGraphError> |  | ||||||
|     where |  | ||||||
|         T: Node, |  | ||||||
|     { |  | ||||||
|         self.node |  | ||||||
|             .downcast_ref::<T>() |  | ||||||
|             .ok_or_else(|| RenderGraphError::WrongNodeType) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub fn node_mut<T>(&mut self) -> Result<&mut T, RenderGraphError> |  | ||||||
|     where |  | ||||||
|         T: Node, |  | ||||||
|     { |  | ||||||
|         self.node |  | ||||||
|             .downcast_mut::<T>() |  | ||||||
|             .ok_or_else(|| RenderGraphError::WrongNodeType) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     pub(crate) fn add_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> { |     pub(crate) fn add_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> { | ||||||
|         if self.has_input_edge(&edge) { |         if self.has_input_edge(&edge) { | ||||||
|             return Err(RenderGraphError::EdgeAlreadyExists(edge.clone())); |             return Err(RenderGraphError::EdgeAlreadyExists(edge.clone())); | ||||||
| @ -144,10 +101,64 @@ impl NodeState { | |||||||
|                 node: self.id, |                 node: self.id, | ||||||
|             }) |             }) | ||||||
|     } |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct NodeState { | ||||||
|  |     pub id: NodeId, | ||||||
|  |     pub name: Option<Cow<'static, str>>, | ||||||
|  |     pub node: Box<dyn Node>, | ||||||
|  |     pub input_slots: ResourceSlots, | ||||||
|  |     pub output_slots: ResourceSlots, | ||||||
|  |     pub edges: Edges, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Debug for NodeState { | ||||||
|  |     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||||
|  |         writeln!(f, "{:?} ({:?})", self.id, self.name) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl NodeState { | ||||||
|  |     pub fn new<T>(id: NodeId, node: T) -> Self | ||||||
|  |     where | ||||||
|  |         T: Node, | ||||||
|  |     { | ||||||
|  |         NodeState { | ||||||
|  |             id, | ||||||
|  |             name: None, | ||||||
|  |             input_slots: ResourceSlots::from(node.input()), | ||||||
|  |             output_slots: ResourceSlots::from(node.output()), | ||||||
|  |             node: Box::new(node), | ||||||
|  |             edges: Edges { | ||||||
|  |                 id, | ||||||
|  |                 input_edges: Vec::new(), | ||||||
|  |                 output_edges: Vec::new(), | ||||||
|  |             }, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn node<T>(&self) -> Result<&T, RenderGraphError> | ||||||
|  |     where | ||||||
|  |         T: Node, | ||||||
|  |     { | ||||||
|  |         self.node | ||||||
|  |             .downcast_ref::<T>() | ||||||
|  |             .ok_or_else(|| RenderGraphError::WrongNodeType) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn node_mut<T>(&mut self) -> Result<&mut T, RenderGraphError> | ||||||
|  |     where | ||||||
|  |         T: Node, | ||||||
|  |     { | ||||||
|  |         self.node | ||||||
|  |             .downcast_mut::<T>() | ||||||
|  |             .ok_or_else(|| RenderGraphError::WrongNodeType) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
|     pub fn validate_output_slots(&self) -> Result<(), RenderGraphError> { |     pub fn validate_output_slots(&self) -> Result<(), RenderGraphError> { | ||||||
|         for i in 0..self.output_slots.len() { |         for i in 0..self.output_slots.len() { | ||||||
|             self.get_output_slot_edge(i)?; |             self.edges.get_output_slot_edge(i)?; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
| @ -155,7 +166,7 @@ impl NodeState { | |||||||
| 
 | 
 | ||||||
|     pub fn validate_input_slots(&self) -> Result<(), RenderGraphError> { |     pub fn validate_input_slots(&self) -> Result<(), RenderGraphError> { | ||||||
|         for i in 0..self.input_slots.len() { |         for i in 0..self.input_slots.len() { | ||||||
|             self.get_input_slot_edge(i)?; |             self.edges.get_input_slot_edge(i)?; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
|  | |||||||
| @ -2,13 +2,13 @@ use super::RenderGraphError; | |||||||
| use crate::render_resource::{RenderResource, ResourceInfo}; | use crate::render_resource::{RenderResource, ResourceInfo}; | ||||||
| use std::borrow::Cow; | use std::borrow::Cow; | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug, Clone)] | ||||||
| pub struct ResourceSlot { | pub struct ResourceSlot { | ||||||
|     pub resource: Option<RenderResource>, |     pub resource: Option<RenderResource>, | ||||||
|     pub info: ResourceSlotInfo, |     pub info: ResourceSlotInfo, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Default, Debug)] | #[derive(Default, Debug, Clone)] | ||||||
| pub struct ResourceSlots { | pub struct ResourceSlots { | ||||||
|     slots: Vec<ResourceSlot>, |     slots: Vec<ResourceSlot>, | ||||||
| } | } | ||||||
| @ -93,6 +93,10 @@ impl ResourceSlots { | |||||||
|         self.slots.iter() |         self.slots.iter() | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut ResourceSlot> { | ||||||
|  |         self.slots.iter_mut() | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn len(&self) -> usize { |     pub fn len(&self) -> usize { | ||||||
|         self.slots.len() |         self.slots.len() | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -23,7 +23,7 @@ impl PassNode { | |||||||
|         for color_attachment in descriptor.color_attachments.iter() { |         for color_attachment in descriptor.color_attachments.iter() { | ||||||
|             if let TextureAttachment::Input(ref name) = color_attachment.attachment { |             if let TextureAttachment::Input(ref name) = color_attachment.attachment { | ||||||
|                 inputs.push(ResourceSlotInfo::new(name.to_string(), ResourceInfo::Texture)); |                 inputs.push(ResourceSlotInfo::new(name.to_string(), ResourceInfo::Texture)); | ||||||
|                 color_attachment_input_indices.push(Some(inputs.len())); |                 color_attachment_input_indices.push(Some(inputs.len() - 1)); | ||||||
|             } else { |             } else { | ||||||
|                 color_attachment_input_indices.push(None); |                 color_attachment_input_indices.push(None); | ||||||
|             } |             } | ||||||
| @ -33,7 +33,7 @@ impl PassNode { | |||||||
|         if let Some(ref depth_stencil_attachment)= descriptor.depth_stencil_attachment { |         if let Some(ref depth_stencil_attachment)= descriptor.depth_stencil_attachment { | ||||||
|             if let TextureAttachment::Input(ref name) = depth_stencil_attachment.attachment { |             if let TextureAttachment::Input(ref name) = depth_stencil_attachment.attachment { | ||||||
|                 inputs.push(ResourceSlotInfo::new(name.to_string(), ResourceInfo::Texture)); |                 inputs.push(ResourceSlotInfo::new(name.to_string(), ResourceInfo::Texture)); | ||||||
|                 depth_stencil_attachment_input_index = Some(inputs.len()); |                 depth_stencil_attachment_input_index = Some(inputs.len() - 1); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -4,23 +4,12 @@ use crate::{ | |||||||
|     renderer_2::RenderContext, |     renderer_2::RenderContext, | ||||||
| }; | }; | ||||||
| use bevy_app::{EventReader, Events}; | use bevy_app::{EventReader, Events}; | ||||||
| use bevy_window::{WindowCreated, WindowId, WindowResized, Windows}; | use bevy_window::{WindowCreated, WindowResized, Windows, WindowReference}; | ||||||
| use legion::prelude::*; | use legion::prelude::*; | ||||||
| use std::borrow::Cow; | use std::borrow::Cow; | ||||||
| 
 | 
 | ||||||
| pub enum SwapChainWindowSource { |  | ||||||
|     Primary, |  | ||||||
|     Id(WindowId), |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl Default for SwapChainWindowSource { |  | ||||||
|     fn default() -> Self { |  | ||||||
|         SwapChainWindowSource::Primary |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| pub struct WindowSwapChainNode { | pub struct WindowSwapChainNode { | ||||||
|     source_window: SwapChainWindowSource, |     window_reference: WindowReference, | ||||||
|     window_created_event_reader: EventReader<WindowCreated>, |     window_created_event_reader: EventReader<WindowCreated>, | ||||||
|     window_resized_event_reader: EventReader<WindowResized>, |     window_resized_event_reader: EventReader<WindowResized>, | ||||||
| } | } | ||||||
| @ -28,12 +17,12 @@ pub struct WindowSwapChainNode { | |||||||
| impl WindowSwapChainNode { | impl WindowSwapChainNode { | ||||||
|     pub const OUT_TEXTURE: &'static str = "texture"; |     pub const OUT_TEXTURE: &'static str = "texture"; | ||||||
|     pub fn new( |     pub fn new( | ||||||
|         source_window: SwapChainWindowSource, |         window_reference: WindowReference, | ||||||
|         window_created_event_reader: EventReader<WindowCreated>, |         window_created_event_reader: EventReader<WindowCreated>, | ||||||
|         window_resized_event_reader: EventReader<WindowResized>, |         window_resized_event_reader: EventReader<WindowResized>, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         WindowSwapChainNode { |         WindowSwapChainNode { | ||||||
|             source_window, |             window_reference, | ||||||
|             window_created_event_reader, |             window_created_event_reader, | ||||||
|             window_resized_event_reader, |             window_resized_event_reader, | ||||||
|         } |         } | ||||||
| @ -62,26 +51,22 @@ impl Node for WindowSwapChainNode { | |||||||
|         let window_resized_events = resources.get::<Events<WindowResized>>().unwrap(); |         let window_resized_events = resources.get::<Events<WindowResized>>().unwrap(); | ||||||
|         let windows = resources.get::<Windows>().unwrap(); |         let windows = resources.get::<Windows>().unwrap(); | ||||||
| 
 | 
 | ||||||
|         let render_resources = render_context.resources_mut(); |         let window = match self.window_reference { | ||||||
|         let window = match self.source_window { |             WindowReference::Primary => { | ||||||
|             SwapChainWindowSource::Primary => { |  | ||||||
|                 windows.get_primary().expect("No primary window exists") |                 windows.get_primary().expect("No primary window exists") | ||||||
|             } |             } | ||||||
|             SwapChainWindowSource::Id(id) => windows |             WindowReference::Id(id) => windows | ||||||
|                 .get(id) |                 .get(id) | ||||||
|                 .expect("Received window resized event for non-existent window"), |                 .expect("Received window resized event for non-existent window"), | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         // create window swapchain
 |         let render_resources = render_context.resources_mut(); | ||||||
|         if let Some(_) = window_created_events |  | ||||||
|             .find_latest(&mut self.window_created_event_reader, |e| e.id == window.id) |  | ||||||
|         { |  | ||||||
|             render_resources.create_swap_chain(window); |  | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         // resize window swapchain
 |         // create window swapchain when window is resized or created
 | ||||||
|         if let Some(_) = window_resized_events |         if window_created_events | ||||||
|             .find_latest(&mut self.window_resized_event_reader, |e| e.id == window.id) |             .find_latest(&mut self.window_created_event_reader, |e| e.id == window.id).is_some() || | ||||||
|  |             window_resized_events | ||||||
|  |             .find_latest(&mut self.window_resized_event_reader, |e| e.id == window.id).is_some() | ||||||
|         { |         { | ||||||
|             render_resources.create_swap_chain(window); |             render_resources.create_swap_chain(window); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -1,23 +1,42 @@ | |||||||
| use crate::{ | use crate::{ | ||||||
|     render_graph_2::{Node, ResourceSlots, ResourceSlotInfo}, |     render_graph_2::{Node, ResourceSlotInfo, ResourceSlots}, | ||||||
|     render_resource::ResourceInfo, |     render_resource::ResourceInfo, | ||||||
|     renderer_2::RenderContext, |     renderer_2::RenderContext, | ||||||
|     texture::TextureDescriptor, |     texture::TextureDescriptor, | ||||||
| }; | }; | ||||||
| use bevy_app::{EventReader, Events}; | use bevy_app::{EventReader, Events}; | ||||||
| use bevy_window::WindowResized; | use bevy_window::{WindowCreated, WindowReference, WindowResized, Windows}; | ||||||
| use legion::prelude::*; | use legion::prelude::*; | ||||||
| use std::borrow::Cow; | use std::borrow::Cow; | ||||||
| 
 | 
 | ||||||
| pub struct WindowTextureNode { | pub struct WindowTextureNode { | ||||||
|     pub descriptor: TextureDescriptor, |     window_reference: WindowReference, | ||||||
|  |     descriptor: TextureDescriptor, | ||||||
|  |     window_created_event_reader: EventReader<WindowCreated>, | ||||||
|     window_resized_event_reader: EventReader<WindowResized>, |     window_resized_event_reader: EventReader<WindowResized>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl WindowTextureNode { | ||||||
|  |     pub const OUT_TEXTURE: &'static str = "texture"; | ||||||
|  |     pub fn new( | ||||||
|  |         window_reference: WindowReference, | ||||||
|  |         descriptor: TextureDescriptor, | ||||||
|  |         window_created_event_reader: EventReader<WindowCreated>, | ||||||
|  |         window_resized_event_reader: EventReader<WindowResized>, | ||||||
|  |     ) -> Self { | ||||||
|  |         WindowTextureNode { | ||||||
|  |             window_reference, | ||||||
|  |             descriptor, | ||||||
|  |             window_created_event_reader, | ||||||
|  |             window_resized_event_reader, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| impl Node for WindowTextureNode { | impl Node for WindowTextureNode { | ||||||
|     fn output(&self) -> &[ResourceSlotInfo] { |     fn output(&self) -> &[ResourceSlotInfo] { | ||||||
|         static OUTPUT: &[ResourceSlotInfo] = &[ResourceSlotInfo { |         static OUTPUT: &[ResourceSlotInfo] = &[ResourceSlotInfo { | ||||||
|             name: Cow::Borrowed("texture"), |             name: Cow::Borrowed(WindowTextureNode::OUT_TEXTURE), | ||||||
|             resource_type: ResourceInfo::Texture, |             resource_type: ResourceInfo::Texture, | ||||||
|         }]; |         }]; | ||||||
|         OUTPUT |         OUTPUT | ||||||
| @ -32,15 +51,29 @@ impl Node for WindowTextureNode { | |||||||
|         output: &mut ResourceSlots, |         output: &mut ResourceSlots, | ||||||
|     ) { |     ) { | ||||||
|         const WINDOW_TEXTURE: usize = 0; |         const WINDOW_TEXTURE: usize = 0; | ||||||
|  |         let window_created_events = resources.get::<Events<WindowCreated>>().unwrap(); | ||||||
|         let window_resized_events = resources.get::<Events<WindowResized>>().unwrap(); |         let window_resized_events = resources.get::<Events<WindowResized>>().unwrap(); | ||||||
|         if let Some(event) = window_resized_events.latest(&mut self.window_resized_event_reader) { |         let windows = resources.get::<Windows>().unwrap(); | ||||||
|  | 
 | ||||||
|  |         let window = match self.window_reference { | ||||||
|  |             WindowReference::Primary => windows.get_primary().expect("No primary window exists"), | ||||||
|  |             WindowReference::Id(id) => windows | ||||||
|  |                 .get(id) | ||||||
|  |                 .expect("Received window resized event for non-existent window"), | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         if window_created_events | ||||||
|  |             .find_latest(&mut self.window_created_event_reader, |e| e.id == window.id).is_some() || | ||||||
|  |             window_resized_events | ||||||
|  |             .find_latest(&mut self.window_resized_event_reader, |e| e.id == window.id).is_some() | ||||||
|  |         { | ||||||
|             let render_resources = render_context.resources_mut(); |             let render_resources = render_context.resources_mut(); | ||||||
|             if let Some(old_texture) = output.get(WINDOW_TEXTURE) { |             if let Some(old_texture) = output.get(WINDOW_TEXTURE) { | ||||||
|                 render_resources.remove_texture(old_texture); |                 render_resources.remove_texture(old_texture); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             self.descriptor.size.width = event.width; |             self.descriptor.size.width = window.width; | ||||||
|             self.descriptor.size.height = event.height; |             self.descriptor.size.height = window.height; | ||||||
|             let texture_resource = render_resources.create_texture(&self.descriptor); |             let texture_resource = render_resources.create_texture(&self.descriptor); | ||||||
|             output.set(WINDOW_TEXTURE, texture_resource); |             output.set(WINDOW_TEXTURE, texture_resource); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -187,6 +187,7 @@ fn stage_node( | |||||||
|     // don't re-visit nodes or visit them before all of their parents have been visited
 |     // don't re-visit nodes or visit them before all of their parents have been visited
 | ||||||
|     if node_stages_and_jobs.contains_key(&node.id) |     if node_stages_and_jobs.contains_key(&node.id) | ||||||
|         || node |         || node | ||||||
|  |             .edges | ||||||
|             .input_edges |             .input_edges | ||||||
|             .iter() |             .iter() | ||||||
|             .find(|e| !node_stages_and_jobs.contains_key(&e.get_output_node())) |             .find(|e| !node_stages_and_jobs.contains_key(&e.get_output_node())) | ||||||
| @ -204,6 +205,7 @@ fn stage_node( | |||||||
| 
 | 
 | ||||||
|     // check to see if the current node has a parent. if so, grab the parent with the highest stage
 |     // check to see if the current node has a parent. if so, grab the parent with the highest stage
 | ||||||
|     if let Some((max_parent_stage, max_parent_job)) = node |     if let Some((max_parent_stage, max_parent_job)) = node | ||||||
|  |         .edges | ||||||
|         .input_edges |         .input_edges | ||||||
|         .iter() |         .iter() | ||||||
|         .map(|e| { |         .map(|e| { | ||||||
| @ -215,6 +217,7 @@ fn stage_node( | |||||||
|     { |     { | ||||||
|         // count the number of parents that are in the highest stage
 |         // count the number of parents that are in the highest stage
 | ||||||
|         let max_stage_parent_count = node |         let max_stage_parent_count = node | ||||||
|  |             .edges | ||||||
|             .input_edges |             .input_edges | ||||||
|             .iter() |             .iter() | ||||||
|             .filter(|e| { |             .filter(|e| { | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ use bevy_render::{ | |||||||
|     }, |     }, | ||||||
|     pipeline::{BindGroupDescriptor, BindType, PipelineDescriptor}, |     pipeline::{BindGroupDescriptor, BindType, PipelineDescriptor}, | ||||||
|     render_resource::{ |     render_resource::{ | ||||||
|         resource_name, RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo, |         RenderResource, RenderResourceAssignments, RenderResourceSetId, ResourceInfo, | ||||||
|     }, |     }, | ||||||
|     renderer_2::{RenderContext, RenderResourceContext}, |     renderer_2::{RenderContext, RenderResourceContext}, | ||||||
|     shader::Shader, |     shader::Shader, | ||||||
| @ -475,26 +475,13 @@ fn get_texture_view<'a>( | |||||||
|     attachment: &TextureAttachment, |     attachment: &TextureAttachment, | ||||||
| ) -> &'a wgpu::TextureView { | ) -> &'a wgpu::TextureView { | ||||||
|     match attachment { |     match attachment { | ||||||
|         TextureAttachment::Name(name) => match name.as_str() { |         TextureAttachment::Name(name) => match global_render_resource_assignments.get(&name) { | ||||||
|             resource_name::texture::SWAP_CHAIN => { |             Some(resource) => refs.textures.get(&resource).unwrap(), | ||||||
|                 if let Some(primary_swap_chain) = refs.swap_chain_outputs.values().next() { |             None => { | ||||||
|                     &primary_swap_chain.view |                 panic!("Color attachment {} does not exist", name); | ||||||
|                 } else { |  | ||||||
|                     panic!("No primary swap chain found for color attachment"); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             _ => match global_render_resource_assignments.get(&name) { |  | ||||||
|                 Some(resource) => refs.textures.get(&resource).unwrap(), |  | ||||||
|                 None => { |  | ||||||
|                     // if let Some(swap_chain_output) = swap_chain_outputs.get(name) {
 |  | ||||||
|                     //     &swap_chain_output.view
 |  | ||||||
|                     // } else {
 |  | ||||||
|                     panic!("Color attachment {} does not exist", name); |  | ||||||
|                     // }
 |  | ||||||
|                 } |  | ||||||
|             }, |  | ||||||
|         }, |         }, | ||||||
|         TextureAttachment::RenderResource(render_resource) => refs.textures.get(&render_resource).unwrap(), |         TextureAttachment::RenderResource(render_resource) => refs.textures.get(&render_resource).unwrap_or_else(|| &refs.swap_chain_outputs.get(&render_resource).unwrap().view), | ||||||
|         TextureAttachment::Input(_) => panic!("Encountered unset TextureAttachment::Input. The RenderGraph executor should always set TextureAttachment::Inputs to TextureAttachment::RenderResource before running. This is a bug"), |         TextureAttachment::Input(_) => panic!("Encountered unset TextureAttachment::Input. The RenderGraph executor should always set TextureAttachment::Inputs to TextureAttachment::RenderResource before running. This is a bug"), | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,7 +1,10 @@ | |||||||
| use super::{WgpuRenderContext, WgpuRenderResourceContext}; | use super::{WgpuRenderContext, WgpuRenderResourceContext}; | ||||||
| use bevy_render::{render_graph_2::StageBorrow, renderer_2::GlobalRenderResourceContext}; | use bevy_render::{ | ||||||
|  |     render_graph_2::{Edge, NodeId, ResourceSlots, StageBorrow}, | ||||||
|  |     renderer_2::GlobalRenderResourceContext, | ||||||
|  | }; | ||||||
| use legion::prelude::{Resources, World}; | use legion::prelude::{Resources, World}; | ||||||
| use std::sync::Arc; | use std::{collections::HashMap, sync::Arc}; | ||||||
| 
 | 
 | ||||||
| pub struct WgpuRenderGraphExecutor { | pub struct WgpuRenderGraphExecutor { | ||||||
|     pub max_thread_count: usize, |     pub max_thread_count: usize, | ||||||
| @ -21,6 +24,7 @@ impl WgpuRenderGraphExecutor { | |||||||
|             .context |             .context | ||||||
|             .downcast_mut::<WgpuRenderResourceContext>() |             .downcast_mut::<WgpuRenderResourceContext>() | ||||||
|             .unwrap(); |             .unwrap(); | ||||||
|  |         let mut node_outputs: HashMap<NodeId, ResourceSlots> = HashMap::new(); | ||||||
|         for stage in stages.iter_mut() { |         for stage in stages.iter_mut() { | ||||||
|             // TODO: sort jobs and slice by "amount of work" / weights
 |             // TODO: sort jobs and slice by "amount of work" / weights
 | ||||||
|             // stage.jobs.sort_by_key(|j| j.node_states.len());
 |             // stage.jobs.sort_by_key(|j| j.node_states.len());
 | ||||||
| @ -29,6 +33,7 @@ impl WgpuRenderGraphExecutor { | |||||||
|             let chunk_size = (stage.jobs.len() + self.max_thread_count - 1) / self.max_thread_count; // divide ints rounding remainder up
 |             let chunk_size = (stage.jobs.len() + self.max_thread_count - 1) / self.max_thread_count; // divide ints rounding remainder up
 | ||||||
|             let mut actual_thread_count = 0; |             let mut actual_thread_count = 0; | ||||||
|             crossbeam_utils::thread::scope(|s| { |             crossbeam_utils::thread::scope(|s| { | ||||||
|  |                 let node_outputs = &node_outputs; | ||||||
|                 for jobs_chunk in stage.jobs.chunks_mut(chunk_size) { |                 for jobs_chunk in stage.jobs.chunks_mut(chunk_size) { | ||||||
|                     let sender = sender.clone(); |                     let sender = sender.clone(); | ||||||
|                     let world = &*world; |                     let world = &*world; | ||||||
| @ -38,8 +43,37 @@ impl WgpuRenderGraphExecutor { | |||||||
|                     s.spawn(move |_| { |                     s.spawn(move |_| { | ||||||
|                         let mut render_context = |                         let mut render_context = | ||||||
|                             WgpuRenderContext::new(device, render_resource_context); |                             WgpuRenderContext::new(device, render_resource_context); | ||||||
|  |                         let mut local_node_outputs = HashMap::new(); | ||||||
|                         for job in jobs_chunk.iter_mut() { |                         for job in jobs_chunk.iter_mut() { | ||||||
|                             for node_state in job.node_states.iter_mut() { |                             for node_state in job.node_states.iter_mut() { | ||||||
|  |                                 // bind inputs from connected node outputs
 | ||||||
|  |                                 for (i, mut input_slot) in node_state.input_slots.iter_mut().enumerate() | ||||||
|  |                                 { | ||||||
|  |                                     if let Edge::SlotEdge { | ||||||
|  |                                         output_node, | ||||||
|  |                                         output_index, | ||||||
|  |                                         .. | ||||||
|  |                                     } = node_state.edges.get_input_slot_edge(i).unwrap() | ||||||
|  |                                     { | ||||||
|  |                                         let outputs = | ||||||
|  |                                             if let Some(outputs) = node_outputs.get(output_node) { | ||||||
|  |                                                 outputs | ||||||
|  |                                             } else if let Some(outputs) = | ||||||
|  |                                                 local_node_outputs.get(output_node) | ||||||
|  |                                             { | ||||||
|  |                                                 outputs | ||||||
|  |                                             } else { | ||||||
|  |                                                 panic!("node inputs not set") | ||||||
|  |                                             }; | ||||||
|  | 
 | ||||||
|  |                                         let output_resource = outputs | ||||||
|  |                                             .get(*output_index) | ||||||
|  |                                             .expect("output should be set"); | ||||||
|  |                                         input_slot.resource = Some(output_resource); | ||||||
|  |                                     } else { | ||||||
|  |                                         panic!("no edge connected to input") | ||||||
|  |                                     } | ||||||
|  |                                 } | ||||||
|                                 node_state.node.update( |                                 node_state.node.update( | ||||||
|                                     world, |                                     world, | ||||||
|                                     resources, |                                     resources, | ||||||
| @ -47,9 +81,14 @@ impl WgpuRenderGraphExecutor { | |||||||
|                                     &node_state.input_slots, |                                     &node_state.input_slots, | ||||||
|                                     &mut node_state.output_slots, |                                     &mut node_state.output_slots, | ||||||
|                                 ); |                                 ); | ||||||
|  | 
 | ||||||
|  |                                 local_node_outputs | ||||||
|  |                                     .insert(node_state.id, node_state.output_slots.clone()); | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|                         sender.send(render_context.finish()).unwrap(); |                         sender | ||||||
|  |                             .send((render_context.finish(), local_node_outputs)) | ||||||
|  |                             .unwrap(); | ||||||
|                     }); |                     }); | ||||||
|                 } |                 } | ||||||
|             }) |             }) | ||||||
| @ -57,10 +96,12 @@ impl WgpuRenderGraphExecutor { | |||||||
| 
 | 
 | ||||||
|             let mut command_buffers = Vec::new(); |             let mut command_buffers = Vec::new(); | ||||||
|             for _i in 0..actual_thread_count { |             for _i in 0..actual_thread_count { | ||||||
|                 let command_buffer = receiver.recv().unwrap(); |                 let (command_buffer, mut local_node_outputs) = receiver.recv().unwrap(); | ||||||
|                 if let Some(command_buffer) = command_buffer { |                 if let Some(command_buffer) = command_buffer { | ||||||
|                     command_buffers.push(command_buffer); |                     command_buffers.push(command_buffer); | ||||||
|                 } |                 } | ||||||
|  | 
 | ||||||
|  |                 node_outputs.extend(local_node_outputs.drain()); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             queue.submit(&command_buffers); |             queue.submit(&command_buffers); | ||||||
|  | |||||||
| @ -1,5 +1,10 @@ | |||||||
| use uuid::Uuid; | use uuid::Uuid; | ||||||
| 
 | 
 | ||||||
|  | pub enum WindowReference { | ||||||
|  |     Primary, | ||||||
|  |     Id(WindowId), | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] | ||||||
| pub struct WindowId(Uuid); | pub struct WindowId(Uuid); | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Carter Anderson
						Carter Anderson