Add a separate ClearPass (#3209)
# 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.
This commit is contained in:
		
							parent
							
								
									4c91613ae6
								
							
						
					
					
						commit
						82c04f93f5
					
				
							
								
								
									
										63
									
								
								pipelined/bevy_core_pipeline/src/clear_pass.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								pipelined/bevy_core_pipeline/src/clear_pass.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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
									
								
								pipelined/bevy_core_pipeline/src/clear_pass_driver.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								pipelined/bevy_core_pipeline/src/clear_pass_driver.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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(()) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -1,7 +1,11 @@ | |||||||
|  | mod clear_pass; | ||||||
|  | mod clear_pass_driver; | ||||||
| mod main_pass_2d; | mod main_pass_2d; | ||||||
| mod main_pass_3d; | mod main_pass_3d; | ||||||
| mod main_pass_driver; | mod main_pass_driver; | ||||||
| 
 | 
 | ||||||
|  | pub use clear_pass::*; | ||||||
|  | pub use clear_pass_driver::*; | ||||||
| pub use main_pass_2d::*; | pub use main_pass_2d::*; | ||||||
| pub use main_pass_3d::*; | pub use main_pass_3d::*; | ||||||
| pub use main_pass_driver::*; | pub use main_pass_driver::*; | ||||||
| @ -24,6 +28,8 @@ use bevy_render2::{ | |||||||
|     RenderApp, RenderStage, RenderWorld, |     RenderApp, RenderStage, RenderWorld, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | use crate::clear_pass::ClearPassNode; | ||||||
|  | 
 | ||||||
| /// Resource that configures the clear color
 | /// Resource that configures the clear color
 | ||||||
| #[derive(Clone, Debug)] | #[derive(Clone, Debug)] | ||||||
| pub struct ClearColor(pub Color); | pub struct ClearColor(pub Color); | ||||||
| @ -42,6 +48,7 @@ impl Default for ClearColor { | |||||||
| pub mod node { | pub mod node { | ||||||
|     pub const MAIN_PASS_DEPENDENCIES: &str = "main_pass_dependencies"; |     pub const MAIN_PASS_DEPENDENCIES: &str = "main_pass_dependencies"; | ||||||
|     pub const MAIN_PASS_DRIVER: &str = "main_pass_driver"; |     pub const MAIN_PASS_DRIVER: &str = "main_pass_driver"; | ||||||
|  |     pub const CLEAR_PASS_DRIVER: &str = "clear_pass_driver"; | ||||||
|     pub const VIEW: &str = "view"; |     pub const VIEW: &str = "view"; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -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)] | #[derive(Default)] | ||||||
| pub struct CorePipelinePlugin; | pub struct CorePipelinePlugin; | ||||||
| 
 | 
 | ||||||
| @ -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::<AlphaMask3d>) | ||||||
|             .add_system_to_stage(RenderStage::PhaseSort, sort_phase_system::<Transparent3d>); |             .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_2d = MainPass2dNode::new(&mut render_app.world); | ||||||
|         let pass_node_3d = MainPass3dNode::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(); |         let mut graph = render_app.world.get_resource_mut::<RenderGraph>().unwrap(); | ||||||
| @ -122,11 +137,19 @@ impl Plugin for CorePipelinePlugin { | |||||||
|             .unwrap(); |             .unwrap(); | ||||||
|         graph.add_sub_graph(draw_3d_graph::NAME, draw_3d_graph); |         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_DEPENDENCIES, EmptyNode); | ||||||
|         graph.add_node(node::MAIN_PASS_DRIVER, MainPassDriverNode); |         graph.add_node(node::MAIN_PASS_DRIVER, MainPassDriverNode); | ||||||
|         graph |         graph | ||||||
|             .add_node_edge(node::MAIN_PASS_DEPENDENCIES, node::MAIN_PASS_DRIVER) |             .add_node_edge(node::MAIN_PASS_DEPENDENCIES, node::MAIN_PASS_DRIVER) | ||||||
|             .unwrap(); |             .unwrap(); | ||||||
|  |         graph.add_node(node::CLEAR_PASS_DRIVER, ClearPassDriverNode); | ||||||
|  |         graph | ||||||
|  |             .add_node_edge(node::CLEAR_PASS_DRIVER, node::MAIN_PASS_DRIVER) | ||||||
|  |             .unwrap(); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| use crate::{ClearColor, Transparent2d}; | use crate::Transparent2d; | ||||||
| use bevy_ecs::prelude::*; | use bevy_ecs::prelude::*; | ||||||
| use bevy_render2::{ | use bevy_render2::{ | ||||||
|     render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, |     render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, | ||||||
| @ -43,14 +43,14 @@ impl Node for MainPass2dNode { | |||||||
|             .query |             .query | ||||||
|             .get_manual(world, view_entity) |             .get_manual(world, view_entity) | ||||||
|             .expect("view entity should exist"); |             .expect("view entity should exist"); | ||||||
|         let clear_color = world.get_resource::<ClearColor>().unwrap(); | 
 | ||||||
|         let pass_descriptor = RenderPassDescriptor { |         let pass_descriptor = RenderPassDescriptor { | ||||||
|             label: Some("main_pass_2d"), |             label: Some("main_pass_2d"), | ||||||
|             color_attachments: &[RenderPassColorAttachment { |             color_attachments: &[RenderPassColorAttachment { | ||||||
|                 view: &target.view, |                 view: &target.view, | ||||||
|                 resolve_target: None, |                 resolve_target: None, | ||||||
|                 ops: Operations { |                 ops: Operations { | ||||||
|                     load: LoadOp::Clear(clear_color.0.into()), |                     load: LoadOp::Load, | ||||||
|                     store: true, |                     store: true, | ||||||
|                 }, |                 }, | ||||||
|             }], |             }], | ||||||
|  | |||||||
| @ -1,4 +1,4 @@ | |||||||
| use crate::{AlphaMask3d, ClearColor, Opaque3d, Transparent3d}; | use crate::{AlphaMask3d, Opaque3d, Transparent3d}; | ||||||
| use bevy_ecs::prelude::*; | use bevy_ecs::prelude::*; | ||||||
| use bevy_render2::{ | use bevy_render2::{ | ||||||
|     render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, |     render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, | ||||||
| @ -51,24 +51,23 @@ impl Node for MainPass3dNode { | |||||||
|             .query |             .query | ||||||
|             .get_manual(world, view_entity) |             .get_manual(world, view_entity) | ||||||
|             .expect("view entity should exist"); |             .expect("view entity should exist"); | ||||||
|         let clear_color = world.get_resource::<ClearColor>().unwrap(); |  | ||||||
| 
 | 
 | ||||||
|         { |         { | ||||||
|             // Run the opaque pass, sorted front-to-back
 |             // Run the opaque pass, sorted front-to-back
 | ||||||
|             // NOTE: Scoped to drop the mutable borrow of render_context
 |             // NOTE: Scoped to drop the mutable borrow of render_context
 | ||||||
|             let pass_descriptor = RenderPassDescriptor { |             let pass_descriptor = RenderPassDescriptor { | ||||||
|                 label: Some("main_opaque_pass_3d"), |                 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.
 |                 // buffer as well as writing to it.
 | ||||||
|                 color_attachments: &[target.get_color_attachment(Operations { |                 color_attachments: &[target.get_color_attachment(Operations { | ||||||
|                     load: LoadOp::Clear(clear_color.0.into()), |                     load: LoadOp::Load, | ||||||
|                     store: true, |                     store: true, | ||||||
|                 })], |                 })], | ||||||
|                 depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { |                 depth_stencil_attachment: Some(RenderPassDepthStencilAttachment { | ||||||
|                     view: &depth.view, |                     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 { |                     depth_ops: Some(Operations { | ||||||
|                         load: LoadOp::Clear(0.0), |                         load: LoadOp::Load, | ||||||
|                         store: true, |                         store: true, | ||||||
|                     }), |                     }), | ||||||
|                     stencil_ops: None, |                     stencil_ops: None, | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Bude
						Bude