render: create a node for sub render graphs, create a graph init node

This commit is contained in:
SeanOMik 2024-06-22 17:00:32 -04:00
parent 9d3de88c50
commit f755a4c53b
Signed by: SeanOMik
GPG Key ID: FEC9E2FC15235964
9 changed files with 83 additions and 28 deletions

View File

@ -123,6 +123,7 @@ pub struct RenderGraph {
queue: Rc<wgpu::Queue>, queue: Rc<wgpu::Queue>,
slots: FxHashMap<RenderGraphLabelValue, ResourcedSlot>, slots: FxHashMap<RenderGraphLabelValue, ResourcedSlot>,
nodes: FxHashMap<RenderGraphLabelValue, PassEntry>, nodes: FxHashMap<RenderGraphLabelValue, PassEntry>,
sub_graphs: FxHashMap<RenderGraphLabelValue, RenderGraph>,
bind_groups: FxHashMap<RenderGraphLabelValue, BindGroupEntry>, bind_groups: FxHashMap<RenderGraphLabelValue, BindGroupEntry>,
/// A directed graph used to determine dependencies of nodes. /// A directed graph used to determine dependencies of nodes.
node_graph: petgraph::matrix_graph::DiMatrix<RenderGraphLabelValue, (), Option<()>, usize>, node_graph: petgraph::matrix_graph::DiMatrix<RenderGraphLabelValue, (), Option<()>, usize>,
@ -135,6 +136,7 @@ impl RenderGraph {
queue, queue,
slots: Default::default(), slots: Default::default(),
nodes: Default::default(), nodes: Default::default(),
sub_graphs: Default::default(),
bind_groups: Default::default(), bind_groups: Default::default(),
node_graph: Default::default(), node_graph: Default::default(),
} }
@ -261,16 +263,27 @@ impl RenderGraph {
#[instrument(skip(self, world))] #[instrument(skip(self, world))]
pub fn prepare(&mut self, world: &mut World) { pub fn prepare(&mut self, world: &mut World) {
// prepare all passes
let mut buffer_writes = VecDeque::<GraphBufferWrite>::new(); let mut buffer_writes = VecDeque::<GraphBufferWrite>::new();
// reserve some buffer writes. not all nodes write so half the amount of them is probably // reserve some buffer writes. not all nodes write so half the amount of them is probably
// fine. // fine.
buffer_writes.reserve(self.nodes.len() / 2); buffer_writes.reserve(self.nodes.len() / 2);
for (label, pass) in &mut self.nodes { let mut sorted: VecDeque<RenderGraphLabelValue> = petgraph::algo::toposort(&self.node_graph, None)
let mut context = RenderGraphContext::new(&self.device, &self.queue, None, label.clone()); .expect("RenderGraph had cycled!")
let mut inner = pass.inner.borrow_mut(); .iter()
inner.prepare(world, &mut context); .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); buffer_writes.append(&mut context.buffer_writes);
} }
@ -465,24 +478,33 @@ impl RenderGraph {
pass.set_bind_group(*index, bg, &[]); pass.set_bind_group(*index, bg, &[]);
} }
} }
pub fn sub_graph_mut<L: Into<RenderGraphLabelValue>>(&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 { 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![]) NodeDesc::new(NodeType::Graph, None, vec![])
} }
fn prepare(&mut self, world: &mut World, _: &mut RenderGraphContext) { fn prepare(&mut self, graph: &mut RenderGraph, world: &mut World, _: &mut RenderGraphContext) {
self.prepare(world); 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( fn execute(
&mut self, &mut self,
_: &mut RenderGraph, graph: &mut RenderGraph,
_: &NodeDesc, _: &NodeDesc,
_: &mut RenderGraphContext, _: &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();
} }
} }

View File

@ -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 /// This phase runs before `execute` and is meant to be used to collect data from the World
/// and write to GPU buffers. /// 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. /// Execute the node.
/// ///

View File

