From 693fca4cc3ca96e1b7adcd9dc3eacf4f5b021dca Mon Sep 17 00:00:00 2001 From: Imbris Date: Mon, 21 Dec 2020 20:53:37 -0500 Subject: [PATCH] Avoid extra set_pipeline calls --- voxygen/src/render/mod.rs | 5 +- voxygen/src/render/renderer/drawer.rs | 315 +++++++++++++++++--------- voxygen/src/scene/figure/mod.rs | 58 +++-- voxygen/src/scene/mod.rs | 145 +++++------- voxygen/src/scene/simple.rs | 5 +- voxygen/src/scene/terrain.rs | 86 +++---- voxygen/src/session/mod.rs | 27 +-- 7 files changed, 325 insertions(+), 316 deletions(-) diff --git a/voxygen/src/render/mod.rs b/voxygen/src/render/mod.rs index 7a44fdb843..4bd6c41860 100644 --- a/voxygen/src/render/mod.rs +++ b/voxygen/src/render/mod.rs @@ -42,8 +42,9 @@ pub use self::{ }, renderer::{ drawer::{ - Drawer, FirstPassDrawer, ParticleDrawer, PreparedUiDrawer, SecondPassDrawer, - ShadowDrawer, ThirdPassDrawer, UiDrawer, + ChunkSpriteDrawer, Drawer, FigureDrawer, FigureShadowDrawer, FirstPassDrawer, + ParticleDrawer, PreparedUiDrawer, SecondPassDrawer, ShadowPassDrawer, SpriteDrawer, + TerrainDrawer, TerrainShadowDrawer, ThirdPassDrawer, UiDrawer, }, ColLightInfo, Renderer, }, diff --git a/voxygen/src/render/renderer/drawer.rs b/voxygen/src/render/renderer/drawer.rs index aebd328ae1..efd764eac1 100644 --- a/voxygen/src/render/renderer/drawer.rs +++ b/voxygen/src/render/renderer/drawer.rs @@ -36,6 +36,38 @@ impl<'a> Drawer<'a> { } } + pub fn shadow_pass(&mut self) -> Option { + if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map { + let mut render_pass = + self.encoder + .as_mut() + .unwrap() + .begin_render_pass(&wgpu::RenderPassDescriptor { + color_attachments: &[], + depth_stencil_attachment: Some( + wgpu::RenderPassDepthStencilAttachmentDescriptor { + attachment: &shadow_renderer.directed_depth.view, + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Clear(1.0), + store: true, + }), + stencil_ops: None, + }, + ), + }); + + render_pass.set_bind_group(0, &self.globals.bind_group, &[]); + + Some(ShadowPassDrawer { + render_pass, + renderer: &self.renderer, + shadow_renderer, + }) + } else { + None + } + } + pub fn first_pass(&mut self) -> FirstPassDrawer { let mut render_pass = self.encoder @@ -71,38 +103,6 @@ impl<'a> Drawer<'a> { } } - pub fn shadow_pass(&mut self) -> Option { - if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map { - let mut render_pass = - self.encoder - .as_mut() - .unwrap() - .begin_render_pass(&wgpu::RenderPassDescriptor { - color_attachments: &[], - depth_stencil_attachment: Some( - wgpu::RenderPassDepthStencilAttachmentDescriptor { - attachment: &shadow_renderer.directed_depth.view, - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Clear(1.0), - store: true, - }), - stencil_ops: None, - }, - ), - }); - - render_pass.set_bind_group(0, &self.globals.bind_group, &[]); - - Some(ShadowDrawer { - render_pass, - renderer: &self.renderer, - shadow_renderer, - }) - } else { - None - } - } - pub fn second_pass(&mut self) -> SecondPassDrawer { let mut render_pass = self.encoder @@ -154,10 +154,11 @@ impl<'a> Drawer<'a> { } } - pub fn draw_point_shadow<'b: 'a>( + pub fn draw_point_shadows<'data: 'a>( &mut self, matrices: &[shadow::PointLightMatrix; 126], - chunks: impl Clone + Iterator, &'b terrain::BoundLocals)>, + chunks: impl Clone + + Iterator, &'data terrain::BoundLocals)>, ) { if let ShadowMap::Enabled(ref shadow_renderer) = self.renderer.shadow_map { const STRIDE: usize = std::mem::size_of::(); @@ -228,57 +229,110 @@ impl<'a> Drop for Drawer<'a> { } } -pub struct FirstPassDrawer<'a> { - pub(super) render_pass: wgpu::RenderPass<'a>, - pub renderer: &'a Renderer, +// Shadow pass +pub struct ShadowPassDrawer<'pass> { + render_pass: wgpu::RenderPass<'pass>, + pub renderer: &'pass Renderer, + shadow_renderer: &'pass ShadowMapRenderer, } -impl<'a> FirstPassDrawer<'a> { - pub fn draw_skybox<'b: 'a>(&mut self, model: &'b Model) { +impl<'pass> ShadowPassDrawer<'pass> { + pub fn draw_figure_shadows(&mut self) -> FigureShadowDrawer<'_, 'pass> { + self.render_pass + .set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline); + + FigureShadowDrawer { + render_pass: &mut self.render_pass, + } + } + + pub fn draw_terrain_shadows(&mut self) -> TerrainShadowDrawer<'_, 'pass> { + self.render_pass + .set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline); + + TerrainShadowDrawer { + render_pass: &mut self.render_pass, + } + } +} + +pub struct FigureShadowDrawer<'pass_ref, 'pass: 'pass_ref> { + render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, +} + +impl<'pass_ref, 'pass: 'pass_ref> FigureShadowDrawer<'pass_ref, 'pass> { + pub fn draw<'data: 'pass>( + &mut self, + model: SubModel<'data, terrain::Vertex>, + locals: &'data figure::BoundLocals, + ) { + self.render_pass.set_bind_group(1, &locals.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, model.buf()); + self.render_pass.draw(0..model.len(), 0..1); + } +} + +pub struct TerrainShadowDrawer<'pass_ref, 'pass: 'pass_ref> { + render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, +} + +impl<'pass_ref, 'pass: 'pass_ref> TerrainShadowDrawer<'pass_ref, 'pass> { + pub fn draw<'data: 'pass>( + &mut self, + model: &'data Model, + locals: &'data terrain::BoundLocals, + ) { + self.render_pass.set_bind_group(1, &locals.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); + self.render_pass.draw(0..model.len() as u32, 0..1); + } +} + +// First pass +pub struct FirstPassDrawer<'pass> { + pub(super) render_pass: wgpu::RenderPass<'pass>, + pub renderer: &'pass Renderer, +} + +impl<'pass> FirstPassDrawer<'pass> { + pub fn draw_skybox<'data: 'pass>(&mut self, model: &'data Model) { self.render_pass .set_pipeline(&self.renderer.skybox_pipeline.pipeline); self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); self.render_pass.draw(0..model.len() as u32, 0..1); } - pub fn draw_lod_terrain<'b: 'a>(&mut self, model: &'b Model) { + pub fn draw_lod_terrain<'data: 'pass>(&mut self, model: &'data Model) { self.render_pass .set_pipeline(&self.renderer.lod_terrain_pipeline.pipeline); self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); self.render_pass.draw(0..model.len() as u32, 0..1); } - pub fn draw_figure<'b: 'a>( - &mut self, - model: SubModel<'b, terrain::Vertex>, - locals: &'b figure::BoundLocals, - col_lights: &'b ColLights, - ) { + pub fn draw_figures(&mut self) -> FigureDrawer<'_, 'pass> { self.render_pass .set_pipeline(&self.renderer.figure_pipeline.pipeline); - self.render_pass.set_bind_group(2, &locals.bind_group, &[]); - self.render_pass - .set_bind_group(3, &col_lights.bind_group, &[]); - self.render_pass.set_vertex_buffer(0, model.buf()); - self.render_pass.draw(0..model.len(), 0..1); + + FigureDrawer { + render_pass: &mut self.render_pass, + } } - pub fn draw_terrain<'b: 'a>( + pub fn draw_terrain<'data: 'pass>( &mut self, - model: &'b Model, - locals: &'b terrain::BoundLocals, - col_lights: &'b ColLights, - ) { + col_lights: &'data ColLights, + ) -> TerrainDrawer<'_, 'pass> { self.render_pass .set_pipeline(&self.renderer.terrain_pipeline.pipeline); - self.render_pass.set_bind_group(2, &locals.bind_group, &[]); self.render_pass .set_bind_group(3, &col_lights.bind_group, &[]); - self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); - self.render_pass.draw(0..model.len() as u32, 0..1) + + TerrainDrawer { + render_pass: &mut self.render_pass, + } } - pub fn draw_particles(&mut self) -> ParticleDrawer<'_, 'a> { + pub fn draw_particles(&mut self) -> ParticleDrawer<'_, 'pass> { self.render_pass .set_pipeline(&self.renderer.particle_pipeline.pipeline); @@ -287,29 +341,24 @@ impl<'a> FirstPassDrawer<'a> { } } - pub fn draw_sprite<'b: 'a>( + pub fn draw_sprites<'data: 'pass>( &mut self, - model: &'b Model, - instances: &'b Instances, - terrain_locals: &'b terrain::BoundLocals, - locals: &'b sprite::BoundLocals, - col_lights: &'b ColLights, - ) { + col_lights: &'data ColLights, + ) -> SpriteDrawer<'_, 'pass> { self.render_pass .set_pipeline(&self.renderer.sprite_pipeline.pipeline); - self.render_pass - .set_bind_group(2, &terrain_locals.bind_group, &[]); - self.render_pass.set_bind_group(3, &locals.bind_group, &[]); self.render_pass .set_bind_group(4, &col_lights.bind_group, &[]); - self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); - self.render_pass - .set_vertex_buffer(1, instances.buf().slice(..)); - self.render_pass - .draw(0..model.len() as u32, 0..instances.count() as u32); + + SpriteDrawer { + render_pass: &mut self.render_pass, + } } - pub fn draw_fluid<'b: 'a>(&mut self, waves: &'b fluid::BindGroup) -> FluidDrawer<'_, 'a> { + pub fn draw_fluid<'data: 'pass>( + &mut self, + waves: &'data fluid::BindGroup, + ) -> FluidDrawer<'_, 'pass> { self.render_pass .set_pipeline(&self.renderer.fluid_pipeline.pipeline); self.render_pass.set_bind_group(2, &waves.bind_group, &[]); @@ -320,6 +369,42 @@ impl<'a> FirstPassDrawer<'a> { } } +pub struct FigureDrawer<'pass_ref, 'pass: 'pass_ref> { + render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, +} + +impl<'pass_ref, 'pass: 'pass_ref> FigureDrawer<'pass_ref, 'pass> { + pub fn draw<'data: 'pass>( + &mut self, + model: SubModel<'data, terrain::Vertex>, + locals: &'data figure::BoundLocals, + // TODO: don't rebind this every time once they are shared between figures + col_lights: &'data ColLights, + ) { + self.render_pass.set_bind_group(2, &locals.bind_group, &[]); + self.render_pass + .set_bind_group(3, &col_lights.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, model.buf()); + self.render_pass.draw(0..model.len(), 0..1); + } +} + +pub struct TerrainDrawer<'pass_ref, 'pass: 'pass_ref> { + render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, +} + +impl<'pass_ref, 'pass: 'pass_ref> TerrainDrawer<'pass_ref, 'pass> { + pub fn draw<'data: 'pass>( + &mut self, + model: &'data Model, + locals: &'data terrain::BoundLocals, + ) { + self.render_pass.set_bind_group(2, &locals.bind_group, &[]); + self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); + self.render_pass.draw(0..model.len() as u32, 0..1) + } +} + pub struct ParticleDrawer<'pass_ref, 'pass: 'pass_ref> { render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, } @@ -341,35 +426,40 @@ impl<'pass_ref, 'pass: 'pass_ref> ParticleDrawer<'pass_ref, 'pass> { } } -pub struct ShadowDrawer<'pass> { - render_pass: wgpu::RenderPass<'pass>, - pub renderer: &'pass Renderer, - shadow_renderer: &'pass ShadowMapRenderer, +pub struct SpriteDrawer<'pass_ref, 'pass: 'pass_ref> { + render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, } -impl<'pass> ShadowDrawer<'pass> { - pub fn draw_figure_shadow<'b: 'pass>( +impl<'pass_ref, 'pass: 'pass_ref> SpriteDrawer<'pass_ref, 'pass> { + pub fn in_chunk<'data: 'pass>( &mut self, - model: SubModel<'b, terrain::Vertex>, - locals: &'b figure::BoundLocals, - ) { + terrain_locals: &'data terrain::BoundLocals, + ) -> ChunkSpriteDrawer<'_, 'pass> { self.render_pass - .set_pipeline(&self.shadow_renderer.figure_directed_pipeline.pipeline); - self.render_pass.set_bind_group(1, &locals.bind_group, &[]); - self.render_pass.set_vertex_buffer(0, model.buf()); - self.render_pass.draw(0..model.len(), 0..1); - } + .set_bind_group(2, &terrain_locals.bind_group, &[]); - pub fn draw_terrain_shadow<'b: 'pass>( + ChunkSpriteDrawer { + render_pass: &mut self.render_pass, + } + } +} +pub struct ChunkSpriteDrawer<'pass_ref, 'pass: 'pass_ref> { + render_pass: &'pass_ref mut wgpu::RenderPass<'pass>, +} + +impl<'pass_ref, 'pass: 'pass_ref> ChunkSpriteDrawer<'pass_ref, 'pass> { + pub fn draw<'data: 'pass>( &mut self, - model: &'b Model, - locals: &'b terrain::BoundLocals, + model: &'data Model, + instances: &'data Instances, + locals: &'data sprite::BoundLocals, ) { - self.render_pass - .set_pipeline(&self.shadow_renderer.terrain_directed_pipeline.pipeline); - self.render_pass.set_bind_group(1, &locals.bind_group, &[]); self.render_pass.set_vertex_buffer(0, model.buf().slice(..)); - self.render_pass.draw(0..model.len() as u32, 0..1); + self.render_pass + .set_vertex_buffer(1, instances.buf().slice(..)); + self.render_pass.set_bind_group(3, &locals.bind_group, &[]); + self.render_pass + .draw(0..model.len() as u32, 0..instances.count() as u32); } } @@ -389,13 +479,14 @@ impl<'pass_ref, 'pass: 'pass_ref> FluidDrawer<'pass_ref, 'pass> { } } -pub struct SecondPassDrawer<'a> { - pub(super) render_pass: wgpu::RenderPass<'a>, - pub renderer: &'a Renderer, +// Second pass: clouds +pub struct SecondPassDrawer<'pass> { + pub(super) render_pass: wgpu::RenderPass<'pass>, + pub renderer: &'pass Renderer, } -impl<'a> SecondPassDrawer<'a> { - pub fn draw_clouds<'b: 'a>(&mut self) { +impl<'pass> SecondPassDrawer<'pass> { + pub fn draw_clouds(&mut self) { self.render_pass .set_pipeline(&self.renderer.clouds_pipeline.pipeline); self.render_pass @@ -404,13 +495,14 @@ impl<'a> SecondPassDrawer<'a> { } } -pub struct ThirdPassDrawer<'a> { - render_pass: wgpu::RenderPass<'a>, - renderer: &'a Renderer, +// Third pass: postprocess + ui +pub struct ThirdPassDrawer<'pass> { + render_pass: wgpu::RenderPass<'pass>, + renderer: &'pass Renderer, } -impl<'a> ThirdPassDrawer<'a> { - pub fn draw_post_process<'b: 'a>(&mut self) { +impl<'pass> ThirdPassDrawer<'pass> { + pub fn draw_post_process(&mut self) { self.render_pass .set_pipeline(&self.renderer.postprocess_pipeline.pipeline); self.render_pass @@ -418,7 +510,7 @@ impl<'a> ThirdPassDrawer<'a> { self.render_pass.draw(0..3, 0..1); } - pub fn draw_ui(&mut self) -> UiDrawer<'_, 'a> { + pub fn draw_ui(&mut self) -> UiDrawer<'_, 'pass> { self.render_pass .set_pipeline(&self.renderer.ui_pipeline.pipeline); @@ -443,7 +535,7 @@ impl<'pass_ref, 'pass: 'pass_ref> UiDrawer<'pass_ref, 'pass> { pub fn prepare<'data: 'pass>( &mut self, locals: &'data ui::BoundLocals, - //texture: &'b ui::TextureBindGroup, + //texture: &'data ui::TextureBindGroup, buf: &'data DynamicModel, scissor: Aabr, ) -> PreparedUiDrawer<'_, 'pass> { @@ -467,8 +559,9 @@ impl<'pass_ref, 'pass: 'pass_ref> PreparedUiDrawer<'pass_ref, 'pass> { self.render_pass.set_bind_group(1, &locals.bind_group, &[]); } - //pub fn set_texture<'b: 'a>(&mut self, texture: &'b ui::TextureBindGroup) { - // self.render_pass.set_bind_group(1, &texture.bind_group, &[]); + //pub fn set_texture<'data: 'pass>(&mut self, texture: &'data + // ui::TextureBindGroup) { self.render_pass.set_bind_group(1, + // &texture.bind_group, &[]); //} pub fn set_model<'data: 'pass>(&mut self, model: &'data DynamicModel) { diff --git a/voxygen/src/scene/figure/mod.rs b/voxygen/src/scene/figure/mod.rs index 009d9d52b5..e667394b11 100644 --- a/voxygen/src/scene/figure/mod.rs +++ b/voxygen/src/scene/figure/mod.rs @@ -8,8 +8,9 @@ use crate::{ ecs::comp::Interpolated, render::{ pipelines::{self, ColLights}, - ColLightInfo, FigureBoneData, FigureLocals, FigureModel, FirstPassDrawer, GlobalModel, - LodData, Mesh, RenderError, Renderer, ShadowDrawer, SubModel, TerrainVertex, + ColLightInfo, FigureBoneData, FigureDrawer, FigureLocals, FigureModel, FigureShadowDrawer, + FirstPassDrawer, GlobalModel, LodData, Mesh, RenderError, Renderer, SubModel, + TerrainVertex, }, scene::{ camera::{Camera, CameraMode, Dependents}, @@ -4708,7 +4709,7 @@ impl FigureMgr { pub fn render_shadows<'a>( &'a self, - drawer: &mut ShadowDrawer<'a>, + drawer: &mut FigureShadowDrawer<'_, 'a>, state: &State, tick: u64, (camera, figure_lod_render_distance): CameraData, @@ -4741,7 +4742,7 @@ impl FigureMgr { figure_lod_render_distance * scale.map_or(1.0, |s| s.0), |state| state.can_shadow_sun(), ) { - drawer.draw_figure_shadow(model, bound); + drawer.draw(model, bound); } }); } @@ -4749,12 +4750,10 @@ impl FigureMgr { #[allow(clippy::too_many_arguments)] // TODO: Pending review in #587 pub fn render<'a>( &'a self, - drawer: &mut FirstPassDrawer<'a>, + drawer: &mut FigureDrawer<'_, 'a>, state: &State, player_entity: EcsEntity, tick: u64, - global: &GlobalModel, - lod: &LodData, (camera, figure_lod_render_distance): CameraData, ) { span!(_guard, "render", "FigureManager::render"); @@ -4763,36 +4762,33 @@ impl FigureMgr { let character_state_storage = state.read_storage::(); let character_state = character_state_storage.get(player_entity); - for (entity, pos, _, body, _, inventory, scale) in ( + for (entity, pos, body, _, inventory, scale) in ( &ecs.entities(), &ecs.read_storage::(), - ecs.read_storage::().maybe(), &ecs.read_storage::(), ecs.read_storage::().maybe(), ecs.read_storage::().maybe(), - ecs.read_storage::().maybe(), + ecs.read_storage::().maybe() ) .join() // Don't render dead entities - .filter(|(_, _, _, _, health, _, _)| health.map_or(true, |h| !h.is_dead)) + .filter(|(_, _, _, health, _)| health.map_or(true, |h| !h.is_dead)) + // Don't render player + .filter(|(entity, _, _, _, _)| *entity != player_entity) { - let is_player = entity == player_entity; - - if !is_player { - if let Some((bound, model, col_lights)) = self.get_model_for_render( - tick, - camera, - character_state, - entity, - body, - inventory, - false, - pos.0, - figure_lod_render_distance * scale.map_or(1.0, |s| s.0), - |state| state.visible(), - ) { - drawer.draw_figure(model, bound, col_lights); - } + if let Some((bound, model, col_lights)) = self.get_model_for_render( + tick, + camera, + character_state, + entity, + body, + inventory, + false, + pos.0, + figure_lod_render_distance * scale.map_or(1.0, |s| s.0), + |state| state.visible(), + ) { + drawer.draw(model, bound, col_lights); } } } @@ -4800,12 +4796,10 @@ impl FigureMgr { #[allow(clippy::too_many_arguments)] // TODO: Pending review in #587 pub fn render_player<'a>( &'a self, - drawer: &mut FirstPassDrawer<'a>, + drawer: &mut FigureDrawer<'_, 'a>, state: &State, player_entity: EcsEntity, tick: u64, - global: &GlobalModel, - lod: &LodData, (camera, figure_lod_render_distance): CameraData, ) { span!(_guard, "render_player", "FigureManager::render_player"); @@ -4839,7 +4833,7 @@ impl FigureMgr { figure_lod_render_distance, |state| state.visible(), ) { - drawer.draw_figure(model, bound, col_lights); + drawer.draw(model, bound, col_lights); /*renderer.render_player_shadow( model, &col_lights, diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index 7531fb77ee..907ba2ff54 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -18,7 +18,7 @@ use crate::{ render::{ create_skybox_mesh, CloudsLocals, Consts, Drawer, FirstPassDrawer, GlobalModel, Globals, GlobalsBindGroup, Light, Model, PointLightMatrix, PostProcessLocals, Renderer, Shadow, - ShadowDrawer, ShadowLocals, SkyboxVertex, + ShadowLocals, SkyboxVertex, }, settings::Settings, window::{AnalogGameInput, Event}, @@ -1034,90 +1034,10 @@ impl Scene { pub fn global_bind_group(&self) -> &GlobalsBindGroup { &self.globals_bind_group } - pub fn render_terrain_shadows<'a>( - &'a self, - drawer: &mut ShadowDrawer<'a>, - state: &State, - player_entity: EcsEntity, - tick: u64, - scene_data: &SceneData, - ) { - let sun_dir = scene_data.get_sun_dir(); - let is_daylight = sun_dir.z < 0.0; - let focus_pos = self.camera.get_focus_pos(); - let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc()); - - let global = &self.data; - let light_data = (is_daylight, &*self.light_data); - let camera_data = (&self.camera, scene_data.figure_lod_render_distance); - - // would instead have this as an extension. - if drawer.renderer.render_mode().shadow.is_map() - && (is_daylight || !light_data.1.is_empty()) - { - // Render terrain shadows. - self.terrain - .render_shadows(drawer, global, light_data, focus_pos); - } - } - - pub fn render_point_shadows<'a>( - &'a self, - drawer: &mut Drawer<'a>, - state: &State, - player_entity: EcsEntity, - tick: u64, - scene_data: &SceneData, - ) { - let sun_dir = scene_data.get_sun_dir(); - let is_daylight = sun_dir.z < 0.0; - let focus_pos = self.camera.get_focus_pos(); - let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc()); - - let global = &self.data; - let light_data = (is_daylight, &*self.light_data); - let camera_data = (&self.camera, scene_data.figure_lod_render_distance); - - if drawer.renderer.render_mode().shadow.is_map() - && (is_daylight || !light_data.1.is_empty()) - { - // Render terrain shadows. - self.terrain - .render_point_shadows(drawer, global, light_data, focus_pos); - } - } - - pub fn render_figure_shadows<'a>( - &'a self, - drawer: &mut ShadowDrawer<'a>, - state: &State, - player_entity: EcsEntity, - tick: u64, - scene_data: &SceneData, - ) { - let sun_dir = scene_data.get_sun_dir(); - let is_daylight = sun_dir.z < 0.0; - let focus_pos = self.camera.get_focus_pos(); - let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc()); - - let global = &self.data; - let light_data = (is_daylight, &*self.light_data); - let camera_data = (&self.camera, scene_data.figure_lod_render_distance); - - // would instead have this as an extension. - if drawer.renderer.render_mode().shadow.is_map() - && (is_daylight || !light_data.1.is_empty()) - { - // Render figure shadows. - self.figure_mgr - .render_shadows(drawer, state, tick, camera_data); - } - } - - /// Render the scene using the provided `FirstPassDrawer`. + /// Render the scene using the provided `Drawer`. pub fn render<'a>( &'a self, - drawer: &mut FirstPassDrawer<'a>, + drawer: &mut Drawer<'a>, state: &State, player_entity: EcsEntity, tick: u64, @@ -1129,26 +1049,63 @@ impl Scene { let focus_pos = self.camera.get_focus_pos(); let cam_pos = self.camera.dependents().cam_pos + focus_pos.map(|e| e.trunc()); - let global = &self.data; let camera_data = (&self.camera, scene_data.figure_lod_render_distance); - let lod = self.lod.get_data(); + // would instead have this as an extension. + if drawer.renderer.render_mode().shadow.is_map() + && (is_daylight || !self.light_data.is_empty()) + { + if is_daylight { + if let Some(mut shadow_pass) = drawer.shadow_pass() { + // Render terrain directed shadows. + self.terrain + .render_shadows(&mut shadow_pass.draw_terrain_shadows(), focus_pos); - self.figure_mgr - .render_player(drawer, state, player_entity, tick, global, lod, camera_data); + // Render figure directed shadows. + self.figure_mgr.render_shadows( + &mut shadow_pass.draw_figure_shadows(), + state, + tick, + camera_data, + ); + } + } - self.terrain.render(drawer, focus_pos); + // Render terrain point light shadows. + drawer.draw_point_shadows( + &self.data.point_light_matrices, + self.terrain.chunks_for_point_shadows(focus_pos), + ) + } - self.figure_mgr - .render(drawer, state, player_entity, tick, global, lod, camera_data); + let mut first_pass = drawer.first_pass(); - self.lod.render(drawer); + self.figure_mgr.render_player( + &mut first_pass.draw_figures(), + state, + player_entity, + tick, + camera_data, + ); + + self.terrain.render(&mut first_pass, focus_pos); + + self.figure_mgr.render( + &mut first_pass.draw_figures(), + state, + player_entity, + tick, + camera_data, + ); + + self.lod.render(&mut first_pass); // Render the skybox. - drawer.draw_skybox(&self.skybox.model); + first_pass.draw_skybox(&self.skybox.model); + // Draws translucent terrain and sprites self.terrain.render_translucent( - drawer, + &mut first_pass, focus_pos, cam_pos, scene_data.sprite_render_distance, @@ -1156,6 +1113,6 @@ impl Scene { // Render particle effects. self.particle_mgr - .render(&mut drawer.draw_particles(), scene_data); + .render(&mut first_pass.draw_particles(), scene_data); } } diff --git a/voxygen/src/scene/simple.rs b/voxygen/src/scene/simple.rs index 2bcf5d893e..c657a2e1e2 100644 --- a/voxygen/src/scene/simple.rs +++ b/voxygen/src/scene/simple.rs @@ -354,6 +354,7 @@ impl Scene { body: Option, inventory: Option<&Inventory>, ) { + let mut figure_drawer = drawer.draw_figures(); if let Some(body) = body { let model = &self.figure_model_cache.get_model( &self.col_lights, @@ -365,7 +366,7 @@ impl Scene { ); if let Some(model) = model { - drawer.draw_figure( + figure_drawer.draw( model.lod_model(0), self.figure_state.bound(), &self.col_lights.texture(model), @@ -374,7 +375,7 @@ impl Scene { } if let Some((model, state)) = &self.backdrop { - drawer.draw_figure( + figure_drawer.draw( model.lod_model(0), state.bound(), &self.col_lights.texture(model), diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 675e94fa58..3109bdd875 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -10,8 +10,8 @@ use crate::{ render::{ pipelines::{self, ColLights}, ColLightInfo, Consts, Drawer, FirstPassDrawer, FluidVertex, FluidWaves, GlobalModel, - Instances, LodData, Mesh, Model, RenderError, Renderer, ShadowDrawer, SpriteInstance, - SpriteLocals, SpriteVertex, TerrainLocals, TerrainVertex, Texture, + Instances, LodData, Mesh, Model, RenderError, Renderer, SpriteInstance, SpriteLocals, + SpriteVertex, TerrainLocals, TerrainShadowDrawer, TerrainVertex, Texture, }, }; @@ -1410,9 +1410,7 @@ impl Terrain { pub fn render_shadows<'a>( &'a self, - drawer: &mut ShadowDrawer<'a>, - global: &GlobalModel, - (is_daylight, light_data): super::LightData, + drawer: &mut TerrainShadowDrawer<'_, 'a>, focus_pos: Vec3, ) { span!(_guard, "render_shadows", "Terrain::render_shadows"); @@ -1432,28 +1430,28 @@ impl Terrain { // NOTE: We also render shadows for dead chunks that were found to still be // potential shadow casters, to avoid shadows suddenly disappearing at // very steep sun angles (e.g. sunrise / sunset). - if is_daylight { - chunk_iter - .clone() - .filter(|chunk| chunk.can_shadow_sun()) - .chain(self.shadow_chunks.iter().map(|(_, chunk)| chunk)) - .for_each(|chunk| drawer.draw_terrain_shadow(&chunk.opaque_model, &chunk.locals)); - } + chunk_iter + .filter(|chunk| chunk.can_shadow_sun()) + .chain(self.shadow_chunks.iter().map(|(_, chunk)| chunk)) + .for_each(|chunk| drawer.draw(&chunk.opaque_model, &chunk.locals)); } - pub fn render_point_shadows<'a>( - &'a self, - drawer: &mut Drawer<'a>, - global: &GlobalModel, - (is_daylight, light_data): super::LightData, + pub fn chunks_for_point_shadows( + &self, focus_pos: Vec3, - ) { + ) -> impl Clone + + Iterator< + Item = ( + &Model, + &pipelines::terrain::BoundLocals, + ), + > { let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| { (e as i32).div_euclid(sz as i32) }); let chunk_iter = Spiral2d::new() - .filter_map(|rpos| { + .filter_map(move |rpos| { let pos = focus_chunk + rpos; self.chunks.get(&pos) }) @@ -1463,35 +1461,27 @@ impl Terrain { // // NOTE: We don't bother retaining chunks unless they cast sun shadows, so we // don't use `shadow_chunks` here. - light_data.iter().take(1).for_each(|_light| { - drawer.draw_point_shadow( - &global.point_light_matrices, - chunk_iter - .clone() - .filter(|chunk| chunk.can_shadow_point) - .map(|chunk| (&chunk.opaque_model, &chunk.locals)), - ); - }); + chunk_iter + .filter(|chunk| chunk.can_shadow_point) + .map(|chunk| (&chunk.opaque_model, &chunk.locals)) } pub fn render<'a>(&'a self, drawer: &mut FirstPassDrawer<'a>, focus_pos: Vec3) { span!(_guard, "render", "Terrain::render"); + let mut drawer = drawer.draw_terrain(&self.col_lights); + let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| { (e as i32).div_euclid(sz as i32) }); - let chunk_iter = Spiral2d::new() + Spiral2d::new() .filter_map(|rpos| { let pos = focus_chunk + rpos; - self.chunks.get(&pos).map(|c| (pos, c)) + self.chunks.get(&pos) }) - .take(self.chunks.len()); - - for (_, chunk) in chunk_iter { - if chunk.visible.is_visible() { - drawer.draw_terrain(&chunk.opaque_model, &chunk.locals, &self.col_lights) - } - } + .take(self.chunks.len()) + .filter(|chunk| chunk.visible.is_visible()) + .for_each(|chunk| drawer.draw(&chunk.opaque_model, &chunk.locals)); } pub fn render_translucent<'a>( @@ -1519,8 +1509,11 @@ impl Terrain { span!(guard, "Terrain sprites"); let chunk_size = V::RECT_SIZE.map(|e| e as f32); let chunk_mag = (chunk_size * (f32::consts::SQRT_2 * 0.5)).magnitude_squared(); - for (pos, chunk) in chunk_iter.clone() { - if chunk.visible.is_visible() { + let mut sprite_drawer = drawer.draw_sprites(&self.sprite_col_lights); + chunk_iter + .clone() + .filter(|(_, c)| c.visible.is_visible()) + .for_each(|(pos, chunk)| { let sprite_low_detail_distance = sprite_render_distance * 0.75; let sprite_mid_detail_distance = sprite_render_distance * 0.5; let sprite_hid_detail_distance = sprite_render_distance * 0.35; @@ -1542,6 +1535,8 @@ impl Terrain { chunk_center + chunk_size.x * 0.5 - chunk_size.y * 0.5, )); if focus_dist_sqrd < sprite_render_distance.powi(2) { + // TODO: skip if sprite_instances is empty + let mut chunk_sprite_drawer = sprite_drawer.in_chunk(&chunk.locals); for (kind, instances) in (&chunk.sprite_instances).into_iter() { let SpriteData { model, locals, .. } = if kind .0 @@ -1563,24 +1558,17 @@ impl Terrain { &self.sprite_data[&kind][4] }; - drawer.draw_sprite( - model, - instances, - &chunk.locals, - locals, - &self.sprite_col_lights, - ); + chunk_sprite_drawer.draw(model, instances, locals); } } - } - } + }); + drop(sprite_drawer); drop(guard); // Translucent span!(guard, "Fluid chunks"); let mut fluid_drawer = drawer.draw_fluid(&self.waves); chunk_iter - .clone() .filter(|(_, chunk)| chunk.visible.is_visible()) .filter_map(|(_, chunk)| { chunk diff --git a/voxygen/src/session/mod.rs b/voxygen/src/session/mod.rs index e54f63c879..0b164cabe1 100644 --- a/voxygen/src/session/mod.rs +++ b/voxygen/src/session/mod.rs @@ -1418,34 +1418,9 @@ impl PlayState for SessionState { particles_enabled: settings.graphics.particles_enabled, is_aiming: self.is_aiming, }; - drawer.shadow_pass().map(|mut drawer| { - self.scene.render_terrain_shadows( - &mut drawer, - client.state(), - client.entity(), - client.get_tick(), - &scene_data, - ); - - self.scene.render_figure_shadows( - &mut drawer, - client.state(), - client.entity(), - client.get_tick(), - &scene_data, - ); - }); - - self.scene.render_point_shadows( - &mut drawer, - client.state(), - client.entity(), - client.get_tick(), - &scene_data, - ); self.scene.render( - &mut drawer.first_pass(), + &mut drawer, client.state(), client.entity(), client.get_tick(),