-
-
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
Schedule build pass #11094
base: main
Are you sure you want to change the base?
Schedule build pass #11094
Conversation
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.
Broadly in favor of generalizing this into a series of passes to modularize the API and add more expressive tools.
I'm quite reluctant about the proposed future API using tuples for config: I think it's much more complex to reason about both internally and externally. I'd much rather have a simple config struct if possible. Perhaps it will become clearer to me as more documentation is added?
@alice-i-cecile schedule.add_systems(
system.before_with_options(another_system, DependencyOptions {
ignore_deferred: true,
})
); However, an external plugin adds a different schedule.add_systems(
system.before_with_options(another_system, DependencyOptions {
ignore_deferred: true,
// Can't add more options here! Not extensible. Sucks!
})
); The natural solution is providing those options as a tuple when adding dependency edges schedule.add_systems(
system.before_with_options(another_system, (
IgnoreDeferred, // Provided by AutoInsertApplyDeferredPass in bevy core
AutoAddPipelineBarrierOptions {
prev_stages: vk::PipelineStages::Compute,
next_stages: vk::PipelineStages::Transfer,
} // Provided by `AutoAddPipelineBarrierPass` from a third party plugin. Extensible. Good!
))
); |
auto_sync_node_ids: HashMap<u32, NodeId>, | ||
} | ||
|
||
/// If added to a dependency edge, the edge will not be considered for auto sync point insertions. |
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 should have a doc test or link to a type that has a doc test :)
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.
We only add this inside after_ignore_deferred
and before_ignore_deferred
. I intend to remove these two APIs and replace them with the API I described above. I can certainly add a doc test in that PR.
auto_sync_node_ids: HashMap<u32, NodeId>, | ||
|
||
/// A map of [`ScheduleBuildPassObj`]es, keyed by the [`TypeId`] of the corresponding [`ScheduleBuildPass`]. | ||
passes: BTreeMap<TypeId, Box<dyn ScheduleBuildPassObj>>, |
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.
Can we use a plain BTreeMap
here? The order of the schedule passes surely matters once we have more complex passes. While the iteration order of a BTree is stable, I don't think it's able to be controlled in the way that we might need.
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.
Not sure what it means? We're already using a BTreeMap
here.
We'd certainly want to control the ordering of those passes but I would defer that to a future PR when such a need arises.
For now, the reason we use a BTreeMap
instead of a Vec
here is that a BTreeMap
makes it easier to remove passes and it guarantees unique instantiation of passes based on type, ensuring that the same type won't be accidentally added twice.
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 meant "is it correct to use a BTreeMap". I'm definitely fine to leave that until a later PR though.
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.
The documentation was extremely helpful, thank you! I suspected that we couldn't use a simple config struct due to extensibility, but I was having trouble putting together the pieces.
A bit delayed because I wanted to make sure that the PR is suitable for my use case. But now it should be ready to merge. Resolved all merge conflicts. No major changes required from the initial implementation. |
@@ -1079,7 +1118,7 @@ impl ScheduleGraph { | |||
/// - checks for system access conflicts and reports ambiguities | |||
pub fn build_schedule( | |||
&mut self, | |||
components: &Components, | |||
world: &mut World, |
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.
why does this now need &mut World access?
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.
Because custom schedule build passes will frequently need &mut World
access to be useful. This allows us to pass the &mut World
all the way down. The custom schedule build pass may want to insert resources into the world for these systems.
fb1f5fd
to
6038595
Compare
6038595
to
45f82f9
Compare
Objective
This is a follow up to #9822, which automatically adds sync points during the Schedule build process.
However, the implementation in #9822 feels very "special case" to me. As the number of things we want to do with the
Schedule
grows, we need a modularized way to manage those behaviors. For example, in one of my current experiments I want to automatically add systems to apply GPU pipeline barriers between systems accessing GPU resources.For dynamic modifications of the schedule, we mostly need these capabilities:
These should be enough to allows us to add "hooks" to the schedule build process for various reasons.
cc @hymm
Solution
This PR abstracts the process of schedule modification and created a new trait,
ScheduleBuildPass
. Most of the logics in #9822 were moved to an implementation ofScheduleBuildPass
,AutoInsertApplyDeferredPass
.Whether a dependency edge should "ignore deferred" is now indicated by the presence of a marker struct,
IgnoreDeferred
.This PR has no externally visible effects. However, in a future PR I propose to change the
before_ignore_deferred
andafter_ignore_deferred
API into a more general form,before_with_options
andafter_with_options
.