-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Type erased materials #19667
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
Type erased materials #19667
Conversation
Material trait bound from all render world systems and resources
|
Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke! If it's expected, please add the M-Deliberate-Rendering-Change label. If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it. |
|
Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke! If it's expected, please add the M-Deliberate-Rendering-Change label. If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it. |
|
Your PR caused a change in the graphical output of an example or rendering test. This might be intentional, but it could also mean that something broke! If it's expected, please add the M-Deliberate-Rendering-Change label. If this change seems unrelated to your PR, you can consider updating your PR to target the latest main branch, either by rebasing or merging main into it. |
Material trait bound from all render world systems and resources| flate2 = "1.0" | ||
| serde = { version = "1", features = ["derive"] } | ||
| serde_json = "1.0.140" | ||
| bytemuck = "1.7" |
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 did this need to change?
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.
So the way that we're erasing material key (aka bind group data) in this PR at the moment is by going through bytemuck (see MaterialProperties where it's stored as a SmallVec), which basically puts it in our public api.
I'm somewhat uncertain about this change as it enforces new constraints on AsBindGroup::Data, namely the bytemuck derives and repr c. On the one hand, our use of bind group data internal to the engine is always in the form of flags and so this just makes that explicit. On the other hand, if people want to have weird material keys, maybe it isn't our place to stop them.
The alternative is doing Box<dyn Any>, but I ran into problems with making that hashable. The key bit here is that while the erased key only needs to be downcast to the concrete material key in the event you are respecializing, it needs to be hashable for the internal pipeline cache check. While actual respecialization is rare, the cache check happens any time a mesh/material changes.
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 I understand how this relates to changing the bytemuck version 😅
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.
Oh sorry! It needs to match the version used in bevy_pbr. If we wanted to add that constraint, we should probably re-export it.
| ( | ||
| check_views_lights_need_specialization.in_set(RenderSystems::PrepareAssets), | ||
| // specialize_shadows also needs to run after prepare_assets::<PreparedMaterial>, | ||
| // which is fine since ManageViews is after PrepareAssets |
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.
will ManageViews always be after PrepareAssets or might something change it down the line? i think a redundant edge for defensiveness doesnt have overhead, right?
atlv24
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.
so cool. so good
| }) | ||
| } | ||
|
|
||
| fn bind_group_data(&self) -> Self::Data {} |
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.
Very minor thing, but if it's valid to not return anything this should probably just the default behaviour of the trait
IceSentry
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.
I think there's a couple of things that could still be simplified, but this is a good starting point and we can iterate on everything else. I'm very excited for what kind of features this will unlock for us!
LGTM to me
# Objective - PrepassPipelineInternal used to exist to optimize compile time and binary size when PrepassPipeline was generic over the material. - After #19667, PrepassPipeline is no longer generic! ## Solution - Flatten all the fields of `PrepassPipelineInternal` into `PrepassPipeline`.
…refactoring as it depended on the generic parameter which has been erased in bevyengine#19667.
# Objective #19667 added a `bytemuck::Pod` type constraint on `AsBindGroup::Data` which, while technically a reasonable constraint to expect from material keys, imposed a breaking change on our users which may be confusing / difficult for them to work around. It's not technically invalid to store arbitrary types in a material key, just probably bad practice. Additionally, the performance concerns here were probably overstated: 1. cold specialization makes re-specialization less likely. 2. we can mitigate going through the vtable unnecessarily by pre-computing our hash which should still make the boxed storage fast in almost all cases where we don't get a collision. ## Solution Use `Box<dyn Any>` for erasure.
# Objective #19667 introduced a type-erased material system that effectively puts all material instances through a single cache: during asset preparation (`ErasedRenderAssetPlugin`), materials are processed into a set of `MaterialProperties` that contains all the data needed to render them, and these are all cached and deduplicated as needed. This allows for maximal flexibility (every single material instance could have a different ""type"") but complicates the logic and makes cache keys really big. So, one goal for the material revamp I have (and I think @tychedelia is on board) is to cache materials at two levels: material "types" and material "instances", where material types roughly map to the rust types that currently implement `Material`. Without getting into implementation details, storing mostly static data separate from instance data would let us simplify a lot of the logic, while only requiring a little more work for fully-dynamic use cases. This PR is a first step in that direction, which stores *all* the available draw functions in `MaterialProperties`, and pushes the decision for "what draw function should I use for this material?" to queue time, where before it was split between there and asset preparation. This makes the list of available draw functions instance-independent, and will later allow us to store it with other "static" material data. ## Solution - Make draw function labels 1:1 with render phases, and include all of them in the list in `MaterialProperties` ## Testing - Ran `3d_scene` - Ran `manual_material`
Objective
Closes #18075
In order to enable a number of patterns for dynamic materials in the engine, it's necessary to decouple the renderer from the
Materialtrait.This opens the possibility for:
AsBindGroup.Solution
In short, remove all trait bounds from render world material systems and resources. This means moving a bunch of stuff onto
MaterialPropertiesand engaging in some hacks to make specialization work. Rather than storing the bind group data inMaterialBindGroupAllocator, right now we're storing it in a closure onMaterialProperties. TBD if this has bad performance characteristics.Benchmarks
many_cubes:cargo run --example many_cubes --release --features=bevy/trace_tracy -- --vary-material-data-per-instance:@DGriffin91's Caldera

cargo run --release --features=bevy/trace_tracy -- --random-materials@DGriffin91's Caldera with 20 unique material types (i.e.

MaterialPlugin<M>) and random materials per meshcargo run --release --features=bevy/trace_tracy -- --random-materialsTODO
Fix meshletsShowcase
See the example for a custom material implemented without the use of the
Materialtrait and thusAsBindGroup.