mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Add workaround for spans with winit loop, configure filtering when the tracy feature is on, spinkle some spans in the codebase
This commit is contained in:
parent
d95e539495
commit
50ceb1c93e
@ -4,6 +4,7 @@ use crate::{
|
||||
Sticky, Vel,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
span,
|
||||
state::DeltaTime,
|
||||
sync::{Uid, UidAllocator},
|
||||
terrain::{Block, BlockKind, TerrainGrid},
|
||||
@ -94,6 +95,7 @@ impl<'a> System<'a> for Sys {
|
||||
projectiles,
|
||||
): Self::SystemData,
|
||||
) {
|
||||
span!(_guard, "<phys::Sys as System>::run");
|
||||
let mut event_emitter = event_bus.emitter();
|
||||
|
||||
// Add/reset physics state components
|
||||
|
@ -23,7 +23,44 @@ macro_rules! span {
|
||||
let $guard_name = span.enter();
|
||||
};
|
||||
($guard_name:tt, $name:expr) => {
|
||||
let span = tracing::span!(tracing::Level::INFO, $name);
|
||||
let span = tracing::span!(tracing::Level::TRACE, $name);
|
||||
let $guard_name = span.enter();
|
||||
};
|
||||
}
|
||||
|
||||
/// There's no guard, but really this is actually the guard
|
||||
pub struct GuardlessSpan {
|
||||
span: tracing::Span,
|
||||
subscriber: tracing::Dispatch,
|
||||
}
|
||||
|
||||
impl GuardlessSpan {
|
||||
pub fn new(span: tracing::Span) -> Self {
|
||||
let subscriber = tracing::dispatcher::get_default(|d| d.clone());
|
||||
span.id().map(|id| subscriber.enter(&id));
|
||||
Self { span, subscriber }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for GuardlessSpan {
|
||||
fn drop(&mut self) { self.span.id().map(|id| self.subscriber.exit(&id)); }
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! no_guard_span {
|
||||
($level:ident, $name:expr, $($fields:tt)*) => {
|
||||
GuardlessSpan::new(
|
||||
tracing::span!(tracing::Level::$level, $name, $($fields)*)
|
||||
)
|
||||
};
|
||||
($level:ident, $name:expr) => {
|
||||
GuardlessSpan::new(
|
||||
tracing::span!(tracing::Level::$level, $name)
|
||||
)
|
||||
};
|
||||
($name:expr) => {
|
||||
GuardlessSpan::new(
|
||||
tracing::span!(tracing::Level::TRACE, $name)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ use crate::{
|
||||
GlobalState,
|
||||
};
|
||||
use client::Client;
|
||||
use common::{assets::Asset, comp, sync::Uid, terrain::TerrainChunk, vol::RectRasterableVol};
|
||||
use common::{assets::Asset, comp, span, sync::Uid, terrain::TerrainChunk, vol::RectRasterableVol};
|
||||
use conrod_core::{
|
||||
text::cursor::Index,
|
||||
widget::{self, Button, Image, Text},
|
||||
@ -688,6 +688,7 @@ impl Hud {
|
||||
info: HudInfo,
|
||||
camera: &Camera,
|
||||
) -> Vec<Event> {
|
||||
span!(_guard, "Hud::update_layout");
|
||||
let mut events = std::mem::replace(&mut self.events, Vec::new());
|
||||
let (ref mut ui_widgets, ref mut tooltip_manager) = self.ui.set_widgets();
|
||||
// pulse time for pulsating elements
|
||||
@ -2532,6 +2533,7 @@ impl Hud {
|
||||
dt: Duration,
|
||||
info: HudInfo,
|
||||
) -> Vec<Event> {
|
||||
span!(_guard, "Hud::maintain");
|
||||
// conrod eats tabs. Un-eat a tabstop so tab completion can work
|
||||
if self.ui.ui.global_input().events().any(|event| {
|
||||
use conrod_core::{event, input};
|
||||
@ -2576,6 +2578,7 @@ impl Hud {
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer, globals: &Consts<Globals>) {
|
||||
span!(_guard, "Hud::render");
|
||||
// Don't show anything if the UI is toggled off.
|
||||
if self.show.ui {
|
||||
self.ui.render(renderer, Some(globals));
|
||||
|
@ -47,6 +47,7 @@ pub fn init(settings: &Settings) -> Vec<impl Drop> {
|
||||
.add_directive(LevelFilter::INFO.into())
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "tracy"))]
|
||||
let filter = match std::env::var_os(RUST_LOG_ENV).map(|s| s.into_string()) {
|
||||
Some(Ok(env)) => {
|
||||
let mut filter = base_exceptions(EnvFilter::new(""));
|
||||
@ -61,6 +62,13 @@ pub fn init(settings: &Settings) -> Vec<impl Drop> {
|
||||
_ => base_exceptions(EnvFilter::from_env(RUST_LOG_ENV)),
|
||||
};
|
||||
|
||||
#[cfg(feature = "tracy")]
|
||||
let filter = EnvFilter::new("dot_vox::parser=warn")
|
||||
.add_directive("gfx_device_gl=warn".parse().unwrap())
|
||||
.add_directive("uvth=warn".parse().unwrap())
|
||||
.add_directive("tiny_http=warn".parse().unwrap())
|
||||
.add_directive(LevelFilter::TRACE.into());
|
||||
|
||||
// Create the terminal writer layer.
|
||||
let (non_blocking, _stdio_guard) = tracing_appender::non_blocking(std::io::stdout());
|
||||
_guards.push(_stdio_guard);
|
||||
@ -77,13 +85,17 @@ pub fn init(settings: &Settings) -> Vec<impl Drop> {
|
||||
tracing_appender::rolling::daily(&settings.log.logs_path, LOG_FILENAME);
|
||||
let (non_blocking_file, _file_guard) = tracing_appender::non_blocking(file_appender);
|
||||
_guards.push(_file_guard);
|
||||
let subscriber = registry()
|
||||
#[cfg(not(feature = "tracy"))]
|
||||
registry()
|
||||
.with(tracing_subscriber::fmt::layer().with_writer(non_blocking))
|
||||
.with(tracing_subscriber::fmt::layer().with_writer(non_blocking_file))
|
||||
.with(filter);
|
||||
.with(filter)
|
||||
.init();
|
||||
#[cfg(feature = "tracy")]
|
||||
let subscriber = subscriber.with(tracing_tracy::TracyLayer::new());
|
||||
subscriber.init();
|
||||
registry()
|
||||
.with(tracing_tracy::TracyLayer::new())
|
||||
.with(filter)
|
||||
.init();
|
||||
let logdir = &settings.log.logs_path;
|
||||
info!(?logdir, "Setup terminal and file logging.");
|
||||
},
|
||||
@ -93,12 +105,15 @@ pub fn init(settings: &Settings) -> Vec<impl Drop> {
|
||||
?e,
|
||||
"Failed to create log file!. Falling back to terminal logging only.",
|
||||
);
|
||||
let subscriber = registry()
|
||||
#[cfg(not(feature = "tracy"))]
|
||||
registry()
|
||||
.with(tracing_subscriber::fmt::layer().with_writer(non_blocking))
|
||||
.with(filter);
|
||||
#[cfg(feature = "tracy")]
|
||||
let subscriber = subscriber.with(tracing_tracy::TracyLayer::new());
|
||||
subscriber.init();
|
||||
registry()
|
||||
.with(tracing_tracy::TracyLayer::new())
|
||||
.with(filter)
|
||||
.init();
|
||||
info!("Setup terminal logging.");
|
||||
},
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::render::{self, mesh::Quad, ColLightFmt, ColLightInfo, TerrainPipeline};
|
||||
use common::span;
|
||||
use vek::*;
|
||||
|
||||
type TerrainVertex = <TerrainPipeline as render::Pipeline>::Vertex;
|
||||
@ -101,6 +102,7 @@ impl<'a> GreedyMesh<'a> {
|
||||
/// most 30 bits total, meaning we are restricted to "only" at most 2^15
|
||||
/// × 2^15 atlases even if the hardware supports larger ones.
|
||||
pub fn new(max_size: guillotiere::Size) -> Self {
|
||||
span!(_guard, "GreedyMesh::new");
|
||||
let min_max_dim = max_size.width.min(max_size.height);
|
||||
assert!(
|
||||
min_max_dim >= 4,
|
||||
@ -148,6 +150,7 @@ impl<'a> GreedyMesh<'a> {
|
||||
FS: for<'r> FnMut(&'r mut D, Vec3<i32>, Vec3<i32>, Vec2<Vec3<i32>>) -> Option<(bool, M)>,
|
||||
FP: FnMut(Vec2<u16>, Vec2<Vec2<u16>>, Vec3<f32>, Vec2<Vec3<f32>>, Vec3<f32>, &M),
|
||||
{
|
||||
span!(_guard, "GreedyMesh::push");
|
||||
let cont = greedy_mesh(
|
||||
&mut self.atlas,
|
||||
&mut self.col_lights_size,
|
||||
@ -167,6 +170,7 @@ impl<'a> GreedyMesh<'a> {
|
||||
///
|
||||
/// Returns the ColLightsInfo corresponding to the constructed atlas.
|
||||
pub fn finalize(self) -> ColLightInfo {
|
||||
span!(_guard, "GreedyMesh::finalize");
|
||||
let cur_size = self.col_lights_size;
|
||||
let col_lights = vec![
|
||||
TerrainVertex::make_col_light(254, Rgb::broadcast(254));
|
||||
@ -205,6 +209,7 @@ where
|
||||
FS: for<'r> FnMut(&'r mut D, Vec3<i32>, Vec3<i32>, Vec2<Vec3<i32>>) -> Option<(bool, M)>,
|
||||
FP: FnMut(Vec2<u16>, Vec2<Vec2<u16>>, Vec3<f32>, Vec2<Vec3<f32>>, Vec3<f32>, &M),
|
||||
{
|
||||
span!(_guard, "greedy_mesh");
|
||||
// TODO: Collect information to see if we can choose a good value here.
|
||||
let mut todo_rects = Vec::with_capacity(1024);
|
||||
|
||||
@ -367,6 +372,7 @@ fn greedy_mesh_cross_section<M: PartialEq>(
|
||||
// Vertex, width and height, and meta information about the block.
|
||||
mut push_quads: impl FnMut(Vec3<usize>, Vec2<usize>, &M),
|
||||
) {
|
||||
span!(_guard, "greedy_mesh_cross_section");
|
||||
// mask represents which faces are either set while the other is unset, or unset
|
||||
// while the other is set.
|
||||
let mut mask = (0..dims.y * dims.x).map(|_| None).collect::<Vec<_>>();
|
||||
|
@ -6,6 +6,7 @@ use crate::{
|
||||
render::{self, ColLightInfo, FluidPipeline, Mesh, ShadowPipeline, TerrainPipeline},
|
||||
};
|
||||
use common::{
|
||||
span,
|
||||
terrain::{Block, BlockKind},
|
||||
vol::{ReadVol, RectRasterableVol, Vox},
|
||||
volumes::vol_grid_2d::{CachedVolGrid2d, VolGrid2d},
|
||||
@ -47,6 +48,7 @@ fn calc_light<V: RectRasterableVol<Vox = Block> + ReadVol + Debug>(
|
||||
vol: &VolGrid2d<V>,
|
||||
lit_blocks: impl Iterator<Item = (Vec3<i32>, u8)>,
|
||||
) -> impl FnMut(Vec3<i32>) -> f32 + '_ {
|
||||
span!(_guard, "calc_light");
|
||||
const UNKNOWN: u8 = 255;
|
||||
const OPAQUE: u8 = 254;
|
||||
|
||||
@ -240,6 +242,7 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
|
||||
self,
|
||||
(range, max_texture_size): Self::Supplement,
|
||||
) -> MeshGen<TerrainPipeline, FluidPipeline, Self> {
|
||||
span!(_guard, "<&VolGrid2d as Meshable<_, _>::generate_mesh");
|
||||
// Find blocks that should glow
|
||||
// FIXME: Replace with real lit blocks when we actually have blocks that glow.
|
||||
let lit_blocks = core::iter::empty();
|
||||
@ -256,6 +259,7 @@ impl<'a, V: RectRasterableVol<Vox = Block> + ReadVol + Debug>
|
||||
let mut lowest_air = range.size().d;
|
||||
let mut highest_air = 0;
|
||||
let flat_get = {
|
||||
span!(_guard, "copy to flat array");
|
||||
let (w, h, d) = range.size().into_tuple();
|
||||
// z can range from -1..range.size().d + 1
|
||||
let d = d + 2;
|
||||
|
@ -12,7 +12,10 @@ use super::{
|
||||
AaMode, CloudMode, FilterMethod, FluidMode, LightingMode, Pipeline, RenderError, RenderMode,
|
||||
ShadowMapMode, ShadowMode, WrapMode,
|
||||
};
|
||||
use common::assets::{self, watch::ReloadIndicator, Asset};
|
||||
use common::{
|
||||
assets::{self, watch::ReloadIndicator, Asset},
|
||||
span,
|
||||
};
|
||||
use core::convert::TryFrom;
|
||||
use gfx::{
|
||||
self,
|
||||
@ -603,6 +606,7 @@ impl Renderer {
|
||||
/// Queue the clearing of the shadow targets ready for a new frame to be
|
||||
/// rendered.
|
||||
pub fn clear_shadows(&mut self) {
|
||||
span!(_guard, "Renderer::clear_shadows");
|
||||
if !self.mode.shadow.is_map() {
|
||||
return;
|
||||
}
|
||||
@ -675,6 +679,7 @@ impl Renderer {
|
||||
/// Queue the clearing of the depth target ready for a new frame to be
|
||||
/// rendered.
|
||||
pub fn clear(&mut self) {
|
||||
span!(_guard, "Renderer::clear");
|
||||
self.encoder.clear_depth(&self.tgt_depth_stencil_view, 1.0);
|
||||
// self.encoder.clear_stencil(&self.tgt_depth_stencil_view, 0);
|
||||
self.encoder.clear_depth(&self.win_depth_view, 1.0);
|
||||
@ -710,6 +715,7 @@ impl Renderer {
|
||||
/// Perform all queued draw calls for this frame and clean up discarded
|
||||
/// items.
|
||||
pub fn flush(&mut self) {
|
||||
span!(_guard, "Renderer::flush");
|
||||
self.encoder.flush(&mut self.device);
|
||||
self.device.cleanup();
|
||||
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
window::{Event, EventLoop},
|
||||
Direction, GlobalState, PlayState, PlayStateResult,
|
||||
};
|
||||
use common::span;
|
||||
use common::{no_guard_span, span, util::GuardlessSpan};
|
||||
use std::{mem, time::Duration};
|
||||
use tracing::debug;
|
||||
|
||||
@ -23,11 +23,8 @@ pub fn run(mut global_state: GlobalState, event_loop: EventLoop) {
|
||||
// See: https://github.com/rust-windowing/winit/issues/1418
|
||||
let mut polled_twice = false;
|
||||
|
||||
let mut poll_span = None::<tracing::Span>;
|
||||
let mut event_span = None::<tracing::Span>;
|
||||
// Assumes dispatcher does not change
|
||||
let dispatcher = tracing::dispatcher::get_default(|d| d.clone());
|
||||
tracing::info_span!("Process Events");
|
||||
let mut poll_span = None;
|
||||
let mut event_span = None;
|
||||
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
// Continuously run loop since we handle sleeping
|
||||
@ -40,25 +37,15 @@ pub fn run(mut global_state: GlobalState, event_loop: EventLoop) {
|
||||
|
||||
match event {
|
||||
winit::event::Event::NewEvents(_) => {
|
||||
if event_span.is_none() {
|
||||
let span = tracing::info_span!("Proccess Events");
|
||||
span.id().map(|id| dispatcher.enter(&id));
|
||||
event_span = Some(span);
|
||||
}
|
||||
event_span = Some(no_guard_span!("Process Events"));
|
||||
},
|
||||
winit::event::Event::MainEventsCleared => {
|
||||
event_span
|
||||
.take()
|
||||
.map(|s| s.id().map(|id| dispatcher.exit(&id)));
|
||||
poll_span
|
||||
.take()
|
||||
.map(|s| s.id().map(|id| dispatcher.exit(&id)));
|
||||
event_span.take();
|
||||
poll_span.take();
|
||||
if polled_twice {
|
||||
handle_main_events_cleared(&mut states, control_flow, &mut global_state);
|
||||
}
|
||||
let span = tracing::info_span!("Poll Winit");
|
||||
span.id().map(|id| dispatcher.enter(&id));
|
||||
poll_span = Some(span);
|
||||
poll_span = Some(no_guard_span!("Poll Winit"));
|
||||
polled_twice = !polled_twice;
|
||||
},
|
||||
winit::event::Event::WindowEvent { event, .. } => {
|
||||
@ -105,23 +92,12 @@ fn handle_main_events_cleared(
|
||||
let mut exit = true;
|
||||
while let Some(state_result) = states.last_mut().map(|last| {
|
||||
let events = global_state.window.fetch_events();
|
||||
span!(_guard, "Tick current playstate");
|
||||
span!(_guard, "PlayState::tick");
|
||||
last.tick(global_state, events)
|
||||
}) {
|
||||
// Implement state transfer logic.
|
||||
match state_result {
|
||||
PlayStateResult::Continue => {
|
||||
// Wait for the next tick.
|
||||
drop(guard);
|
||||
span!(_guard, "Main thread sleep");
|
||||
global_state.clock.tick(Duration::from_millis(
|
||||
1000 / global_state.settings.graphics.max_fps as u64,
|
||||
));
|
||||
|
||||
span!(_guard, "Maintain global state");
|
||||
// Maintain global state.
|
||||
global_state.maintain(global_state.clock.get_last_delta().as_secs_f32());
|
||||
|
||||
exit = false;
|
||||
break;
|
||||
},
|
||||
@ -168,8 +144,9 @@ fn handle_main_events_cleared(
|
||||
*control_flow = winit::event_loop::ControlFlow::Exit;
|
||||
}
|
||||
|
||||
drop(guard);
|
||||
if let Some(last) = states.last_mut() {
|
||||
span!(_guard, "Render");
|
||||
span!(guard, "Render");
|
||||
let renderer = global_state.window.renderer_mut();
|
||||
// Clear the shadow maps.
|
||||
renderer.clear_shadows();
|
||||
@ -184,5 +161,19 @@ fn handle_main_events_cleared(
|
||||
.window
|
||||
.swap_buffers()
|
||||
.expect("Failed to swap window buffers!");
|
||||
drop(guard);
|
||||
tracing::trace!(tracy.frame_mark = true);
|
||||
}
|
||||
|
||||
if !exit {
|
||||
// Wait for the next tick.
|
||||
span!(_guard, "Main thread sleep");
|
||||
global_state.clock.tick(Duration::from_millis(
|
||||
1000 / global_state.settings.graphics.max_fps as u64,
|
||||
));
|
||||
|
||||
span!(_guard, "Maintain global state");
|
||||
// Maintain global state.
|
||||
global_state.maintain(global_state.clock.get_last_delta().as_secs_f32());
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
use common::vol::{ReadVol, Vox};
|
||||
use common::{
|
||||
span,
|
||||
vol::{ReadVol, Vox},
|
||||
};
|
||||
use std::f32::consts::PI;
|
||||
use treeculler::Frustum;
|
||||
use vek::*;
|
||||
@ -78,6 +81,7 @@ impl Camera {
|
||||
/// Compute the transformation matrices (view matrix and projection matrix)
|
||||
/// and position of the camera.
|
||||
pub fn compute_dependents(&mut self, terrain: &impl ReadVol) {
|
||||
span!(_guard, "Camera::compute_dependents");
|
||||
let dist = {
|
||||
let (start, end) = (self.focus - self.forward() * self.dist, self.focus);
|
||||
|
||||
|
@ -28,6 +28,7 @@ use common::{
|
||||
item::ItemKind, Body, CharacterState, Item, Last, LightAnimation, LightEmitter, Loadout,
|
||||
Ori, PhysicsState, Pos, Scale, Stats, Vel,
|
||||
},
|
||||
span,
|
||||
state::{DeltaTime, State},
|
||||
states::triple_strike,
|
||||
terrain::TerrainChunk,
|
||||
@ -195,6 +196,7 @@ impl FigureMgrStates {
|
||||
}
|
||||
|
||||
fn retain(&mut self, mut f: impl FnMut(&EcsEntity, &mut FigureStateMeta) -> bool) {
|
||||
span!(_guard, "FigureManagerStates::retain");
|
||||
self.character_states.retain(|k, v| f(k, &mut *v));
|
||||
self.quadruped_small_states.retain(|k, v| f(k, &mut *v));
|
||||
self.quadruped_medium_states.retain(|k, v| f(k, &mut *v));
|
||||
@ -337,6 +339,7 @@ impl FigureMgr {
|
||||
pub fn col_lights(&self) -> &FigureColLights { &self.col_lights }
|
||||
|
||||
pub fn clean(&mut self, tick: u64) {
|
||||
span!(_guard, "FigureManager::clean");
|
||||
self.model_cache.clean(&mut self.col_lights, tick);
|
||||
self.critter_model_cache.clean(&mut self.col_lights, tick);
|
||||
self.quadruped_small_model_cache
|
||||
@ -363,6 +366,7 @@ impl FigureMgr {
|
||||
#[allow(clippy::redundant_pattern_matching)]
|
||||
// TODO: Pending review in #587
|
||||
pub fn update_lighting(&mut self, scene_data: &SceneData) {
|
||||
span!(_guard, "FigureManager::update_lighting");
|
||||
let ecs = scene_data.state.ecs();
|
||||
for (entity, body, light_emitter) in (
|
||||
&ecs.entities(),
|
||||
@ -451,6 +455,7 @@ impl FigureMgr {
|
||||
visible_psr_bounds: math::Aabr<f32>,
|
||||
camera: &Camera,
|
||||
) -> anim::vek::Aabb<f32> {
|
||||
span!(_guard, "FigureManager::maintain");
|
||||
let state = scene_data.state;
|
||||
let time = state.get_time();
|
||||
let tick = scene_data.tick;
|
||||
@ -2130,6 +2135,7 @@ impl FigureMgr {
|
||||
(is_daylight, _light_data): super::LightData,
|
||||
(camera, figure_lod_render_distance): CameraData,
|
||||
) {
|
||||
span!(_guard, "FigureManager::render_shadows");
|
||||
let ecs = state.ecs();
|
||||
|
||||
if is_daylight && renderer.render_mode().shadow.is_map() {
|
||||
@ -2181,6 +2187,7 @@ impl FigureMgr {
|
||||
lod: &LodData,
|
||||
(camera, figure_lod_render_distance): CameraData,
|
||||
) {
|
||||
span!(_guard, "FigureManager::render");
|
||||
let ecs = state.ecs();
|
||||
|
||||
let character_state_storage = state.read_storage::<common::comp::CharacterState>();
|
||||
@ -2231,6 +2238,7 @@ impl FigureMgr {
|
||||
lod: &LodData,
|
||||
(camera, figure_lod_render_distance): CameraData,
|
||||
) {
|
||||
span!(_guard, "FigureManager::render_player");
|
||||
let ecs = state.ecs();
|
||||
|
||||
let character_state_storage = state.read_storage::<common::comp::CharacterState>();
|
||||
@ -2614,6 +2622,7 @@ impl FigureColLights {
|
||||
(opaque, bounds): (Mesh<TerrainPipeline>, math::Aabb<f32>),
|
||||
vertex_range: [Range<u32>; N],
|
||||
) -> Result<FigureModelEntry<N>, RenderError> {
|
||||
span!(_guard, "FigureColLights::create_figure");
|
||||
let atlas = &mut self.atlas;
|
||||
let allocation = atlas
|
||||
.allocate(guillotiere::Size::new(
|
||||
|
@ -28,6 +28,7 @@ use client::Client;
|
||||
use common::{
|
||||
comp,
|
||||
outcome::Outcome,
|
||||
span,
|
||||
state::{DeltaTime, State},
|
||||
terrain::{BlockKind, TerrainChunk},
|
||||
vol::ReadVol,
|
||||
@ -379,6 +380,7 @@ impl Scene {
|
||||
scene_data: &SceneData,
|
||||
audio: &mut AudioFrontend,
|
||||
) {
|
||||
span!(_guard, "Scene::handle_outcome");
|
||||
self.particle_mgr.handle_outcome(&outcome, &scene_data);
|
||||
self.sfx_mgr.handle_outcome(&outcome, audio);
|
||||
|
||||
@ -422,6 +424,7 @@ impl Scene {
|
||||
audio: &mut AudioFrontend,
|
||||
scene_data: &SceneData,
|
||||
) {
|
||||
span!(_guard, "Scene::maintain");
|
||||
// Get player position.
|
||||
let ecs = scene_data.state.ecs();
|
||||
|
||||
@ -973,6 +976,7 @@ impl Scene {
|
||||
tick: u64,
|
||||
scene_data: &SceneData,
|
||||
) {
|
||||
span!(_guard, "Scene::render");
|
||||
let sun_dir = scene_data.get_sun_dir();
|
||||
let is_daylight = sun_dir.z < 0.0;
|
||||
let focus_pos = self.camera.get_focus_pos();
|
||||
|
@ -11,6 +11,7 @@ use common::{
|
||||
comp::{item::Reagent, object, Body, CharacterState, Pos},
|
||||
figure::Segment,
|
||||
outcome::Outcome,
|
||||
span,
|
||||
spiral::Spiral2d,
|
||||
state::DeltaTime,
|
||||
terrain::TerrainChunk,
|
||||
@ -48,6 +49,7 @@ impl ParticleMgr {
|
||||
}
|
||||
|
||||
pub fn handle_outcome(&mut self, outcome: &Outcome, scene_data: &SceneData) {
|
||||
span!(_guard, "ParticleMgr::handle_outcome");
|
||||
let time = scene_data.state.get_time();
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
@ -98,6 +100,7 @@ impl ParticleMgr {
|
||||
scene_data: &SceneData,
|
||||
terrain: &Terrain<TerrainChunk>,
|
||||
) {
|
||||
span!(_guard, "ParticleMgr::maintain");
|
||||
if scene_data.particles_enabled {
|
||||
// update timings
|
||||
self.scheduler.maintain(scene_data.state.get_time());
|
||||
@ -122,6 +125,7 @@ impl ParticleMgr {
|
||||
}
|
||||
|
||||
fn maintain_body_particles(&mut self, scene_data: &SceneData) {
|
||||
span!(_guard, "ParticleMgr::maintain_body_particles");
|
||||
let ecs = scene_data.state.ecs();
|
||||
for (body, pos) in (&ecs.read_storage::<Body>(), &ecs.read_storage::<Pos>()).join() {
|
||||
match body {
|
||||
@ -148,6 +152,7 @@ impl ParticleMgr {
|
||||
}
|
||||
|
||||
fn maintain_campfirelit_particles(&mut self, scene_data: &SceneData, pos: &Pos) {
|
||||
span!(_guard, "ParticleMgr::maintain_campfirelit_particles");
|
||||
let time = scene_data.state.get_time();
|
||||
|
||||
for _ in 0..self.scheduler.heartbeats(Duration::from_millis(10)) {
|
||||
@ -168,6 +173,7 @@ impl ParticleMgr {
|
||||
}
|
||||
|
||||
fn maintain_boltfire_particles(&mut self, scene_data: &SceneData, pos: &Pos) {
|
||||
span!(_guard, "ParticleMgr::maintain_boltfire_particles");
|
||||
let time = scene_data.state.get_time();
|
||||
|
||||
for _ in 0..self.scheduler.heartbeats(Duration::from_millis(10)) {
|
||||
@ -187,6 +193,7 @@ impl ParticleMgr {
|
||||
}
|
||||
|
||||
fn maintain_boltfirebig_particles(&mut self, scene_data: &SceneData, pos: &Pos) {
|
||||
span!(_guard, "ParticleMgr::maintain_boltfirebig_particles");
|
||||
let time = scene_data.state.get_time();
|
||||
|
||||
// fire
|
||||
@ -217,6 +224,7 @@ impl ParticleMgr {
|
||||
}
|
||||
|
||||
fn maintain_bomb_particles(&mut self, scene_data: &SceneData, pos: &Pos) {
|
||||
span!(_guard, "ParticleMgr::maintain_bomb_particles");
|
||||
let time = scene_data.state.get_time();
|
||||
|
||||
for _ in 0..self.scheduler.heartbeats(Duration::from_millis(10)) {
|
||||
@ -239,6 +247,7 @@ impl ParticleMgr {
|
||||
}
|
||||
|
||||
fn maintain_boost_particles(&mut self, scene_data: &SceneData) {
|
||||
span!(_guard, "ParticleMgr::maintain_boost_particles");
|
||||
let state = scene_data.state;
|
||||
let ecs = state.ecs();
|
||||
let time = state.get_time();
|
||||
@ -272,6 +281,7 @@ impl ParticleMgr {
|
||||
scene_data: &SceneData,
|
||||
terrain: &Terrain<TerrainChunk>,
|
||||
) {
|
||||
span!(_guard, "ParticleMgr::maintain_block_particles");
|
||||
let dt = scene_data.state.ecs().fetch::<DeltaTime>().0;
|
||||
let time = scene_data.state.get_time();
|
||||
let player_pos = scene_data
|
||||
@ -383,6 +393,7 @@ impl ParticleMgr {
|
||||
}
|
||||
|
||||
fn upload_particles(&mut self, renderer: &mut Renderer) {
|
||||
span!(_guard, "ParticleMgr::upload_particles");
|
||||
let all_cpu_instances = self
|
||||
.particles
|
||||
.iter()
|
||||
@ -404,6 +415,7 @@ impl ParticleMgr {
|
||||
global: &GlobalModel,
|
||||
lod: &LodData,
|
||||
) {
|
||||
span!(_guard, "ParticleMgr::render");
|
||||
if scene_data.particles_enabled {
|
||||
let model = &self
|
||||
.model_cache
|
||||
@ -489,6 +501,7 @@ impl HeartbeatScheduler {
|
||||
/// updates the last elapsed times and elapsed counts
|
||||
/// this should be called once, and only once per tick.
|
||||
pub fn maintain(&mut self, now: f64) {
|
||||
span!(_guard, "HeartbeatScheduler::maintain");
|
||||
self.last_known_time = now;
|
||||
|
||||
for (frequency, (last_update, heartbeats)) in self.timers.iter_mut() {
|
||||
@ -520,6 +533,7 @@ impl HeartbeatScheduler {
|
||||
/// - if it's equal to the tick rate, it could be between 2 and 0, due to
|
||||
/// delta time variance.
|
||||
pub fn heartbeats(&mut self, frequency: Duration) -> u8 {
|
||||
span!(_guard, "HeartbeatScheduler::heartbeats");
|
||||
let last_known_time = self.last_known_time;
|
||||
|
||||
self.timers
|
||||
|
@ -15,6 +15,7 @@ use super::{math, LodData, SceneData};
|
||||
use common::{
|
||||
assets::{Asset, Ron},
|
||||
figure::Segment,
|
||||
span,
|
||||
spiral::Spiral2d,
|
||||
terrain::{block, Block, BlockKind, TerrainChunk},
|
||||
vol::{BaseVol, ReadVol, RectRasterableVol, SampleVol, Vox},
|
||||
@ -124,6 +125,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
|
||||
sprite_data: &HashMap<(BlockKind, usize), Vec<SpriteData>>,
|
||||
sprite_config: &SpriteSpec,
|
||||
) -> MeshWorkerResponse {
|
||||
span!(_guard, "mesh_worker");
|
||||
let (opaque_mesh, fluid_mesh, _shadow_mesh, (bounds, col_lights_info)) =
|
||||
volume.generate_mesh((range, Vec2::new(max_texture_size, max_texture_size)));
|
||||
MeshWorkerResponse {
|
||||
@ -134,6 +136,7 @@ fn mesh_worker<V: BaseVol<Vox = Block> + RectRasterableVol + ReadVol + Debug>(
|
||||
col_lights_info,
|
||||
// Extract sprite locations from volume
|
||||
sprite_instances: {
|
||||
span!(_guard, "extract sprite_instances");
|
||||
let mut instances = HashMap::new();
|
||||
|
||||
for x in 0..V::RECT_SIZE.x as i32 {
|
||||
@ -382,6 +385,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
fn make_atlas(
|
||||
renderer: &mut Renderer,
|
||||
) -> Result<(AtlasAllocator, Texture<ColLightFmt>), RenderError> {
|
||||
span!(_guard, "Terrain::make_atlas");
|
||||
let max_texture_size = renderer.max_texture_size();
|
||||
let atlas_size =
|
||||
guillotiere::Size::new(i32::from(max_texture_size), i32::from(max_texture_size));
|
||||
@ -449,12 +453,14 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
view_mat: Mat4<f32>,
|
||||
proj_mat: Mat4<f32>,
|
||||
) -> (Aabb<f32>, Vec<math::Vec3<f32>>, math::Aabr<f32>) {
|
||||
span!(_guard, "Terrain::maintain");
|
||||
let current_tick = scene_data.tick;
|
||||
let current_time = scene_data.state.get_time();
|
||||
let mut visible_bounding_box: Option<Aabb<f32>> = None;
|
||||
|
||||
// Add any recently created or changed chunks to the list of chunks to be
|
||||
// meshed.
|
||||
span!(guard, "Add new/modified chunks to mesh todo list");
|
||||
for (modified, pos) in scene_data
|
||||
.state
|
||||
.terrain_changes()
|
||||
@ -501,9 +507,12 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(guard);
|
||||
|
||||
// Add the chunks belonging to recently changed blocks to the list of chunks to
|
||||
// be meshed
|
||||
span!(guard, "Add chunks with modified blocks to mesh todo list");
|
||||
// TODO: would be useful if modified blocks were grouped by chunk
|
||||
for pos in scene_data
|
||||
.state
|
||||
.terrain_changes()
|
||||
@ -542,6 +551,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(guard);
|
||||
|
||||
// Remove any models for chunks that have been recently removed.
|
||||
for &pos in &scene_data.state.terrain_changes().removed_chunks {
|
||||
@ -551,6 +561,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
// Limit ourselves to u16::MAX even if larger textures are supported.
|
||||
let max_texture_size = renderer.max_texture_size();
|
||||
|
||||
span!(guard, "Queue meshing from todo list");
|
||||
for (todo, chunk) in self
|
||||
.mesh_todo
|
||||
.values_mut()
|
||||
@ -637,11 +648,13 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
});
|
||||
todo.active_worker = Some(todo.started_tick);
|
||||
}
|
||||
drop(guard);
|
||||
|
||||
// Receive a chunk mesh from a worker thread and upload it to the GPU, then
|
||||
// store it. Only pull out one chunk per frame to avoid an unacceptable
|
||||
// amount of blocking lag due to the GPU upload. That still gives us a
|
||||
// 60 chunks / second budget to play with.
|
||||
span!(guard, "Get/upload meshed chunk");
|
||||
if let Ok(response) = self.mesh_recv.recv_timeout(Duration::new(0, 0)) {
|
||||
match self.mesh_todo.get(&response.pos) {
|
||||
// It's the mesh we want, insert the newly finished model into the terrain model
|
||||
@ -739,14 +752,18 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
None => {},
|
||||
}
|
||||
}
|
||||
drop(guard);
|
||||
|
||||
// Construct view frustum
|
||||
span!(guard, "Construct view frustum");
|
||||
let focus_off = focus_pos.map(|e| e.trunc());
|
||||
let frustum = Frustum::from_modelview_projection(
|
||||
(proj_mat * view_mat * Mat4::translation_3d(-focus_off)).into_col_arrays(),
|
||||
);
|
||||
drop(guard);
|
||||
|
||||
// Update chunk visibility
|
||||
span!(guard, "Update chunk visibility");
|
||||
let chunk_sz = V::RECT_SIZE.x as f32;
|
||||
for (pos, chunk) in &mut self.chunks {
|
||||
let chunk_pos = pos.as_::<f32>() * chunk_sz;
|
||||
@ -796,7 +813,9 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
// (and hardcodes the shadow distance). Should ideally exist per-light, too.
|
||||
chunk.can_shadow_point = distance_2 < (128.0 * 128.0);
|
||||
}
|
||||
drop(guard);
|
||||
|
||||
span!(guard, "Shadow magic");
|
||||
// PSRs: potential shadow receivers
|
||||
let visible_bounding_box = visible_bounding_box.unwrap_or(Aabb {
|
||||
min: focus_pos - 2.0,
|
||||
@ -901,6 +920,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
max: math::Vec2::zero(),
|
||||
})
|
||||
};
|
||||
drop(guard);
|
||||
|
||||
(
|
||||
visible_bounding_box,
|
||||
@ -931,6 +951,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
(is_daylight, light_data): super::LightData,
|
||||
focus_pos: Vec3<f32>,
|
||||
) {
|
||||
span!(_guard, "Terrain::render_shadows");
|
||||
if !renderer.render_mode().shadow.is_map() {
|
||||
return;
|
||||
};
|
||||
@ -992,6 +1013,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
lod: &LodData,
|
||||
focus_pos: Vec3<f32>,
|
||||
) {
|
||||
span!(_guard, "Terrain::render");
|
||||
let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| {
|
||||
(e as i32).div_euclid(sz as i32)
|
||||
});
|
||||
@ -1025,6 +1047,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
cam_pos: Vec3<f32>,
|
||||
sprite_render_distance: f32,
|
||||
) {
|
||||
span!(_guard, "Terrain::render_translucent");
|
||||
let focus_chunk = Vec2::from(focus_pos).map2(TerrainChunk::RECT_SIZE, |e: f32, sz| {
|
||||
(e as i32).div_euclid(sz as i32)
|
||||
});
|
||||
@ -1038,6 +1061,8 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
.take(self.chunks.len());
|
||||
|
||||
// Terrain sprites
|
||||
// TODO: move to separate functions
|
||||
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() {
|
||||
@ -1096,6 +1121,7 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(guard);
|
||||
|
||||
// Translucent
|
||||
chunk_iter
|
||||
|
@ -1,4 +1,5 @@
|
||||
use common::{
|
||||
span,
|
||||
terrain::{BlockKind, TerrainChunk},
|
||||
vol::{IntoVolIterator, RectRasterableVol},
|
||||
};
|
||||
@ -16,6 +17,7 @@ pub struct BlocksOfInterest {
|
||||
|
||||
impl BlocksOfInterest {
|
||||
pub fn from_chunk(chunk: &TerrainChunk) -> Self {
|
||||
span!(_guard, "BlocksOfInterest::from_chunk");
|
||||
let mut leaves = Vec::new();
|
||||
let mut grass = Vec::new();
|
||||
let mut embers = Vec::new();
|
||||
|
@ -22,6 +22,7 @@ use common::{
|
||||
event::EventBus,
|
||||
msg::ClientState,
|
||||
outcome::Outcome,
|
||||
span,
|
||||
terrain::{Block, BlockKind},
|
||||
util::Dir,
|
||||
vol::ReadVol,
|
||||
@ -111,6 +112,7 @@ impl SessionState {
|
||||
global_state: &mut GlobalState,
|
||||
outcomes: &mut Vec<Outcome>,
|
||||
) -> Result<TickAction, Error> {
|
||||
span!(_guard, "Session::tick");
|
||||
self.inputs.tick(dt);
|
||||
|
||||
let mut client = self.client.borrow_mut();
|
||||
@ -195,6 +197,7 @@ impl PlayState for SessionState {
|
||||
}
|
||||
|
||||
fn tick(&mut self, global_state: &mut GlobalState, events: Vec<Event>) -> PlayStateResult {
|
||||
span!(_guard, "<Session as PlayState>::tick");
|
||||
// NOTE: Not strictly necessary, but useful for hotloading translation changes.
|
||||
self.voxygen_i18n = VoxygenLocalization::load_expect(&i18n_asset_key(
|
||||
&global_state.settings.language.selected_language,
|
||||
@ -1113,6 +1116,7 @@ impl PlayState for SessionState {
|
||||
///
|
||||
/// This method should be called once per frame.
|
||||
fn render(&mut self, renderer: &mut Renderer, settings: &Settings) {
|
||||
span!(_guard, "<Session as PlayState>::render");
|
||||
// Render the screen using the global renderer
|
||||
{
|
||||
let client = self.client.borrow();
|
||||
|
@ -32,7 +32,7 @@ use crate::{
|
||||
#[rustfmt::skip]
|
||||
use ::image::GenericImageView;
|
||||
use cache::Cache;
|
||||
use common::{assets, util::srgba_to_linear};
|
||||
use common::{assets, span, util::srgba_to_linear};
|
||||
use conrod_core::{
|
||||
event::Input,
|
||||
graph::{self, Graph},
|
||||
@ -292,6 +292,7 @@ impl Ui {
|
||||
|
||||
#[allow(clippy::float_cmp)] // TODO: Pending review in #587
|
||||
pub fn maintain(&mut self, renderer: &mut Renderer, view_projection_mat: Option<Mat4<f32>>) {
|
||||
span!(_guard, "Ui::maintain");
|
||||
// Maintain tooltip manager
|
||||
self.tooltip_manager
|
||||
.maintain(self.ui.global_input(), self.scale.scale_factor_logical());
|
||||
@ -333,6 +334,7 @@ impl Ui {
|
||||
view_projection_mat: Option<Mat4<f32>>,
|
||||
retry: &mut bool,
|
||||
) {
|
||||
span!(_guard, "Ui::maintain_internal");
|
||||
let (graphic_cache, text_cache, glyph_cache, cache_tex) = self.cache.cache_mut_and_tex();
|
||||
|
||||
let mut primitives = if *retry {
|
||||
@ -977,6 +979,7 @@ impl Ui {
|
||||
}
|
||||
|
||||
pub fn render(&self, renderer: &mut Renderer, maybe_globals: Option<&Consts<Globals>>) {
|
||||
span!(_guard, "Ui::render");
|
||||
let mut scissor = default_scissor(renderer);
|
||||
let globals = maybe_globals.unwrap_or(&self.default_globals);
|
||||
let mut locals = &self.interface_locals;
|
||||
|
@ -4,6 +4,7 @@ use crate::{
|
||||
settings::{ControlSettings, Settings},
|
||||
ui, Error,
|
||||
};
|
||||
use common::span;
|
||||
use crossbeam::channel;
|
||||
use gilrs::{EventType, Gilrs};
|
||||
use hashbrown::HashMap;
|
||||
@ -1048,6 +1049,7 @@ impl Window {
|
||||
}
|
||||
|
||||
pub fn swap_buffers(&self) -> Result<(), Error> {
|
||||
span!(_guard, "Window::swap_buffers");
|
||||
self.window
|
||||
.swap_buffers()
|
||||
.map_err(|err| Error::BackendError(Box::new(err)))
|
||||
|
Loading…
Reference in New Issue
Block a user