-
-
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
Composable Pipeline Specialization #17373
base: main
Are you sure you want to change the base?
Conversation
cc5d27d
to
3b79eb0
Compare
still dying because of HashMap. Why?
3b79eb0
to
7e084d4
Compare
620170e
to
5a33a21
Compare
Ok(field_info) | ||
} | ||
|
||
fn get_struct_fields<'a>(ast: &'a DeriveInput, derive_name: &str) -> syn::Result<&'a Fields> { |
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.
u can use bevy_macro_utils::get_struct_fields. Probably also for more things here.
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.
good point. I used a custom version originally for better error messages, but I should probably just upstream those changes to get_struct_fields
Objective
Our pipeline specialization APIs are confusing and duplicated in several places.
The relationship between the several traits we have (
SpecializedMeshPipeline
,etc.) and the various wrappers that implement them (
MaterialPipeline
,MeshPipeline
etc.) isn't very clear-cut, and adding new logic often requires a new trait or wrapper.Solution
Add a unifying trait:
Specialize
, a container:Specializer
, along witha derive macro to compose specializers together.
Rather than the workflow we have now, defining several layers of wrappers, which each defer to some internal logic, new specializers are "flat" and composed of a series of objects which take in a key and transform a pipeline descriptor one-by-one. Note that this means
Specialize
implementations no longer produce descriptors, but transform them. This also means that we have to get a "base" descriptor from somewhere. This can either be passed in manually when creating aSpecializer
, or created usingSpecializer::from_world
forSpecialize
implementations that also satisfyFromWorld
andHasBaseDescriptor
.What this might mean for our internal logic: we could split the view bind group layout info outside of
MeshPipeline
, allowing us to clean things up a little there and maybe move more of our mesh stuff tobevy_mesh
. We could also makeMaterialPipeline
no longer a wrapper, to simplify things a bit. Also, making our specialization more modular should reduce duplication for users doing any kind of custom queuing.Testing
Showcase
What material specialization might look like after this change:
Migration Guide
For manual implementers
SpecializedRenderPipeline
->Specialize<RenderPipeline>
.SpecializedMeshPipeline
->Specialize<RenderPipeline>
but include a mesh specializer.SpecializedComputePipeline
->Specialize<ComputePipeline>
.SpecializedXPipelines<S>
->Specializer<X, S>
For derive macro usage
Derive macro names can't have generic parameters, so to derive
Specialize<RenderPipeline>
use#[derive(Specialize)]
and#[specialize(RenderPipeline)]
.To derive
Specialize<RenderPipeline>
use#[derive(Specialize)]
and#[specialize(RenderPipeline)]
.#[specialize(..targets)]
can take multiple specialize targets, or use#[specialize(all)]
to generate a fully generic implementation, at the cost of slightly worse error messages when the trait bounds aren't satisfied.For Followup
SpecializedMeshPipeline
, see if we want to search for "compatible" keys rather than the same key (how to do so quickly?)