Skip to content

Commit

Permalink
Add a separate ClearPass (#3209)
Browse files Browse the repository at this point in the history
# Objective

- Rendering before MainPass should be possible, so clearing needs to happen in an earlier pass.
- Fixes #3190.

## Solution

- I added a "Clear" SubGraph, a "ClearPassNode" Node, that clears the color and depth attachments of all views and a "ClearNodeDriver" Node, that schedules the "ClearPassNode" before MainPass.
- Make sure that the 2d and 3d draw passes do not clear their attachments anymore.

### Notes

- It works in the way, that with the current pipeline examples nothing should have changed in their behaviour
- I would like to add an example that adds a pass inbetween ClearPass and MainPass, but I do not understand enough about the new render architecture to do that yet
- Clears all attachment for all views: I do not know enough about rendering in general to say, whether there is a use case for not clearing
- Does not solve #3043 as we still need Cameras/ViewTargets to clear.
  • Loading branch information
KirmesBude committed Dec 9, 2021
1 parent 4c91613 commit 82c04f9
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 9 deletions.
63 changes: 63 additions & 0 deletions pipelined/bevy_core_pipeline/src/clear_pass.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use crate::ClearColor;
use bevy_ecs::prelude::*;
use bevy_render2::{
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo},
render_resource::{LoadOp, Operations, RenderPassDepthStencilAttachment, RenderPassDescriptor},
renderer::RenderContext,
view::{ExtractedView, ViewDepthTexture, ViewTarget},
};

pub struct ClearPassNode {
query: QueryState<(&'static ViewTarget, &'static ViewDepthTexture), With<ExtractedView>>,
}

impl ClearPassNode {
pub fn new(world: &mut World) -> Self {
Self {
query: QueryState::new(world),
}
}
}

impl Node for ClearPassNode {
fn input(&self) -> Vec<SlotInfo> {
vec![]
}

fn update(&mut self, world: &mut World) {
self.query.update_archetypes(world);
}

fn run(
&self,
_graph: &mut RenderGraphContext,
render_context: &mut RenderContext,
world: &World,
) -> Result<(), NodeRunError> {
/* This gets all ViewTargets and ViewDepthTextures and clears its attachments */
for (target, depth) in self.query.iter_manual(world) {
let clear_color = world.get_resource::<ClearColor>().unwrap();
let pass_descriptor = RenderPassDescriptor {
label: Some("clear_pass"),
color_attachments: &[target.get_color_attachment(Operations {
load: LoadOp::Clear(clear_color.0.into()),
store: true,
})],
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
view: &depth.view,
depth_ops: Some(Operations {
load: LoadOp::Clear(0.0),
store: true,
}),
stencil_ops: None,
}),
};

render_context
.command_encoder
.begin_render_pass(&pass_descriptor);
}

Ok(())
}
}
20 changes: 20 additions & 0 deletions pipelined/bevy_core_pipeline/src/clear_pass_driver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use bevy_ecs::world::World;
use bevy_render2::{
render_graph::{Node, NodeRunError, RenderGraphContext},
renderer::RenderContext,
};

pub struct ClearPassDriverNode;

impl Node for ClearPassDriverNode {
fn run(
&self,
graph: &mut RenderGraphContext,
_render_context: &mut RenderContext,
_world: &World,
) -> Result<(), NodeRunError> {
graph.run_sub_graph(crate::clear_graph::NAME, vec![])?;

Ok(())
}
}
23 changes: 23 additions & 0 deletions pipelined/bevy_core_pipeline/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
mod clear_pass;
mod clear_pass_driver;
mod main_pass_2d;
mod main_pass_3d;
mod main_pass_driver;

pub use clear_pass::*;
pub use clear_pass_driver::*;
pub use main_pass_2d::*;
pub use main_pass_3d::*;
pub use main_pass_driver::*;
Expand All @@ -24,6 +28,8 @@ use bevy_render2::{
RenderApp, RenderStage, RenderWorld,
};

use crate::clear_pass::ClearPassNode;

/// Resource that configures the clear color
#[derive(Clone, Debug)]
pub struct ClearColor(pub Color);
Expand All @@ -42,6 +48,7 @@ impl Default for ClearColor {
pub mod node {
pub const MAIN_PASS_DEPENDENCIES: &str = "main_pass_dependencies";
pub const MAIN_PASS_DRIVER: &str = "main_pass_driver";
pub const CLEAR_PASS_DRIVER: &str = "clear_pass_driver";
pub const VIEW: &str = "view";
}

Expand All @@ -65,6 +72,13 @@ pub mod draw_3d_graph {
}
}

