Skip to content

Commit

Permalink
RenderGraph Labelization (bevyengine#10644)
Browse files Browse the repository at this point in the history
# Objective

The whole `Cow<'static, str>` naming for nodes and subgraphs in
`RenderGraph` is a mess.

## Solution

Replaces hardcoded and potentially overlapping strings for nodes and
subgraphs inside `RenderGraph` with bevy's labelsystem.

---

## Changelog

* Two new labels: `RenderLabel` and `RenderSubGraph`.
* Replaced all uses for hardcoded strings with those labels
* Moved `Taa` label from its own mod to all the other `Labels3d`
* `add_render_graph_edges` now needs a tuple of labels
* Moved `ScreenSpaceAmbientOcclusion` label from its own mod with the
`ShadowPass` label to `LabelsPbr`
* Removed  `NodeId`
* Renamed `Edges.id()` to `Edges.label()`
* Removed `NodeLabel`
* Changed examples according to the new label system
* Introduced new `RenderLabel`s: `Labels2d`, `Labels3d`, `LabelsPbr`,
`LabelsUi`
* Introduced new `RenderSubGraph`s: `SubGraph2d`, `SubGraph3d`,
`SubGraphUi`
* Removed `Reflect` and `Default` derive from `CameraRenderGraph`
component struct
* Improved some error messages

## Migration Guide

For Nodes and SubGraphs, instead of using hardcoded strings, you now
pass labels, which can be derived with structs and enums.

```rs
// old
#[derive(Default)]
struct MyRenderNode;
impl MyRenderNode {
    pub const NAME: &'static str = "my_render_node"
}

render_app
    .add_render_graph_node::<ViewNodeRunner<MyRenderNode>>(
        core_3d::graph::NAME,
        MyRenderNode::NAME,
    )
    .add_render_graph_edges(
        core_3d::graph::NAME,
        &[
            core_3d::graph::node::TONEMAPPING,
            MyRenderNode::NAME,
            core_3d::graph::node::END_MAIN_PASS_POST_PROCESSING,
        ],
    );

// new
use bevy::core_pipeline::core_3d::graph::{Labels3d, SubGraph3d};

#[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
pub struct MyRenderLabel;

#[derive(Default)]
struct MyRenderNode;

render_app
    .add_render_graph_node::<ViewNodeRunner<MyRenderNode>>(
        SubGraph3d,
        MyRenderLabel,
    )
    .add_render_graph_edges(
        SubGraph3d,
        (
            Labels3d::Tonemapping,
            MyRenderLabel,
            Labels3d::EndMainPassPostProcessing,
        ),
    );
```

### SubGraphs

#### in `bevy_core_pipeline::core_2d::graph`
| old string-based path | new label |
|-----------------------|-----------|
| `NAME` | `SubGraph2d` |

#### in `bevy_core_pipeline::core_3d::graph`
| old string-based path | new label |
|-----------------------|-----------|
| `NAME` | `SubGraph3d` |

#### in `bevy_ui::render`
| old string-based path | new label |
|-----------------------|-----------|
| `draw_ui_graph::NAME` | `graph::SubGraphUi` |

### Nodes

#### in `bevy_core_pipeline::core_2d::graph`
| old string-based path | new label |
|-----------------------|-----------|
| `node::MSAA_WRITEBACK` | `Labels2d::MsaaWriteback` | 
| `node::MAIN_PASS` | `Labels2d::MainPass` | 
| `node::BLOOM` | `Labels2d::Bloom` | 
| `node::TONEMAPPING` | `Labels2d::Tonemapping` | 
| `node::FXAA` | `Labels2d::Fxaa` | 
| `node::UPSCALING` | `Labels2d::Upscaling` | 
| `node::CONTRAST_ADAPTIVE_SHARPENING` |
`Labels2d::ConstrastAdaptiveSharpening` |
| `node::END_MAIN_PASS_POST_PROCESSING` |
`Labels2d::EndMainPassPostProcessing` |

#### in `bevy_core_pipeline::core_3d::graph`
| old string-based path | new label |
|-----------------------|-----------|
| `node::MSAA_WRITEBACK` | `Labels3d::MsaaWriteback` | 
| `node::PREPASS` | `Labels3d::Prepass` | 
| `node::DEFERRED_PREPASS` | `Labels3d::DeferredPrepass` | 
| `node::COPY_DEFERRED_LIGHTING_ID` | `Labels3d::CopyDeferredLightingId`
|
| `node::END_PREPASSES` | `Labels3d::EndPrepasses` | 
| `node::START_MAIN_PASS` | `Labels3d::StartMainPass` | 
| `node::MAIN_OPAQUE_PASS` | `Labels3d::MainOpaquePass` | 
| `node::MAIN_TRANSMISSIVE_PASS` | `Labels3d::MainTransmissivePass` | 
| `node::MAIN_TRANSPARENT_PASS` | `Labels3d::MainTransparentPass` | 
| `node::END_MAIN_PASS` | `Labels3d::EndMainPass` | 
| `node::BLOOM` | `Labels3d::Bloom` | 
| `node::TONEMAPPING` | `Labels3d::Tonemapping` | 
| `node::FXAA` | `Labels3d::Fxaa` | 
| `node::UPSCALING` | `Labels3d::Upscaling` | 
| `node::CONTRAST_ADAPTIVE_SHARPENING` |
`Labels3d::ContrastAdaptiveSharpening` |
| `node::END_MAIN_PASS_POST_PROCESSING` |
`Labels3d::EndMainPassPostProcessing` |

#### in `bevy_core_pipeline`
| old string-based path | new label |
|-----------------------|-----------|
| `taa::draw_3d_graph::node::TAA` | `Labels3d::Taa` |

#### in `bevy_pbr`
| old string-based path | new label |
|-----------------------|-----------|
| `draw_3d_graph::node::SHADOW_PASS` | `LabelsPbr::ShadowPass` |
| `ssao::draw_3d_graph::node::SCREEN_SPACE_AMBIENT_OCCLUSION` |
`LabelsPbr::ScreenSpaceAmbientOcclusion` |
| `deferred::DEFFERED_LIGHTING_PASS` | `LabelsPbr::DeferredLightingPass`
|

#### in `bevy_render`
| old string-based path | new label |
|-----------------------|-----------|
| `main_graph::node::CAMERA_DRIVER` | `graph::CameraDriverLabel` |

#### in `bevy_ui::render`
| old string-based path | new label |
|-----------------------|-----------|
| `draw_ui_graph::node::UI_PASS` | `graph::LabelsUi::UiPass` |

---

## Future work

* Make `NodeSlot`s also use types. Ideally, we have an enum with unit
variants where every variant resembles one slot. Then to make sure you
are using the right slot enum and make rust-analyzer play nicely with
it, we should make an associated type in the `Node` trait. With today's
system, we can introduce 3rd party slots to a node, and i wasnt sure if
this was used, so I didn't do this in this PR.

## Unresolved Questions

When looking at the `post_processing` example, we have a struct for the
label and a struct for the node, this seems like boilerplate and on
discord, @IceSentry (sowy for the ping)
[asked](https://discord.com/channels/691052431525675048/743663924229963868/1175197016947699742)
if a node could automatically introduce a label (or i completely
misunderstood that). The problem with that is, that nodes like
`EmptyNode` exist multiple times *inside the same* (sub)graph, so there
we need extern labels to distinguish between those. Hopefully we can
find a way to reduce boilerplate and still have everything unique. For
EmptyNode, we could maybe make a macro which implements an "empty node"
for a type, but for nodes which contain code and need to be present
multiple times, this could get nasty...
  • Loading branch information
DasLixou authored and tjamaan committed Feb 6, 2024
1 parent 870b364 commit 41cee45
Show file tree
Hide file tree
Showing 27 changed files with 725 additions and 671 deletions.
34 changes: 12 additions & 22 deletions crates/bevy_core_pipeline/src/bloom/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ mod upsampling_pipeline;
pub use settings::{BloomCompositeMode, BloomPrefilterSettings, BloomSettings};

use crate::{
core_2d::{self, CORE_2D},
core_3d::{self, CORE_3D},
core_2d::graph::{Labels2d, SubGraph2d},
core_3d::graph::{Labels3d, SubGraph3d},
};
use bevy_app::{App, Plugin};
use bevy_asset::{load_internal_asset, Handle};
Expand Down Expand Up @@ -72,30 +72,20 @@ impl Plugin for BloomPlugin {
),
)
// Add bloom to the 3d render graph
.add_render_graph_node::<ViewNodeRunner<BloomNode>>(
CORE_3D,
core_3d::graph::node::BLOOM,
)
.add_render_graph_node::<ViewNodeRunner<BloomNode>>(SubGraph3d, Labels3d::Bloom)
.add_render_graph_edges(
CORE_3D,
&[
core_3d::graph::node::END_MAIN_PASS,
core_3d::graph::node::BLOOM,
core_3d::graph::node::TONEMAPPING,
],
SubGraph3d,
(
Labels3d::EndMainPass,
Labels3d::Bloom,
Labels3d::Tonemapping,
),
)
// Add bloom to the 2d render graph
.add_render_graph_node::<ViewNodeRunner<BloomNode>>(
CORE_2D,
core_2d::graph::node::BLOOM,
)
.add_render_graph_node::<ViewNodeRunner<BloomNode>>(SubGraph2d, Labels2d::Bloom)
.add_render_graph_edges(
CORE_2D,
&[
core_2d::graph::node::MAIN_PASS,
core_2d::graph::node::BLOOM,
core_2d::graph::node::TONEMAPPING,
],
SubGraph2d,
(Labels2d::MainPass, Labels2d::Bloom, Labels2d::Tonemapping),
);
}

