mirror of
https://github.com/bevyengine/bevy.git
synced 2026-07-26 19:31:21 -04:00
98639670f5
# Objective
- Introduce a dedicated example to measure performance overhead when
dealing with a high number of meshlet instances and unique materials.
## Solution
- Added a new example `many_meshlet_materials` that spawns a
configurable grid of meshlet bunnies.
## Testing
- `SystemInfo { os: "Linux (CachyOS Linux rolling)", kernel:
"6.19.10-1-cachyos", cpu: "AMD Ryzen 7 5800H with Radeon Graphics",
core_count: "8", memory: "15.0 GiB" }`
- `AdapterInfo { name: "AMD Radeon Graphics (RADV RENOIR)", vendor:
4098, device: 5688, device_type: IntegratedGpu, device_pci_bus_id:
"0000:03:00.0", driver: "radv", driver_info: "Mesa 26.0.3-arch2.2",
backend: Vulkan, subgroup_min_size: 64, subgroup_max_size: 64,
transient_saves_memory: false }`
- `cargo run --features=meshlet,https --release --example
many_meshlet_materials`
---
## Showcase
Example works perfectly with 5x5 grid.
<img width="1024" height="599" alt="image"
src="https://github.com/user-attachments/assets/948b42b7-e88e-4a91-9fb7-f1c1b4d27e32"
/>
The issue begins when grid count increases to 10x10. Meshes start
flickering.
<img width="1024" height="598" alt="image"
src="https://github.com/user-attachments/assets/055df47f-39dc-41bc-be05-1978ec352e3a"
/>
With 50x50 meshes, the whole screen flickers.
<img width="1024" height="595" alt="image"
src="https://github.com/user-attachments/assets/7d685a2b-7389-43fe-b04e-a5987136f459"
/>
When running with unique materials, performance significantly drops on
my hardware.
<img width="2224" height="1298" alt="image"
src="https://github.com/user-attachments/assets/8d5b4677-7851-4234-9467-992f8db62a9d"
/>
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
132 lines
3.7 KiB
Rust
132 lines
3.7 KiB
Rust
//! A stress test for the Meshlet pipeline specialization overhead.
|
|
//!
|
|
//! Run with `--unique-materials` to trigger the unconditional specialization bug.
|
|
//! Run without it (shared material) to see the baseline performance.
|
|
|
|
use argh::FromArgs;
|
|
use bevy::{
|
|
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
|
|
pbr::experimental::meshlet::{MeshletMesh3d, MeshletPlugin},
|
|
prelude::*,
|
|
window::{PresentMode, WindowResolution},
|
|
winit::WinitSettings,
|
|
};
|
|
|
|
#[derive(FromArgs, Resource)]
|
|
#[argh(description = "Meshlet Material Stress Test")]
|
|
struct Args {
|
|
/// the grid size (e.g., 50 means 50x50 = 2500 meshlets)
|
|
#[argh(option, short = 'n', default = "50")]
|
|
grid_size: usize,
|
|
|
|
/// if set, every meshlet gets a unique material asset.
|
|
/// This triggers the unconditional pipeline specialization bug in `prepare_material_meshlet_meshes`.
|
|
#[argh(switch)]
|
|
unique_materials: bool,
|
|
}
|
|
|
|
const ASSET_URL: &str =
|
|
"https://github.com/bevyengine/bevy_asset_files/raw/6dccaef517bde74d1969734703709aead7211dbc/meshlet/bunny.meshlet_mesh";
|
|
|
|
fn main() {
|
|
let args: Args = argh::from_env();
|
|
|
|
warn!(include_str!("warning_string.txt"));
|
|
println!("Meshlet Stress Test");
|
|
println!(
|
|
"Grid size: {}x{} ({} instances)",
|
|
args.grid_size,
|
|
args.grid_size,
|
|
args.grid_size * args.grid_size
|
|
);
|
|
println!(
|
|
"Materials: {}",
|
|
if args.unique_materials {
|
|
"UNIQUE"
|
|
} else {
|
|
"SHARED"
|
|
}
|
|
);
|
|
|
|
App::new()
|
|
.add_plugins((
|
|
DefaultPlugins.set(WindowPlugin {
|
|
primary_window: Some(Window {
|
|
present_mode: PresentMode::AutoNoVsync,
|
|
resolution: WindowResolution::new(1920, 1080).with_scale_factor_override(1.0),
|
|
..default()
|
|
}),
|
|
..default()
|
|
}),
|
|
FrameTimeDiagnosticsPlugin::default(),
|
|
LogDiagnosticsPlugin::default(),
|
|
MeshletPlugin {
|
|
cluster_buffer_slots: 8192,
|
|
},
|
|
))
|
|
.insert_resource(WinitSettings::continuous())
|
|
.insert_resource(args)
|
|
.add_systems(Startup, setup)
|
|
.run();
|
|
}
|
|
|
|
fn setup(
|
|
mut commands: Commands,
|
|
args: Res<Args>,
|
|
asset_server: Res<AssetServer>,
|
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
|
) {
|
|
let meshlet_handle = asset_server.load(ASSET_URL);
|
|
|
|
let n = args.grid_size;
|
|
let spacing = 2.0;
|
|
|
|
commands.spawn((
|
|
Camera3d::default(),
|
|
Transform::from_xyz(0.0, n as f32, n as f32 * 1.5).looking_at(Vec3::ZERO, Vec3::Y),
|
|
Msaa::Off,
|
|
));
|
|
|
|
commands.spawn((
|
|
DirectionalLight {
|
|
illuminance: 3000.0,
|
|
shadow_maps_enabled: true,
|
|
..default()
|
|
},
|
|
Transform::from_rotation(Quat::from_euler(
|
|
EulerRot::ZYX,
|
|
0.0,
|
|
1.0,
|
|
-std::f32::consts::FRAC_PI_4,
|
|
)),
|
|
));
|
|
|
|
let shared_material = materials.add(StandardMaterial {
|
|
base_color: Color::WHITE,
|
|
..default()
|
|
});
|
|
|
|
for x in 0..n {
|
|
for z in 0..n {
|
|
let material = if args.unique_materials {
|
|
materials.add(StandardMaterial {
|
|
base_color: Color::srgb(x as f32 / n as f32, 0.5, z as f32 / n as f32),
|
|
..default()
|
|
})
|
|
} else {
|
|
shared_material.clone()
|
|
};
|
|
|
|
commands.spawn((
|
|
MeshletMesh3d(meshlet_handle.clone()),
|
|
MeshMaterial3d(material),
|
|
Transform::from_xyz(
|
|
x as f32 * spacing - n as f32,
|
|
0.0,
|
|
z as f32 * spacing - n as f32,
|
|
),
|
|
));
|
|
}
|
|
}
|
|
}
|