pub mod clear_graph {
pub const NAME: &str = "clear";
pub mod node {
pub const CLEAR_PASS: &str = "clear_pass";
}
}

#[derive(Default)]
pub struct CorePipelinePlugin;

Expand All @@ -86,6 +100,7 @@ impl Plugin for CorePipelinePlugin {
.add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<AlphaMask3d>)
.add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<Transparent3d>);

let clear_pass_node = ClearPassNode::new(&mut render_app.world);
let pass_node_2d = MainPass2dNode::new(&mut render_app.world);
let pass_node_3d = MainPass3dNode::new(&mut render_app.world);
let mut graph = render_app.world.get_resource_mut::<RenderGraph>().unwrap();
Expand Down Expand Up @@ -122,11 +137,19 @@ impl Plugin for CorePipelinePlugin {
.unwrap();
graph.add_sub_graph(draw_3d_graph::NAME, draw_3d_graph);

let mut clear_graph = RenderGraph::default();
clear_graph.add_node(clear_graph::node::CLEAR_PASS, clear_pass_node);
graph.add_sub_graph(clear_graph::NAME, clear_graph);

graph.add_node(node::MAIN_PASS_DEPENDENCIES, EmptyNode);
graph.add_node(node::MAIN_PASS_DRIVER, MainPassDriverNode);
graph
.add_node_edge(node::MAIN_PASS_DEPENDENCIES, node::MAIN_PASS_DRIVER)
.unwrap();
graph.add_node(node::CLEAR_PASS_DRIVER, ClearPassDriverNode);
graph
.add_node_edge(node::CLEAR_PASS_DRIVER, node::MAIN_PASS_DRIVER)
.unwrap();
}
}

Expand Down
6 changes: 3 additions & 3 deletions pipelined/bevy_core_pipeline/src/main_pass_2d.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{ClearColor, Transparent2d};
use crate::Transparent2d;
use bevy_ecs::prelude::*;
use bevy_render2::{
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
Expand Down Expand Up @@ -43,14 +43,14 @@ impl Node for MainPass2dNode {
.query
.get_manual(world, view_entity)
.expect("view entity should exist");
let clear_color = world.get_resource::<ClearColor>().unwrap();

let pass_descriptor = RenderPassDescriptor {
label: Some("main_pass_2d"),
color_attachments: &[RenderPassColorAttachment {
view: &target.view,
resolve_target: None,
ops: Operations {
load: LoadOp::Clear(clear_color.0.into()),
load: LoadOp::Load,
store: true,
},
}],
Expand Down
11 changes: 5 additions & 6 deletions pipelined/bevy_core_pipeline/src/main_pass_3d.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{AlphaMask3d, ClearColor, Opaque3d, Transparent3d};
use crate::{AlphaMask3d, Opaque3d, Transparent3d};
use bevy_ecs::prelude::*;
use bevy_render2::{
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
Expand Down Expand Up @@ -51,24 +51,23 @@ impl Node for MainPass3dNode {
.query
.get_manual(world, view_entity)
.expect("view entity should exist");
let clear_color = world.get_resource::<ClearColor>().unwrap();

{
// Run the opaque pass, sorted front-to-back
// NOTE: Scoped to drop the mutable borrow of render_context
let pass_descriptor = RenderPassDescriptor {
label: Some("main_opaque_pass_3d"),
// NOTE: The opaque pass clears and initializes the color
// NOTE: The opaque pass loads the color
// buffer as well as writing to it.
color_attachments: &[target.get_color_attachment(Operations {
load: LoadOp::Clear(clear_color.0.into()),
load: LoadOp::Load,
store: true,
})],
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
view: &depth.view,
// NOTE: The opaque main pass clears and writes to the depth buffer.
// NOTE: The opaque main pass loads the depth buffer and possibly overwrites it
depth_ops: Some(Operations {
load: LoadOp::Clear(0.0),
load: LoadOp::Load,
store: true,
}),
stencil_ops: None,
Expand Down

0 comments on commit 82c04f9

Please sign in to comment.