Allow to reuse the same RenderPass for multiple RenderPhases (#7043)

# 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>
This commit is contained in:
Kurt Kühnert 2023-01-02 21:39:54 +00:00
parent a5b1c46d5b
commit b833bdab17
5 changed files with 59 additions and 54 deletions

View file

@ -3,6 +3,7 @@ use crate::{
core_2d::{camera_2d::Camera2d, Transparent2d}, core_2d::{camera_2d::Camera2d, Transparent2d},
}; };
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use bevy_render::render_phase::TrackedRenderPass;
use bevy_render::{ use bevy_render::{
camera::ExtractedCamera, camera::ExtractedCamera,
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
@ -77,13 +78,16 @@ impl Node for MainPass2dNode {
depth_stencil_attachment: None, depth_stencil_attachment: None,
}; };
transparent_phase.render( let render_pass = render_context
world, .command_encoder
render_context, .begin_render_pass(&pass_descriptor);
view_entity, let mut render_pass = TrackedRenderPass::new(render_pass);
camera.viewport.as_ref(),
pass_descriptor, 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 // WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't

View file

@ -3,6 +3,7 @@ use crate::{
core_3d::{AlphaMask3d, Camera3d, Opaque3d, Transparent3d}, core_3d::{AlphaMask3d, Camera3d, Opaque3d, Transparent3d},
}; };
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use bevy_render::render_phase::TrackedRenderPass;
use bevy_render::{ use bevy_render::{
camera::ExtractedCamera, camera::ExtractedCamera,
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType}, render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
@ -95,13 +96,16 @@ impl Node for MainPass3dNode {
}), }),
}; };
opaque_phase.render( let render_pass = render_context
world, .command_encoder
render_context, .begin_render_pass(&pass_descriptor);
view_entity, let mut render_pass = TrackedRenderPass::new(render_pass);
camera.viewport.as_ref(),
pass_descriptor, 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() { if !alpha_mask_phase.items.is_empty() {
@ -127,13 +131,16 @@ impl Node for MainPass3dNode {
}), }),
}; };
alpha_mask_phase.render( let render_pass = render_context
world, .command_encoder
render_context, .begin_render_pass(&pass_descriptor);
view_entity, let mut render_pass = TrackedRenderPass::new(render_pass);
camera.viewport.as_ref(),
pass_descriptor, 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() { if !transparent_phase.items.is_empty() {
@ -164,13 +171,16 @@ impl Node for MainPass3dNode {
}), }),
}; };
transparent_phase.render( let render_pass = render_context
world, .command_encoder
render_context, .begin_render_pass(&pass_descriptor);
view_entity, let mut render_pass = TrackedRenderPass::new(render_pass);
camera.viewport.as_ref(),
pass_descriptor, 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 // WebGL2 quirk: if ending with a render pass with a custom viewport, the viewport isn't

View file

@ -1785,13 +1785,12 @@ impl Node for ShadowPassNode {
}), }),
}; };
shadow_phase.render( let render_pass = render_context
world, .command_encoder
render_context, .begin_render_pass(&pass_descriptor);
view_light_entity, let mut render_pass = TrackedRenderPass::new(render_pass);
None,
pass_descriptor, shadow_phase.render(&mut render_pass, world, view_light_entity);
);
} }
} }

View file

@ -4,10 +4,7 @@ mod draw_state;
use bevy_ecs::entity::Entity; use bevy_ecs::entity::Entity;
pub use draw::*; pub use draw::*;
pub use draw_state::*; pub use draw_state::*;
use wgpu::RenderPassDescriptor;
use crate::camera::Viewport;
use crate::renderer::RenderContext;
use bevy_ecs::prelude::{Component, Query}; use bevy_ecs::prelude::{Component, Query};
use bevy_ecs::world::World; use bevy_ecs::world::World;
@ -35,29 +32,18 @@ impl<I: PhaseItem> RenderPhase<I> {
I::sort(&mut self.items); I::sort(&mut self.items);
} }
pub fn render( pub fn render<'w>(
&self, &self,
world: &World, render_pass: &mut TrackedRenderPass<'w>,
render_context: &mut RenderContext, world: &'w World,
view: Entity, 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::<DrawFunctions<I>>(); let draw_functions = world.resource::<DrawFunctions<I>>();
let mut draw_functions = draw_functions.write(); let mut draw_functions = draw_functions.write();
for item in &self.items { for item in &self.items {
let draw_function = draw_functions.get_mut(item.draw_function()).unwrap(); 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);
} }
} }
} }

View file

@ -85,7 +85,13 @@ impl Node for UiPassNode {
depth_stencil_attachment: None, 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(()) Ok(())
} }
} }