From e87b5739f063c8ab86dc770f033d73d0899c245f Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Thu, 29 Dec 2022 18:38:25 +0000 Subject: [PATCH] Separated volumetrics and transparents into independent passes to fix UB --- voxygen/src/menu/char_selection/mod.rs | 6 +-- voxygen/src/render/mod.rs | 6 +-- voxygen/src/render/pipelines/clouds.rs | 17 +------ voxygen/src/render/renderer/drawer.rs | 64 +++++++++++++++++++++----- voxygen/src/session/mod.rs | 22 ++++----- 5 files changed, 70 insertions(+), 45 deletions(-) diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 24ea77dfae..a024fa8f5c 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -284,9 +284,9 @@ impl PlayState for CharSelectionState { .render(&mut first_pass, client.get_tick(), humanoid_body, loadout); } - // Clouds - if let Some(mut second_pass) = drawer.second_pass() { - second_pass.draw_clouds(); + if let Some(mut volumetric_pass) = drawer.volumetric_pass() { + // Clouds + volumetric_pass.draw_clouds(); } // Bloom (does nothing if bloom is disabled) drawer.run_bloom_passes(); diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 69ef40c92a..650e4e7d31 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -50,9 +50,9 @@ pub use self::{ renderer::{ drawer::{ DebugDrawer, DebugShadowDrawer, Drawer, FigureDrawer, FigureShadowDrawer, - FirstPassDrawer, ParticleDrawer, PreparedUiDrawer, SecondPassDrawer, ShadowPassDrawer, - SpriteDrawer, TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, TrailDrawer, - UiDrawer, + FirstPassDrawer, ParticleDrawer, PreparedUiDrawer, ShadowPassDrawer, SpriteDrawer, + TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, TrailDrawer, + TransparentPassDrawer, UiDrawer, VolumetricPassDrawer, }, ColLightInfo, Renderer, }, diff --git a/voxygen/src/render/pipelines/clouds.rs b/voxygen/src/render/pipelines/clouds.rs index e64356ee56..801728c154 100644 --- a/voxygen/src/render/pipelines/clouds.rs +++ b/voxygen/src/render/pipelines/clouds.rs @@ -177,22 +177,7 @@ impl CloudsPipeline { polygon_mode: wgpu::PolygonMode::Fill, conservative: false, }, - depth_stencil: Some(wgpu::DepthStencilState { - 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, - }, - }), + depth_stencil: None, multisample: wgpu::MultisampleState { count: samples, mask: !0, diff --git a/voxygen/src/render/renderer/drawer.rs b/voxygen/src/render/renderer/drawer.rs index 64594dbc3b..b4f750a792 100644 --- a/voxygen/src/render/renderer/drawer.rs +++ b/voxygen/src/render/renderer/drawer.rs @@ -252,16 +252,16 @@ impl<'frame> Drawer<'frame> { }) } - /// Returns None if the clouds pipeline is not available - pub fn second_pass(&mut self) -> Option { + /// Returns None if the volumetrics pipeline is not available + pub fn volumetric_pass(&mut self) -> Option { 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("second_pass", device, &wgpu::RenderPassDescriptor { - label: Some("second pass (clouds)"), + encoder.scoped_render_pass("volumetric_pass", device, &wgpu::RenderPassDescriptor { + label: Some("volumetric pass (clouds)"), color_attachments: &[wgpu::RenderPassColorAttachment { view: &self.borrow.views.tgt_color_pp, resolve_target: None, @@ -270,9 +270,43 @@ impl<'frame> Drawer<'frame> { 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 { + 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 { view: &self.borrow.views.tgt_depth, - depth_ops: None, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Load, + store: false, + }), 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(1, &shadow.bind.bind_group, &[]); - Some(SecondPassDrawer { + Some(TransparentPassDrawer { render_pass, borrow: &self.borrow, - clouds_pipeline: &pipelines.clouds, 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] -pub struct SecondPassDrawer<'pass> { +pub struct VolumetricPassDrawer<'pass> { render_pass: OwningScope<'pass, wgpu::RenderPass<'pass>>, borrow: &'pass RendererBorrow<'pass>, clouds_pipeline: &'pass clouds::CloudsPipeline, - trail_pipeline: &'pass trail::TrailPipeline, } -impl<'pass> SecondPassDrawer<'pass> { +impl<'pass> VolumetricPassDrawer<'pass> { pub fn draw_clouds(&mut self) { self.render_pass .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, &[]); 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> { let shadow = &self.borrow.shadow?; diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index e93cc80a59..6105c1246c 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -1836,20 +1836,18 @@ impl PlayState for SessionState { &scene_data, ); - if let Some(mut second_pass) = drawer.second_pass() { + if let Some(mut volumetric_pass) = drawer.volumetric_pass() { // Clouds - { - prof_span!("clouds"); - second_pass.draw_clouds(); - } + prof_span!("clouds"); + volumetric_pass.draw_clouds(); + } + if let Some(mut transparent_pass) = drawer.transparent_pass() { // Trails - { - prof_span!("trails"); - if let Some(mut trail_drawer) = second_pass.draw_trails() { - self.scene - .trail_mgr() - .render(&mut trail_drawer, &scene_data); - } + prof_span!("trails"); + if let Some(mut trail_drawer) = transparent_pass.draw_trails() { + self.scene + .trail_mgr() + .render(&mut trail_drawer, &scene_data); } } // Bloom (call does nothing if bloom is off)