bevy_render/render_graph/
node.rs

1use crate::{
2    render_graph::{
3        Edge, InputSlotError, OutputSlotError, RenderGraphContext, RenderGraphError,
4        RunSubGraphError, SlotInfo, SlotInfos,
5    },
6    renderer::RenderContext,
7};
8pub use bevy_ecs::label::DynEq;
9use bevy_ecs::{
10    define_label,
11    intern::Interned,
12    query::{QueryItem, QueryState, ReadOnlyQueryData},
13    world::{FromWorld, World},
14};
15use bevy_utils::all_tuples_with_size;
16use downcast_rs::{impl_downcast, Downcast};
17use std::fmt::Debug;
18use thiserror::Error;
19
20pub use bevy_render_macros::RenderLabel;
21
22use super::{InternedRenderSubGraph, RenderSubGraph};
23
24define_label!(
25    /// A strongly-typed class of labels used to identify a [`Node`] in a render graph.
26    RenderLabel,
27    RENDER_LABEL_INTERNER
28);
29
30/// A shorthand for `Interned<dyn RenderLabel>`.
31pub type InternedRenderLabel = Interned<dyn RenderLabel>;
32
33pub trait IntoRenderNodeArray<const N: usize> {
34    fn into_array(self) -> [InternedRenderLabel; N];
35}
36
37macro_rules! impl_render_label_tuples {
38    ($N: expr, $(($T: ident, $I: ident)),*) => {
39        impl<$($T: RenderLabel),*> IntoRenderNodeArray<$N> for ($($T,)*) {
40            #[inline]
41            fn into_array(self) -> [InternedRenderLabel; $N] {
42                let ($($I,)*) = self;
43                [$($I.intern(), )*]
44            }
45        }
46    }
47}
48
49all_tuples_with_size!(impl_render_label_tuples, 1, 32, T, l);
50
51/// A render node that can be added to a [`RenderGraph`](super::RenderGraph).
52///
53/// Nodes are the fundamental part of the graph and used to extend its functionality, by
54/// generating draw calls and/or running subgraphs.
55/// They are added via the `render_graph::add_node(my_node)` method.
56///
57/// To determine their position in the graph and ensure that all required dependencies (inputs)
58/// are already executed, [`Edges`](Edge) are used.
59///
60/// A node can produce outputs used as dependencies by other nodes.
61/// Those inputs and outputs are called slots and are the default way of passing render data
62/// inside the graph. For more information see [`SlotType`](super::SlotType).
63pub trait Node: Downcast + Send + Sync + 'static {
64    /// Specifies the required input slots for this node.
65    /// They will then be available during the run method inside the [`RenderGraphContext`].
66    fn input(&self) -> Vec<SlotInfo> {
67        Vec::new()
68    }
69
70    /// Specifies the produced output slots for this node.
71    /// They can then be passed one inside [`RenderGraphContext`] during the run method.
72    fn output(&self) -> Vec<SlotInfo> {
73        Vec::new()
74    }
75
76    /// Updates internal node state using the current render [`World`] prior to the run method.
77    fn update(&mut self, _world: &mut World) {}
78
79    /// Runs the graph node logic, issues draw calls, updates the output slots and
80    /// optionally queues up subgraphs for execution. The graph data, input and output values are
81    /// passed via the [`RenderGraphContext`].
82    fn run<'w>(
83        &self,
84        graph: &mut RenderGraphContext,
85        render_context: &mut RenderContext<'w>,
86        world: &'w World,
87    ) -> Result<(), NodeRunError>;
88}
89
90impl_downcast!(Node);
91
92#[derive(Error, Debug, Eq, PartialEq)]
93pub enum NodeRunError {
94    #[error("encountered an input slot error")]
95    InputSlotError(#[from] InputSlotError),
96    #[error("encountered an output slot error")]
97    OutputSlotError(#[from] OutputSlotError),
98    #[error("encountered an error when running a sub-graph")]
99    RunSubGraphError(#[from] RunSubGraphError),
100}
101
102/// A collection of input and output [`Edges`](Edge) for a [`Node`].
103#[derive(Debug)]
104pub struct Edges {
105    label: InternedRenderLabel,
106    input_edges: Vec<Edge>,
107    output_edges: Vec<Edge>,
108}
109
110impl Edges {
111    /// Returns all "input edges" (edges going "in") for this node .
112    #[inline]
113    pub fn input_edges(&self) -> &[Edge] {
114        &self.input_edges
115    }
116
117    /// Returns all "output edges" (edges going "out") for this node .
118    #[inline]
119    pub fn output_edges(&self) -> &[Edge] {
120        &self.output_edges
121    }
122
123    /// Returns this node's label.
124    #[inline]
125    pub fn label(&self) -> InternedRenderLabel {
126        self.label
127    }
128
129    /// Adds an edge to the `input_edges` if it does not already exist.
130    pub(crate) fn add_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {
131        if self.has_input_edge(&edge) {
132            return Err(RenderGraphError::EdgeAlreadyExists(edge));
133        }
134        self.input_edges.push(edge);
135        Ok(())
136    }
137
138    /// Removes an edge from the `input_edges` if it exists.
139    pub(crate) fn remove_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {
140        if let Some(index) = self.input_edges.iter().position(|e| *e == edge) {
141            self.input_edges.swap_remove(index);
142            Ok(())
143        } else {
144            Err(RenderGraphError::EdgeDoesNotExist(edge))
145        }
146    }
147
148    /// Adds an edge to the `output_edges` if it does not already exist.
149    pub(crate) fn add_output_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {
150        if self.has_output_edge(&edge) {
151            return Err(RenderGraphError::EdgeAlreadyExists(edge));
152        }
153        self.output_edges.push(edge);
154        Ok(())
155    }
156
157    /// Removes an edge from the `output_edges` if it exists.
158    pub(crate) fn remove_output_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {
159        if let Some(index) = self.output_edges.iter().position(|e| *e == edge) {
160            self.output_edges.swap_remove(index);
161            Ok(())
162        } else {
163            Err(RenderGraphError::EdgeDoesNotExist(edge))
164        }
165    }
166
167    /// Checks whether the input edge already exists.
168    pub fn has_input_edge(&self, edge: &Edge) -> bool {
169        self.input_edges.contains(edge)
170    }
171
172    /// Checks whether the output edge already exists.
173    pub fn has_output_edge(&self, edge: &Edge) -> bool {
174        self.output_edges.contains(edge)
175    }
176
177    /// Searches the `input_edges` for a [`Edge::SlotEdge`],
178    /// which `input_index` matches the `index`;
179    pub fn get_input_slot_edge(&self, index: usize) -> Result<&Edge, RenderGraphError> {
180        self.input_edges
181            .iter()
182            .find(|e| {
183                if let Edge::SlotEdge { input_index, .. } = e {
184                    *input_index == index
185                } else {
186                    false
187                }
188            })
189            .ok_or(RenderGraphError::UnconnectedNodeInputSlot {
190                input_slot: index,
191                node: self.label,
192            })
193    }
194
195    /// Searches the `output_edges` for a [`Edge::SlotEdge`],
196    /// which `output_index` matches the `index`;
197    pub fn get_output_slot_edge(&self, index: usize) -> Result<&Edge, RenderGraphError> {
198        self.output_edges
199            .iter()
200            .find(|e| {
201                if let Edge::SlotEdge { output_index, .. } = e {
202                    *output_index == index
203                } else {
204                    false
205                }
206            })
207            .ok_or(RenderGraphError::UnconnectedNodeOutputSlot {
208                output_slot: index,
209                node: self.label,
210            })
211    }
212}
213
214/// The internal representation of a [`Node`], with all data required
215/// by the [`RenderGraph`](super::RenderGraph).
216///
217/// The `input_slots` and `output_slots` are provided by the `node`.
218pub struct NodeState {
219    pub label: InternedRenderLabel,
220    /// The name of the type that implements [`Node`].
221    pub type_name: &'static str,
222    pub node: Box<dyn Node>,
223    pub input_slots: SlotInfos,
224    pub output_slots: SlotInfos,
225    pub edges: Edges,
226}
227
228impl Debug for NodeState {
229    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
230        writeln!(f, "{:?} ({:?})", self.label, self.type_name)
231    }
232}
233
234impl NodeState {
235    /// Creates an [`NodeState`] without edges, but the `input_slots` and `output_slots`
236    /// are provided by the `node`.
237    pub fn new<T>(label: InternedRenderLabel, node: T) -> Self
238    where
239        T: Node,
240    {
241        NodeState {
242            label,
243            input_slots: node.input().into(),
244            output_slots: node.output().into(),
245            node: Box::new(node),
246            type_name: std::any::type_name::<T>(),
247            edges: Edges {
248                label,
249                input_edges: Vec::new(),
250                output_edges: Vec::new(),
251            },
252        }
253    }
254
255    /// Retrieves the [`Node`].
256    pub fn node<T>(&self) -> Result<&T, RenderGraphError>
257    where
258        T: Node,
259    {
260        self.node
261            .downcast_ref::<T>()
262            .ok_or(RenderGraphError::WrongNodeType)
263    }
264
265    /// Retrieves the [`Node`] mutably.
266    pub fn node_mut<T>(&mut self) -> Result<&mut T, RenderGraphError>
267    where
268        T: Node,
269    {
270        self.node
271            .downcast_mut::<T>()
272            .ok_or(RenderGraphError::WrongNodeType)
273    }
274
275    /// Validates that each input slot corresponds to an input edge.
276    pub fn validate_input_slots(&self) -> Result<(), RenderGraphError> {
277        for i in 0..self.input_slots.len() {
278            self.edges.get_input_slot_edge(i)?;
279        }
280
281        Ok(())
282    }
283
284    /// Validates that each output slot corresponds to an output edge.
285    pub fn validate_output_slots(&self) -> Result<(), RenderGraphError> {
286        for i in 0..self.output_slots.len() {
287            self.edges.get_output_slot_edge(i)?;
288        }
289
290        Ok(())
291    }
292}
293
294/// A [`Node`] without any inputs, outputs and subgraphs, which does nothing when run.
295/// Used (as a label) to bundle multiple dependencies into one inside
296/// the [`RenderGraph`](super::RenderGraph).
297#[derive(Default)]
298pub struct EmptyNode;
299
300impl Node for EmptyNode {
301    fn run(
302        &self,
303        _graph: &mut RenderGraphContext,
304        _render_context: &mut RenderContext,
305        _world: &World,
306    ) -> Result<(), NodeRunError> {
307        Ok(())
308    }
309}
310
311/// A [`RenderGraph`](super::RenderGraph) [`Node`] that runs the configured subgraph once.
312/// This makes it easier to insert sub-graph runs into a graph.
313pub struct RunGraphOnViewNode {
314    sub_graph: InternedRenderSubGraph,
315}
316
317impl RunGraphOnViewNode {
318    pub fn new<T: RenderSubGraph>(sub_graph: T) -> Self {
319        Self {
320            sub_graph: sub_graph.intern(),
321        }
322    }
323}
324
325impl Node for RunGraphOnViewNode {
326    fn run(
327        &self,
328        graph: &mut RenderGraphContext,
329        _render_context: &mut RenderContext,
330        _world: &World,
331    ) -> Result<(), NodeRunError> {
332        graph.run_sub_graph(self.sub_graph, vec![], Some(graph.view_entity()))?;
333        Ok(())
334    }
335}
336
337/// This trait should be used instead of the [`Node`] trait when making a render node that runs on a view.
338///
339/// It is intended to be used with [`ViewNodeRunner`]
340pub trait ViewNode {
341    /// The query that will be used on the view entity.
342    /// It is guaranteed to run on the view entity, so there's no need for a filter
343    type ViewQuery: ReadOnlyQueryData;
344
345    /// Updates internal node state using the current render [`World`] prior to the run method.
346    fn update(&mut self, _world: &mut World) {}
347
348    /// Runs the graph node logic, issues draw calls, updates the output slots and
349    /// optionally queues up subgraphs for execution. The graph data, input and output values are
350    /// passed via the [`RenderGraphContext`].
351    fn run<'w>(
352        &self,
353        graph: &mut RenderGraphContext,
354        render_context: &mut RenderContext<'w>,
355        view_query: QueryItem<'w, Self::ViewQuery>,
356        world: &'w World,
357    ) -> Result<(), NodeRunError>;
358}
359
360/// This [`Node`] can be used to run any [`ViewNode`].
361/// It will take care of updating the view query in `update()` and running the query in `run()`.
362///
363/// This [`Node`] exists to help reduce boilerplate when making a render node that runs on a view.
364pub struct ViewNodeRunner<N: ViewNode> {
365    view_query: QueryState<N::ViewQuery>,
366    node: N,
367}
368
369impl<N: ViewNode> ViewNodeRunner<N> {
370    pub fn new(node: N, world: &mut World) -> Self {
371        Self {
372            view_query: world.query_filtered(),
373            node,
374        }
375    }
376}
377
378impl<N: ViewNode + FromWorld> FromWorld for ViewNodeRunner<N> {
379    fn from_world(world: &mut World) -> Self {
380        Self::new(N::from_world(world), world)
381    }
382}
383
384impl<T> Node for ViewNodeRunner<T>
385where
386    T: ViewNode + Send + Sync + 'static,
387{
388    fn update(&mut self, world: &mut World) {
389        self.view_query.update_archetypes(world);
390        self.node.update(world);
391    }
392
393    fn run<'w>(
394        &self,
395        graph: &mut RenderGraphContext,
396        render_context: &mut RenderContext<'w>,
397        world: &'w World,
398    ) -> Result<(), NodeRunError> {
399        let Ok(view) = self.view_query.get_manual(world, graph.view_entity()) else {
400            return Ok(());
401        };
402
403        ViewNode::run(&self.node, graph, render_context, view, world)?;
404        Ok(())
405    }
406}