Skip to content

Commit 5849c15

Browse files
committed
render graph utils
1 parent 53667de commit 5849c15

File tree

9 files changed

+192
-116
lines changed

9 files changed

+192
-116
lines changed

crates/bevy_core_pipeline/src/bloom/mod.rs

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use bevy_render::{
1616
ComponentUniforms, DynamicUniformIndex, ExtractComponentPlugin, UniformComponentPlugin,
1717
},
1818
prelude::Color,
19-
render_graph::{Node, NodeRunError, RenderGraph, RenderGraphContext},
19+
render_graph::{add_node, Node, NodeRunError, RenderGraphContext},
2020
render_resource::*,
2121
renderer::{RenderContext, RenderDevice},
2222
texture::{CachedTexture, TextureCache},
@@ -74,42 +74,28 @@ impl Plugin for BloomPlugin {
7474
);
7575

7676
// Add bloom to the 3d render graph
77-
{
78-
let bloom_node = BloomNode::new(&mut render_app.world);
79-
let mut graph = render_app.world.resource_mut::<RenderGraph>();
80-
let draw_3d_graph = graph
81-
.get_sub_graph_mut(crate::core_3d::graph::NAME)
82-
.unwrap();
83-
draw_3d_graph.add_node(core_3d::graph::node::BLOOM, bloom_node);
84-
// MAIN_PASS -> BLOOM -> TONEMAPPING
85-
draw_3d_graph.add_node_edge(
86-
crate::core_3d::graph::node::MAIN_PASS,
87-
core_3d::graph::node::BLOOM,
88-
);
89-
draw_3d_graph.add_node_edge(
77+
add_node::<BloomNode>(
78+
render_app,
79+
core_3d::graph::NAME,
80+
core_3d::graph::node::BLOOM,
81+
&[
82+
core_3d::graph::node::MAIN_PASS,
9083
core_3d::graph::node::BLOOM,
91-
crate::core_3d::graph::node::TONEMAPPING,
92-
);
93-
}
84+
core_3d::graph::node::TONEMAPPING,
85+
],
86+
);
9487

9588
// Add bloom to the 2d render graph
96-
{
97-
let bloom_node = BloomNode::new(&mut render_app.world);
98-
let mut graph = render_app.world.resource_mut::<RenderGraph>();
99-
let draw_2d_graph = graph
100-
.get_sub_graph_mut(crate::core_2d::graph::NAME)
101-
.unwrap();
102-
draw_2d_graph.add_node(core_2d::graph::node::BLOOM, bloom_node);
103-
// MAIN_PASS -> BLOOM -> TONEMAPPING
104-
draw_2d_graph.add_node_edge(
105-
crate::core_2d::graph::node::MAIN_PASS,
106-
core_2d::graph::node::BLOOM,
107-
);
108-
draw_2d_graph.add_node_edge(
89+
add_node::<BloomNode>(
90+
render_app,
91+
core_2d::graph::NAME,
92+
core_2d::graph::node::BLOOM,
93+
&[
94+
core_2d::graph::node::MAIN_PASS,
10995
core_2d::graph::node::BLOOM,
110-
crate::core_2d::graph::node::TONEMAPPING,
111-
);
112-
}
96+
core_2d::graph::node::TONEMAPPING,
97+
],
98+
);
11399
}
114100
}
115101

@@ -126,8 +112,8 @@ pub struct BloomNode {
126112
)>,
127113
}
128114

