Skip to content

Commit

Permalink
Add MSAA to new renderer (#3042)
Browse files Browse the repository at this point in the history
Adds support for MSAA to the new renderer. This is done using the new [pipeline specialization](#3031) support to specialize on sample count. This is an alternative implementation to #2541 that cuts out the need for complicated render graph edge management by moving the relevant target information into View entities. This reuses @superdump's clever MSAA bitflag range code from #2541.

Note that wgpu currently only supports 1 or 4 samples due to those being the values supported by WebGPU. However they do plan on exposing ways to [enable/query for natively supported sample counts](gfx-rs/wgpu#1832). When this happens we should integrate
  • Loading branch information
cart committed Oct 29, 2021
1 parent 7d932ac commit c5af133
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 123 deletions.
58 changes: 13 additions & 45 deletions pipelined/bevy_core_pipeline/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use bevy_render2::{
render_resource::*,
renderer::RenderDevice,
texture::{Image, TextureCache},
view::ExtractedView,
view::{ExtractedView, Msaa, ViewDepthTexture},
RenderApp, RenderStage, RenderWorld,
};

Expand Down Expand Up @@ -53,7 +53,6 @@ pub mod draw_2d_graph {
pub const NAME: &str = "draw_2d";
pub mod input {
pub const VIEW_ENTITY: &str = "view_entity";
pub const RENDER_TARGET: &str = "render_target";
}
pub mod node {
pub const MAIN_PASS: &str = "main_pass";
Expand All @@ -64,8 +63,6 @@ pub mod draw_3d_graph {
pub const NAME: &str = "draw_3d";
pub mod input {
pub const VIEW_ENTITY: &str = "view_entity";
pub const RENDER_TARGET: &str = "render_target";
pub const DEPTH: &str = "depth";
}
pub mod node {
pub const MAIN_PASS: &str = "main_pass";
Expand Down Expand Up @@ -95,10 +92,10 @@ impl Plugin for CorePipelinePlugin {

let mut draw_2d_graph = RenderGraph::default();
draw_2d_graph.add_node(draw_2d_graph::node::MAIN_PASS, pass_node_2d);
let input_node_id = draw_2d_graph.set_input(vec![
SlotInfo::new(draw_2d_graph::input::VIEW_ENTITY, SlotType::Entity),
SlotInfo::new(draw_2d_graph::input::RENDER_TARGET, SlotType::TextureView),
]);
let input_node_id = draw_2d_graph.set_input(vec![SlotInfo::new(
draw_2d_graph::input::VIEW_ENTITY,
SlotType::Entity,
)]);
draw_2d_graph
.add_slot_edge(
input_node_id,
Expand All @@ -107,23 +104,14 @@ impl Plugin for CorePipelinePlugin {
MainPass2dNode::IN_VIEW,
)
.unwrap();
draw_2d_graph
.add_slot_edge(
input_node_id,
draw_2d_graph::input::RENDER_TARGET,
draw_2d_graph::node::MAIN_PASS,
MainPass2dNode::IN_COLOR_ATTACHMENT,
)
.unwrap();
graph.add_sub_graph(draw_2d_graph::NAME, draw_2d_graph);

let mut draw_3d_graph = RenderGraph::default();
draw_3d_graph.add_node(draw_3d_graph::node::MAIN_PASS, pass_node_3d);
let input_node_id = draw_3d_graph.set_input(vec![
SlotInfo::new(draw_3d_graph::input::VIEW_ENTITY, SlotType::Entity),
SlotInfo::new(draw_3d_graph::input::RENDER_TARGET, SlotType::TextureView),
SlotInfo::new(draw_3d_graph::input::DEPTH, SlotType::TextureView),
]);
let input_node_id = draw_3d_graph.set_input(vec![SlotInfo::new(
draw_3d_graph::input::VIEW_ENTITY,
SlotType::Entity,
)]);
draw_3d_graph
.add_slot_edge(
input_node_id,
Expand All @@ -132,22 +120,6 @@ impl Plugin for CorePipelinePlugin {
MainPass3dNode::IN_VIEW,
)
.unwrap();
draw_3d_graph
.add_slot_edge(
input_node_id,
draw_3d_graph::input::RENDER_TARGET,
draw_3d_graph::node::MAIN_PASS,
MainPass3dNode::IN_COLOR_ATTACHMENT,
)
.unwrap();
draw_3d_graph
.add_slot_edge(
input_node_id,
draw_3d_graph::input::DEPTH,
draw_3d_graph::node::MAIN_PASS,
MainPass3dNode::IN_DEPTH,
)
.unwrap();
graph.add_sub_graph(draw_3d_graph::NAME, draw_3d_graph);

graph.add_node(node::MAIN_PASS_DEPENDENCIES, EmptyNode);
Expand Down Expand Up @@ -235,11 +207,6 @@ impl RenderCommand<Transparent2d> for SetItemPipeline {
}
}

pub struct ViewDepthTexture {
pub texture: Texture,
pub view: TextureView,
}

pub fn extract_clear_color(clear_color: Res<ClearColor>, mut render_world: ResMut<RenderWorld>) {
// If the clear color has changed
if clear_color.is_changed() {
Expand Down Expand Up @@ -271,10 +238,11 @@ pub fn extract_core_pipeline_camera_phases(
pub fn prepare_core_views_system(
mut commands: Commands,
mut texture_cache: ResMut<TextureCache>,
msaa: Res<Msaa>,
render_device: Res<RenderDevice>,
views: Query<(Entity, &ExtractedView), With<RenderPhase<Transparent3d>>>,
views_3d: Query<(Entity, &ExtractedView), With<RenderPhase<Transparent3d>>>,
) {
for (entity, view) in views.iter() {
for (entity, view) in views_3d.iter() {
let cached_texture = texture_cache.get(
&render_device,
TextureDescriptor {
Expand All @@ -285,7 +253,7 @@ pub fn prepare_core_views_system(
height: view.height as u32,
},
mip_level_count: 1,
sample_count: 1,
sample_count: msaa.samples,
dimension: TextureDimension::D2,
format: TextureFormat::Depth32Float, /* PERF: vulkan docs recommend using 24
* bit depth for better performance */
Expand Down
25 changes: 10 additions & 15 deletions pipelined/bevy_core_pipeline/src/main_pass_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ use bevy_render2::{
render_phase::{DrawFunctions, RenderPhase, TrackedRenderPass},
render_resource::{LoadOp, Operations, RenderPassColorAttachment, RenderPassDescriptor},
renderer::RenderContext,
view::ExtractedView,
view::{ExtractedView, ViewTarget},
};

pub struct MainPass2dNode {
query: QueryState<&'static RenderPhase<Transparent2d>, With<ExtractedView>>,
query:
QueryState<(&'static RenderPhase<Transparent2d>, &'static ViewTarget), With<ExtractedView>>,
}

impl MainPass2dNode {
pub const IN_COLOR_ATTACHMENT: &'static str = "color_attachment";
pub const IN_VIEW: &'static str = "view";

pub fn new(world: &mut World) -> Self {
Expand All @@ -25,10 +25,7 @@ impl MainPass2dNode {

impl Node for MainPass2dNode {
fn input(&self) -> Vec<SlotInfo> {
vec![
SlotInfo::new(MainPass2dNode::IN_COLOR_ATTACHMENT, SlotType::TextureView),
SlotInfo::new(MainPass2dNode::IN_VIEW, SlotType::Entity),
]
vec![SlotInfo::new(MainPass2dNode::IN_VIEW, SlotType::Entity)]
}

fn update(&mut self, world: &mut World) {
Expand All @@ -41,12 +38,16 @@ impl Node for MainPass2dNode {
render_context: &mut RenderContext,
world: &World,
) -> Result<(), NodeRunError> {
let color_attachment_texture = graph.get_input_texture(Self::IN_COLOR_ATTACHMENT)?;
let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
let (transparent_phase, target) = self
.query
.get_manual(world, view_entity)
.expect("view entity should exist");
let clear_color = world.get_resource::<ClearColor>().unwrap();
let pass_descriptor = RenderPassDescriptor {
label: Some("main_pass_2d"),
color_attachments: &[RenderPassColorAttachment {
view: color_attachment_texture,
view: &target.view,
resolve_target: None,
ops: Operations {
load: LoadOp::Clear(clear_color.0.into()),
Expand All @@ -56,16 +57,10 @@ impl Node for MainPass2dNode {
depth_stencil_attachment: None,
};

let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
let draw_functions = world
.get_resource::<DrawFunctions<Transparent2d>>()
.unwrap();

let transparent_phase = self
.query
.get_manual(world, view_entity)
.expect("view entity should exist");

let render_pass = render_context
.command_encoder
.begin_render_pass(&pass_descriptor);
Expand Down
45 changes: 26 additions & 19 deletions pipelined/bevy_core_pipeline/src/main_pass_3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,21 @@ use bevy_render2::{
RenderPassDescriptor,
},
renderer::RenderContext,
view::ExtractedView,
view::{ExtractedView, ViewDepthTexture, ViewTarget},
};

pub struct MainPass3dNode {
query: QueryState<&'static RenderPhase<Transparent3d>, With<ExtractedView>>,
query: QueryState<
(
&'static RenderPhase<Transparent3d>,
&'static ViewTarget,
&'static ViewDepthTexture,
),
With<ExtractedView>,
>,
}

impl MainPass3dNode {
pub const IN_COLOR_ATTACHMENT: &'static str = "color_attachment";
pub const IN_DEPTH: &'static str = "depth";
pub const IN_VIEW: &'static str = "view";

pub fn new(world: &mut World) -> Self {
Expand All @@ -29,11 +34,7 @@ impl MainPass3dNode {

impl Node for MainPass3dNode {
fn input(&self) -> Vec<SlotInfo> {
vec![
SlotInfo::new(MainPass3dNode::IN_COLOR_ATTACHMENT, SlotType::TextureView),
SlotInfo::new(MainPass3dNode::IN_DEPTH, SlotType::TextureView),
SlotInfo::new(MainPass3dNode::IN_VIEW, SlotType::Entity),
]
vec![SlotInfo::new(MainPass3dNode::IN_VIEW, SlotType::Entity)]
}

fn update(&mut self, world: &mut World) {
Expand All @@ -46,21 +47,32 @@ impl Node for MainPass3dNode {
render_context: &mut RenderContext,
world: &World,
) -> Result<(), NodeRunError> {
let color_attachment_texture = graph.get_input_texture(Self::IN_COLOR_ATTACHMENT)?;
let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
let (transparent_phase, target, depth) = self
.query
.get_manual(world, view_entity)
.expect("view entity should exist");
let clear_color = world.get_resource::<ClearColor>().unwrap();
let depth_texture = graph.get_input_texture(Self::IN_DEPTH)?;
let pass_descriptor = RenderPassDescriptor {
label: Some("main_pass_3d"),
color_attachments: &[RenderPassColorAttachment {
view: color_attachment_texture,
resolve_target: None,
view: if let Some(sampled_target) = &target.sampled_target {
sampled_target
} else {
&target.view
},
resolve_target: if target.sampled_target.is_some() {
Some(&target.view)
} else {
None
},
ops: Operations {
load: LoadOp::Clear(clear_color.0.into()),
store: true,
},
}],
depth_stencil_attachment: Some(RenderPassDepthStencilAttachment {
view: depth_texture,
view: &depth.view,
depth_ops: Some(Operations {
load: LoadOp::Clear(0.0),
store: true,
Expand All @@ -69,14 +81,9 @@ impl Node for MainPass3dNode {
}),
};

let view_entity = graph.get_input_entity(Self::IN_VIEW)?;
let draw_functions = world
.get_resource::<DrawFunctions<Transparent3d>>()
.unwrap();
let transparent_phase = self
.query
.get_manual(world, view_entity)
.expect("view entity should exist");

let render_pass = render_context
.command_encoder
Expand Down
32 changes: 3 additions & 29 deletions pipelined/bevy_core_pipeline/src/main_pass_driver.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use crate::ViewDepthTexture;
use bevy_ecs::world::World;
use bevy_render2::{
camera::{CameraPlugin, ExtractedCamera, ExtractedCameraNames},
camera::{CameraPlugin, ExtractedCameraNames},
render_graph::{Node, NodeRunError, RenderGraphContext, SlotValue},
renderer::RenderContext,
view::ExtractedWindows,
};

pub struct MainPassDriverNode;
Expand All @@ -17,41 +15,17 @@ impl Node for MainPassDriverNode {
world: &World,
) -> Result<(), NodeRunError> {
let extracted_cameras = world.get_resource::<ExtractedCameraNames>().unwrap();
let extracted_windows = world.get_resource::<ExtractedWindows>().unwrap();

if let Some(camera_2d) = extracted_cameras.entities.get(CameraPlugin::CAMERA_2D) {
let extracted_camera = world.entity(*camera_2d).get::<ExtractedCamera>().unwrap();
let extracted_window = extracted_windows.get(&extracted_camera.window_id).unwrap();
let swap_chain_texture = extracted_window
.swap_chain_texture
.as_ref()
.unwrap()
.clone();
graph.run_sub_graph(
crate::draw_2d_graph::NAME,
vec![
SlotValue::Entity(*camera_2d),
SlotValue::TextureView(swap_chain_texture),
],
vec![SlotValue::Entity(*camera_2d)],
)?;
}

if let Some(camera_3d) = extracted_cameras.entities.get(CameraPlugin::CAMERA_3D) {
let extracted_camera = world.entity(*camera_3d).get::<ExtractedCamera>().unwrap();
let depth_texture = world.entity(*camera_3d).get::<ViewDepthTexture>().unwrap();
let extracted_window = extracted_windows.get(&extracted_camera.window_id).unwrap();
let swap_chain_texture = extracted_window
.swap_chain_texture
.as_ref()
.unwrap()
.clone();
graph.run_sub_graph(
crate::draw_3d_graph::NAME,
vec![
SlotValue::Entity(*camera_3d),
SlotValue::TextureView(swap_chain_texture),
SlotValue::TextureView(depth_texture.view.clone()),
],
vec![SlotValue::Entity(*camera_3d)],
)?;
}

Expand Down
Loading

0 comments on commit c5af133

Please sign in to comment.