Skip to content

Commit

Permalink
added TrackedRenderPass::create_for_camera method
Browse files Browse the repository at this point in the history
  • Loading branch information
kurtkuehnert committed Jan 3, 2023
1 parent 9a24eee commit 26234c8
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 143 deletions.
67 changes: 31 additions & 36 deletions crates/bevy_core_pipeline/src/core_2d/main_pass_2d_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use bevy_render::{
camera::ExtractedCamera,
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
render_phase::RenderPhase,
render_resource::{LoadOp, Operations, RenderPassDescriptor},
render_resource::{LoadOp, Operations},
renderer::RenderContext,
view::{ExtractedView, ViewTarget},
};
Expand Down Expand Up @@ -61,31 +61,27 @@ impl Node for MainPass2dNode {
return Ok(());
};
{
#[cfg(feature = "trace")]
let _main_pass_2d = info_span!("main_pass_2d").entered();
let pass_descriptor = RenderPassDescriptor {
label: Some("main_pass_2d"),
color_attachments: &[Some(target.get_color_attachment(Operations {
load: match camera_2d.clear_color {
ClearColorConfig::Default => {
LoadOp::Clear(world.resource::<ClearColor>().0.into())
}
ClearColorConfig::Custom(color) => LoadOp::Clear(color.into()),
ClearColorConfig::None => LoadOp::Load,
},
store: true,
}))],
depth_stencil_attachment: None,
let color_ops = Operations {
load: match camera_2d.clear_color {
ClearColorConfig::Default => {
LoadOp::Clear(world.resource::<ClearColor>().0.into())
}
ClearColorConfig::Custom(color) => LoadOp::Clear(color.into()),
ClearColorConfig::None => LoadOp::Load,
},
store: true,
};

let render_pass = render_context
.command_encoder
.begin_render_pass(&pass_descriptor);
let mut render_pass = TrackedRenderPass::new(render_pass, view_entity);

if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(viewport);
}
let mut render_pass = TrackedRenderPass::create_for_camera(
render_context,
"main_pass_2d",
view_entity,
target,
color_ops,
None,
None,
&camera.viewport,
);

render_pass.render_phase(transparent_phase, world);
}
Expand All @@ -94,20 +90,19 @@ impl Node for MainPass2dNode {
// reset for the next render pass so add an empty render pass without a custom viewport
#[cfg(feature = "webgl")]
if camera.viewport.is_some() {
#[cfg(feature = "trace")]
let _reset_viewport_pass_2d = info_span!("reset_viewport_pass_2d").entered();
let pass_descriptor = RenderPassDescriptor {
label: Some("reset_viewport_pass_2d"),
color_attachments: &[Some(target.get_color_attachment(Operations {
let _render_pass = TrackedRenderPass::create_for_camera(
render_context,
"reset_viewport_pass_2d",
view_entity,
target,
Operations {
load: LoadOp::Load,
store: true,
}))],
depth_stencil_attachment: None,
};

render_context
.command_encoder
.begin_render_pass(&pass_descriptor);
},
None,
None,
&None,
);
}

Ok(())
Expand Down
182 changes: 76 additions & 106 deletions crates/bevy_core_pipeline/src/core_3d/main_pass_3d_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use bevy_render::{
camera::ExtractedCamera,
render_graph::{Node, NodeRunError, RenderGraphContext, SlotInfo, SlotType},
render_phase::RenderPhase,
render_resource::{LoadOp, Operations, RenderPassDepthStencilAttachment, RenderPassDescriptor},
render_resource::{LoadOp, Operations},
renderer::RenderContext,
view::{ExtractedView, ViewDepthTexture, ViewTarget},
};
Expand Down Expand Up @@ -67,118 +67,89 @@ impl Node for MainPass3dNode {
// Always run opaque pass to ensure screen is cleared
{
// Run the opaque pass, sorted front-to-back
// NOTE: Scoped to drop the mutable borrow of render_context
#[cfg(feature = "trace")]
let _main_opaque_pass_3d_span = info_span!("main_opaque_pass_3d").entered();
let pass_descriptor = RenderPassDescriptor {
label: Some("main_opaque_pass_3d"),
// NOTE: The opaque pass loads the color
// buffer as well as writing to it.
color_attachments: &[Some(target.get_color_attachment(Operations {
load: match camera_3d.clear_color {
ClearColorConfig::Default => {
LoadOp::Clear(world.resource::<ClearColor>().0.into())
}
ClearColorConfig::Custom(color) => LoadOp::Clear(color.into()),
ClearColorConfig::None => LoadOp::Load,
},
store: true,
}))],
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
view: &depth.view,
// NOTE: The opaque main pass loads the depth buffer and possibly overwrites it
depth_ops: Some(Operations {
// NOTE: 0.0 is the far plane due to bevy's use of reverse-z projections.
load: camera_3d.depth_load_op.clone().into(),
store: true,
}),
stencil_ops: None,
}),
};

let render_pass = render_context
.command_encoder
.begin_render_pass(&pass_descriptor);
let mut render_pass = TrackedRenderPass::new(render_pass, view_entity);
// NOTE: The opaque pass loads the color buffer as well as writing to it.
let color_ops = Operations {
load: match camera_3d.clear_color {
ClearColorConfig::Default => {
LoadOp::Clear(world.resource::<ClearColor>().0.into())
}
ClearColorConfig::Custom(color) => LoadOp::Clear(color.into()),
ClearColorConfig::None => LoadOp::Load,
},
store: true,
};

if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(viewport);
}
let depth_ops = Some(Operations {
// NOTE: 0.0 is the far plane due to bevy's use of reverse-z projections.
load: camera_3d.depth_load_op.clone().into(),
store: true,
});

