From 41d1a56dac06a7d6e25f13faedaa79f742d2e872 Mon Sep 17 00:00:00 2001 From: Paris DOUADY Date: Thu, 8 Feb 2024 23:45:17 +0100 Subject: [PATCH] parallelize command encoding --- engine/src/drawables/mod.rs | 20 +- engine/src/framework.rs | 27 +- engine/src/gfx.rs | 390 +++++++++++------- engine/src/passes/background.rs | 14 +- engine/src/passes/blur.rs | 43 +- engine/src/passes/fog.rs | 11 +- engine/src/passes/ssao.rs | 10 +- engine/src/shader.rs | 6 +- engine/src/texture.rs | 77 ++-- .../src/rendering/map_rendering/map_mesh.rs | 18 +- 10 files changed, 335 insertions(+), 281 deletions(-) diff --git a/engine/src/drawables/mod.rs b/engine/src/drawables/mod.rs index e2e7226e..06d5451c 100644 --- a/engine/src/drawables/mod.rs +++ b/engine/src/drawables/mod.rs @@ -1,5 +1,4 @@ use crate::GfxContext; -use std::rc::Rc; use wgpu::RenderPass; mod instanced_mesh; @@ -20,7 +19,7 @@ use std::sync::Arc; pub type IndexType = u32; -pub trait Drawable { +pub trait Drawable: Send + Sync { fn draw<'a>(&'a self, gfx: &'a GfxContext, rp: &mut RenderPass<'a>); #[allow(unused)] @@ -50,23 +49,6 @@ impl Drawable for Arc { } } -impl Drawable for Rc { - fn draw<'a>(&'a self, gfx: &'a GfxContext, rp: &mut RenderPass<'a>) { - let s: &T = self; - s.draw(gfx, rp); - } - - fn draw_depth<'a>( - &'a self, - gfx: &'a GfxContext, - rp: &mut RenderPass<'a>, - shadow_cascade: Option<&Matrix4>, - ) { - let s: &T = self; - s.draw_depth(gfx, rp, shadow_cascade); - } -} - impl Drawable for Option { fn draw<'a>(&'a self, gfx: &'a GfxContext, rp: &mut RenderPass<'a>) { if let Some(s) = self { diff --git a/engine/src/framework.rs b/engine/src/framework.rs index 436a8b99..0070f758 100644 --- a/engine/src/framework.rs +++ b/engine/src/framework.rs @@ -1,3 +1,4 @@ +use rayon::ThreadPoolBuilder; use std::sync::Arc; use std::time::Instant; @@ -123,23 +124,18 @@ async fn run(el: EventLoop<()>, window: Arc) { state.update(&mut ctx); let (mut enc, view) = ctx.gfx.start_frame(&sco); - ctx.engine_time = ctx + (ctx.engine_time, ctx.gui_time) = ctx .gfx - .render_objs(&mut enc, &view, |fc| state.render(fc)) - .as_secs_f32(); - - let gui_start = Instant::now(); - #[allow(unused_mut)] - ctx.gfx.render_gui(&mut enc, &view, |mut gctx| { - #[cfg(feature = "yakui")] - ctx.yakui.render(&mut gctx, || { - state.render_yakui(); - }); - ctx.egui.render(gctx, |ui| { - state.render_gui(ui); + .render(&mut enc, &view, &mut state, |state, mut gctx| { + #[cfg(feature = "yakui")] + ctx.yakui.render(&mut gctx, || { + state.render_yakui(); + }); + ctx.egui.render(gctx, |ui| { + state.render_gui(ui); + }); }); - }); - ctx.gui_time = gui_start.elapsed().as_secs_f32(); + ctx.gfx.finish_frame(enc); ctx.gfx.window.set_cursor_icon(get_cursor_icon()); ctx.input.end_frame(); @@ -170,6 +166,7 @@ pub fn init() { } pub fn start() { + let _ = ThreadPoolBuilder::new().num_threads(8).build_global(); let el = EventLoop::new().expect("Failed to create event loop"); #[cfg(target_arch = "wasm32")] diff --git a/engine/src/gfx.rs b/engine/src/gfx.rs index cf967221..175141bd 100644 --- a/engine/src/gfx.rs +++ b/engine/src/gfx.rs @@ -1,18 +1,9 @@ -use crate::passes::{BackgroundPipeline, Pbr}; -use crate::perf_counters::PerfCounters; -use crate::{ - bg_layout_litmesh, passes, CompiledModule, Drawable, IndexType, LampLights, Material, - MaterialID, MaterialMap, MetallicRoughness, MipmapGenerator, PipelineBuilder, Pipelines, - Texture, TextureBuildError, TextureBuilder, Uniform, UvVertex, WaterPipeline, TL, -}; -use common::FastMap; -use geom::{vec2, Camera, InfiniteFrustrum, LinearColor, Matrix4, Plane, Vec2, Vec3}; -use serde::{Deserialize, Serialize}; -use std::cell::RefCell; use std::collections::HashMap; use std::path::PathBuf; -use std::sync::{Arc, Mutex}; -use std::time::{Duration, Instant}; +use std::sync::{Arc, Mutex, RwLock}; +use std::time::Instant; + +use serde::{Deserialize, Serialize}; use wgpu::util::{backend_bits_from_env, BufferInitDescriptor, DeviceExt}; use wgpu::{ Adapter, Backends, BindGroupLayout, BlendState, CommandBuffer, CommandEncoder, @@ -25,6 +16,18 @@ use wgpu::{ }; use winit::window::{Fullscreen, Window}; +use common::FastMap; +use geom::{vec2, Camera, InfiniteFrustrum, LinearColor, Matrix4, Plane, Vec2, Vec3}; + +use crate::framework::State; +use crate::passes::{BackgroundPipeline, Pbr}; +use crate::perf_counters::PerfCounters; +use crate::{ + bg_layout_litmesh, passes, CompiledModule, Drawable, IndexType, LampLights, Material, + MaterialID, MaterialMap, MetallicRoughness, MipmapGenerator, PipelineBuilder, Pipelines, + Texture, TextureBuildError, TextureBuilder, Uniform, UvVertex, WaterPipeline, TL, +}; + pub struct FBOs { pub(crate) depth: Texture, pub(crate) depth_bg: wgpu::BindGroup, @@ -51,7 +54,7 @@ pub struct GfxContext { pub(crate) default_material: Material, pub tess_material: MaterialID, pub tick: u64, - pub(crate) pipelines: RefCell, + pub(crate) pipelines: RwLock, pub frustrum: InfiniteFrustrum, pub(crate) sun_params: [Uniform; N_CASCADES], pub render_params: Uniform, @@ -157,9 +160,12 @@ impl Default for GfxSettings { pub struct Encoders { pub pbr: Option, - pub smap: Option, + pub smap: Vec, pub depth_prepass: Option, - pub end: CommandEncoder, + pub main: Option, + pub before_main: CommandEncoder, + pub after_main: CommandEncoder, + pub gui: Option, } pub const N_CASCADES: usize = 4; @@ -225,7 +231,7 @@ impl Default for RenderParams { u8slice_impl!(RenderParams); pub struct GuiRenderContext<'a> { - pub gfx: &'a mut GfxContext, + pub gfx: &'a GfxContext, pub encoder: &'a mut CommandEncoder, pub view: &'a TextureView, pub size: (u32, u32, f64), @@ -392,7 +398,7 @@ impl GfxContext { adapter, fbos, surface, - pipelines: RefCell::new(Pipelines::new()), + pipelines: RwLock::new(Pipelines::new()), materials, tess_material: tess_material_id, default_material: Material::new_default(&device, &queue, &null_texture), @@ -599,10 +605,15 @@ impl GfxContext { } pub fn start_frame(&mut self, sco: &SurfaceTexture) -> (Encoders, TextureView) { - let mut end = self + let mut before_main = self + .device + .create_command_encoder(&CommandEncoderDescriptor { + label: Some("Before main encoder"), + }); + let after_main = self .device .create_command_encoder(&CommandEncoderDescriptor { - label: Some("End encoder"), + label: Some("After main encoder"), }); for (uni, mat) in self @@ -618,21 +629,24 @@ impl GfxContext { self.render_params.upload_to_gpu(&self.queue); self.lamplights - .apply_changes(&self.queue, &self.device, &mut end); + .apply_changes(&self.queue, &self.device, &mut before_main); ( Encoders { pbr: None, - smap: None, + smap: Default::default(), depth_prepass: None, - end, + main: None, + before_main, + after_main, + gui: None, }, sco.texture.create_view(&TextureViewDescriptor::default()), ) } pub fn get_module(&self, name: &str) -> CompiledModule { - let p = &mut *self.pipelines.try_borrow_mut().unwrap(); + let p = &mut *self.pipelines.write().unwrap(); Pipelines::get_module( &mut p.shader_cache, @@ -643,12 +657,13 @@ impl GfxContext { ) } - pub fn render_objs( + pub fn render( &mut self, encs: &mut Encoders, frame: &TextureView, - mut prepare: impl FnMut(&mut FrameContext<'_>), - ) -> Duration { + state: &mut S, + render_gui: impl FnOnce(&mut S, GuiRenderContext<'_>), + ) -> (f32, f32) { profiling::scope!("gfx::render_objs"); self.perf.clear(); @@ -658,156 +673,208 @@ impl GfxContext { gfx: self, }; - prepare(&mut fc); + state.render(&mut fc); let start_time = Instant::now(); let objsref = &*objs; - let enc_dep_ext = &mut encs.depth_prepass; - let enc_smap_ext = &mut encs.smap; - - if self.defines.contains_key("PBR_ENABLED") { - profiling::scope!("pbr prepass"); - let mut pbr_enc = self - .device - .create_command_encoder(&CommandEncoderDescriptor { - label: Some("init encoder"), - }); - self.pbr.update(self, &mut pbr_enc); - encs.pbr = Some(pbr_enc.finish()); - } - { - profiling::scope!("depth prepass"); - let mut prepass = self - .device - .create_command_encoder(&CommandEncoderDescriptor { - label: Some("depth prepass encoder"), - }); - let mut depth_prepass = prepass.begin_render_pass(&RenderPassDescriptor { - label: Some("depth prepass"), - color_attachments: &[], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.fbos.depth.view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(0.0), - store: wgpu::StoreOp::Store, - }), - stencil_ops: None, - }), - timestamp_writes: None, - occlusion_query_set: None, + + let mut gui_elapsed = 0.0; + rayon::in_place_scope(|scope| { + scope.spawn(|_| { + encs.pbr = self.pbr_prepass(); + }); + scope.spawn(|_| { + encs.depth_prepass = Some(self.depth_prepass(objsref)); }); + scope.spawn(|_| { + passes::render_ssao(self, &mut encs.before_main); + passes::render_fog(self, &mut encs.before_main); - depth_prepass.set_bind_group(0, &self.render_params.bindgroup, &[]); + passes::render_background(self, &mut encs.after_main, frame); + passes::gen_ui_blur(self, &mut encs.after_main, frame); + }); + scope.spawn(|_| { + encs.smap = self.shadow_map_pass(objsref); + }); - for obj in objsref.iter() { - obj.draw_depth(self, &mut depth_prepass, None); - } - drop(depth_prepass); - *enc_dep_ext = Some(prepass.finish()); - } - if self.render_params.value().shadow_mapping_resolution != 0 { - profiling::scope!("shadow pass"); - let mut smap_enc = self - .device - .create_command_encoder(&CommandEncoderDescriptor { - label: Some("shadow map encoder"), - }); - for (i, u) in self.sun_params.iter().enumerate() { - let sun_view = self - .sun_shadowmap - .texture - .create_view(&TextureViewDescriptor { - label: Some("sun shadow view"), - format: Some(self.sun_shadowmap.format), - dimension: Some(TextureViewDimension::D2), - aspect: TextureAspect::DepthOnly, - base_mip_level: 0, - mip_level_count: None, - base_array_layer: i as u32, - array_layer_count: Some(1), + scope.spawn(|_| { + encs.main = Some(self.main_render_pass(&frame, objsref)); + }); + + { + profiling::scope!("gfx::render_gui"); + let gui_start = Instant::now(); + let mut gui_enc = self + .device + .create_command_encoder(&CommandEncoderDescriptor { + label: Some("GUI encoder"), }); - let mut sun_shadow_pass = smap_enc.begin_render_pass(&RenderPassDescriptor { - label: Some("sun shadow pass"), - color_attachments: &[], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &sun_view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: wgpu::StoreOp::Store, - }), - stencil_ops: None, - }), - timestamp_writes: None, - occlusion_query_set: None, - }); + render_gui( + state, + GuiRenderContext { + size: self.size, + gfx: self, + encoder: &mut gui_enc, + view: frame, + }, + ); + encs.gui = Some(gui_enc.finish()); + gui_elapsed = gui_start.elapsed().as_secs_f32(); + } + }); - sun_shadow_pass.set_bind_group(0, &u.bindgroup, &[]); + (start_time.elapsed().as_secs_f32(), gui_elapsed) + } - for obj in objsref.iter() { - obj.draw_depth(self, &mut sun_shadow_pass, Some(&u.value().proj)); - } - } - *enc_smap_ext = Some(smap_enc.finish()); - } + fn main_render_pass( + &self, + frame: &TextureView, + objsref: &[Box], + ) -> CommandBuffer { + profiling::scope!("main render pass"); + let mut main_enc = self + .device + .create_command_encoder(&CommandEncoderDescriptor { + label: Some("shadow map encoder"), + }); - if self.defines.contains_key("SSAO") { - passes::render_ssao(self, &mut encs.end); + let mut render_pass = main_enc.begin_render_pass(&RenderPassDescriptor { + label: Some("main render pass"), + color_attachments: &[Some(RenderPassColorAttachment { + view: &self.fbos.color_msaa, + resolve_target: Some(frame), + ops: wgpu::Operations { + load: wgpu::LoadOp::Clear(wgpu::Color { + r: 0.0, + g: 0.0, + b: 0.0, + a: 0.0, + }), + store: wgpu::StoreOp::Store, + }, + })], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.fbos.depth.view, + depth_ops: None, + stencil_ops: None, + }), + timestamp_writes: None, + occlusion_query_set: None, + }); + render_pass.set_bind_group(0, &self.render_params.bindgroup, &[]); + + for obj in objsref.iter() { + obj.draw(self, &mut render_pass); } - passes::render_fog(self, &mut encs.end); + drop(render_pass); - { - profiling::scope!("main render pass"); - let mut render_pass = encs.end.begin_render_pass(&RenderPassDescriptor { - label: Some("main render pass"), - color_attachments: &[Some(RenderPassColorAttachment { - view: &self.fbos.color_msaa, - resolve_target: Some(frame), - ops: wgpu::Operations { - load: wgpu::LoadOp::Clear(wgpu::Color { - r: 0.0, - g: 0.0, - b: 0.0, - a: 0.0, - }), - store: wgpu::StoreOp::Store, - }, - })], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &self.fbos.depth.view, - depth_ops: None, - stencil_ops: None, - }), - timestamp_writes: None, - occlusion_query_set: None, - }); - render_pass.set_bind_group(0, &self.render_params.bindgroup, &[]); + main_enc.finish() + } - for obj in objsref.iter() { - obj.draw(self, &mut render_pass); - } + fn pbr_prepass(&self) -> Option { + if !self.defines.contains_key("PBR_ENABLED") { + return None; } + profiling::scope!("pbr prepass"); + let mut pbr_enc = self + .device + .create_command_encoder(&CommandEncoderDescriptor { + label: Some("init encoder"), + }); + self.pbr.update(self, &mut pbr_enc); + Some(pbr_enc.finish()) + } + + fn shadow_map_pass(&self, objsref: &[Box]) -> Vec { + if self.render_params.value().shadow_mapping_resolution != 0 { + use rayon::prelude::*; + let results = self + .sun_params + .iter() + .enumerate() + .par_bridge() + .map(|(i, u)| { + profiling::scope!(&format!("cascade shadow pass {}", i)); + let mut smap_enc = + self.device + .create_command_encoder(&CommandEncoderDescriptor { + label: Some("shadow map encoder"), + }); + let sun_view = self + .sun_shadowmap + .texture + .create_view(&TextureViewDescriptor { + label: Some("sun shadow view"), + format: Some(self.sun_shadowmap.format), + dimension: Some(TextureViewDimension::D2), + aspect: TextureAspect::DepthOnly, + base_mip_level: 0, + mip_level_count: None, + base_array_layer: i as u32, + array_layer_count: Some(1), + }); + let mut sun_shadow_pass = smap_enc.begin_render_pass(&RenderPassDescriptor { + label: Some("sun shadow pass"), + color_attachments: &[], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &sun_view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: wgpu::StoreOp::Store, + }), + stencil_ops: None, + }), + timestamp_writes: None, + occlusion_query_set: None, + }); + + sun_shadow_pass.set_bind_group(0, &u.bindgroup, &[]); - passes::render_background(self, encs, frame); - passes::gen_ui_blur(self, encs, frame); + for obj in objsref.iter() { + obj.draw_depth(self, &mut sun_shadow_pass, Some(&u.value().proj)); + } + + drop(sun_shadow_pass); - start_time.elapsed() + smap_enc.finish() + }) + .collect::>(); + return results; + } + return vec![]; } - pub fn render_gui( - &mut self, - encoders: &mut Encoders, - frame: &TextureView, - mut render_gui: impl FnMut(GuiRenderContext<'_>), - ) { - profiling::scope!("gfx::render_gui"); - render_gui(GuiRenderContext { - size: self.size, - gfx: self, - encoder: &mut encoders.end, - view: frame, + fn depth_prepass(&self, objsref: &[Box]) -> CommandBuffer { + profiling::scope!("depth prepass"); + let mut prepass = self + .device + .create_command_encoder(&CommandEncoderDescriptor { + label: Some("depth prepass encoder"), + }); + let mut depth_prepass = prepass.begin_render_pass(&RenderPassDescriptor { + label: Some("depth prepass"), + color_attachments: &[], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &self.fbos.depth.view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(0.0), + store: wgpu::StoreOp::Store, + }), + stencil_ops: None, + }), + timestamp_writes: None, + occlusion_query_set: None, }); + + depth_prepass.set_bind_group(0, &self.render_params.bindgroup, &[]); + + for obj in objsref.iter() { + obj.draw_depth(self, &mut depth_prepass, None); + } + drop(depth_prepass); + prepass.finish() } pub fn finish_frame(&mut self, encoder: Encoders) { @@ -817,19 +884,22 @@ impl GfxContext { .into_iter() .chain(encoder.pbr) .chain(encoder.smap) - .chain(Some(encoder.end.finish())), + .chain(Some(encoder.before_main.finish())) + .chain(encoder.main) + .chain(Some(encoder.after_main.finish())) + .chain(encoder.gui), ); if self.defines_changed { self.defines_changed = false; self.pipelines - .try_borrow_mut() + .write() .unwrap() .invalidate_all(&self.defines, &self.device); } if self.tick % 30 == 0 { #[cfg(debug_assertions)] self.pipelines - .try_borrow_mut() + .write() .unwrap() .check_shader_updates(&self.defines, &self.device); } @@ -1062,7 +1132,7 @@ impl GfxContext { } pub fn get_pipeline(&self, obj: impl PipelineBuilder) -> &'static RenderPipeline { - let pipelines = &mut *self.pipelines.try_borrow_mut().unwrap(); + let pipelines = &mut *self.pipelines.write().unwrap(); pipelines.get_pipeline(self, obj, &self.device) } } diff --git a/engine/src/passes/background.rs b/engine/src/passes/background.rs index 5e66f506..274bcc3b 100644 --- a/engine/src/passes/background.rs +++ b/engine/src/passes/background.rs @@ -1,16 +1,16 @@ use crate::{ - CompiledModule, Encoders, GfxContext, PipelineBuilder, RenderParams, Texture, Uniform, - UvVertex, TL, + CompiledModule, GfxContext, PipelineBuilder, RenderParams, Texture, Uniform, UvVertex, TL, }; use wgpu::{ - BindGroupLayout, BlendState, DepthBiasState, FragmentState, IndexFormat, MultisampleState, - PipelineLayoutDescriptor, PrimitiveState, RenderPassColorAttachment, RenderPassDescriptor, - RenderPipeline, RenderPipelineDescriptor, TextureFormat, TextureView, VertexState, + BindGroupLayout, BlendState, CommandEncoder, DepthBiasState, FragmentState, IndexFormat, + MultisampleState, PipelineLayoutDescriptor, PrimitiveState, RenderPassColorAttachment, + RenderPassDescriptor, RenderPipeline, RenderPipelineDescriptor, TextureFormat, TextureView, + VertexState, }; -pub fn render_background(gfx: &GfxContext, encs: &mut Encoders, frame: &TextureView) { +pub fn render_background(gfx: &GfxContext, enc: &mut CommandEncoder, frame: &TextureView) { profiling::scope!("bg pass"); - let mut bg_pass = encs.end.begin_render_pass(&RenderPassDescriptor { + let mut bg_pass = enc.begin_render_pass(&RenderPassDescriptor { label: Some("bg pass"), color_attachments: &[Some(RenderPassColorAttachment { view: &gfx.fbos.color_msaa, diff --git a/engine/src/passes/blur.rs b/engine/src/passes/blur.rs index 4d19272f..93bfa213 100644 --- a/engine/src/passes/blur.rs +++ b/engine/src/passes/blur.rs @@ -1,10 +1,10 @@ use wgpu::{ - Device, FragmentState, PipelineLayoutDescriptor, PrimitiveState, RenderPassColorAttachment, - RenderPassDescriptor, RenderPipeline, RenderPipelineDescriptor, SurfaceConfiguration, - TextureUsages, TextureView, VertexState, + CommandEncoder, Device, FragmentState, PipelineLayoutDescriptor, PrimitiveState, + RenderPassColorAttachment, RenderPassDescriptor, RenderPipeline, RenderPipelineDescriptor, + SurfaceConfiguration, TextureUsages, TextureView, VertexState, }; -use crate::{CompiledModule, Encoders, GfxContext, PipelineBuilder, Texture, TextureBuilder, TL}; +use crate::{CompiledModule, GfxContext, PipelineBuilder, Texture, TextureBuilder, TL}; const DOWNSCALE_PASSES: u32 = 2; @@ -16,12 +16,12 @@ const DOWNSCALE_PASSES: u32 = 2; /// 1. Downsample the image to half resolution using bi-linear filtering /// 2. Downsample then upsample using the equations from the paper /// 3. Sample from the UI directly (bi-linearly filtered) -pub fn gen_ui_blur(gfx: &GfxContext, encs: &mut Encoders, frame: &TextureView) { +pub fn gen_ui_blur(gfx: &GfxContext, enc: &mut CommandEncoder, frame: &TextureView) { profiling::scope!("ui blur pass"); let tex = &gfx.fbos.ui_blur; - initial_downscale(gfx, encs, frame); + initial_downscale(gfx, enc, frame); //do_pass( // gfx, @@ -34,7 +34,7 @@ pub fn gen_ui_blur(gfx: &GfxContext, encs: &mut Encoders, frame: &TextureView) { for mip_level in 0..DOWNSCALE_PASSES { do_pass( gfx, - encs, + enc, UIBlurPipeline::Downscale, &tex.mip_view(mip_level), &tex.mip_view(mip_level + 1), @@ -44,7 +44,7 @@ pub fn gen_ui_blur(gfx: &GfxContext, encs: &mut Encoders, frame: &TextureView) { for mip_level in (0..DOWNSCALE_PASSES).rev() { do_pass( gfx, - encs, + enc, if mip_level == 0 { UIBlurPipeline::UpscaleDeband } else { @@ -57,22 +57,23 @@ pub fn gen_ui_blur(gfx: &GfxContext, encs: &mut Encoders, frame: &TextureView) { } // Simple downscale we can use mipmap gen (less expensive: 1 sample vs 5) -fn initial_downscale(gfx: &GfxContext, encs: &mut Encoders, frame: &TextureView) { - let pipe = gfx.mipmap_gen.get_pipeline(&gfx.device, gfx.fbos.format); - - gfx.mipmap_gen.mipmap_one( - &mut encs.end, - &gfx.device, - &pipe, - frame, - &gfx.fbos.ui_blur.mip_view(0), - "ui blur", - ); +fn initial_downscale(gfx: &GfxContext, enc: &mut CommandEncoder, frame: &TextureView) { + gfx.mipmap_gen + .with_pipeline(&gfx.device, gfx.fbos.format, |pipe| { + gfx.mipmap_gen.mipmap_one( + enc, + &gfx.device, + pipe, + frame, + &gfx.fbos.ui_blur.mip_view(0), + "ui blur", + ); + }); } fn do_pass( gfx: &GfxContext, - encs: &mut Encoders, + enc: &mut CommandEncoder, pipeline: UIBlurPipeline, src_view: &TextureView, dst_view: &TextureView, @@ -94,7 +95,7 @@ fn do_pass( ], }); - let mut blur_pass = encs.end.begin_render_pass(&RenderPassDescriptor { + let mut blur_pass = enc.begin_render_pass(&RenderPassDescriptor { label: Some(&*format!("ui blur pass {:?}", pipeline)), color_attachments: &[Some(RenderPassColorAttachment { view: dst_view, diff --git a/engine/src/passes/fog.rs b/engine/src/passes/fog.rs index aa89018c..d42ceb80 100644 --- a/engine/src/passes/fog.rs +++ b/engine/src/passes/fog.rs @@ -10,13 +10,12 @@ use wgpu::{ #[derive(Copy, Clone, Hash)] pub struct FogPipeline; -pub fn render_fog(gfx: &mut GfxContext, enc: &mut CommandEncoder) { +pub fn render_fog(gfx: &GfxContext, enc: &mut CommandEncoder) { + //if !gfx.defines.contains_key("FOG") { + // return; + //} profiling::scope!("fog"); let pipeline = gfx.get_pipeline(FogPipeline); - let bg = gfx - .fbos - .depth - .bindgroup(&gfx.device, &pipeline.get_bind_group_layout(1)); let mut fog_pass = enc.begin_render_pass(&RenderPassDescriptor { label: Some("fog pass"), @@ -40,7 +39,7 @@ pub fn render_fog(gfx: &mut GfxContext, enc: &mut CommandEncoder) { fog_pass.set_pipeline(pipeline); fog_pass.set_bind_group(0, &gfx.render_params.bindgroup, &[]); - fog_pass.set_bind_group(1, &bg, &[]); + fog_pass.set_bind_group(1, &gfx.fbos.depth_bg, &[]); fog_pass.set_vertex_buffer(0, gfx.screen_uv_vertices.slice(..)); fog_pass.set_index_buffer(gfx.rect_indices.slice(..), IndexFormat::Uint32); fog_pass.draw_indexed(0..6, 0, 0..1); diff --git a/engine/src/passes/ssao.rs b/engine/src/passes/ssao.rs index 229b1cf1..d36b363c 100644 --- a/engine/src/passes/ssao.rs +++ b/engine/src/passes/ssao.rs @@ -9,13 +9,11 @@ use wgpu::{ pub struct SSAOPipeline; pub fn render_ssao(gfx: &GfxContext, enc: &mut CommandEncoder) { + if !gfx.defines.contains_key("SSAO") { + return; + } profiling::scope!("ssao"); let pipeline = gfx.get_pipeline(SSAOPipeline); - let bg = gfx - .fbos - .depth - .bindgroup(&gfx.device, &pipeline.get_bind_group_layout(1)); - let mut ssao_pass = enc.begin_render_pass(&RenderPassDescriptor { label: Some("ssao pass"), color_attachments: &[Some(RenderPassColorAttachment { @@ -33,7 +31,7 @@ pub fn render_ssao(gfx: &GfxContext, enc: &mut CommandEncoder) { ssao_pass.set_pipeline(pipeline); ssao_pass.set_bind_group(0, &gfx.render_params.bindgroup, &[]); - ssao_pass.set_bind_group(1, &bg, &[]); + ssao_pass.set_bind_group(1, &gfx.fbos.depth_bg, &[]); ssao_pass.set_vertex_buffer(0, gfx.screen_uv_vertices.slice(..)); ssao_pass.set_index_buffer(gfx.rect_indices.slice(..), IndexFormat::Uint32); ssao_pass.draw_indexed(0..6, 0, 0..1); diff --git a/engine/src/shader.rs b/engine/src/shader.rs index b0c39521..58d4edcd 100644 --- a/engine/src/shader.rs +++ b/engine/src/shader.rs @@ -5,12 +5,12 @@ use common::FastMap; use std::borrow::Cow; use std::ops::Deref; use std::path::{Path, PathBuf}; -use std::rc::Rc; +use std::sync::Arc; use std::time::Instant; use wgpu::{Device, ShaderModule}; #[derive(Clone)] -pub struct CompiledModule(Rc<(ShaderModule, Vec)>); +pub struct CompiledModule(Arc<(ShaderModule, Vec)>); impl Deref for CompiledModule { type Target = ShaderModule; @@ -67,7 +67,7 @@ pub fn compile_shader( let wgsl = mk_module(source, device); - CompiledModule(Rc::new((wgsl, deps))) + CompiledModule(Arc::new((wgsl, deps))) } /// apply_ifdefs updates the source taking into account #ifdef and #ifndef diff --git a/engine/src/texture.rs b/engine/src/texture.rs index 1fa0f78b..a8053cf3 100644 --- a/engine/src/texture.rs +++ b/engine/src/texture.rs @@ -1,10 +1,10 @@ #![allow(dead_code)] -use std::cell::{Ref, RefCell}; use std::fs::File; use std::io; use std::io::Read; use std::path::Path; +use std::sync::RwLock; use derive_more::{Display, From}; use image::{DynamicImage, GenericImageView}; @@ -620,7 +620,7 @@ impl<'a> TextureBuilder<'a> { } pub struct MipmapGenerator { - pipelines: RefCell>, + pipelines: RwLock>, sampler: wgpu::Sampler, module: CompiledModule, } @@ -658,41 +658,48 @@ impl MipmapGenerator { mip_count: u32, label: &str, ) { - let pipeline = self.get_pipeline(device, format); - - let views = (0..mip_count) - .map(|mip| { - texture.create_view(&TextureViewDescriptor { - label: Some("mip"), - format: None, - dimension: None, - aspect: wgpu::TextureAspect::All, - base_mip_level: mip, - mip_level_count: Some(1), - base_array_layer: 0, - array_layer_count: None, + self.with_pipeline(device, format, |pipe| { + let views = (0..mip_count) + .map(|mip| { + texture.create_view(&TextureViewDescriptor { + label: Some("mip"), + format: None, + dimension: None, + aspect: wgpu::TextureAspect::All, + base_mip_level: mip, + mip_level_count: Some(1), + base_array_layer: 0, + array_layer_count: None, + }) }) - }) - .collect::>(); - - let mut encoder = device.create_command_encoder(&CommandEncoderDescriptor { label: None }); - for target_mip in 1..mip_count as usize { - self.mipmap_one( - &mut encoder, - device, - &pipeline, - &views[target_mip - 1], - &views[target_mip], - label, - ); - } - queue.submit(Some(encoder.finish())); + .collect::>(); + + let mut encoder = + device.create_command_encoder(&CommandEncoderDescriptor { label: None }); + for target_mip in 1..mip_count as usize { + self.mipmap_one( + &mut encoder, + device, + pipe, + &views[target_mip - 1], + &views[target_mip], + label, + ); + } + queue.submit(Some(encoder.finish())); + }); } - pub fn get_pipeline(&self, device: &Device, format: TextureFormat) -> Ref<'_, RenderPipeline> { - let b = self.pipelines.borrow(); + pub fn with_pipeline( + &self, + device: &Device, + format: TextureFormat, + f: impl FnOnce(&RenderPipeline), + ) { + let b = self.pipelines.read().unwrap(); if b.contains_key(&format) { - return Ref::map(b, |b| &b[&format]); + f(&b[&format]); + return; } drop(b); @@ -723,9 +730,9 @@ impl MipmapGenerator { multiview: None, }); - self.pipelines.borrow_mut().insert(format, pipeline); + self.pipelines.write().unwrap().insert(format, pipeline); - Ref::map(self.pipelines.borrow(), |b| &b[&format]) + f(&self.pipelines.read().unwrap()[&format]); } pub fn mipmap_one( diff --git a/native_app/src/rendering/map_rendering/map_mesh.rs b/native_app/src/rendering/map_rendering/map_mesh.rs index 8e409588..5a396d18 100644 --- a/native_app/src/rendering/map_rendering/map_mesh.rs +++ b/native_app/src/rendering/map_rendering/map_mesh.rs @@ -16,7 +16,7 @@ use simulation::map::{ }; use simulation::Simulation; use std::ops::{Mul, Neg}; -use std::rc::Rc; +use std::sync::Arc; /// This is the main struct that handles the map rendering. /// It is responsible for generating the meshes and sprites for the map @@ -30,8 +30,8 @@ pub struct MapMeshHandler { #[derive(Default)] struct CachedObj { - road: Vec>, - build: Vec>, + road: Vec>, + build: Vec>, lots: Option, arrows: Option, } @@ -194,10 +194,10 @@ impl MapMeshHandler { cached.road.reserve(2); if let Some(mesh) = b.mesh_map.build(ctx.gfx) { - cached.road.push(Rc::new(mesh)); + cached.road.push(Arc::new(mesh)); } if let Some(mesh) = b.crosswalk_builder.build(ctx.gfx) { - cached.road.push(Rc::new(mesh)); + cached.road.push(Arc::new(mesh)); } cached.lots = b.mesh_lots.build(ctx.gfx); @@ -226,7 +226,7 @@ impl MapMeshHandler { .collect::>(); if !sprites.is_empty() { - cached.build.push(Rc::new(sprites)); + cached.build.push(Arc::new(sprites)); } let buildmeshes = b @@ -236,11 +236,11 @@ impl MapMeshHandler { .collect::>(); if !buildmeshes.is_empty() { - cached.build.push(Rc::new(buildmeshes)); + cached.build.push(Arc::new(buildmeshes)); } if let Some(mesh) = b.houses_mesh.build(ctx.gfx) { - cached.build.push(Rc::new(mesh)); + cached.build.push(Arc::new(mesh)); } let zonemeshes = b @@ -249,7 +249,7 @@ impl MapMeshHandler { .flat_map(|(a, b, _)| a.build(ctx.gfx).zip(b.build(ctx.gfx))) .collect::>(); if !zonemeshes.is_empty() { - cached.build.push(Rc::new(zonemeshes)); + cached.build.push(Arc::new(zonemeshes)); } if cached.is_empty() {