bevy_render/diagnostic/
mod.rs1mod erased_render_asset_diagnostic_plugin;
6pub(crate) mod internal;
7mod mesh_allocator_diagnostic_plugin;
8mod render_asset_diagnostic_plugin;
9#[cfg(feature = "tracing-tracy")]
10mod tracy_gpu;
11
12use alloc::{borrow::Cow, sync::Arc};
13use core::marker::PhantomData;
14
15use bevy_app::{App, Plugin, PreUpdate};
16
17use crate::{renderer::RenderAdapterInfo, RenderApp};
18
19use self::internal::{
20 sync_diagnostics, DiagnosticsRecorder, Pass, RenderDiagnosticsMutex, WriteTimestamp,
21};
22pub use self::{
23 erased_render_asset_diagnostic_plugin::ErasedRenderAssetDiagnosticPlugin,
24 mesh_allocator_diagnostic_plugin::MeshAllocatorDiagnosticPlugin,
25 render_asset_diagnostic_plugin::RenderAssetDiagnosticPlugin,
26};
27
28use crate::renderer::{RenderDevice, RenderQueue};
29
30#[derive(Default)]
57pub struct RenderDiagnosticsPlugin;
58
59impl Plugin for RenderDiagnosticsPlugin {
60 fn build(&self, app: &mut App) {
61 let render_diagnostics_mutex = RenderDiagnosticsMutex::default();
62 app.insert_resource(render_diagnostics_mutex.clone())
63 .add_systems(PreUpdate, sync_diagnostics);
64
65 if let Some(render_app) = app.get_sub_app_mut(RenderApp) {
66 render_app.insert_resource(render_diagnostics_mutex);
67 }
68 }
69
70 fn finish(&self, app: &mut App) {
71 let Some(render_app) = app.get_sub_app_mut(RenderApp) else {
72 return;
73 };
74
75 let adapter_info = render_app.world().resource::<RenderAdapterInfo>();
76 let device = render_app.world().resource::<RenderDevice>();
77 let queue = render_app.world().resource::<RenderQueue>();
78 render_app.insert_resource(DiagnosticsRecorder::new(adapter_info, device, queue));
79 }
80}
81
82pub trait RecordDiagnostics: Send + Sync {
84 fn time_span<E, N>(&self, encoder: &mut E, name: N) -> TimeSpanGuard<'_, Self, E>
88 where
89 E: WriteTimestamp,
90 N: Into<Cow<'static, str>>,
91 {
92 self.begin_time_span(encoder, name.into());
93 TimeSpanGuard {
94 recorder: self,
95 marker: PhantomData,
96 }
97 }
98
99 fn pass_span<P, N>(&self, pass: &mut P, name: N) -> PassSpanGuard<'_, Self, P>
104 where
105 P: Pass,
106 N: Into<Cow<'static, str>>,
107 {
108 let name = name.into();
109 self.begin_pass_span(pass, name.clone());
110 PassSpanGuard {
111 recorder: self,
112 name,
113 marker: PhantomData,
114 }
115 }
116
117 #[doc(hidden)]
118 fn begin_time_span<E: WriteTimestamp>(&self, encoder: &mut E, name: Cow<'static, str>);
119
120 #[doc(hidden)]
121 fn end_time_span<E: WriteTimestamp>(&self, encoder: &mut E);
122
123 #[doc(hidden)]
124 fn begin_pass_span<P: Pass>(&self, pass: &mut P, name: Cow<'static, str>);
125
126 #[doc(hidden)]
127 fn end_pass_span<P: Pass>(&self, pass: &mut P);
128}
129
130pub struct TimeSpanGuard<'a, R: ?Sized, E> {
134 recorder: &'a R,
135 marker: PhantomData<E>,
136}
137
138impl<R: RecordDiagnostics + ?Sized, E: WriteTimestamp> TimeSpanGuard<'_, R, E> {
139 pub fn end(self, encoder: &mut E) {
141 self.recorder.end_time_span(encoder);
142 core::mem::forget(self);
143 }
144}
145
146impl<R: ?Sized, E> Drop for TimeSpanGuard<'_, R, E> {
147 fn drop(&mut self) {
148 panic!("TimeSpanScope::end was never called")
149 }
150}
151
152pub struct PassSpanGuard<'a, R: ?Sized, P> {
156 recorder: &'a R,
157 name: Cow<'static, str>,
158 marker: PhantomData<P>,
159}
160
161impl<R: RecordDiagnostics + ?Sized, P: Pass> PassSpanGuard<'_, R, P> {
162 pub fn end(self, pass: &mut P) {
164 self.recorder.end_pass_span(pass);
165 core::mem::forget(self);
166 }
167}
168
169impl<R: ?Sized, P> Drop for PassSpanGuard<'_, R, P> {
170 fn drop(&mut self) {
171 panic!("PassSpanGuard::end was never called for {}", self.name)
172 }
173}
174
175impl<T: RecordDiagnostics> RecordDiagnostics for Option<Arc<T>> {
176 fn begin_time_span<E: WriteTimestamp>(&self, encoder: &mut E, name: Cow<'static, str>) {
177 if let Some(recorder) = &self {
178 recorder.begin_time_span(encoder, name);
179 }
180 }
181
182 fn end_time_span<E: WriteTimestamp>(&self, encoder: &mut E) {
183 if let Some(recorder) = &self {
184 recorder.end_time_span(encoder);
185 }
186 }
187
188 fn begin_pass_span<P: Pass>(&self, pass: &mut P, name: Cow<'static, str>) {
189 if let Some(recorder) = &self {
190 recorder.begin_pass_span(pass, name);
191 }
192 }
193
194 fn end_pass_span<P: Pass>(&self, pass: &mut P) {
195 if let Some(recorder) = &self {
196 recorder.end_pass_span(pass);
197 }
198 }
199}