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},
};
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

View file

@ -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

View file

@ -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);
}
}

View file

@ -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<I: PhaseItem> RenderPhase<I> {
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::<DrawFunctions<I>>();
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);
}
}
}

View file

@ -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(())
}
}