bevy_render/render_graph/
node.rs

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