bevy_render/diagnostic/
erased_render_asset_diagnostic_plugin.rs

1use core::{any::type_name, marker::PhantomData};
2
3use bevy_app::{Plugin, PreUpdate};
4use bevy_diagnostic::{Diagnostic, DiagnosticPath, Diagnostics, RegisterDiagnostic};
5use bevy_ecs::{resource::Resource, system::Res};
6use bevy_platform::sync::atomic::{AtomicUsize, Ordering};
7
8use crate::{
9    erased_render_asset::{ErasedRenderAsset, ErasedRenderAssets},
10    Extract, ExtractSchedule, RenderApp,
11};
12
13/// Collects diagnostics for a [`ErasedRenderAsset`].
14///
15/// If the [`ErasedRenderAsset::ErasedAsset`] is shared between other
16/// [`ErasedRenderAsset`], they all will report the same number.
17pub struct ErasedRenderAssetDiagnosticPlugin<A: ErasedRenderAsset> {
18    suffix: &'static str,
19    _phantom: PhantomData<A>,
20}
21
22impl<A: ErasedRenderAsset> ErasedRenderAssetDiagnosticPlugin<A> {
23    pub fn new(suffix: &'static str) -> Self {
24        Self {
25            suffix,
26            _phantom: PhantomData,
27        }
28    }
29
30    pub fn render_asset_diagnostic_path() -> DiagnosticPath {
31        DiagnosticPath::from_components(["erased_render_asset", type_name::<A>()])
32    }
33}
34
35impl<A: ErasedRenderAsset> Plugin for ErasedRenderAssetDiagnosticPlugin<A> {
36    fn build(&self, app: &mut bevy_app::App) {
37        app.register_diagnostic(
38            Diagnostic::new(Self::render_asset_diagnostic_path()).with_suffix(self.suffix),
39        )
40        .init_resource::<ErasedRenderAssetMeasurements<A>>()
41        .add_systems(PreUpdate, add_erased_render_asset_measurement::<A>);
42
43        if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
44            render_app.add_systems(ExtractSchedule, measure_erased_render_asset::<A>);
45        }
46    }
47}
48
49#[derive(Debug, Resource)]
50struct ErasedRenderAssetMeasurements<A: ErasedRenderAsset> {
51    assets: AtomicUsize,
52    _phantom: PhantomData<A>,
53}
54
55impl<A: ErasedRenderAsset> Default for ErasedRenderAssetMeasurements<A> {
56    fn default() -> Self {
57        Self {
58            assets: AtomicUsize::default(),
59            _phantom: PhantomData,
60        }
61    }
62}
63
64fn add_erased_render_asset_measurement<A: ErasedRenderAsset>(
65    mut diagnostics: Diagnostics,
66    measurements: Res<ErasedRenderAssetMeasurements<A>>,
67) {
68    diagnostics.add_measurement(
69        &ErasedRenderAssetDiagnosticPlugin::<A>::render_asset_diagnostic_path(),
70        || measurements.assets.load(Ordering::Relaxed) as f64,
71    );
72}
73
74fn measure_erased_render_asset<A: ErasedRenderAsset>(
75    measurements: Extract<Res<ErasedRenderAssetMeasurements<A>>>,
76    assets: Res<ErasedRenderAssets<A::ErasedAsset>>,
77) {
78    measurements
79        .assets
80        .store(assets.iter().count(), Ordering::Relaxed);
81}