use astrelis_core::logging;
use astrelis_render::{Color, GraphicsContext, RenderWindow, RenderWindowBuilder, wgpu};
use astrelis_winit::{
FrameTime, WindowId,
app::{App, AppCtx, run_app},
event::{Event, EventBatch, HandleStatus, Key, NamedKey},
window::{WindowDescriptor, WinitPhysicalSize},
};
use std::sync::Arc;
use std::time::Instant;
struct PerformanceBenchmark {
_context: Arc<GraphicsContext>,
window: RenderWindow,
window_id: WindowId,
object_count: usize,
rendering: bool,
frame_count: u64,
last_fps_time: Instant,
fps: f32,
last_frame_time: f32,
}
fn main() {
logging::init();
run_app(|ctx| {
let graphics_ctx =
GraphicsContext::new_owned_sync().expect("Failed to create graphics context");
let window = ctx
.create_window(WindowDescriptor {
title: "Performance Benchmark - Render Stress Test".to_string(),
size: Some(WinitPhysicalSize::new(1280.0, 720.0)),
..Default::default()
})
.expect("Failed to create window");
let window = RenderWindowBuilder::new()
.color_format(wgpu::TextureFormat::Bgra8UnormSrgb)
.with_depth_default()
.build(window, graphics_ctx.clone())
.expect("Failed to create render window");
let window_id = window.id();
println!("\n═══════════════════════════════════════════════════════");
println!(" ⚡ PERFORMANCE BENCHMARK - Render Stress Test");
println!("═══════════════════════════════════════════════════════");
println!(" CONTROLS:");
println!(" [Space] Toggle rendering on/off");
println!(" [+/-] Increase/decrease object count");
println!(" Starting with 1000 objects");
println!("═══════════════════════════════════════════════════════\n");
Box::new(PerformanceBenchmark {
_context: graphics_ctx,
window,
window_id,
object_count: 1000,
rendering: true,
frame_count: 0,
last_fps_time: Instant::now(),
fps: 0.0,
last_frame_time: 0.0,
})
});
}
impl App for PerformanceBenchmark {
fn update(&mut self, _ctx: &mut AppCtx, _time: &FrameTime) {
self.frame_count += 1;
let now = Instant::now();
if now.duration_since(self.last_fps_time).as_secs_f32() >= 1.0 {
self.fps = self.frame_count as f32;
self.frame_count = 0;
self.last_fps_time = now;
println!(
"FPS: {:.1} | Frame Time: {:.2}ms | Objects: {} | Rendering: {}",
self.fps, self.last_frame_time, self.object_count, self.rendering
);
}
}
fn render(&mut self, _ctx: &mut AppCtx, window_id: WindowId, events: &mut EventBatch) {
if window_id != self.window_id {
return;
}
let frame_start = Instant::now();
events.dispatch(|event| {
if let Event::WindowResized(size) = event {
self.window.resized(*size);
HandleStatus::consumed()
} else {
HandleStatus::ignored()
}
});
events.dispatch(|event| {
if let Event::KeyInput(key) = event
&& key.state == astrelis_winit::event::ElementState::Pressed
{
match &key.logical_key {
Key::Named(NamedKey::Space) => {
self.rendering = !self.rendering;
println!("Rendering: {}", self.rendering);
return HandleStatus::consumed();
}
Key::Character(c) if c == "+" || c == "=" => {
self.object_count = (self.object_count + 500).min(50000);
println!("Object count: {}", self.object_count);
return HandleStatus::consumed();
}
Key::Character(c) if c == "-" => {
self.object_count = self.object_count.saturating_sub(500).max(100);
println!("Object count: {}", self.object_count);
return HandleStatus::consumed();
}
_ => {}
}
}
HandleStatus::ignored()
});
let Some(frame) = self.window.begin_frame() else {
return; };
if self.rendering {
let _pass = frame
.render_pass()
.clear_color(Color::from_rgb_u8(10, 10, 15))
.label("benchmark_pass")
.build();
} else {
let _pass = frame
.render_pass()
.clear_color(Color::from_rgb_u8(10, 10, 15))
.label("benchmark_pass")
.build();
}
let frame_end = Instant::now();
self.last_frame_time = frame_end.duration_since(frame_start).as_secs_f32() * 1000.0;
}
}