Path: blob/main/crates/bevy_render/src/render_graph/node.rs
6596 views
use crate::{1render_graph::{2Edge, InputSlotError, OutputSlotError, RenderGraphContext, RenderGraphError,3RunSubGraphError, SlotInfo, SlotInfos,4},5render_phase::DrawError,6renderer::RenderContext,7};8pub use bevy_ecs::label::DynEq;9use bevy_ecs::{10define_label,11intern::Interned,12query::{QueryItem, QueryState, ReadOnlyQueryData},13world::{FromWorld, World},14};15use core::fmt::Debug;16use downcast_rs::{impl_downcast, Downcast};17use thiserror::Error;18use variadics_please::all_tuples_with_size;1920pub use bevy_render_macros::RenderLabel;2122use super::{InternedRenderSubGraph, RenderSubGraph};2324define_label!(25#[diagnostic::on_unimplemented(26note = "consider annotating `{Self}` with `#[derive(RenderLabel)]`"27)]28/// A strongly-typed class of labels used to identify a [`Node`] in a render graph.29RenderLabel,30RENDER_LABEL_INTERNER31);3233/// A shorthand for `Interned<dyn RenderLabel>`.34pub type InternedRenderLabel = Interned<dyn RenderLabel>;3536pub trait IntoRenderNodeArray<const N: usize> {37fn into_array(self) -> [InternedRenderLabel; N];38}3940macro_rules! impl_render_label_tuples {41($N: expr, $(#[$meta:meta])* $(($T: ident, $I: ident)),*) => {42$(#[$meta])*43impl<$($T: RenderLabel),*> IntoRenderNodeArray<$N> for ($($T,)*) {44#[inline]45fn into_array(self) -> [InternedRenderLabel; $N] {46let ($($I,)*) = self;47[$($I.intern(), )*]48}49}50}51}5253all_tuples_with_size!(54#[doc(fake_variadic)]55impl_render_label_tuples,561,5732,58T,59l60);6162/// A render node that can be added to a [`RenderGraph`](super::RenderGraph).63///64/// Nodes are the fundamental part of the graph and used to extend its functionality, by65/// generating draw calls and/or running subgraphs.66/// They are added via the `render_graph::add_node(my_node)` method.67///68/// To determine their position in the graph and ensure that all required dependencies (inputs)69/// are already executed, [`Edges`](Edge) are used.70///71/// A node can produce outputs used as dependencies by other nodes.72/// Those inputs and outputs are called slots and are the default way of passing render data73/// inside the graph. For more information see [`SlotType`](super::SlotType).74pub trait Node: Downcast + Send + Sync + 'static {75/// Specifies the required input slots for this node.76/// They will then be available during the run method inside the [`RenderGraphContext`].77fn input(&self) -> Vec<SlotInfo> {78Vec::new()79}8081/// Specifies the produced output slots for this node.82/// They can then be passed one inside [`RenderGraphContext`] during the run method.83fn output(&self) -> Vec<SlotInfo> {84Vec::new()85}8687/// Updates internal node state using the current render [`World`] prior to the run method.88fn update(&mut self, _world: &mut World) {}8990/// Runs the graph node logic, issues draw calls, updates the output slots and91/// optionally queues up subgraphs for execution. The graph data, input and output values are92/// passed via the [`RenderGraphContext`].93fn run<'w>(94&self,95graph: &mut RenderGraphContext,96render_context: &mut RenderContext<'w>,97world: &'w World,98) -> Result<(), NodeRunError>;99}100101impl_downcast!(Node);102103#[derive(Error, Debug, Eq, PartialEq)]104pub enum NodeRunError {105#[error("encountered an input slot error")]106InputSlotError(#[from] InputSlotError),107#[error("encountered an output slot error")]108OutputSlotError(#[from] OutputSlotError),109#[error("encountered an error when running a sub-graph")]110RunSubGraphError(#[from] RunSubGraphError),111#[error("encountered an error when executing draw command")]112DrawError(#[from] DrawError),113}114115/// A collection of input and output [`Edges`](Edge) for a [`Node`].116#[derive(Debug)]117pub struct Edges {118label: InternedRenderLabel,119input_edges: Vec<Edge>,120output_edges: Vec<Edge>,121}122123impl Edges {124/// Returns all "input edges" (edges going "in") for this node .125#[inline]126pub fn input_edges(&self) -> &[Edge] {127&self.input_edges128}129130/// Returns all "output edges" (edges going "out") for this node .131#[inline]132pub fn output_edges(&self) -> &[Edge] {133&self.output_edges134}135136/// Returns this node's label.137#[inline]138pub fn label(&self) -> InternedRenderLabel {139self.label140}141142/// Adds an edge to the `input_edges` if it does not already exist.143pub(crate) fn add_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {144if self.has_input_edge(&edge) {145return Err(RenderGraphError::EdgeAlreadyExists(edge));146}147self.input_edges.push(edge);148Ok(())149}150151/// Removes an edge from the `input_edges` if it exists.152pub(crate) fn remove_input_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {153if let Some(index) = self.input_edges.iter().position(|e| *e == edge) {154self.input_edges.swap_remove(index);155Ok(())156} else {157Err(RenderGraphError::EdgeDoesNotExist(edge))158}159}160161/// Adds an edge to the `output_edges` if it does not already exist.162pub(crate) fn add_output_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {163if self.has_output_edge(&edge) {164return Err(RenderGraphError::EdgeAlreadyExists(edge));165}166self.output_edges.push(edge);167Ok(())168}169170/// Removes an edge from the `output_edges` if it exists.171pub(crate) fn remove_output_edge(&mut self, edge: Edge) -> Result<(), RenderGraphError> {172if let Some(index) = self.output_edges.iter().position(|e| *e == edge) {173self.output_edges.swap_remove(index);174Ok(())175} else {176Err(RenderGraphError::EdgeDoesNotExist(edge))177}178}179180/// Checks whether the input edge already exists.181pub fn has_input_edge(&self, edge: &Edge) -> bool {182self.input_edges.contains(edge)183}184185/// Checks whether the output edge already exists.186pub fn has_output_edge(&self, edge: &Edge) -> bool {187self.output_edges.contains(edge)188}189190/// Searches the `input_edges` for a [`Edge::SlotEdge`],191/// which `input_index` matches the `index`;192pub fn get_input_slot_edge(&self, index: usize) -> Result<&Edge, RenderGraphError> {193self.input_edges194.iter()195.find(|e| {196if let Edge::SlotEdge { input_index, .. } = e {197*input_index == index198} else {199false200}201})202.ok_or(RenderGraphError::UnconnectedNodeInputSlot {203input_slot: index,204node: self.label,205})206}207208/// Searches the `output_edges` for a [`Edge::SlotEdge`],209/// which `output_index` matches the `index`;210pub fn get_output_slot_edge(&self, index: usize) -> Result<&Edge, RenderGraphError> {211self.output_edges212.iter()213.find(|e| {214if let Edge::SlotEdge { output_index, .. } = e {215*output_index == index216} else {217false218}219})220.ok_or(RenderGraphError::UnconnectedNodeOutputSlot {221output_slot: index,222node: self.label,223})224}225}226227/// The internal representation of a [`Node`], with all data required228/// by the [`RenderGraph`](super::RenderGraph).229///230/// The `input_slots` and `output_slots` are provided by the `node`.231pub struct NodeState {232pub label: InternedRenderLabel,233/// The name of the type that implements [`Node`].234pub type_name: &'static str,235pub node: Box<dyn Node>,236pub input_slots: SlotInfos,237pub output_slots: SlotInfos,238pub edges: Edges,239}240241impl Debug for NodeState {242fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {243writeln!(f, "{:?} ({})", self.label, self.type_name)244}245}246247impl NodeState {248/// Creates an [`NodeState`] without edges, but the `input_slots` and `output_slots`249/// are provided by the `node`.250pub fn new<T>(label: InternedRenderLabel, node: T) -> Self251where252T: Node,253{254NodeState {255label,256input_slots: node.input().into(),257output_slots: node.output().into(),258node: Box::new(node),259type_name: core::any::type_name::<T>(),260edges: Edges {261label,262input_edges: Vec::new(),263output_edges: Vec::new(),264},265}266}267268/// Retrieves the [`Node`].269pub fn node<T>(&self) -> Result<&T, RenderGraphError>270where271T: Node,272{273self.node274.downcast_ref::<T>()275.ok_or(RenderGraphError::WrongNodeType)276}277278/// Retrieves the [`Node`] mutably.279pub fn node_mut<T>(&mut self) -> Result<&mut T, RenderGraphError>280where281T: Node,282{283self.node284.downcast_mut::<T>()285.ok_or(RenderGraphError::WrongNodeType)286}287288/// Validates that each input slot corresponds to an input edge.289pub fn validate_input_slots(&self) -> Result<(), RenderGraphError> {290for i in 0..self.input_slots.len() {291self.edges.get_input_slot_edge(i)?;292}293294Ok(())295}296297/// Validates that each output slot corresponds to an output edge.298pub fn validate_output_slots(&self) -> Result<(), RenderGraphError> {299for i in 0..self.output_slots.len() {300self.edges.get_output_slot_edge(i)?;301}302303Ok(())304}305}306307/// A [`Node`] without any inputs, outputs and subgraphs, which does nothing when run.308/// Used (as a label) to bundle multiple dependencies into one inside309/// the [`RenderGraph`](super::RenderGraph).310#[derive(Default)]311pub struct EmptyNode;312313impl Node for EmptyNode {314fn run(315&self,316_graph: &mut RenderGraphContext,317_render_context: &mut RenderContext,318_world: &World,319) -> Result<(), NodeRunError> {320Ok(())321}322}323324/// A [`RenderGraph`](super::RenderGraph) [`Node`] that runs the configured subgraph once.325/// This makes it easier to insert sub-graph runs into a graph.326pub struct RunGraphOnViewNode {327sub_graph: InternedRenderSubGraph,328}329330impl RunGraphOnViewNode {331pub fn new<T: RenderSubGraph>(sub_graph: T) -> Self {332Self {333sub_graph: sub_graph.intern(),334}335}336}337338impl Node for RunGraphOnViewNode {339fn run(340&self,341graph: &mut RenderGraphContext,342_render_context: &mut RenderContext,343_world: &World,344) -> Result<(), NodeRunError> {345graph.run_sub_graph(self.sub_graph, vec![], Some(graph.view_entity()))?;346Ok(())347}348}349350/// This trait should be used instead of the [`Node`] trait when making a render node that runs on a view.351///352/// It is intended to be used with [`ViewNodeRunner`]353pub trait ViewNode {354/// The query that will be used on the view entity.355/// It is guaranteed to run on the view entity, so there's no need for a filter356type ViewQuery: ReadOnlyQueryData;357358/// Updates internal node state using the current render [`World`] prior to the run method.359fn update(&mut self, _world: &mut World) {}360361/// Runs the graph node logic, issues draw calls, updates the output slots and362/// optionally queues up subgraphs for execution. The graph data, input and output values are363/// passed via the [`RenderGraphContext`].364fn run<'w>(365&self,366graph: &mut RenderGraphContext,367render_context: &mut RenderContext<'w>,368view_query: QueryItem<'w, '_, Self::ViewQuery>,369world: &'w World,370) -> Result<(), NodeRunError>;371}372373/// This [`Node`] can be used to run any [`ViewNode`].374/// It will take care of updating the view query in `update()` and running the query in `run()`.375///376/// This [`Node`] exists to help reduce boilerplate when making a render node that runs on a view.377pub struct ViewNodeRunner<N: ViewNode> {378view_query: QueryState<N::ViewQuery>,379node: N,380}381382impl<N: ViewNode> ViewNodeRunner<N> {383pub fn new(node: N, world: &mut World) -> Self {384Self {385view_query: world.query_filtered(),386node,387}388}389}390391impl<N: ViewNode + FromWorld> FromWorld for ViewNodeRunner<N> {392fn from_world(world: &mut World) -> Self {393Self::new(N::from_world(world), world)394}395}396397impl<T> Node for ViewNodeRunner<T>398where399T: ViewNode + Send + Sync + 'static,400{401fn update(&mut self, world: &mut World) {402self.view_query.update_archetypes(world);403self.node.update(world);404}405406fn run<'w>(407&self,408graph: &mut RenderGraphContext,409render_context: &mut RenderContext<'w>,410world: &'w World,411) -> Result<(), NodeRunError> {412let Ok(view) = self.view_query.get_manual(world, graph.view_entity()) else {413return Ok(());414};415416ViewNode::run(&self.node, graph, render_context, view, world)?;417Ok(())418}419}420421422