use bevy::prelude::*;
use noesis_runtime::diagnostics;
#[derive(Resource, Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct NoesisDiagnostics {
pub allocated_memory: u32,
pub allocated_memory_accum: u32,
pub allocations_count: u32,
pub ffi_hops: u64,
pub live_scenes: usize,
pub live_panels: usize,
pub live_lists: usize,
pub apply_time: std::time::Duration,
}
pub struct NoesisDiagnosticsPlugin {
pub route_errors: bool,
}
impl Default for NoesisDiagnosticsPlugin {
fn default() -> Self {
Self { route_errors: true }
}
}
impl Plugin for NoesisDiagnosticsPlugin {
fn build(&self, app: &mut App) {
app.init_resource::<NoesisDiagnostics>();
app.add_systems(Update, refresh_diagnostics);
if self.route_errors {
install_error_routing();
}
}
}
fn install_error_routing() {
let guard = diagnostics::set_error_handler(|file, line, message, fatal| {
if fatal {
error!(target: "noesis", "{file}:{line}: {message}");
} else {
warn!(target: "noesis", "{file}:{line}: {message}");
}
});
std::mem::forget(guard);
}
#[allow(clippy::needless_pass_by_value)]
fn refresh_diagnostics(
mut diag: ResMut<NoesisDiagnostics>,
state: Option<NonSend<crate::render::NoesisRenderState>>,
timer: Option<Res<crate::render::NoesisApplyTimer>>,
) {
let next = NoesisDiagnostics {
allocated_memory: diagnostics::allocated_memory(),
allocated_memory_accum: diagnostics::allocated_memory_accum(),
allocations_count: diagnostics::allocations_count(),
ffi_hops: crate::render::ffi_hops(),
live_scenes: state.as_ref().map_or(0, |s| s.live_scene_count()),
live_panels: state.as_ref().map_or(0, |s| s.live_panel_count()),
live_lists: state.as_ref().map_or(0, |s| s.live_list_count()),
apply_time: timer.as_ref().map_or(std::time::Duration::ZERO, |t| t.last),
};
diag.set_if_neq(next);
}