129-
impl BloomNode {
130-
pub fn new(world: &mut World) -> Self {
115+
impl FromWorld for BloomNode {
116+
fn from_world(world: &mut World) -> Self {
131117
Self {
132118
view_query: QueryState::new(world),
133119
}

crates/bevy_core_pipeline/src/core_2d/mod.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,14 @@ impl Plugin for Core2dPlugin {
7373
draw_2d_graph.add_node(graph::node::TONEMAPPING, tonemapping);
7474
draw_2d_graph.add_node(graph::node::END_MAIN_PASS_POST_PROCESSING, EmptyNode);
7575
draw_2d_graph.add_node(graph::node::UPSCALING, upscaling);
76-
draw_2d_graph.add_node_edge(graph::node::MAIN_PASS, graph::node::TONEMAPPING);
77-
draw_2d_graph.add_node_edge(
76+
77+
draw_2d_graph.add_node_edges(&[
78+
graph::node::MAIN_PASS,
7879
graph::node::TONEMAPPING,
7980
graph::node::END_MAIN_PASS_POST_PROCESSING,
80-
);
81-
draw_2d_graph.add_node_edge(
82-
graph::node::END_MAIN_PASS_POST_PROCESSING,
8381
graph::node::UPSCALING,
84-
);
82+
]);
83+
8584
graph.add_sub_graph(graph::NAME, draw_2d_graph);
8685
}
8786
}

crates/bevy_core_pipeline/src/core_3d/mod.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,13 @@ impl Plugin for Core3dPlugin {
9494
draw_3d_graph.add_node(graph::node::END_MAIN_PASS_POST_PROCESSING, EmptyNode);
9595
draw_3d_graph.add_node(graph::node::UPSCALING, upscaling);
9696

97-
draw_3d_graph.add_node_edge(graph::node::PREPASS, graph::node::MAIN_PASS);
98-
draw_3d_graph.add_node_edge(graph::node::MAIN_PASS, graph::node::TONEMAPPING);
99-
draw_3d_graph.add_node_edge(
97+
draw_3d_graph.add_node_edges(&[
98+
graph::node::MAIN_PASS,
10099
graph::node::TONEMAPPING,
101100
graph::node::END_MAIN_PASS_POST_PROCESSING,
102-
);
103-
draw_3d_graph.add_node_edge(
104-
graph::node::END_MAIN_PASS_POST_PROCESSING,
105101
graph::node::UPSCALING,
106-
);
102+
]);
103+
107104
graph.add_sub_graph(graph::NAME, draw_3d_graph);
108105
}
109106
}

crates/bevy_core_pipeline/src/fxaa/mod.rs

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use bevy_reflect::{
99
use bevy_render::{
1010
extract_component::{ExtractComponent, ExtractComponentPlugin},
1111
prelude::Camera,
12-
render_graph::RenderGraph,
12+
render_graph::add_node,
1313
render_resource::*,
1414
renderer::RenderDevice,
1515
texture::BevyDefault,
@@ -92,38 +92,27 @@ impl Plugin for FxaaPlugin {
9292
.init_resource::<SpecializedRenderPipelines<FxaaPipeline>>()
9393
.add_systems(Render, prepare_fxaa_pipelines.in_set(RenderSet::Prepare));
9494

95-
{
96-
let fxaa_node = FxaaNode::new(&mut render_app.world);
97-
let mut binding = render_app.world.resource_mut::<RenderGraph>();
98-
let graph = binding.get_sub_graph_mut(core_3d::graph::NAME).unwrap();
99-
100-
graph.add_node(core_3d::graph::node::FXAA, fxaa_node);
101-
102-
graph.add_node_edge(
95+
add_node::<FxaaNode>(
96+
render_app,
97+
core_3d::graph::NAME,
98+
core_3d::graph::node::FXAA,
99+
&[
103100
core_3d::graph::node::TONEMAPPING,
104101
core_3d::graph::node::FXAA,
105-
);
106-
graph.add_node_edge(
107-
core_3d::graph::node::FXAA,
108102
core_3d::graph::node::END_MAIN_PASS_POST_PROCESSING,
109-
);
110-
}
111-
{
112-
let fxaa_node = FxaaNode::new(&mut render_app.world);
113-
let mut binding = render_app.world.resource_mut::<RenderGraph>();
114-
let graph = binding.get_sub_graph_mut(core_2d::graph::NAME).unwrap();
115-
116-
graph.add_node(core_2d::graph::node::FXAA, fxaa_node);
103+
],
104+
);
117105

118-
graph.add_node_edge(
106+
add_node::<FxaaNode>(
107+
render_app,
108+
core_2d::graph::NAME,
109+
core_2d::graph::node::FXAA,
110+
&[
119111
core_2d::graph::node::TONEMAPPING,
120112
core_2d::graph::node::FXAA,
121-
);
122-
graph.add_node_edge(
123-
core_2d::graph::node::FXAA,
124113
core_2d::graph::node::END_MAIN_PASS_POST_PROCESSING,
125-
);
126-
}
114+
],
115+
);
127116
}
128117
}
129118

crates/bevy_core_pipeline/src/fxaa/node.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ pub struct FxaaNode {
2727
cached_texture_bind_group: Mutex<Option<(TextureViewId, BindGroup)>>,
2828
}
2929

30-
impl FxaaNode {
31-
pub fn new(world: &mut World) -> Self {
30+
impl FromWorld for FxaaNode {
31+
fn from_world(world: &mut World) -> Self {
3232
Self {
3333
query: QueryState::new(world),
3434
cached_texture_bind_group: Mutex::new(None),

crates/bevy_render/src/render_graph/graph.rs

Lines changed: 99 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@ impl RenderGraph {
119119
id
120120
}
121121

122+
/// Add `node_edge` based on the order of the given `edges` array.
123+
pub fn add_node_edges(&mut self, edges: &[&'static str]) {
124+
for window in edges.windows(2) {
125+
let [a, b] = window else { break; };
126+
self.add_node_edge(*a, *b);
127+
}
128+
}
129+
122130
/// Removes the `node` with the `name` from the graph.
123131
/// If the name is does not exist, nothing happens.
124132
pub fn remove_node(
@@ -583,6 +591,36 @@ impl RenderGraph {
583591
pub fn get_sub_graph_mut(&mut self, name: impl AsRef<str>) -> Option<&mut RenderGraph> {
584592
self.sub_graphs.get_mut(name.as_ref())
585593
}
594+
595+
/// Retrieves the sub graph corresponding to the `name`.
596+
///
597+
/// # Panics
598+
///
599+
/// Panics if any invalid node name is given.
600+
///
601+
/// # See also
602+
///
603+
/// - [`get_sub_graph`](Self::get_sub_graph) for a fallible version.
604+
pub fn sub_graph(&self, name: impl AsRef<str>) -> &RenderGraph {
605+
self.sub_graphs
606+
.get(name.as_ref())
607+
.unwrap_or_else(|| panic!("Node {} not found in sub_graph", name.as_ref()))
608+
}
609+
610+
/// Retrieves the sub graph corresponding to the `name` mutably.
611+
///
612+
/// # Panics
613+
///
614+
/// Panics if any invalid node name is given.
615+
///
616+
/// # See also
617+
///
618+
/// - [`get_sub_graph_mut`](Self::get_sub_graph_mut) for a fallible version.
619+
pub fn sub_graph_mut(&mut self, name: impl AsRef<str>) -> &mut RenderGraph {
620+
self.sub_graphs
621+
.get_mut(name.as_ref())
622+
.unwrap_or_else(|| panic!("Node {} not found in sub_graph", name.as_ref()))
623+
}
586624
}
587625

588626
impl Debug for RenderGraph {
@@ -635,7 +673,7 @@ mod tests {
635673
},
636674
renderer::RenderContext,
637675
};
638-
use bevy_ecs::world::World;
676+
use bevy_ecs::world::{FromWorld, World};
639677
use bevy_utils::HashSet;
640678

641679
#[derive(Debug)]
@@ -676,6 +714,22 @@ mod tests {
676714
}
677715
}
678716

717+
fn input_nodes(name: &'static str, graph: &RenderGraph) -> HashSet<NodeId> {
718+
graph
719+
.iter_node_inputs(name)
720+
.unwrap()
721+
.map(|(_edge, node)| node.id)
722+
.collect::<HashSet<NodeId>>()
723+
}
724+
725+
fn output_nodes(name: &'static str, graph: &RenderGraph) -> HashSet<NodeId> {
726+
graph
727+
.iter_node_outputs(name)
728+
.unwrap()
729+
.map(|(_edge, node)| node.id)
730+
.collect::<HashSet<NodeId>>()
731+
}
732+
679733
#[test]
680734
fn test_graph_edges() {
681735
let mut graph = RenderGraph::default();
@@ -688,22 +742,6 @@ mod tests {
688742
graph.add_node_edge("B", "C");
689743
graph.add_slot_edge("C", 0, "D", 0);
690744

691-
fn input_nodes(name: &'static str, graph: &RenderGraph) -> HashSet<NodeId> {
692-
graph
693-
.iter_node_inputs(name)
694-
.unwrap()
695-
.map(|(_edge, node)| node.id)
696-
.collect::<HashSet<NodeId>>()
697-
}
698-
699-
fn output_nodes(name: &'static str, graph: &RenderGraph) -> HashSet<NodeId> {
700-
graph
701-
.iter_node_outputs(name)
702-
.unwrap()
703-
.map(|(_edge, node)| node.id)
704-
.collect::<HashSet<NodeId>>()
705-
}
706-
707745
assert!(input_nodes("A", &graph).is_empty(), "A has no inputs");
708746
assert!(
709747
output_nodes("A", &graph) == HashSet::from_iter(vec![c_id]),
@@ -803,4 +841,48 @@ mod tests {
803841
"Adding to a duplicate edge should return an error"
804842
);
805843
}
844+
845+
#[test]
846+
fn test_add_node_edges() {
847+
struct SimpleNode;
848+
impl Node for SimpleNode {
849+
fn run(
850+
&self,
851+
_graph: &mut RenderGraphContext,
852+
_render_context: &mut RenderContext,
853+
_world: &World,
854+
) -> Result<(), NodeRunError> {
855+
Ok(())
856+
}
857+
}
858+
impl FromWorld for SimpleNode {
859+
fn from_world(_world: &mut World) -> Self {
860+
Self
861+
}
862+
}
863+
864+
let mut graph = RenderGraph::default();
865+
let a_id = graph.add_node("A", SimpleNode);
866+
let b_id = graph.add_node("B", SimpleNode);
867+
let c_id = graph.add_node("C", SimpleNode);
868+
869+
graph.add_node_edges(&["A", "B", "C"]);
870+
871+
assert!(
872+
output_nodes("A", &graph) == HashSet::from_iter(vec![b_id]),
873+
"A -> B"
874+
);
875+
assert!(
876+
input_nodes("B", &graph) == HashSet::from_iter(vec![a_id]),
877+
"B -> C"
878+
);
879+
assert!(
880+
output_nodes("B", &graph) == HashSet::from_iter(vec![c_id]),
881+
"B -> C"
882+
);
883+
assert!(
884+
input_nodes("C", &graph) == HashSet::from_iter(vec![b_id]),
885+
"B -> C"
886+
);
887+
}
806888
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use bevy_app::App;
2+
use bevy_ecs::world::FromWorld;
3+
4+
use super::{Node, RenderGraph};
5+
6+
/// Utility function to add a [`Node`] to the [`RenderGraph`]
7+
/// * Create the [`Node`] using the [`FromWorld`] implementation
8+
/// * Add it to the graph
9+
/// * Automatically add the required node edges based on the given ordering
10+
pub fn add_node<T: Node + FromWorld>(
11+
render_app: &mut App,
12+
sub_graph_name: &'static str,
13+
node_name: &'static str,
14+
edges: &[&'static str],
15+
) {
16+
let node = T::from_world(&mut render_app.world);
17+
let mut render_graph = render_app.world.resource_mut::<RenderGraph>();
18+
19+
let graph = render_graph.get_sub_graph_mut(sub_graph_name).unwrap();
20+
graph.add_node(node_name, node);
21+
graph.add_node_edges(edges);
22+
}

crates/bevy_render/src/render_graph/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
mod context;
22
mod edge;
33
mod graph;
4+
mod helpers;
45
mod node;
56
mod node_slot;
67

78
pub use context::*;
89
pub use edge::*;
910
pub use graph::*;
11+
pub use helpers::*;
1012
pub use node::*;
1113
pub use node_slot::*;
1214

0 commit comments

Comments
 (0)