diff --git a/lyra-game/src/render/graph/mod.rs b/lyra-game/src/render/graph/mod.rs index d173003..255917e 100644 --- a/lyra-game/src/render/graph/mod.rs +++ b/lyra-game/src/render/graph/mod.rs @@ -123,6 +123,7 @@ pub struct RenderGraph { queue: Rc, slots: FxHashMap, nodes: FxHashMap, + sub_graphs: FxHashMap, bind_groups: FxHashMap, /// A directed graph used to determine dependencies of nodes. node_graph: petgraph::matrix_graph::DiMatrix, usize>, @@ -135,6 +136,7 @@ impl RenderGraph { queue, slots: Default::default(), nodes: Default::default(), + sub_graphs: Default::default(), bind_groups: Default::default(), node_graph: Default::default(), } @@ -261,16 +263,27 @@ impl RenderGraph { #[instrument(skip(self, world))] pub fn prepare(&mut self, world: &mut World) { - // prepare all passes let mut buffer_writes = VecDeque::::new(); // reserve some buffer writes. not all nodes write so half the amount of them is probably // fine. buffer_writes.reserve(self.nodes.len() / 2); - for (label, pass) in &mut self.nodes { - let mut context = RenderGraphContext::new(&self.device, &self.queue, None, label.clone()); - let mut inner = pass.inner.borrow_mut(); - inner.prepare(world, &mut context); + let mut sorted: VecDeque = petgraph::algo::toposort(&self.node_graph, None) + .expect("RenderGraph had cycled!") + .iter() + .map(|i| self.node_graph[i.clone()].clone()) + .collect(); + + while let Some(pass_label) = sorted.pop_front() { + let pass = self.nodes.get(&pass_label).unwrap(); + let device = self.device.clone(); + let queue = self.queue.clone(); + + let inner = pass.inner.clone(); + let mut inner = inner.borrow_mut(); + + let mut context = RenderGraphContext::new(&device, &queue, None, pass_label.clone()); + inner.prepare(self, world, &mut context); buffer_writes.append(&mut context.buffer_writes); } @@ -465,24 +478,33 @@ impl RenderGraph { pass.set_bind_group(*index, bg, &[]); } } + + pub fn sub_graph_mut>(&mut self, label: L) -> Option<&mut RenderGraph> { + self.sub_graphs.get_mut(&label.into()) + } } -impl Node for RenderGraph { +pub struct SubGraphNode(RenderGraphLabelValue); + +impl Node for SubGraphNode { fn desc<'a, 'b>(&'a mut self, _: &'b mut RenderGraph) -> NodeDesc { - // TODO: how would bind groups be shared between sub-graphs? NodeDesc::new(NodeType::Graph, None, vec![]) } - fn prepare(&mut self, world: &mut World, _: &mut RenderGraphContext) { - self.prepare(world); + fn prepare(&mut self, graph: &mut RenderGraph, world: &mut World, _: &mut RenderGraphContext) { + let sg = graph.sub_graph_mut(self.0.clone()) + .unwrap_or_else(|| panic!("failed to find sub graph for SubGraphNode: {:?}", self.0)); + sg.prepare(world); } fn execute( &mut self, - _: &mut RenderGraph, + graph: &mut RenderGraph, _: &NodeDesc, _: &mut RenderGraphContext, ) { - self.render(); + let sg = graph.sub_graph_mut(self.0.clone()) + .unwrap_or_else(|| panic!("failed to find sub graph for SubGraphNode: {:?}", self.0)); + sg.render(); } -} \ No newline at end of file +} diff --git a/lyra-game/src/render/graph/node.rs b/lyra-game/src/render/graph/node.rs index 5e9823f..069a6a0 100644 --- a/lyra-game/src/render/graph/node.rs +++ b/lyra-game/src/render/graph/node.rs @@ -351,7 +351,7 @@ pub trait Node: 'static { /// /// This phase runs before `execute` and is meant to be used to collect data from the World /// and write to GPU buffers. - fn prepare(&mut self, world: &mut World, context: &mut RenderGraphContext); + fn prepare(&mut self, graph: &mut RenderGraph, world: &mut World, context: &mut RenderGraphContext); /// Execute the node. /// diff --git a/lyra-game/src/render/graph/passes/base.rs b/lyra-game/src/render/graph/passes/base.rs index e524398..3316c0d 100644 --- a/lyra-game/src/render/graph/passes/base.rs +++ b/lyra-game/src/render/graph/passes/base.rs @@ -9,8 +9,7 @@ use crate::{ render::{ camera::{CameraUniform, RenderCamera}, graph::{ - RenderGraphContext, Node, NodeDesc, NodeSlot, - NodeType, RenderTarget, SlotAttribute, SlotType, SlotValue, + Node, NodeDesc, NodeSlot, NodeType, RenderGraph, RenderGraphContext, RenderTarget, SlotAttribute, SlotType, SlotValue }, render_buffer::BufferWrapper, texture::RenderTexture, }, @@ -147,7 +146,7 @@ impl Node for BasePass { desc } - fn prepare(&mut self, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) { + fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) { if let Some(camera) = world.view_iter::<&mut CameraComponent>().next() { let mut render_cam = RenderCamera::new(PhysicalSize::new(self.screen_size.x, self.screen_size.y)); diff --git a/lyra-game/src/render/graph/passes/init.rs b/lyra-game/src/render/graph/passes/init.rs new file mode 100644 index 0000000..1adb0ed --- /dev/null +++ b/lyra-game/src/render/graph/passes/init.rs @@ -0,0 +1,33 @@ +use lyra_game_derive::RenderGraphLabel; + +use crate::render::graph::{Node, NodeDesc, NodeSlot, NodeType}; + +#[derive(Debug, Default, Clone, Copy, Hash, RenderGraphLabel)] +pub struct InitNodeLabel; + +pub struct InitNode { + slots: Vec, +} + +impl Node for InitNode { + fn desc<'a, 'b>(&'a mut self, _: &'b mut crate::render::graph::RenderGraph) -> crate::render::graph::NodeDesc { + let mut desc = NodeDesc::new(NodeType::Node, None, vec![]); + // the slots can just be cloned since the slot attribute doesn't really matter much. + desc.slots = self.slots.clone(); + + desc + } + + fn prepare(&mut self, _: &mut crate::render::graph::RenderGraph, _: &mut lyra_ecs::World, _: &mut crate::render::graph::RenderGraphContext) { + + } + + fn execute( + &mut self, + _: &mut crate::render::graph::RenderGraph, + _: &crate::render::graph::NodeDesc, + _: &mut crate::render::graph::RenderGraphContext, + ) { + + } +} \ No newline at end of file diff --git a/lyra-game/src/render/graph/passes/light_base.rs b/lyra-game/src/render/graph/passes/light_base.rs index 62c3416..3e78401 100644 --- a/lyra-game/src/render/graph/passes/light_base.rs +++ b/lyra-game/src/render/graph/passes/light_base.rs @@ -2,8 +2,7 @@ use lyra_game_derive::RenderGraphLabel; use crate::render::{ graph::{ - RenderGraphContext, Node, NodeDesc, NodeType, SlotAttribute, - SlotValue, + Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext, SlotAttribute, SlotValue }, light::LightUniformBuffers, }; @@ -58,7 +57,7 @@ impl Node for LightBasePass { desc } - fn prepare(&mut self, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) { + fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) { let tick = world.current_tick(); let lights = self.light_buffers.as_mut().unwrap(); lights.update_lights(context.queue, tick, world); diff --git a/lyra-game/src/render/graph/passes/light_cull_compute.rs b/lyra-game/src/render/graph/passes/light_cull_compute.rs index edfd0d0..9dbc88d 100644 --- a/lyra-game/src/render/graph/passes/light_cull_compute.rs +++ b/lyra-game/src/render/graph/passes/light_cull_compute.rs @@ -7,7 +7,7 @@ use wgpu::util::DeviceExt; use crate::render::{ graph::{ - Node, NodeDesc, NodeType, RenderGraphContext, SlotAttribute, SlotValue + Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext, SlotAttribute, SlotValue }, renderer::ScreenSize, resource::{ComputePipelineDescriptor, PipelineDescriptor, Shader} }; @@ -215,7 +215,7 @@ impl Node for LightCullComputePass { desc } - fn prepare(&mut self, world: &mut World, context: &mut RenderGraphContext) { + fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut World, context: &mut RenderGraphContext) { context.queue_buffer_write_with(LightCullComputePassSlots::IndexCounterBuffer, 0, 0); let screen_size = world.get_resource::(); diff --git a/lyra-game/src/render/graph/passes/meshes.rs b/lyra-game/src/render/graph/passes/meshes.rs index c773ecb..1a06255 100644 --- a/lyra-game/src/render/graph/passes/meshes.rs +++ b/lyra-game/src/render/graph/passes/meshes.rs @@ -15,8 +15,7 @@ use wgpu::util::DeviceExt; use crate::{ render::{ desc_buf_lay::DescVertexBufferLayout, graph::{ - RenderGraphContext, Node, NodeDesc, - NodeType, + Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext }, material::{Material, MaterialUniform}, render_buffer::{BufferStorage, BufferWrapper}, render_job::RenderJob, resource::{FragmentState, PipelineDescriptor, RenderPipelineDescriptor, Shader, VertexState}, texture::RenderTexture, transform_buffer_storage::{TransformBuffers, TransformGroup}, vertex::Vertex }, DeltaTime, @@ -297,8 +296,8 @@ impl Node for MeshPass { desc } - #[instrument(skip(self, world, context))] - fn prepare(&mut self, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) { + #[instrument(skip(self, _graph, world, context))] + fn prepare(&mut self, _graph: &mut RenderGraph, world: &mut lyra_ecs::World, context: &mut RenderGraphContext) { let device = context.device; let queue = context.queue; let render_limits = device.limits(); diff --git a/lyra-game/src/render/graph/passes/mod.rs b/lyra-game/src/render/graph/passes/mod.rs index 967d440..c7950d2 100644 --- a/lyra-game/src/render/graph/passes/mod.rs +++ b/lyra-game/src/render/graph/passes/mod.rs @@ -11,4 +11,7 @@ mod light_base; pub use light_base::*; mod present_pass; -pub use present_pass::*; \ No newline at end of file +pub use present_pass::*; + +mod init; +pub use init::*; \ No newline at end of file diff --git a/lyra-game/src/render/graph/passes/present_pass.rs b/lyra-game/src/render/graph/passes/present_pass.rs index af7d52d..ad6e513 100644 --- a/lyra-game/src/render/graph/passes/present_pass.rs +++ b/lyra-game/src/render/graph/passes/present_pass.rs @@ -2,7 +2,7 @@ use std::hash::Hash; use lyra_game_derive::RenderGraphLabel; -use crate::render::graph::{RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, Node, NodeDesc, NodeSlot, NodeType, SlotAttribute, SlotType}; +use crate::render::graph::{Node, NodeDesc, NodeSlot, NodeType, RenderGraph, RenderGraphContext, RenderGraphLabel, RenderGraphLabelValue, SlotAttribute, SlotType}; #[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)] pub struct PresentPassLabel(RenderGraphLabelValue); @@ -50,7 +50,7 @@ impl Node for PresentPass { desc } - fn prepare(&mut self, _world: &mut lyra_ecs::World, _context: &mut RenderGraphContext) { + fn prepare(&mut self, _graph: &mut RenderGraph, _world: &mut lyra_ecs::World, _context: &mut RenderGraphContext) { }