Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add bevymark benchmark example #273

Merged
merged 6 commits into from
Nov 13, 2020
Merged

add bevymark benchmark example #273

merged 6 commits into from
Nov 13, 2020

Conversation

RobDavenport
Copy link
Contributor

Added a "bunnymark" example we can all use for testing performance as the engine progresses. Wasn't sure where to put this, so I just made a new folder called "Tools." Perhaps we can put future 3d benchmarks in there as well?

bevymark

Run the example with `cargo run --release --example bevymark

Click in the screens pace to spawn some sprites.
Check the for FPS output.

@StarArawn
Copy link
Contributor

This is cool! Can we add the FPS to the screen as well? I think that should be pretty straight forward.

@karroffel karroffel added C-Examples An addition or correction to our examples C-Performance A change motivated by improving speed, memory usage or compile times A-Rendering Drawing game state to the screen labels Aug 21, 2020
@Fishrock123
Copy link
Contributor

Fishrock123 commented Aug 21, 2020

I agree that FPS as UI would be helpful here.

Edit: it would probably be nice to have something even more fine grained, akin to RTSS's per-cpu-core-usage stats. That is probably out of scope though.

@cart
Copy link
Member

cart commented Aug 21, 2020

Yup this will be a nice way to measure progress on performance. I'm sold!

@RobDavenport
Copy link
Contributor Author

Had a bit of a busy weekend, will look into adding the FPS counter on screen updates over the next few days.

@RobDavenport
Copy link
Contributor Author

RobDavenport commented Aug 27, 2020

@cart, added the FPS display as requested

image

.run();
}

fn setup(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can clean up this optional resource a little bit like this:

struct BirdMaterial(Handle<ColorMaterial>);

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut materials: ResMut<Assets<ColorMaterial>>,
) {
    commands.insert_resource(BirdMaterial(
        materials.add(
            asset_server
                .load("assets/branding/icon.png")
                .unwrap()
                .into(),
        ),
    ));

Comment on lines 125 to 126
let new_y = bird.velocity.y() + GRAVITY;
bird.velocity.set_y(new_y);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes gravity acceleration framerate dependent. We can correct this (and make it a bit terser) like this:

*bird.velocity.y_mut() += GRAVITY * time.delta_seconds;

This correction exposes something interesting: the scale is quite "off". You'll notice the birds appear to accelerate very slowly. This is because each pixel is currently a "meter", so the window is 800 "meters" tall.

We can fix this by just cranking up the gravity:

const GRAVITY: f32 = -9.8 * 100.0; // multiply by 100 to account for scale

}
}

fn counter_system(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pretty good case for a "for-each system":

fn counter_system(diagnostics: Res<Diagnostics>, counter: Res<BevyCounter>, mut text: Mut<Text>) {
    if let Some(fps) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) {
        if let Some(average) = fps.average() {
            text.value = format!("Bird Count: {}\nAverage FPS: {:.2}", counter.count, average);
        }
    };
}

@Nazariglez
Copy link

Nazariglez commented Nov 13, 2020

Leaving this here in case it helps. I used the changes that @cart suggested and updated the API to use v0.3

use bevy::{
    diagnostic::{Diagnostics, FrameTimeDiagnosticsPlugin},
    prelude::*,
};

const BIRDS_PER_SECOND: u32 = 1000;
const GRAVITY: f32 = -9.8 * 100.0;
const MAX_VELOCITY: f32 = 750.;
const BIRD_SCALE: f32 = 0.15;
const HALF_BIRD_SIZE: f32 = 256. * BIRD_SCALE * 0.5;
struct BevyCounter {
    pub count: u128,
}

struct Bird {
    velocity: Vec3,
}

fn main() {
    App::build()
        .add_resource(WindowDescriptor {
            title: "BevyMark".to_string(),
            width: 800,
            height: 600,
            vsync: true,
            resizable: false,
            ..Default::default()
        })
        .add_plugins(DefaultPlugins)
        .add_plugin(FrameTimeDiagnosticsPlugin::default())
        .add_resource(BevyCounter { count: 0 })
        .add_resource(Option::<Handle<ColorMaterial>>::None)
        .add_startup_system(setup.system())
        .add_system(mouse_handler.system())
        .add_system(movement_system.system())
        .add_system(collision_system.system())
        .add_system(counter_system.system())
        .run();
}

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut materials: ResMut<Assets<ColorMaterial>>,
    mut out_material_handle: ResMut<Option<Handle<ColorMaterial>>>,
) {
    *out_material_handle = Some(
        materials.add(
            asset_server
                .load("branding/icon.png")
                .into(),
        ),
    );

    commands
        .spawn(Camera2dComponents::default())
        .spawn(UiCameraComponents::default())
        .spawn(TextComponents {
            text: Text {
                font: asset_server.load("fonts/FiraSans-Bold.ttf"),
                value: "Bird Count:".to_string(),
                style: TextStyle {
                    color: Color::rgb(0.0, 1.0, 0.0),
                    font_size: 40.0,
                },
            },
            style: Style {
                position_type: PositionType::Absolute,
                position: Rect {
                    top: Val::Px(5.0),
                    left: Val::Px(5.0),
                    ..Default::default()
                },
                ..Default::default()
            },
            ..Default::default()
        });
}

fn mouse_handler(
    mut commands: Commands,
    time: Res<Time>,
    mouse_button_input: Res<Input<MouseButton>>,
    window: Res<WindowDescriptor>,
    material_handle: Res<Option<Handle<ColorMaterial>>>,
    mut counter: ResMut<BevyCounter>,
) {
    if mouse_button_input.pressed(MouseButton::Left) {
        let spawn_count = (BIRDS_PER_SECOND as f32 * time.delta_seconds) as u128;
        let bird_x = (window.width as i32 / -2) as f32 + HALF_BIRD_SIZE;
        let bird_y = (window.height / 2) as f32 - HALF_BIRD_SIZE;

        for count in 0..spawn_count {
            let bird_position = Vec3::new(bird_x, bird_y, (counter.count + count) as f32 * 0.00001);
            let mut transform = Transform::from_translation(bird_position);
            transform.scale = Vec3::new(BIRD_SCALE, BIRD_SCALE, BIRD_SCALE);

            commands
                .spawn(SpriteComponents {
                    material: material_handle.clone().unwrap(),
                    transform: transform,
                    draw: Draw {
                        is_transparent: true,
                        ..Default::default()
                    },
                    ..Default::default()
                })
                .with(Bird {
                    velocity: Vec3::new(
                        rand::random::<f32>() * MAX_VELOCITY - (MAX_VELOCITY * 0.5),
                        0.,
                        0.,
                    ),
                });
        }

        counter.count += spawn_count;
    }
}

fn movement_system(time: Res<Time>, mut bird_query: Query<(&mut Bird, &mut Transform)>) {
    for (mut bird, mut transform) in bird_query.iter_mut() {
        *transform.translation.x_mut() += bird.velocity.x() * time.delta_seconds;
        *transform.translation.y_mut() += bird.velocity.y() * time.delta_seconds;
        *bird.velocity.y_mut() += GRAVITY * time.delta_seconds;
    }
}

fn collision_system(
    window: Res<WindowDescriptor>,
    mut bird_query: Query<(&mut Bird, &Transform)>,
) {
    let half_width = window.width as f32 * 0.5;
    let half_height = window.height as f32 * 0.5;

    for (mut bird, transform) in bird_query.iter_mut() {
        let x_vel = bird.velocity.x();
        let y_vel = bird.velocity.y();
        let x_pos = transform.translation.x();
        let y_pos = transform.translation.y();

        if (x_vel > 0. && x_pos + HALF_BIRD_SIZE > half_width)
            || (x_vel <= 0. && x_pos - HALF_BIRD_SIZE < -(half_width))
        {
            bird.velocity.set_x(-x_vel);
        }
        if y_vel < 0. && y_pos - HALF_BIRD_SIZE < -half_height {
            bird.velocity.set_y(-y_vel);
        }
    }
}

fn counter_system(diagnostics: Res<Diagnostics>, counter: Res<BevyCounter>, mut text: Mut<Text>) {
    if let Some(fps) = diagnostics.get(FrameTimeDiagnosticsPlugin::FPS) {
        if let Some(average) = fps.average() {
            text.value = format!("Bird Count: {}\nAverage FPS: {:.2}", counter.count, average);
        }
    };
}

This are my stats with a MacBook Pro i9 2.3GHz - 32GB Ram - Intel UHD Graphics 630 1536MB:

Screenshot 2020-11-13 at 00 17 34

cargo run --release

@cart
Copy link
Member

cart commented Nov 13, 2020

Alrighty I updated it with the changes from @Nazariglez, as well as a few more changes to adapt to the latest master branch.

@cart cart merged commit 6b8b8e7 into bevyengine:master Nov 13, 2020
@DJMcNab
Copy link
Member

DJMcNab commented Jul 3, 2021

@RobDavenport @Nazariglez we need your permissions in #2373 to keep this example in the repository. Please read that and comment at your earliest convenience. Thanks!

@Nazariglez
Copy link

Done: #2373 (comment)

Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Examples An addition or correction to our examples C-Performance A change motivated by improving speed, memory usage or compile times
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants