bevy_render/render_graph/
node.rs1use 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 RenderLabel,
27 RENDER_LABEL_INTERNER
28);
29
30pub 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
51pub trait Node: Downcast + Send + Sync + 'static {
64 fn input(&self) -> Vec<SlotInfo> {
67 Vec::new()
68 }
69
70 fn output(&self) -> Vec<SlotInfo> {
73 Vec::new()
74 }
75
76 fn update(&mut self, _world: &mut World) {}
78
79 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#[derive(Debug)]
104pub struct Edges {
105 label: InternedRenderLabel,
106 input_edges: Vec<Edge>,
107 output_edges: Vec<Edge>,
108}
109
110impl Edges {
111 #[inline]
113 pub fn input_edges(&self) -> &[Edge] {
114 &self.input_edges
115 }
116
117 #[inline]
119 pub fn output_edges(&self) -> &[Edge] {
120 &self.output_edges
121 }
122
123 #[inline]
125 pub fn label(&self) -> InternedRenderLabel {
126 self.label
127 }
128
129 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 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 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 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 pub fn has_input_edge(&self, edge: &Edge) -> bool {
169 self.input_edges.contains(edge)
170 }
171
172 pub fn has_output_edge(&self, edge: &Edge) -> bool {
174 self.output_edges.contains(edge)
175 }
176
177 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 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
214pub struct NodeState {
219 pub label: InternedRenderLabel,
220 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 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 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 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 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 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#[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
311pub 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
337pub trait ViewNode {
341 type ViewQuery: ReadOnlyQueryData;
344
345 fn update(&mut self, _world: &mut World) {}
347
348 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
360pub 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}