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