From af3a84fc0b312209707b5f10d713ba2e7b2460b4 Mon Sep 17 00:00:00 2001 From: Rostyslav Toch Date: Fri, 24 Jan 2025 05:46:23 +0000 Subject: [PATCH] Add many_materials stress test (#17346) # Objective - This PR adds a new stress test called `many_materials` to benchmark the rendering performance of many animated materials. - Fixes #11588 - This PR continues the work started in the previous PR #11592, which was closed due to inactivity. ## Solution - Created a new example (`examples/stress_tests/many_materials.rs`) that renders a grid of cubes with animated materials. - The size of the grid can be configured using the `-n` command-line argument (or `--grid-size`). The default grid size is 10x10. - The materials animate by cycling through colors in the HSL color space. ## Testing - I have tested these changes locally on my Linux machine. - Reviewers can test the changes by running the example with different grid sizes and observing the performance (FPS, frame time). - I have not tested on other platforms (macOS, Windows, wasm), but I expect it to work as the code uses standard Bevy features. --- ## Showcase
Click to view showcase ![image](https://github.com/user-attachments/assets/b15209d4-f832-402b-a527-58e5048971d1)
--- Cargo.toml | 11 +++ examples/README.md | 1 + examples/stress_tests/many_materials.rs | 103 ++++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 examples/stress_tests/many_materials.rs diff --git a/Cargo.toml b/Cargo.toml index 61999102db..06b3902e95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2910,6 +2910,17 @@ description = "Displays many Text2d! Used for performance testing." category = "Stress Tests" wasm = true +[[example]] +name = "many_materials" +path = "examples/stress_tests/many_materials.rs" +doc-scrape-examples = true + +[package.metadata.example.many_materials] +name = "Many Animated Materials" +description = "Benchmark to test rendering many animated materials" +category = "Stress Tests" +wasm = true + [[example]] name = "transform_hierarchy" path = "examples/stress_tests/transform_hierarchy.rs" diff --git a/examples/README.md b/examples/README.md index a61457bff8..dcf72fc0e4 100644 --- a/examples/README.md +++ b/examples/README.md @@ -468,6 +468,7 @@ cargo run --release --example Example | Description --- | --- [Bevymark](../examples/stress_tests/bevymark.rs) | A heavy sprite rendering workload to benchmark your system with Bevy +[Many Animated Materials](../examples/stress_tests/many_materials.rs) | Benchmark to test rendering many animated materials [Many Animated Sprites](../examples/stress_tests/many_animated_sprites.rs) | Displays many animated sprites in a grid arrangement with slight offsets to their animation timers. Used for performance testing. [Many Buttons](../examples/stress_tests/many_buttons.rs) | Test rendering of many UI elements [Many Cameras & Lights](../examples/stress_tests/many_cameras_lights.rs) | Test rendering of many cameras and lights diff --git a/examples/stress_tests/many_materials.rs b/examples/stress_tests/many_materials.rs new file mode 100644 index 0000000000..f2af7fb382 --- /dev/null +++ b/examples/stress_tests/many_materials.rs @@ -0,0 +1,103 @@ +//! Benchmark to test rendering many animated materials +use argh::FromArgs; +use bevy::{ + diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, + prelude::*, + window::{PresentMode, WindowPlugin, WindowResolution}, +}; +use std::f32::consts::PI; + +#[derive(FromArgs, Resource)] +/// Command-line arguments for the `many_materials` stress test. +struct Args { + /// the size of the grid of materials to render (n x n) + #[argh(option, short = 'n', default = "10")] + grid_size: usize, +} + +fn main() { + // `from_env` panics on the web + #[cfg(not(target_arch = "wasm32"))] + let args: Args = argh::from_env(); + #[cfg(target_arch = "wasm32")] + let args = Args::from_args(&[], &[]).unwrap(); + + App::new() + .add_plugins(( + DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + resolution: WindowResolution::new(1920.0, 1080.0) + .with_scale_factor_override(1.0), + title: "many_materials".into(), + present_mode: PresentMode::AutoNoVsync, + ..default() + }), + ..default() + }), + FrameTimeDiagnosticsPlugin::default(), + LogDiagnosticsPlugin::default(), + )) + .insert_resource(args) + .add_systems(Startup, setup) + .add_systems(Update, animate_materials) + .run(); +} + +fn setup( + mut commands: Commands, + args: Res, + mesh_assets: ResMut>, + material_assets: ResMut>, +) { + let args = args.into_inner(); + let material_assets = material_assets.into_inner(); + let mesh_assets = mesh_assets.into_inner(); + let n = args.grid_size; + + // Camera + let w = n as f32; + commands.spawn(( + Camera3d::default(), + Transform::from_xyz(w * 1.25, w + 1.0, w * 1.25) + .looking_at(Vec3::new(0.0, (w * -1.1) + 1.0, 0.0), Vec3::Y), + )); + + // Light + commands.spawn(( + Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)), + DirectionalLight { + illuminance: 3000.0, + shadows_enabled: true, + ..default() + }, + )); + + // Cubes + let mesh_handle = mesh_assets.add(Cuboid::from_size(Vec3::ONE)); + for x in 0..n { + for z in 0..n { + commands.spawn(( + Mesh3d(mesh_handle.clone()), + MeshMaterial3d(material_assets.add(Color::WHITE)), + Transform::from_translation(Vec3::new(x as f32, 0.0, z as f32)), + )); + } + } +} + +fn animate_materials( + material_handles: Query<&MeshMaterial3d>, + time: Res