From b833bdab17a74d68c74862564d31fa986efd1ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kurt=20K=C3=BChnert?= Date: Mon, 2 Jan 2023 21:39:54 +0000 Subject: [PATCH] Allow to reuse the same RenderPass for multiple RenderPhases (#7043) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Objective - The recently merged PR #7013 does not allow multiple `RenderPhase`s to share the same `RenderPass`. - Due to the introduced overhead we want to minimize the number of `RenderPass`es recorded during each frame. ## Solution - Take a constructed `TrackedRenderPass` instead of a `RenderPassDiscriptor` as a parameter to the `RenderPhase::render` method. --- ## Changelog To enable multiple `RenderPhases` to share the same `TrackedRenderPass`, the `RenderPhase::render` signature has changed. ```rust pub fn render<'w>( &self, render_pass: &mut TrackedRenderPass<'w>, world: &'w World, view: Entity) ``` Co-authored-by: Kurt Kühnert <51823519+kurtkuehnert@users.noreply.github.com> --- .../src/core_2d/main_pass_2d_node.rs | 18 ++++--- .../src/core_3d/main_pass_3d_node.rs | 52 +++++++++++-------- crates/bevy_pbr/src/render/light.rs | 13 +++-- crates/bevy_render/src/render_phase/mod.rs | 22 ++------ crates/bevy_ui/src/render/render_pass.rs | 8 ++- 5 files changed, 59 insertions(+), 54 deletions(-) diff --git a/crates/bevy_core_pipeline/src/core_2d/main_pass_2d_node.rs b/crates/bevy_core_pipeline/src/core_2d/main_pass_2d_node.rs index 1ab2f1dda86ac..2a262b426195b 100644 --- a/crates/bevy_core_pipeline/src/core_2d/main_pass_2d_node.rs +++ b/crates/bevy_core_pipeline/src/core_2d/main_pass_2d_node.rs @@ -3,6 +3,7 @@ use crate::{ core_2d::{camera_2d::Camera2d, Transparent2d}, }; use bevy_ecs::prelude::*; +use bevy_render::render_phase::TrackedRenderPass; use bevy_render::{ camera::ExtractedCamera, render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, @@ -77,13 +78,16 @@ impl Node for MainPass2dNode { depth_stencil_attachment: None, }; - transparent_phase.render( - world, - render_context, - view_entity, - camera.viewport.as_ref(), - pass_descriptor, - ); + let render_pass = render_context + .command_encoder + .begin_render_pass(&pass_descriptor); + let mut render_pass = TrackedRenderPass::new(render_pass); + + if let Some(viewport) = camera.viewport.as_ref() { + render_pass.set_camera_viewport(viewport); + } + + transparent_phase.render(&mut render_pass, world, view_entity); } // WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't diff --git a/crates/bevy_core_pipeline/src/core_3d/main_pass_3d_node.rs b/crates/bevy_core_pipeline/src/core_3d/main_pass_3d_node.rs index 3ba8e3c0d4a68..1067643e03b12 100644 --- a/crates/bevy_core_pipeline/src/core_3d/main_pass_3d_node.rs +++ b/crates/bevy_core_pipeline/src/core_3d/main_pass_3d_node.rs @@ -3,6 +3,7 @@ use crate::{ core_3d::{AlphaMask3d, Camera3d, Opaque3d, Transparent3d}, }; use bevy_ecs::prelude::*; +use bevy_render::render_phase::TrackedRenderPass; use bevy_render::{ camera::ExtractedCamera, render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, @@ -95,13 +96,16 @@ impl Node for MainPass3dNode { }), }; - opaque_phase.render( - world, - render_context, - view_entity, - camera.viewport.as_ref(), - pass_descriptor, - ); + let render_pass = render_context + .command_encoder + .begin_render_pass(&pass_descriptor); + let mut render_pass = TrackedRenderPass::new(render_pass); + + if let Some(viewport) = camera.viewport.as_ref() { + render_pass.set_camera_viewport(viewport); + } + + opaque_phase.render(&mut render_pass, world, view_entity); } if !alpha_mask_phase.items.is_empty() { @@ -127,13 +131,16 @@ impl Node for MainPass3dNode { }), }; - alpha_mask_phase.render( - world, - render_context, - view_entity, - camera.viewport.as_ref(), - pass_descriptor, - ); + let render_pass = render_context + .command_encoder + .begin_render_pass(&pass_descriptor); + let mut render_pass = TrackedRenderPass::new(render_pass); + + if let Some(viewport) = camera.viewport.as_ref() { + render_pass.set_camera_viewport(viewport); + } + + alpha_mask_phase.render(&mut render_pass, world, view_entity); } if !transparent_phase.items.is_empty() { @@ -164,13 +171,16 @@ impl Node for MainPass3dNode { }), }; - transparent_phase.render( - world, - render_context, - view_entity, - camera.viewport.as_ref(), - pass_descriptor, - ); + let render_pass = render_context + .command_encoder + .begin_render_pass(&pass_descriptor); + let mut render_pass = TrackedRenderPass::new(render_pass); + + if let Some(viewport) = camera.viewport.as_ref() { + render_pass.set_camera_viewport(viewport); + } + + transparent_phase.render(&mut render_pass, world, view_entity); } // WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't diff --git a/crates/bevy_pbr/src/render/light.rs b/crates/bevy_pbr/src/render/light.rs index e9baee72281d3..9a821073b0d0d 100644 --- a/crates/bevy_pbr/src/render/light.rs +++ b/crates/bevy_pbr/src/render/light.rs @@ -1785,13 +1785,12 @@ impl Node for ShadowPassNode { }), }; - shadow_phase.render( - world, - render_context, - view_light_entity, - None, - pass_descriptor, - ); + let render_pass = render_context + .command_encoder + .begin_render_pass(&pass_descriptor); + let mut render_pass = TrackedRenderPass::new(render_pass); + + shadow_phase.render(&mut render_pass, world, view_light_entity); } } diff --git a/crates/bevy_render/src/render_phase/mod.rs b/crates/bevy_render/src/render_phase/mod.rs index c4f0ce1abb0c7..2aa684ece7867 100644 --- a/crates/bevy_render/src/render_phase/mod.rs +++ b/crates/bevy_render/src/render_phase/mod.rs @@ -4,10 +4,7 @@ mod draw_state; use bevy_ecs::entity::Entity; pub use draw::*; pub use draw_state::*; -use wgpu::RenderPassDescriptor; -use crate::camera::Viewport; -use crate::renderer::RenderContext; use bevy_ecs::prelude::{Component, Query}; use bevy_ecs::world::World; @@ -35,29 +32,18 @@ impl RenderPhase { I::sort(&mut self.items); } - pub fn render( + pub fn render<'w>( &self, - world: &World, - render_context: &mut RenderContext, + render_pass: &mut TrackedRenderPass<'w>, + world: &'w World, view: Entity, - viewport: Option<&Viewport>, - pass_descriptor: RenderPassDescriptor, ) { - let render_pass = render_context - .command_encoder - .begin_render_pass(&pass_descriptor); - let mut render_pass = TrackedRenderPass::new(render_pass); - - if let Some(viewport) = viewport { - render_pass.set_camera_viewport(viewport); - } - let draw_functions = world.resource::>(); let mut draw_functions = draw_functions.write(); for item in &self.items { let draw_function = draw_functions.get_mut(item.draw_function()).unwrap(); - draw_function.draw(world, &mut render_pass, view, item); + draw_function.draw(world, render_pass, view, item); } } } diff --git a/crates/bevy_ui/src/render/render_pass.rs b/crates/bevy_ui/src/render/render_pass.rs index eddb6c1809b49..70406c7240bdc 100644 --- a/crates/bevy_ui/src/render/render_pass.rs +++ b/crates/bevy_ui/src/render/render_pass.rs @@ -85,7 +85,13 @@ impl Node for UiPassNode { depth_stencil_attachment: None, }; - transparent_phase.render(world, render_context, view_entity, None, pass_descriptor); + let render_pass = render_context + .command_encoder + .begin_render_pass(&pass_descriptor); + let mut render_pass = TrackedRenderPass::new(render_pass); + + transparent_phase.render(&mut render_pass, world, view_entity); + Ok(()) } }