11use alloc:: { boxed:: Box , vec:: Vec } ;
22use bevy_platform:: sync:: Arc ;
33use bevy_tasks:: { ComputeTaskPool , Scope , TaskPool , ThreadExecutor } ;
4- use bevy_utils:: { default , syncunsafecell:: SyncUnsafeCell } ;
4+ use bevy_utils:: syncunsafecell:: SyncUnsafeCell ;
55use concurrent_queue:: ConcurrentQueue ;
66use core:: { any:: Any , panic:: AssertUnwindSafe } ;
77use fixedbitset:: FixedBitSet ;
@@ -13,10 +13,8 @@ use std::sync::{Mutex, MutexGuard};
1313use tracing:: { info_span, Span } ;
1414
1515use crate :: {
16- archetype:: ArchetypeComponentId ,
1716 error:: { default_error_handler, BevyError , ErrorContext , Result } ,
1817 prelude:: Resource ,
19- query:: Access ,
2018 schedule:: { is_apply_deferred, BoxedCondition , ExecutorKind , SystemExecutor , SystemSchedule } ,
2119 system:: ScheduleSystem ,
2220 world:: { unsafe_world_cell:: UnsafeWorldCell , World } ,
@@ -62,8 +60,13 @@ impl<'env, 'sys> Environment<'env, 'sys> {
6260/// Per-system data used by the [`MultiThreadedExecutor`].
6361// Copied here because it can't be read from the system when it's running.
6462struct SystemTaskMetadata {
65- /// The [`ArchetypeComponentId`] access of the system.
66- archetype_component_access : Access < ArchetypeComponentId > ,
63+ /// The set of systems whose `component_access_set()` conflicts with this one.
64+ conflicting_systems : FixedBitSet ,
65+ /// The set of systems whose `component_access_set()` conflicts with this system's conditions.
66+ /// Note that this is separate from `conflicting_systems` to handle the case where
67+ /// a system is skipped by an earlier system set condition or system stepping,
68+ /// and needs access to run its conditions but not for itself.
69+ condition_conflicting_systems : FixedBitSet ,
6770 /// Indices of the systems that directly depend on the system.
6871 dependents : Vec < usize > ,
6972 /// Is `true` if the system does not access `!Send` data.
@@ -97,8 +100,8 @@ pub struct MultiThreadedExecutor {
97100pub struct ExecutorState {
98101 /// Metadata for scheduling and running system tasks.
99102 system_task_metadata : Vec < SystemTaskMetadata > ,
100- /// Union of the accesses of all currently running systems .
101- active_access : Access < ArchetypeComponentId > ,
103+ /// The set of systems whose `component_access_set()` conflicts with this system set's conditions .
104+ set_condition_conflicting_systems : Vec < FixedBitSet > ,
102105 /// Returns `true` if a system with non-`Send` access is running.
103106 local_thread_running : bool ,
104107 /// Returns `true` if an exclusive system is running.
@@ -164,7 +167,8 @@ impl SystemExecutor for MultiThreadedExecutor {
164167 state. system_task_metadata = Vec :: with_capacity ( sys_count) ;
165168 for index in 0 ..sys_count {
166169 state. system_task_metadata . push ( SystemTaskMetadata {
167- archetype_component_access : default ( ) ,
170+ conflicting_systems : FixedBitSet :: with_capacity ( sys_count) ,
171+ condition_conflicting_systems : FixedBitSet :: with_capacity ( sys_count) ,
168172 dependents : schedule. system_dependents [ index] . clone ( ) ,
169173 is_send : schedule. systems [ index] . is_send ( ) ,
170174 is_exclusive : schedule. systems [ index] . is_exclusive ( ) ,
@@ -174,6 +178,60 @@ impl SystemExecutor for MultiThreadedExecutor {
174178 }
175179 }
176180
181+ {
182+ #[ cfg( feature = "trace" ) ]
183+ let _span = info_span ! ( "calculate conflicting systems" ) . entered ( ) ;
184+ for index1 in 0 ..sys_count {
185+ let system1 = & schedule. systems [ index1] ;
186+ for index2 in 0 ..index1 {
187+ let system2 = & schedule. systems [ index2] ;
188+ if !system2
189+ . component_access_set ( )
190+ . is_compatible ( system1. component_access_set ( ) )
191+ {
192+ state. system_task_metadata [ index1]
193+ . conflicting_systems
194+ . insert ( index2) ;
195+ state. system_task_metadata [ index2]
196+ . conflicting_systems
197+ . insert ( index1) ;
198+ }
199+ }
200+
201+ for index2 in 0 ..sys_count {
202+ let system2 = & schedule. systems [ index2] ;
203+ if schedule. system_conditions [ index1] . iter ( ) . any ( |condition| {
204+ !system2
205+ . component_access_set ( )
206+ . is_compatible ( condition. component_access_set ( ) )
207+ } ) {
208+ state. system_task_metadata [ index1]
209+ . condition_conflicting_systems
210+ . insert ( index2) ;
211+ }
212+ }
213+ }
214+
215+ state. set_condition_conflicting_systems . clear ( ) ;
216+ state. set_condition_conflicting_systems . reserve ( set_count) ;
217+ for set_idx in 0 ..set_count {
218+ let mut conflicting_systems = FixedBitSet :: with_capacity ( sys_count) ;
219+ for sys_index in 0 ..sys_count {
220+ let system = & schedule. systems [ sys_index] ;
221+ if schedule. set_conditions [ set_idx] . iter ( ) . any ( |condition| {
222+ !system
223+ . component_access_set ( )
224+ . is_compatible ( condition. component_access_set ( ) )
225+ } ) {
226+ conflicting_systems. insert ( sys_index) ;
227+ }
228+ }
229+ state
230+ . set_condition_conflicting_systems
231+ . push ( conflicting_systems) ;
232+ }
233+ }
234+
177235 state. num_dependencies_remaining = Vec :: with_capacity ( sys_count) ;
178236 }
179237
@@ -257,7 +315,6 @@ impl SystemExecutor for MultiThreadedExecutor {
257315
258316 debug_assert ! ( state. ready_systems. is_clear( ) ) ;
259317 debug_assert ! ( state. running_systems. is_clear( ) ) ;
260- state. active_access . clear ( ) ;
261318 state. evaluated_sets . clear ( ) ;
262319 state. skipped_systems . clear ( ) ;
263320 state. completed_systems . clear ( ) ;
@@ -345,9 +402,9 @@ impl ExecutorState {
345402 fn new ( ) -> Self {
346403 Self {
347404 system_task_metadata : Vec :: new ( ) ,
405+ set_condition_conflicting_systems : Vec :: new ( ) ,
348406 num_running_systems : 0 ,
349407 num_dependencies_remaining : Vec :: new ( ) ,
350- active_access : default ( ) ,
351408 local_thread_running : false ,
352409 exclusive_running : false ,
353410 evaluated_sets : FixedBitSet :: new ( ) ,
@@ -368,8 +425,6 @@ impl ExecutorState {
368425 self . finish_system_and_handle_dependents ( result) ;
369426 }
370427
371- self . rebuild_active_access ( ) ;
372-
373428 // SAFETY:
374429 // - `finish_system_and_handle_dependents` has updated the currently running systems.
375430 // - `rebuild_active_access` locks access for all currently running systems.
@@ -488,37 +543,30 @@ impl ExecutorState {
488543 {
489544 for condition in & mut conditions. set_conditions [ set_idx] {
490545 condition. update_archetype_component_access ( world) ;
491- if !condition
492- . archetype_component_access ( )
493- . is_compatible ( & self . active_access )
494- {
495- return false ;
496- }
546+ }
547+ if !self . set_condition_conflicting_systems [ set_idx] . is_disjoint ( & self . running_systems ) {
548+ return false ;
497549 }
498550 }
499551
500552 for condition in & mut conditions. system_conditions [ system_index] {
501553 condition. update_archetype_component_access ( world) ;
502- if !condition
503- . archetype_component_access ( )
504- . is_compatible ( & self . active_access )
505- {
506- return false ;
507- }
554+ }
555+ if !system_meta
556+ . condition_conflicting_systems
557+ . is_disjoint ( & self . running_systems )
558+ {
559+ return false ;
508560 }
509561
510562 if !self . skipped_systems . contains ( system_index) {
511563 system. update_archetype_component_access ( world) ;
512- if !system
513- . archetype_component_access ( )
514- . is_compatible ( & self . active_access )
564+ if !system_meta
565+ . conflicting_systems
566+ . is_disjoint ( & self . running_systems )
515567 {
516568 return false ;
517569 }
518-
519- self . system_task_metadata [ system_index]
520- . archetype_component_access
521- . clone_from ( system. archetype_component_access ( ) ) ;
522570 }
523571
524572 true
@@ -648,9 +696,6 @@ impl ExecutorState {
648696 context. system_completed ( system_index, res, system) ;
649697 } ;
650698
651- self . active_access
652- . extend ( & system_meta. archetype_component_access ) ;
653-
654699 if system_meta. is_send {
655700 context. scope . spawn ( task) ;
656701 } else {
@@ -741,15 +786,6 @@ impl ExecutorState {
741786 }
742787 }
743788 }
744-
745- fn rebuild_active_access ( & mut self ) {
746- self . active_access . clear ( ) ;
747- for index in self . running_systems . ones ( ) {
748- let system_meta = & self . system_task_metadata [ index] ;
749- self . active_access
750- . extend ( & system_meta. archetype_component_access ) ;
751- }
752- }
753789}
754790
755791fn apply_deferred (
0 commit comments