diff --git a/Cargo.toml b/Cargo.toml index 5efa16115826e..32841e9bbf113 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -562,3 +562,9 @@ icon = "@mipmap/ic_launcher" build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"] min_sdk_version = 16 target_sdk_version = 29 + +# Stress Tests +[[example]] +name = "transform_hierarchy" +path = "examples/stress_tests/transform_hierarchy.rs" + diff --git a/examples/README.md b/examples/README.md index 53d276d646d81..cc8a20ea16a2a 100644 --- a/examples/README.md +++ b/examples/README.md @@ -65,6 +65,7 @@ git checkout v0.4.0 - [WASM](#wasm) - [Setup](#setup-2) - [Build & Run](#build--run-2) +- [Stree Tests](#stress-tests) # The Bare Minimum @@ -408,3 +409,9 @@ ruby -run -ehttpd examples/wasm To load assets, they need to be available in the folder examples/wasm/assets. Cloning this repository will set it up as a symlink on Linux and macOS, but you will need to manually move the assets on Windows. + +# Stress Tests + +Example | File | Description +--- | --- | --- +`transform_hierarchy.rs` | [`stress_tests/transform_hierarchy.rs`](./stress_tests/transform_hierarchy.rs) | Configurable test for hierarchy and transform propagation performance diff --git a/examples/stress_tests/transform_hierarchy.rs b/examples/stress_tests/transform_hierarchy.rs new file mode 100644 index 0000000000000..5bcf32512fedd --- /dev/null +++ b/examples/stress_tests/transform_hierarchy.rs @@ -0,0 +1,500 @@ +//! hierarchy and transform propagation stress test +//! set the test parameters inside [main] + +use bevy::{ + prelude::*, + sprite::{MaterialMesh2dBundle, Mesh2dHandle}, +}; +use rand::Rng; + +fn main() { + let cfg = Cfg { + test_case: TestCase::NonUniformTree { + depth: 18, + branch_width: 8, + }, + update_filter: UpdateFilter { + probability: 0.5, + ..default() + }, + visuals: Visuals { + visible_nodes: VisibleNodes::None, + unique_meshes: false, + unique_materials: false, + }, + }; + + App::new() + .insert_resource(ClearColor(Color::BLACK)) + .insert_resource(cfg) + .add_plugins(DefaultPlugins) + .add_startup_system(setup) + .add_system(update) + .run() +} + +/// test configuration +struct Cfg { + /// which test case should be inserted + test_case: TestCase, + /// which entities should be updated + update_filter: UpdateFilter, + /// which entities should be displayed + visuals: Visuals, +} + +#[allow(unused)] +enum TestCase { + /// a uniform tree, exponentially growing with depth + Tree { + /// total depth + depth: u32, + /// number of children per node + branch_width: u32, + }, + /// a non uniform tree (one side is deeper than the other) + /// creates significantly less nodes than `TestCase::Tree` with the same parameters + NonUniformTree { + /// the maximum depth + depth: u32, + /// max number of children per node + branch_width: u32, + }, + /// one or multiple humanoid rigs + Humanoids { + /// number of active instances (uses the specified [UpdateFilter]) + active: u32, + /// numer of inactive instances (always inactive) + inactive: u32, + }, +} + +/// restrict which nodes are updated +struct UpdateFilter { + /// starting depth (inclusive) + min_depth: u32, + /// end depth (inclusive) + max_depth: u32, + /// probability (evaluated at insertion time, not during update) + probability: f32, +} + +impl Default for UpdateFilter { + fn default() -> Self { + Self { + min_depth: 0, + max_depth: u32::MAX, + probability: f32::MAX, + } + } +} + +/// visibility of nodes +#[allow(unused)] +#[derive(PartialEq)] +enum VisibleNodes { + /// draw nothing + None, + /// draw only leaves + Leaves, + /// draw all nodes + All, +} + +/// visual configuration +struct Visuals { + /// visibility of nodes + visible_nodes: VisibleNodes, + /// insert a unique mesh for each node, otherwise share the same mesh + unique_meshes: bool, + /// insert a unique material for each node, otherwise share the same material + unique_materials: bool, +} + +// update component with some per-component value +#[derive(Component)] +struct Update(f32); + +// update positions system +fn update(time: Res