profiling_demo/
profiling_demo.rs1use std::sync::Arc;
17
18use astrelis_core::logging;
19use astrelis_core::profiling::{init_profiling, new_frame, ProfilingBackend, profile_function, profile_scope};
20use astrelis_render::{
21 Color, GraphicsContext, GraphicsContextDescriptor, RenderTarget, RenderableWindow,
22 WindowContextDescriptor, wgpu,
23};
24use astrelis_winit::{
25 FrameTime, WindowId,
26 app::{App, AppCtx, run_app},
27 event::EventBatch,
28 window::{WinitPhysicalSize, WindowBackend, WindowDescriptor},
29};
30
31struct ProfilingDemo {
32 #[allow(dead_code)]
33 context: Arc<GraphicsContext>,
34 window: RenderableWindow,
35 window_id: WindowId,
36 frame_count: u64,
37}
38
39fn main() {
40 logging::init();
41 init_profiling(ProfilingBackend::PuffinHttp);
42
43 run_app(|ctx| {
44 profile_function!();
45
46 let graphics_ctx = pollster::block_on(GraphicsContext::new_owned_with_descriptor(
48 GraphicsContextDescriptor::new()
49 .request_capability::<astrelis_render::gpu_profiling::GpuFrameProfiler>(),
50 ))
51 .expect("Failed to create graphics context");
52
53 let window = ctx
54 .create_window(WindowDescriptor {
55 title: "Profiling Demo — CPU + GPU".to_string(),
56 size: Some(WinitPhysicalSize::new(800.0, 600.0)),
57 ..Default::default()
58 })
59 .expect("Failed to create window");
60
61 #[allow(unused_mut)]
62 let mut window = RenderableWindow::new_with_descriptor(
63 window,
64 graphics_ctx.clone(),
65 WindowContextDescriptor {
66 format: Some(wgpu::TextureFormat::Bgra8UnormSrgb),
67 ..Default::default()
68 },
69 )
70 .expect("Failed to create renderable window");
71
72 let window_id = window.id();
73
74 let has_gpu_profiling;
76 #[cfg(feature = "gpu-profiling")]
77 {
78 match astrelis_render::gpu_profiling::GpuFrameProfiler::new(&graphics_ctx) {
79 Ok(profiler) => {
80 let has_timestamps = profiler.has_timestamp_queries();
81 window.set_gpu_profiler(Arc::new(profiler));
82 has_gpu_profiling = true;
83 if has_timestamps {
84 println!(" GPU profiling: enabled with TIMESTAMP_QUERY (full timing)");
85 } else {
86 println!(" GPU profiling: enabled (debug groups only, no timing data)");
87 println!(" TIMESTAMP_QUERY not supported by this GPU");
88 }
89 }
90 Err(e) => {
91 has_gpu_profiling = false;
92 tracing::warn!("Failed to create GPU profiler: {e}. GPU profiling disabled.");
93 println!(" GPU profiling: failed to create profiler");
94 }
95 }
96 }
97 #[cfg(not(feature = "gpu-profiling"))]
98 {
99 has_gpu_profiling = false;
100 }
101
102 println!();
103 println!("═══════════════════════════════════════════════════");
104 println!(" PROFILING DEMO — CPU + GPU");
105 println!("═══════════════════════════════════════════════════");
106 println!();
107 println!(" CPU profiling: enabled (puffin)");
108 if !has_gpu_profiling {
109 #[cfg(not(feature = "gpu-profiling"))]
110 println!(" GPU profiling: disabled (compile with --features gpu-profiling)");
111 }
112 println!();
113 println!(" Open puffin_viewer at 127.0.0.1:8585 to see the flame graph.");
114 println!(" Install with: cargo install puffin_viewer");
115 println!("═══════════════════════════════════════════════════");
116 println!();
117
118 Box::new(ProfilingDemo {
119 context: graphics_ctx,
120 window,
121 window_id,
122 frame_count: 0,
123 })
124 });
125}
126
127impl App for ProfilingDemo {
128 fn update(&mut self, _ctx: &mut AppCtx, _time: &FrameTime) {
129 profile_function!();
130
131 {
133 profile_scope!("simulate_game_logic");
134 let mut _sum = 0.0f64;
135 for i in 0..1000 {
136 _sum += (i as f64).sin();
137 }
138 }
139
140 self.frame_count += 1;
141 if self.frame_count % 300 == 0 {
142 tracing::info!("Frame {}", self.frame_count);
143 }
144 }
145
146 fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
147 new_frame();
148 profile_function!();
149
150 if window_id != self.window_id {
151 return;
152 }
153
154 events.dispatch(|event| {
155 if let astrelis_winit::event::Event::WindowResized(size) = event {
156 self.window.resized(*size);
157 astrelis_winit::event::HandleStatus::consumed()
158 } else {
159 astrelis_winit::event::HandleStatus::ignored()
160 }
161 });
162
163 let t = (self.frame_count as f32 * 0.01).sin() * 0.5 + 0.5;
165 let clear_color = Color::rgb(0.05 + t * 0.1, 0.05, 0.15 + (1.0 - t) * 0.1);
166
167 let mut frame = self.window.begin_drawing();
171
172 {
173 profile_scope!("render_frame");
174 frame.clear_and_render(RenderTarget::Surface, clear_color, |_pass| {
175 profile_scope!("draw_commands");
176 });
178 }
179
180 frame.finish();
181
182 {
184 profile_scope!("post_render");
185 let _ = &self.context;
186 }
187 }
188}