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

bevy_render: Reserve only entities from the last frame #4322

Closed
wants to merge 4 commits into from
Closed

bevy_render: Reserve only entities from the last frame #4322

wants to merge 4 commits into from

Conversation

zyllian
Copy link

@zyllian zyllian commented Mar 24, 2022

Objective

Solution

  • Reserve only the number of entities used during the previous frame in the render world

@github-actions github-actions bot added the S-Needs-Triage This issue needs to be labelled label Mar 24, 2022
@alice-i-cecile alice-i-cecile added A-Rendering Drawing game state to the screen C-Performance A change motivated by improving speed, memory usage or compile times and removed S-Needs-Triage This issue needs to be labelled labels Mar 24, 2022
@@ -107,6 +107,10 @@ pub struct RenderApp;
#[derive(Default)]
struct ScratchRenderWorld(World);

/// The number of entities used in the render world in the previous frame.
#[derive(Default)]
Copy link
Member

Choose a reason for hiding this comment

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

I think it may make sense to initialize this at something low but not tiny, like perhaps 100?

Copy link
Author

@zyllian zyllian Mar 24, 2022

Choose a reason for hiding this comment

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

Initializing would only work if rendering entities are added in the first frame. I think a minimum or offset applied when reserving would probably be better.

@alice-i-cecile
Copy link
Member

This strategy makes sense to me: it's certainly better than the existing solution. I think we can actually just compute the exact number of entities to reserve quickly and correctly, which should be preferred (see #3953), but this PR has my approval if that doesn't pan out.

@zyllian
Copy link
Author

zyllian commented Mar 24, 2022

Sounds good to me.

@nicopap
Copy link
Contributor

nicopap commented Apr 15, 2022

Yeah, it should be possible to use #4244 in addition with a Query<(), RenderCriteriaFilter> (where RenderCriteriaFilter is a "good enough" filter that selects only renderable entities) to solve this without having an additional explicitly declared cache. Note that due to the nature of Visibility.is_visible, the cached value approach is always going to be more accurate (and therefore efficient) than relying on the archetype array size. So I would vouch for the explicit cached value.

Note the same problem has been encountered and solved similarly in the extract_mesh system in bevy_pbr, here they store in a Local the size of the array last frame and re-use it.

Comment on lines 282 to 285
render_app
.world
.resource_mut::<NumberOfRenderingEntitiesToReserve>()
.0 = render_app.world.entities().meta.len() as u32;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
render_app
.world
.resource_mut::<NumberOfRenderingEntitiesToReserve>()
.0 = render_app.world.entities().meta.len() as u32;
let mut entities_to_reserve = render_app
.world
.resource_mut::<NumberOfRenderingEntitiesToReserve>();
entities_to_reserve.0 = render_app.world.entities().meta.len() as u32;

The PR looks good. But I find assignments at the end of field access chains a bit difficult to read. It could be improved this way.

@alice-i-cecile
Copy link
Member

#4244 is merged now; can you update this PR to use it?

@alice-i-cecile alice-i-cecile added this to the Bevy 0.8 milestone May 12, 2022
@nicopap
Copy link
Contributor

nicopap commented May 13, 2022

@alice-i-cecile As I mentioned in my earlier reply. Size hint is a double-edged sword. As soon as there is filtering based on non-archetype criteria, it goes woop.

I did an analysis of the impact of size hints on another PR: #4240

To make sure the benefits are there, I suggest benchmarking.

@alice-i-cecile
Copy link
Member

alice-i-cecile commented May 13, 2022

Ah right, good choice.

In that case, I'm in favor of merging this as is and creating an issue to investigate this further. The existing strategy is clearly poor.

I'll defer to @superdump on the final call though. @zyllian can you rebase this?

@@ -187,13 +192,13 @@ impl Plugin for RenderPlugin {
bevy_utils::tracing::info_span!("stage", name = "reserve_and_flush")
.entered();

// reserve all existing app entities for use in render_app
// reserve the number of entities used in the previous frame for use in render_app
Copy link
Contributor

@superdump superdump May 13, 2022

Choose a reason for hiding this comment

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

The point of reserving the entities is so that the same entity from the main world can be used to refer to an entity in the render world. If we don’t reserve the entire active main world entity address space, something could be spawned after what is reserved and then something else is supposed to refer to that. I’m not convinced this change is safe to do. I’ll need to think about it some more. Maybe @cart can beat me to it.

Copy link
Member

Choose a reason for hiding this comment

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

Yup the approach in this PR breaks the intended behavior. This line isn't about reserving space for rendering entities. Its about ensuring that rendering entities don't get spawned in the "current app id space".

We should not merge this PR.

Copy link
Author

Choose a reason for hiding this comment

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

When I made the change I was expecting it to not work at all so I could learn more about Bevy's internals. I'm curious why it doesn't obviously break things, though.

@alice-i-cecile alice-i-cecile added the S-Needs-Benchmarking This set of changes needs performance benchmarking to double-check that they help label May 18, 2022
@zyllian zyllian deleted the performance_fix branch June 8, 2024 16:48
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-Performance A change motivated by improving speed, memory usage or compile times S-Needs-Benchmarking This set of changes needs performance benchmarking to double-check that they help
Projects
None yet
Development

Successfully merging this pull request may close these issues.

High entity counts cause decreased rendering performance even when rendering nothing.
5 participants