bevy_render/render_graph/
node.rs1use 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 RenderLabel,
31 RENDER_LABEL_INTERNER
32);
33
34pub 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
63pub trait Node: Downcast + Send + Sync + 'static {
76 fn input(&self) -> Vec<SlotInfo> {
79 Vec::new()
80 }
81
82 fn output(&self) -> Vec<SlotInfo> {
85 Vec::new()
86 }
87
88 fn update(&mut self, _world: &mut World) {}
90
91 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#[derive(Debug)]
118pub struct Edges {
119 label: InternedRenderLabel,
120 input_edges: Vec<Edge>,
121 output_edges: Vec<Edge>,
122}
123
124impl Edges {
125 #[inline]
127 pub fn input_edges(&self) -> &[Edge] {
128 &self.input_edges
129 }
130
131 #[inline]
133 pub fn output_edges(&self) -> &[Edge] {
134 &self.output_edges
135 }
136
137 #[inline]
139 pub fn label(&self) -> InternedRenderLabel {
140 self.label
141 }
142
143 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 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 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 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 pub fn has_input_edge(&self, edge: &Edge) -> bool {
183 self.input_edges.contains(edge)
184 }
185
186 pub fn has_output_edge(&self, edge: &Edge) -> bool {
188 self.output_edges.contains(edge)
189 }
190
191 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 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
228pub struct NodeState {
233 pub label: InternedRenderLabel,
234 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 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 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 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 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 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#[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
325pub 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
351pub trait ViewNode {
355 type ViewQuery: ReadOnlyQueryData;
358
359 fn update(&mut self, _world: &mut World) {}
361
362 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
374pub 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}