-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Add tools to avoid unnecessary AssetEvent::Modified events that lead to rendering performance costs (#16751)
#22460
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
base: main
Are you sure you want to change the base?
Conversation
|
Welcome, new contributor! Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨ |
…to rendering performance costs (bevyengine#16751)
f5c7534 to
031302f
Compare
|
A little more details on the test app. As mentioned in the original issue, I've noticed this slowdown in the debug mode and above values are also for the debug mode. But it doesn't take much to have similar slowdown also in the release mode as well. Debug mode, 441 object (21x21 grid):
Release mode, 1 681 object (41x41 grid):
This PR doesn't actually fix the slowdown itself (which is caused by a huge amount of material extractions) but only provides some tools to avoid it. |
HugoPeters1024
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your contribution! I think this change makes sense and your implementation is quite reasonable. I did want to point out 2 things though.
You mentioned that you weren't really sure how to add a test for this, but you then actually go on to describe a pretty good way to test this new functionality! Perhaps you can check out how_to_test_systems.rs to get some inspiration on how to write a test for it. While the implementation is quite simple and almost certainly correct, I think a test is still very valuable to make sure things keep working going forward.
Secondly, your approached reminds me a lot of ResMut, which is good because it serves a similar goal. But I did notice that ResMut relies on the Ticks struct for change detection. From what I understand this tracks the last tick that a certain change happened. Because this appears to be a general change detection mechanism, I wonder if it makes sense to re-use it here. That said, I'm not very familiar with that part of the codebase but it's something to consider.
Thanks again for the contribution and congratulations on very first Bevy PR! I hope it's the first of many :)
|
@HugoPeters1024 , thanks for your comments. TestI've added a test for the Potentially I can also move slightly modified test from my repo to Stress Tests folder. Ticks approachI also looked at change detection for
Maybe there is a way to make them use |
4a39b8f to
412b115
Compare
|
@HugoPeters1024, thanks for your review.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for incorporating the feedback, this LGTM! (Make sure you check out any CI failures though)
|
@HugoPeters1024, thanks for your approval. I've also resolved all of the CI errors that you've mentioned. what should be my next steps for this issue? |
Now we wait for a maintainer to label this as "ready for final review", if all is well it will be merged when deemed convenient. When there are breaking changes like this it might happen that the PR is deferred to the next release, as we are currently quite close to v0.18. So for now just keep an eye out if there is any followup review :). If nothing happens in the next week or 2 feel free to reach out on the discord. |
andriyDev
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel strongly about this change. Users can work around it fairly easily by just using get() and then upgrading to get_mut if they realize they need to mutate. Yes there's a perf cost, but it's probably not that big a deal.
Practically with assets-as-entities we'll get this exact thing for free, since we'll likely just use change detection like normal components. So I think it's fine to do this early.
crates/bevy_asset/src/assets.rs
Outdated
| asset_modified_counter: u32, | ||
| } | ||
|
|
||
| let mut app = App::new(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the create_app function from crates/bevy_asset/src/lib.rs. It prevents you from doing bad stuff accidentally, and hides away some setup code we don't care about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
crates/bevy_asset/src/assets.rs
Outdated
| app.add_systems( | ||
| Update, | ||
| move |mut assets: ResMut<Assets<TestAsset>>, state: Res<TestState>| { | ||
| let mut asset = assets.get_mut(my_asset_id).unwrap(); | ||
|
|
||
| if asset.value != state.asset_target_value { | ||
| asset.value = state.asset_target_value; | ||
| } | ||
| }, | ||
| ); | ||
| app.add_systems( | ||
| Last, | ||
| move |mut reader: MessageReader<AssetEvent<TestAsset>>, | ||
| mut state: ResMut<TestState>| { | ||
| for event in reader.read() { | ||
| if event.is_modified(my_asset_id) { | ||
| state.asset_modified_counter += 1; | ||
| } | ||
| } | ||
| }, | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These don't need to be systems for this test. Can we just use app.world_mut().resource::<Assets<TestAsset>>() in the loop and access the asset that way? And then we can just access the Messages<AssetEvent<TestAsset>> resource to drain out any events. I prefer to keep systems out of these tests for simplicity (for example we can delete the TestState resource I think).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done. it is really easier to track what happens without the systems. thanks for suggestion.
| // is best to cache the handle somewhere, as having multiple materials | ||
| // that are identical is expensive | ||
| let mut new_material = material.clone(); | ||
| let mut new_material = material.into_inner_untracked().clone(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem like we should be using into_inner_untracked here. It seems more like we should stop using get_mut at all for this material.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're correct, it looks like get_mut here was redundant.
8ce97a9 to
6c4eed9
Compare
|
@andriyDev, thanks for your review. All your comments hopefully should be resolved now. I agree that "assets-as-entities" feature will solve this problem by default and will make this change obsolete but I don't know what is current progress on it nor when it is expected to be released. I also agree that users have ability to achieve this functionality by themself (I even wrote how to do it in the original issue) but it is a somewhat cumbersome, not user-friendly and has some overhead (even if very minimal). Personally, on my projects, I use exactly the same implementation, just calling Anyways, I'd be happy if this can be a part of the assets API itself even if just as a temporary fix until "assets-as-entities" arrive. |
Objective
Solution
Assets::get_mutnow returns a wrapperAssetMuttype instead of&mut impl Asset.AssetMutimplementsDerefandDerefMut.DerefMutmarks assets as changed.AssetMutwill addAssetEvent::Modifiedevent to a queue only in case asset was marked as changed.Testing
AssetEvent::Modifiedwill now be sent after the asset was modified instead of before. It should not affect anything but still worth noting.PS: This is my first PR, so please don’t judge.