let mut render_pass = TrackedRenderPass::create_for_camera(
render_context,
"main_opaque_pass_3d",
view_entity,
target,
color_ops,
Some(depth),
depth_ops,
&camera.viewport,
);

render_pass.render_phase(opaque_phase, world);
}

if !alpha_mask_phase.items.is_empty() {
// Run the alpha mask pass, sorted front-to-back
// NOTE: Scoped to drop the mutable borrow of render_context
#[cfg(feature = "trace")]
let _main_alpha_mask_pass_3d_span = info_span!("main_alpha_mask_pass_3d").entered();
let pass_descriptor = RenderPassDescriptor {
label: Some("main_alpha_mask_pass_3d"),
// NOTE: The alpha_mask pass loads the color buffer as well as overwriting it where appropriate.
color_attachments: &[Some(target.get_color_attachment(Operations {

let mut render_pass = TrackedRenderPass::create_for_camera(
render_context,
"main_alpha_mask_pass_3d",
view_entity,
target,
Operations {
load: LoadOp::Load,
store: true,
},
Some(depth),
Some(Operations {
load: LoadOp::Load,
store: true,
}))],
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
view: &depth.view,
// NOTE: The alpha mask pass loads the depth buffer and possibly overwrites it
depth_ops: Some(Operations {
load: LoadOp::Load,
store: true,
}),
stencil_ops: None,
}),
};

let render_pass = render_context
.command_encoder
.begin_render_pass(&pass_descriptor);
let mut render_pass = TrackedRenderPass::new(render_pass, view_entity);

if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(viewport);
}
&camera.viewport,
);

render_pass.render_phase(alpha_mask_phase, world);
}

if !transparent_phase.items.is_empty() {
// Run the transparent pass, sorted back-to-front
// NOTE: Scoped to drop the mutable borrow of render_context
#[cfg(feature = "trace")]
let _main_transparent_pass_3d_span = info_span!("main_transparent_pass_3d").entered();
let pass_descriptor = RenderPassDescriptor {
label: Some("main_transparent_pass_3d"),
// NOTE: The transparent pass loads the color buffer as well as overwriting it where appropriate.
color_attachments: &[Some(target.get_color_attachment(Operations {

// NOTE: For the transparent pass we load the depth buffer. There should be no
// need to write to it, but store is set to `true` as a workaround for issue #3776,
// https://github.com/bevyengine/bevy/issues/3776
// so that wgpu does not clear the depth buffer.
// As the opaque and alpha mask passes run first, opaque meshes can occlude
// transparent ones.
let depth_ops = Some(Operations {
load: LoadOp::Load,
store: true,
});

let mut render_pass = TrackedRenderPass::create_for_camera(
render_context,
"main_transparent_pass_3d",
view_entity,
target,
Operations {
load: LoadOp::Load,
store: true,
}))],
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
view: &depth.view,
// NOTE: For the transparent pass we load the depth buffer. There should be no
// need to write to it, but store is set to `true` as a workaround for issue #3776,
// https://github.com/bevyengine/bevy/issues/3776
// so that wgpu does not clear the depth buffer.
// As the opaque and alpha mask passes run first, opaque meshes can occlude
// transparent ones.
depth_ops: Some(Operations {
load: LoadOp::Load,
store: true,
}),
stencil_ops: None,
}),
};

let render_pass = render_context
.command_encoder
.begin_render_pass(&pass_descriptor);
let mut render_pass = TrackedRenderPass::new(render_pass, view_entity);

if let Some(viewport) = camera.viewport.as_ref() {
render_pass.set_camera_viewport(viewport);
}
},
Some(depth),
depth_ops,
&camera.viewport,
);

