Skip to content

High entity counts cause decreased rendering performance even when rendering nothing. #3953

Closed
@StarArawn

Description

@StarArawn

Bevy version

Main branch commit: d8974e7c3d84189313268f475ceeff9393cedffa

Operating system & version

Windows 10 Vulkan and DX12 API.

What you did

The example code is small and easy to understand:

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

#[derive(Component)]
pub struct Nothing;

#[derive(Bundle)]
pub struct NoBundle {
    nothing: Nothing,
}

fn startup(
    mut commands: Commands,
) {
    let mut entities = Vec::new();
    for _ in 0..5000000 {
        entities.push(NoBundle {
            nothing: Nothing,
        });
    }

    commands.spawn_batch(entities);
}

fn main() {
    App::new()
        .insert_resource(WindowDescriptor {
            width: 1270.0,
            height: 720.0,
            title: String::from("Bug"),
            ..Default::default()
        })
        .insert_resource(ClearColor(Color::rgb(0.211, 0.643, 0.949)))
        .add_plugin(FrameTimeDiagnosticsPlugin::default())
        .add_plugin(LogDiagnosticsPlugin::default())
        .add_plugins(DefaultPlugins)
        .add_startup_system(startup)
        .run();
}

What you expected to happen

Creating large amounts of entities shouldn't decrease rendering performance unless they are actually drawing something to the screen.

What actually happened

Performance decreases rapidly with increased entity counts. On higher end machines this is less noticeable, but still becomes an issue.

Additional information

The decrease in performance can be traced to this:

let meta_len = app_world.entities().meta.len();
render_app
.world
.entities()
.reserve_entities(meta_len as u32);
// flushing as "invalid" ensures that app world entities aren't added as "empty archetype" entities by default
// these entities cannot be accessed without spawning directly onto them
// this _only_ works as expected because clear_entities() is called at the end of every frame.
render_app.world.entities_mut().flush_as_invalid();

Reserving entity ID's for every entity seems to be costly when dealing with a large number of entities.

Possible solutions:

  • Don't reserve entities that don't render anything. I'm not sure how performant that will be overall?
  • Possibly this could be mitigated by using a sub world where you could store extremely large numbers of entities without the rendering world being aware of said entities.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-RenderingDrawing game state to the screenC-BugAn unexpected or incorrect behaviorC-PerformanceA change motivated by improving speed, memory usage or compile timesP-HighThis is particularly urgent, and deserves immediate attention

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions