Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_render/src/render_graph/node.rs
6596 views
1
use crate::{
2
render_graph::{
3
Edge, InputSlotError, OutputSlotError, RenderGraphContext, RenderGraphError,
4
RunSubGraphError, SlotInfo, SlotInfos,
5
},
6
render_phase::DrawError,
7
renderer::RenderContext,
8
};
9
pub use bevy_ecs::label::DynEq;
10
use bevy_ecs::{
11
define_label,
12
intern::Interned,
13
query::{QueryItem, QueryState, ReadOnlyQueryData},
14
world::{FromWorld, World},
15
};
16
use core::fmt::Debug;
17
use downcast_rs::{impl_downcast, Downcast};
18
use thiserror::Error;
19
use variadics_please::all_tuples_with_size;
20
21
pub use bevy_render_macros::RenderLabel;
22
23
use super::{InternedRenderSubGraph, RenderSubGraph};
24
25
define_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>`.
35
pub type InternedRenderLabel = Interned<dyn RenderLabel>;
36
37
pub trait IntoRenderNodeArray<const N: usize> {
38
fn into_array(self) -> [InternedRenderLabel; N];
39
}
40
41
macro_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
54
all_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).
75
pub 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
102
impl_downcast!(Node);
103
104
#[derive(Error, Debug, Eq, PartialEq)]
105
pub 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)]
118
pub struct Edges {
119
label: InternedRenderLabel,
120
input_edges: Vec<Edge>,
121
output_edges: Vec<Edge>,
122
}
123
124
impl 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`.
232
pub 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
242
impl 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
248
impl 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)]
312
pub struct EmptyNode;
313
314
impl 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.
327
pub struct RunGraphOnViewNode {
328
sub_graph: InternedRenderSubGraph,
329
}
330
331
impl RunGraphOnViewNode {
332
pub fn new<T: RenderSubGraph>(sub_graph: T) -> Self {
333
Self {
334
sub_graph: sub_graph.intern(),
335
}
336
}
337
}
338
339
impl 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`]
354
pub 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.
378
pub struct ViewNodeRunner<N: ViewNode> {
379
view_query: QueryState<N::ViewQuery>,
380
node: N,
381
}
382
383
impl<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
392
impl<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
398
impl<T> Node for ViewNodeRunner<T>
399
where
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
}
421
422