@ -9,8 +9,7 @@ use crate::{
render::{ render::{
camera::{CameraUniform, RenderCamera}, camera::{CameraUniform, RenderCamera},
graph::{ graph::{
RenderGraphContext, Node, NodeDesc, NodeSlot, Node, NodeDesc, NodeSlot, NodeType, RenderGraph, RenderGraphContext, RenderTarget, SlotAttribute, SlotType, SlotValue
NodeType, RenderTarget, SlotAttribute, SlotType, SlotValue,
}, },
render_buffer::BufferWrapper, texture::RenderTexture, render_buffer::BufferWrapper, texture::RenderTexture,
}, },
@ -147,7 +146,7 @@ impl Node for BasePass {
desc 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() { if let Some(camera) = world.view_iter::<&mut CameraComponent>().next() {
let mut render_cam = let mut render_cam =
RenderCamera::new(PhysicalSize::new(self.screen_size.x, self.screen_size.y)); RenderCamera::new(PhysicalSize::new(self.screen_size.x, self.screen_size.y));

View File

@ -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<NodeSlot>,
}
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,
) {
}
}

View File

@ -2,8 +2,7 @@ use lyra_game_derive::RenderGraphLabel;
use crate::render::{ use crate::render::{
graph::{ graph::{
RenderGraphContext, Node, NodeDesc, NodeType, SlotAttribute, Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext, SlotAttribute, SlotValue
SlotValue,
}, },
light::LightUniformBuffers, light::LightUniformBuffers,
}; };
@ -58,7 +57,7 @@ impl Node for LightBasePass {
desc 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 tick = world.current_tick();
let lights = self.light_buffers.as_mut().unwrap(); let lights = self.light_buffers.as_mut().unwrap();
lights.update_lights(context.queue, tick, world); lights.update_lights(context.queue, tick, world);

View File

@ -7,7 +7,7 @@ use wgpu::util::DeviceExt;
use crate::render::{ use crate::render::{
graph::{ graph::{
Node, NodeDesc, NodeType, RenderGraphContext, SlotAttribute, SlotValue Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext, SlotAttribute, SlotValue
}, renderer::ScreenSize, resource::{ComputePipelineDescriptor, PipelineDescriptor, Shader} }, renderer::ScreenSize, resource::{ComputePipelineDescriptor, PipelineDescriptor, Shader}
}; };
@ -215,7 +215,7 @@ impl Node for LightCullComputePass {
desc 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); context.queue_buffer_write_with(LightCullComputePassSlots::IndexCounterBuffer, 0, 0);
let screen_size = world.get_resource::<ScreenSize>(); let screen_size = world.get_resource::<ScreenSize>();

View File

@ -15,8 +15,7 @@ use wgpu::util::DeviceExt;
use crate::{ use crate::{
render::{ render::{
desc_buf_lay::DescVertexBufferLayout, graph::{ desc_buf_lay::DescVertexBufferLayout, graph::{
RenderGraphContext, Node, NodeDesc, Node, NodeDesc, NodeType, RenderGraph, RenderGraphContext
NodeType,
}, 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 }, 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, DeltaTime,
@ -297,8 +296,8 @@ impl Node for MeshPass {
desc desc
} }
#[instrument(skip(self, world, context))] #[instrument(skip(self, _graph, world, context))]
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 device = context.device; let device = context.device;
let queue = context.queue; let queue = context.queue;
let render_limits = device.limits(); let render_limits = device.limits();

View File

@ -11,4 +11,7 @@ mod light_base;
pub use light_base::*; pub use light_base::*;
mod present_pass; mod present_pass;
pub use present_pass::*; pub use present_pass::*;
mod init;
pub use init::*;

View File

@ -2,7 +2,7 @@ use std::hash::Hash;
use lyra_game_derive::RenderGraphLabel; 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)] #[derive(Debug, Clone, Hash, PartialEq, RenderGraphLabel)]
pub struct PresentPassLabel(RenderGraphLabelValue); pub struct PresentPassLabel(RenderGraphLabelValue);
@ -50,7 +50,7 @@ impl Node for PresentPass {
desc 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) {
} }