render_pass.render_phase(transparent_phase, world);
}
Expand All @@ -187,20 +158,19 @@ impl Node for MainPass3dNode {
// reset for the next render pass so add an empty render pass without a custom viewport
#[cfg(feature = "webgl")]
if camera.viewport.is_some() {
#[cfg(feature = "trace")]
let _reset_viewport_pass_3d = info_span!("reset_viewport_pass_3d").entered();
let pass_descriptor = RenderPassDescriptor {
label: Some("reset_viewport_pass_3d"),
color_attachments: &[Some(target.get_color_attachment(Operations {
let _render_pass = TrackedRenderPass::create_for_camera(
render_context,
"reset_viewport_pass_3d",
view_entity,
target,
Operations {
load: LoadOp::Load,
store: true,
}))],
depth_stencil_attachment: None,
};

render_context
.command_encoder
.begin_render_pass(&pass_descriptor);
},
None,
None,
&None,
);
}

Ok(())
Expand Down
56 changes: 55 additions & 1 deletion crates/bevy_render/src/render_phase/draw_state.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::renderer::RenderContext;
use crate::view::{ViewDepthTexture, ViewTarget};
use crate::{
camera::Viewport,
prelude::Color,
Expand All @@ -8,9 +10,13 @@ use crate::{
},
};
use bevy_ecs::prelude::{Entity, World};
#[cfg(feature = "trace")]
use bevy_utils::tracing::info_span;
use bevy_utils::tracing::trace;
use std::ops::Range;
use wgpu::{IndexFormat, RenderPass};
use wgpu::{
IndexFormat, Operations, RenderPass, RenderPassDepthStencilAttachment, RenderPassDescriptor,
};

/// Tracks the current [`TrackedRenderPass`] state to ensure draw calls are valid.
#[derive(Debug, Default)]
Expand Down Expand Up @@ -109,6 +115,54 @@ impl<'a> TrackedRenderPass<'a> {
}
}

pub fn create_for_camera(
render_context: &'a mut RenderContext,
label: &'static str,
view_entity: Entity,
view_target: &'a ViewTarget,
color_ops: Operations<wgpu::Color>,
view_depth: Option<&'a ViewDepthTexture>,
depth_ops: Option<Operations<f32>>,
viewport: &Option<Viewport>,
) -> Self {
#[cfg(feature = "trace")]
let _pass_span = info_span!(label).entered();

// Todo: makes this configurable
let stencil_ops = None;

let color_attachments = &[Some(view_target.get_color_attachment(color_ops))];

let depth_stencil_attachment = match view_depth {
None => None,
Some(view_depth) => Some(RenderPassDepthStencilAttachment {
view: &view_depth.view,
depth_ops,
stencil_ops,
}),
};

let pass_descriptor = RenderPassDescriptor {
label: Some(label),
color_attachments,
depth_stencil_attachment,
};

let mut pass = Self {
state: DrawState::default(),
pass: render_context
.command_encoder
.begin_render_pass(&pass_descriptor),
view_entity,
};

if let Some(viewport) = viewport.as_ref() {
pass.set_camera_viewport(viewport);
}

pass
}

pub fn render_phase<I: PhaseItem>(&mut self, render_phase: &RenderPhase<I>, world: &'a World) {
let draw_functions = world.resource::<DrawFunctions<I>>();
let mut draw_functions = draw_functions.write();
Expand Down

0 comments on commit 26234c8

Please sign in to comment.