-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Regression in query filter #1955
Comments
This is coming from #1929 and as far as I understand, it's not a bug. |
We could technically remove the |
This is very much something we should support on the end user level, yes. Changed and Added filters don't actually need write access to the component data, fixing this bug is sound. The trick is that they may need write access to their own data. But this only occurs if the underlying component data is changed. As long as the mutability rules are obeyed by the queries for the component data itself, this will always remain sound. |
They don't ask for write, they only ask for read, but there's already a write access for the same component, so we can't take a read on it. Should we add a third level of permission? |
This is an interesting idea... I don't mind it as a workaround. Overall this feels like an indication that the change tracker needs to somehow be more closely integrated onto the component storage itself. I'm not at all sure how we might do that though. |
Okay, thinking this through a bit more clearly... The fundamental reason why this works is that the query filter reads the component data before the components are actually handed out to be changed. Thus, we should be able to use a Changed filter in one query, and a mutable fetch of the same data in another query on the same system. Doing so across systems is much more dangerous though (I think just shouldn't be allowed), because we have no guarantees on whether the system will have started mutating things before or after we check what's changed. As a result, I think the correct solution is actually to split this out into two phases of access within each system, with the system's total access being the union of the access across the two phases. In the "filter" phase, we handle With / Without / Changed / Added, and then in the "query" phase we handle the actual data. You could even free up data access once the filter phase is complete to allow for enhanced parallelism in the future, reducing the duration that systems which only filter on particular components block new writes on them. |
We already have two levels of check done: to check if a system can run
bevy/crates/bevy_ecs/src/query/access.rs Lines 75 to 84 in b17f8a4
updated by update_archetype_component_access :bevy/crates/bevy_ecs/src/query/fetch.rs Lines 216 to 226 in 9657f58
to check if a query is validAnd bevy/crates/bevy_ecs/src/query/fetch.rs Lines 208 to 214 in 9657f58
Meta solution?A solution with a |
I'm not sure I understand how this proposal would work; could you expand on why it would help? As I understand it this problem would arise even if we only had a single archetype per component. |
we are storing read and write for the archetype and the components level, so that already works when you have a single component and two systems that need a The idea would be to add a right |
Not quite. These queries still "conflict" in that you could "collect" references of the mutable query fetches, then iterate the "changed filter" query, which could result in an immutable reference being accessed while the mutable reference exists. In practice it probably wouldn't cause problems for most people, but I still wouldn't be comfortable doing it.
I don't think we need to complicate the access control here. I think the current logic behaves correctly when comparing two different queries / accesses (both within systems and across systems). I think this can be resolved by simply adjusting our order of operations slightly and "sandboxing" query filter evaluation. When we first construct a query and collect component access:
|
I'm putting this together now. Should be a pretty quick fix. |
…ion (bevyengine#1977) Fixes bevyengine#1955 See this comment for implementation details / motivation: bevyengine#1955 (comment)
Using latest main 20673db
This worked in 0.5:
Query<&mut MyComponent, Changed<MyComponent>>
In latest main it gives this error:
thread 'main' panicked at '$state_name<game::MyComponent> conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.', /home/user/Code/bevy/crates/bevy_ecs/src/query/filter.rs:635:1
This is probably caused by #1929.
If anyone runs into this, you can remove Changed (or Added), and manually filter afterwards using
my_component.is_changed()
The text was updated successfully, but these errors were encountered: