-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Fix panic when specializing materials for entities spawned in PostUpdate
#19064
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
|
(edited your PR description to avoid accidentally closing the related issue) |
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'm not sure that just changing the schedule of check_entities_needing_specialization to Last is correct. Some systems expect it to run in PostUpdate
As an example, in material.rs in bevy_pbr:
if self.shadows_enabled {
app.add_systems(
PostUpdate,
check_light_entities_needing_specialization::<M>
.after(check_entities_needing_specialization::<M>),
);
}check_light_entities_needing_specialization writes in EntitiesNeedingSpecialization after the clear done by check_entities_needing_specialization
- We could maybe? move also these systems to the
Lastschedule, but there may be other reasons for those to be inPostUpdatethat I did not deduce yet. - But we could instead explicitly specify
.after(VisibilitySystems::CheckVisibility)as a condition forcheck_entities_needing_specialization
@tychedelia, maybe you would know what decision would be the best ?
Notes:
AssetChangeddoc has an error, it says that it runs inLast, while it runs inPostUpdate. l opened a PR to fix it.
| PostUpdate, | ||
| check_entities_needing_specialization::<M>.after(AssetEvents), | ||
| ); | ||
| .add_systems(Last, check_entities_needing_specialization::<M>); |
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.
Going with option 2 as described above
| .add_systems(Last, check_entities_needing_specialization::<M>); | |
| .add_systems( | |
| PostUpdate, | |
| check_entities_needing_specialization::<M> | |
| .after(AssetEvents) | |
| .after(VisibilitySystems::CheckVisibility), | |
| ); |
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 was actually my initial choice for a fix, but @tychedelia mentioned on discord that moving the system to Last might be safer if it turns out there's no benefit to keeping it in LastUpdate. I think they were going to take a look when they had time.
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.
(Then we should at least move check_light_entities_needing_specialization to Last in bevy_pbr)
| .add_systems( | ||
| PostUpdate, | ||
| ( | ||
| mark_meshes_as_changed_if_their_materials_changed::<M>.ambiguous_with_all(), | ||
| check_entities_needing_specialization::<M>.after(AssetEvents), | ||
| ) | ||
| mark_meshes_as_changed_if_their_materials_changed::<M> | ||
| .ambiguous_with_all() | ||
| .after(mark_3d_meshes_as_changed_if_their_assets_changed), | ||
| ); | ||
| ) | ||
| .add_systems(Last, check_entities_needing_specialization::<M>); |
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.
With option 2. described above, this would look like:
.add_systems(
PostUpdate,
(
mark_3d_meshes_as_changed_if_their_assets_changed,
mark_meshes_as_changed_if_their_materials_changed::<M>.ambiguous_with_all(),
check_entities_needing_specialization::<M>,
)
.chain()
.after(AssetEvents)
.after(VisibilitySystems::CheckVisibility),
);The chaining is not strictly necessary, we could just add the new aftercondition to check_entities_needing_specialization.
But that's also a point I'd like to discuss. Currently check_entities_needing_specialization needlessly? checks for
Or<(
Changed<Mesh3d>,
AssetChanged<Mesh3d>,
Changed<MeshMaterial3d<M>>,
AssetChanged<MeshMaterial3d<M>>,
)>,But that is literally what mark_3d_meshes_as_changed_if_their_assets_changed and mark_meshes_as_changed_if_their_materials_changed seem to be there for (marking Mesh3d as changed) ? So chaining, and just checking for Changed<Mesh3d> in check_entities_needing_specialization would probably be simpler and achieve the expected goal.
Also:
- with the current PR
mark_meshes_as_changed_if_their_materials_changedandmark_3d_meshes_as_changed_if_their_assets_changedare not properly scheduled afterAssetEvents - on
main,mark_meshes_as_changed_if_their_materials_changedis not either, which could expain why all theOrparameters were introduced incheck_entities_needing_specialization
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 think you may have misread something here. mark_3d_meshes_as_changed_if_their_assets_changed is from bevy_render, and isn't added here. The only ordering constraint related to it in either main or this PR should be mark_meshes_as_changed_if_their_materials_changed.after(mark_3d_meshes_as_changed_if_their_assets_changed) unless there's some other interaction happening.
The minimal change from main to ensure ordering relative to CheckVisibility would just be:
.add_systems(
PostUpdate,
(
mark_meshes_as_changed_if_their_materials_changed::<M>.ambiguous_with_all(),
check_entities_needing_specialization::<M>
.after(AssetEventSystems)
.after(VisibilitySystems::CheckVisibility),
)
.after(mark_3d_meshes_as_changed_if_their_assets_changed)
);mark_3d_meshes_as_changed_if_their_assets_changed is also already explicitly ordered before asset events here:
bevy/crates/bevy_render/src/mesh/mod.rs
Lines 74 to 76 in 4051465
| mark_3d_meshes_as_changed_if_their_assets_changed | |
| .ambiguous_with(VisibilitySystems::CalculateBounds) | |
| .before(AssetEventSystems), |
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 right about mark_3d_meshes_as_changed_if_their_assets_changed, it's only used for ordering in bevy_pbr, my bad.
I'm still surprised though that mark_3d_meshes_as_changed_if_their_assets_changed is ordered before AssetEvents all the while reading the asset events. If anyone knows why I'd gladly take an explanation.
And, even a bit worse, mark_meshes_as_changed_if_their_materials_changed is also reading asset events. Its execution order is not deterministic as its only ordered after mark_3d_meshes_as_changed_if_their_assets_changed which itself is before AssetEvents. So mark_meshes_as_changed_if_their_materials_changed can end up running before or after AssetEvents depending on scheduling (and as such, marking meshes as modifed or not depending on scheduling).
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.
Looks to me like you just uncovered another bug
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 thinking about this deeply. These indeed seem to be sketchy to me. I think that both these systems were implemented before the AssetChanged filter was added and so they are ad-hoc implementations of the same thing. We should be able to simply add that filter in extract_meshes_for_gpu_building for mark_3d_meshes_as_changed_if_their_assets_changed. mark_meshes_as_changed_if_their_materials_changed is a bit more complicated because it requires the material type, so needs to stay in place with the potential for fixing post #18075 potentially.
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 think there's a chance that this scheduling ambiguity I just ran into is also caused by this.
|
From reading this, I'm fairly sure this fixes my issue #18980 as well, so let's close that one on merging :) |
|
For context, the reason these were added to
Given we've rooted out a lot of the cold specialization bugs, I could be convinced that we maybe could swap the |
tychedelia
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.
If we move these to Last we should also revert the change to move AssetEvents into PostUpdate. I'd like to see some benchmarking too if possible.
|
Hi @grind086, do you have time to do the requested changes right now? This has ended up in the 0.17 milestone, but I'm tempted to cut it unless it's fixed up in the next couple of days. |
|
hey, I would really love this being in 0.17, as this crash is prominent in my wasm builds. |
|
@mirsella, are you up for adopting this PR then? I'd like to get this in too, but we need help finishing this work. |
|
as much i would like to contribute to this level, sadly my knowledge of internal bevy things are nowhere near enough to understand the implications of each internal system ordering. also, i remember now when i tried using this fix it was still happening, so i instead removed the panic instead to be sure: let Some(entity_tick) = entity_specialization_ticks.get(visible_entity) else {
continue;
};now, ive tried using 0.16.1 again without these patch to try to get it to crash again but couldn't reproduce it this time :( but i can help if its about moving back
which is basically what i did in my fork minus the log |
|
what about i do a small PR just to remove the panic and instead |
I would be very happy to review that PR :) |
# Objective prevent panics talked about in #19064 this a “temporary” fix to get in 0.17, until the above PR is finalized, and the source problem is fixed. ## Solution remove the unwrap ## Testing - anything is better than panic - been using this patch in my own games for months without any apparent issue ## Note please improve the actual error missing if needed, i doubt its perfect --------- Co-authored-by: Alice Cecile <[email protected]>
|
Punting this to 0.18 because we have landed github.com//pull/20677 |
Objective
If an entity requiring specialization is spawned during
PostUpdateafter its material'scheck_entities_needing_specialization, but beforeCheckVisibility, a panic occurs during material specialization. This happens because the view assumes that every visible entity will be present in the specialization ticks map, but in this scenario the entity won't be added to the map until the next frame.Fixes #19048. This may also fix the related #18980, but I wasn't able to reproduce that one and it could be unrelated.
Edit by Alice: Fixes #18980 too!
Solution
Move
check_entities_needing_specializationsystems toLast. This ensures that they always runs afterCheckVisibility.Testing
Confirmed the reproduction from #19048 is fixed, and ran several 3d and 2d examples with no apparent change.