Expand Down
46 changes: 26 additions & 20 deletions crates/bevy_core_pipeline/src/contrast_adaptive_sharpening/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::{
core_2d::{self, CORE_2D},
core_3d::{self, CORE_3D},
core_2d::graph::{Labels2d, SubGraph2d},
core_3d::graph::{Labels3d, SubGraph3d},
fullscreen_vertex_shader::fullscreen_shader_vertex_state,
};
use bevy_app::prelude::*;
Expand Down Expand Up @@ -124,31 +124,37 @@ impl Plugin for CASPlugin {
.add_systems(Render, prepare_cas_pipelines.in_set(RenderSet::Prepare));

{
use core_3d::graph::node::*;
render_app
.add_render_graph_node::<CASNode>(CORE_3D, CONTRAST_ADAPTIVE_SHARPENING)
.add_render_graph_edge(CORE_3D, TONEMAPPING, CONTRAST_ADAPTIVE_SHARPENING)
.add_render_graph_node::<CASNode>(SubGraph3d, Labels3d::ContrastAdaptiveSharpening)
.add_render_graph_edge(
SubGraph3d,
Labels3d::Tonemapping,
Labels3d::ContrastAdaptiveSharpening,
)
.add_render_graph_edges(
CORE_3D,
&[
FXAA,
CONTRAST_ADAPTIVE_SHARPENING,
END_MAIN_PASS_POST_PROCESSING,
],
SubGraph3d,
(
Labels3d::Fxaa,
Labels3d::ContrastAdaptiveSharpening,
Labels3d::EndMainPassPostProcessing,
),
);
}
{
use core_2d::graph::node::*;
render_app
.add_render_graph_node::<CASNode>(CORE_2D, CONTRAST_ADAPTIVE_SHARPENING)
.add_render_graph_edge(CORE_2D, TONEMAPPING, CONTRAST_ADAPTIVE_SHARPENING)
.add_render_graph_node::<CASNode>(SubGraph2d, Labels2d::ConstrastAdaptiveSharpening)
.add_render_graph_edge(
SubGraph2d,
Labels2d::Tonemapping,
Labels2d::ConstrastAdaptiveSharpening,
)
.add_render_graph_edges(
CORE_2D,
&[
FXAA,
CONTRAST_ADAPTIVE_SHARPENING,
END_MAIN_PASS_POST_PROCESSING,
],
SubGraph2d,
(
Labels2d::Fxaa,
Labels2d::ConstrastAdaptiveSharpening,
Labels2d::EndMainPassPostProcessing,
),
);
}
}
Expand Down
11 changes: 8 additions & 3 deletions crates/bevy_core_pipeline/src/core_2d/camera_2d.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::tonemapping::{DebandDither, Tonemapping};
use crate::{
core_3d::graph::SubGraph3d,
tonemapping::{DebandDither, Tonemapping},
};
use bevy_ecs::prelude::*;
use bevy_reflect::Reflect;
use bevy_render::{
Expand All @@ -12,6 +15,8 @@ use bevy_render::{
};
use bevy_transform::prelude::{GlobalTransform, Transform};

use super::graph::SubGraph2d;

#[derive(Component, Default, Reflect, Clone, ExtractComponent)]
#[extract_component_filter(With<Camera>)]
#[reflect(Component)]
Expand Down Expand Up @@ -49,7 +54,7 @@ impl Default for Camera2dBundle {
projection.far(),
);
Self {
camera_render_graph: CameraRenderGraph::new(crate::core_2d::graph::NAME),
camera_render_graph: CameraRenderGraph::new(SubGraph2d),
projection,
visible_entities: VisibleEntities::default(),
frustum,
Expand Down Expand Up @@ -88,7 +93,7 @@ impl Camera2dBundle {
projection.far(),
);
Self {
camera_render_graph: CameraRenderGraph::new(crate::core_2d::graph::NAME),
camera_render_graph: CameraRenderGraph::new(SubGraph3d),
projection,
visible_entities: VisibleEntities::default(),
frustum,
Expand Down
57 changes: 33 additions & 24 deletions crates/bevy_core_pipeline/src/core_2d/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,27 @@ mod camera_2d;
mod main_pass_2d_node;

pub mod graph {
pub const NAME: &str = "core_2d";
use bevy_render::render_graph::{RenderLabel, RenderSubGraph};

#[derive(Debug, Hash, PartialEq, Eq, Clone, RenderSubGraph)]
pub struct SubGraph2d;

pub mod input {
pub const VIEW_ENTITY: &str = "view_entity";
}
pub mod node {
pub const MSAA_WRITEBACK: &str = "msaa_writeback";
pub const MAIN_PASS: &str = "main_pass";
pub const BLOOM: &str = "bloom";
pub const TONEMAPPING: &str = "tonemapping";
pub const FXAA: &str = "fxaa";
pub const UPSCALING: &str = "upscaling";
pub const CONTRAST_ADAPTIVE_SHARPENING: &str = "contrast_adaptive_sharpening";
pub const END_MAIN_PASS_POST_PROCESSING: &str = "end_main_pass_post_processing";

#[derive(Debug, Hash, PartialEq, Eq, Clone, RenderLabel)]
pub enum Labels2d {
MsaaWriteback,
MainPass,
Bloom,
Tonemapping,
Fxaa,
Upscaling,
ConstrastAdaptiveSharpening,
EndMainPassPostProcessing,
}
}
pub const CORE_2D: &str = graph::NAME;

use std::ops::Range;

Expand All @@ -41,6 +46,8 @@ use bevy_utils::{nonmax::NonMaxU32, FloatOrd};

use crate::{tonemapping::TonemappingNode, upscaling::UpscalingNode};

use self::graph::{Labels2d, SubGraph2d};

pub struct Core2dPlugin;

impl Plugin for Core2dPlugin {
Expand All @@ -60,21 +67,23 @@ impl Plugin for Core2dPlugin {
sort_phase_system::<Transparent2d>.in_set(RenderSet::PhaseSort),
);

use graph::node::*;
render_app
.add_render_sub_graph(CORE_2D)
.add_render_graph_node::<MainPass2dNode>(CORE_2D, MAIN_PASS)
.add_render_graph_node::<ViewNodeRunner<TonemappingNode>>(CORE_2D, TONEMAPPING)
.add_render_graph_node::<EmptyNode>(CORE_2D, END_MAIN_PASS_POST_PROCESSING)
.add_render_graph_node::<ViewNodeRunner<UpscalingNode>>(CORE_2D, UPSCALING)
.add_render_sub_graph(SubGraph2d)
.add_render_graph_node::<MainPass2dNode>(SubGraph2d, Labels2d::MainPass)
.add_render_graph_node::<ViewNodeRunner<TonemappingNode>>(
SubGraph2d,
Labels2d::Tonemapping,
)
.add_render_graph_node::<EmptyNode>(SubGraph2d, Labels2d::EndMainPassPostProcessing)
.add_render_graph_node::<ViewNodeRunner<UpscalingNode>>(SubGraph2d, Labels2d::Upscaling)
.add_render_graph_edges(
CORE_2D,
&[
MAIN_PASS,
TONEMAPPING,
END_MAIN_PASS_POST_PROCESSING,
UPSCALING,
],
SubGraph2d,
(
Labels2d::MainPass,
Labels2d::Tonemapping,
Labels2d::EndMainPassPostProcessing,
Labels2d::Upscaling,
),
);
}
}
Expand Down
4 changes: 3 additions & 1 deletion crates/bevy_core_pipeline/src/core_3d/camera_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use bevy_render::{
use bevy_transform::prelude::{GlobalTransform, Transform};
use serde::{Deserialize, Serialize};

use super::graph::SubGraph3d;

/// Configuration for the "main 3d render graph".
#[derive(Component, Reflect, Clone, ExtractComponent)]
#[extract_component_filter(With<Camera>)]
Expand Down Expand Up @@ -150,7 +152,7 @@ pub struct Camera3dBundle {
impl Default for Camera3dBundle {
fn default() -> Self {
Self {
camera_render_graph: CameraRenderGraph::new(crate::core_3d::graph::NAME),
camera_render_graph: CameraRenderGraph::new(SubGraph3d),
camera: Default::default(),
projection: Default::default(),
visible_entities: Default::default(),
Expand Down
Loading

0 comments on commit 41cee45

Please sign in to comment.