Separated volumetrics and transparents into independent passes to fix UB

This commit is contained in:
Joshua Barretto
2022-12-29 18:38:25 +00:00
parent 6070bd6538
commit e87b5739f0
5 changed files with 70 additions and 45 deletions

View File

@ -284,9 +284,9 @@ impl PlayState for CharSelectionState {
.render(&mut first_pass, client.get_tick(), humanoid_body, loadout); .render(&mut first_pass, client.get_tick(), humanoid_body, loadout);
} }
// Clouds if let Some(mut volumetric_pass) = drawer.volumetric_pass() {
if let Some(mut second_pass) = drawer.second_pass() { // Clouds
second_pass.draw_clouds(); volumetric_pass.draw_clouds();
} }
// Bloom (does nothing if bloom is disabled) // Bloom (does nothing if bloom is disabled)
drawer.run_bloom_passes(); drawer.run_bloom_passes();

View File

@ -50,9 +50,9 @@ pub use self::{
renderer::{ renderer::{
drawer::{ drawer::{
DebugDrawer, DebugShadowDrawer, Drawer, FigureDrawer, FigureShadowDrawer, DebugDrawer, DebugShadowDrawer, Drawer, FigureDrawer, FigureShadowDrawer,
FirstPassDrawer, ParticleDrawer, PreparedUiDrawer, SecondPassDrawer, ShadowPassDrawer, FirstPassDrawer, ParticleDrawer, PreparedUiDrawer, ShadowPassDrawer, SpriteDrawer,
SpriteDrawer, TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, TrailDrawer, TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, TrailDrawer,
UiDrawer, TransparentPassDrawer, UiDrawer, VolumetricPassDrawer,
}, },
ColLightInfo, Renderer, ColLightInfo, Renderer,
}, },

View File

@ -177,22 +177,7 @@ impl CloudsPipeline {
polygon_mode: wgpu::PolygonMode::Fill, polygon_mode: wgpu::PolygonMode::Fill,
conservative: false, conservative: false,
}, },
depth_stencil: Some(wgpu::DepthStencilState { depth_stencil: None,
format: wgpu::TextureFormat::Depth32Float,
depth_write_enabled: false,
depth_compare: wgpu::CompareFunction::Always,
stencil: wgpu::StencilState {
front: wgpu::StencilFaceState::IGNORE,
back: wgpu::StencilFaceState::IGNORE,
read_mask: !0,
write_mask: 0,
},
bias: wgpu::DepthBiasState {
constant: 0,
slope_scale: 0.0,
clamp: 0.0,
},
}),
multisample: wgpu::MultisampleState { multisample: wgpu::MultisampleState {
count: samples, count: samples,
mask: !0, mask: !0,

View File

@ -252,16 +252,16 @@ impl<'frame> Drawer<'frame> {
}) })
} }
/// Returns None if the clouds pipeline is not available /// Returns None if the volumetrics pipeline is not available
pub fn second_pass(&mut self) -> Option<SecondPassDrawer> { pub fn volumetric_pass(&mut self) -> Option<VolumetricPassDrawer> {
let pipelines = &self.borrow.pipelines.all()?; let pipelines = &self.borrow.pipelines.all()?;
let shadow = self.borrow.shadow?; let shadow = self.borrow.shadow?;
let encoder = self.encoder.as_mut().unwrap(); let encoder = self.encoder.as_mut().unwrap();
let device = self.borrow.device; let device = self.borrow.device;
let mut render_pass = let mut render_pass =
encoder.scoped_render_pass("second_pass", device, &wgpu::RenderPassDescriptor { encoder.scoped_render_pass("volumetric_pass", device, &wgpu::RenderPassDescriptor {
label: Some("second pass (clouds)"), label: Some("volumetric pass (clouds)"),
color_attachments: &[wgpu::RenderPassColorAttachment { color_attachments: &[wgpu::RenderPassColorAttachment {
view: &self.borrow.views.tgt_color_pp, view: &self.borrow.views.tgt_color_pp,
resolve_target: None, resolve_target: None,
@ -270,9 +270,43 @@ impl<'frame> Drawer<'frame> {
store: true, store: true,
}, },
}], }],
depth_stencil_attachment: None,
});
render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
Some(VolumetricPassDrawer {
render_pass,
borrow: &self.borrow,
clouds_pipeline: &pipelines.clouds,
})
}
/// Returns None if the trail pipeline is not available
pub fn transparent_pass(&mut self) -> Option<TransparentPassDrawer> {
let pipelines = &self.borrow.pipelines.all()?;
let shadow = self.borrow.shadow?;
let encoder = self.encoder.as_mut().unwrap();
let device = self.borrow.device;
let mut render_pass =
encoder.scoped_render_pass("transparent_pass", device, &wgpu::RenderPassDescriptor {
label: Some("transparent pass (trails)"),
color_attachments: &[wgpu::RenderPassColorAttachment {
view: &self.borrow.views.tgt_color_pp,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Load,
store: true,
},
}],
depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment {
view: &self.borrow.views.tgt_depth, view: &self.borrow.views.tgt_depth,
depth_ops: None, depth_ops: Some(wgpu::Operations {
load: wgpu::LoadOp::Load,
store: false,
}),
stencil_ops: None, stencil_ops: None,
}), }),
}); });
@ -280,10 +314,9 @@ impl<'frame> Drawer<'frame> {
render_pass.set_bind_group(0, &self.globals.bind_group, &[]); render_pass.set_bind_group(0, &self.globals.bind_group, &[]);
render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]); render_pass.set_bind_group(1, &shadow.bind.bind_group, &[]);
Some(SecondPassDrawer { Some(TransparentPassDrawer {
render_pass, render_pass,
borrow: &self.borrow, borrow: &self.borrow,
clouds_pipeline: &pipelines.clouds,
trail_pipeline: &pipelines.trail, trail_pipeline: &pipelines.trail,
}) })
} }
@ -1043,16 +1076,15 @@ impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> {
} }
} }
// Second pass: clouds // Second pass: volumetrics
#[must_use] #[must_use]
pub struct SecondPassDrawer<'pass> { pub struct VolumetricPassDrawer<'pass> {
render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>, render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
borrow: &'pass RendererBorrow<'pass>, borrow: &'pass RendererBorrow<'pass>,
clouds_pipeline: &'pass clouds::CloudsPipeline, clouds_pipeline: &'pass clouds::CloudsPipeline,
trail_pipeline: &'pass trail::TrailPipeline,
} }
impl<'pass> SecondPassDrawer<'pass> { impl<'pass> VolumetricPassDrawer<'pass> {
pub fn draw_clouds(&mut self) { pub fn draw_clouds(&mut self) {
self.render_pass self.render_pass
.set_pipeline(&self.clouds_pipeline.pipeline); .set_pipeline(&self.clouds_pipeline.pipeline);
@ -1060,7 +1092,17 @@ impl<'pass> SecondPassDrawer<'pass> {
.set_bind_group(2, &self.borrow.locals.clouds_bind.bind_group, &[]); .set_bind_group(2, &self.borrow.locals.clouds_bind.bind_group, &[]);
self.render_pass.draw(0..3, 0..1); self.render_pass.draw(0..3, 0..1);
} }
}
// Third pass: transparents
#[must_use]
pub struct TransparentPassDrawer<'pass> {
render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>,
borrow: &'pass RendererBorrow<'pass>,
trail_pipeline: &'pass trail::TrailPipeline,
}
impl<'pass> TransparentPassDrawer<'pass> {
pub fn draw_trails(&mut self) -> Option<TrailDrawer<'_, 'pass>> { pub fn draw_trails(&mut self) -> Option<TrailDrawer<'_, 'pass>> {
let shadow = &self.borrow.shadow?; let shadow = &self.borrow.shadow?;

View File

@ -1836,20 +1836,18 @@ impl PlayState for SessionState {
&scene_data, &scene_data,
); );
if let Some(mut second_pass) = drawer.second_pass() { if let Some(mut volumetric_pass) = drawer.volumetric_pass() {
// Clouds // Clouds
{ prof_span!("clouds");
prof_span!("clouds"); volumetric_pass.draw_clouds();
second_pass.draw_clouds(); }
} if let Some(mut transparent_pass) = drawer.transparent_pass() {
// Trails // Trails
{ prof_span!("trails");
prof_span!("trails"); if let Some(mut trail_drawer) = transparent_pass.draw_trails() {
if let Some(mut trail_drawer) = second_pass.draw_trails() { self.scene
self.scene .trail_mgr()
.trail_mgr() .render(&mut trail_drawer, &scene_data);
.render(&mut trail_drawer, &scene_data);
}
} }
} }
// Bloom (call does nothing if bloom is off) // Bloom (call does nothing if bloom is off)