Skip to content

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

Merged
merged 34 commits into from
Jun 27, 2025

Conversation

tychedelia
Copy link
Member

@tychedelia tychedelia commented Jun 16, 2025

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 Material trait.

This opens the possibility for:

  • Materials that aren't coupled to AsBindGroup.
  • 2d using the underlying 3d bindless infrastructure.
  • Dynamic materials that can change their layout at runtime.
  • Materials that aren't even backed by a Rust struct at all.

Solution

In short, remove all trait bounds from render world material systems and resources. This means moving a bunch of stuff onto MaterialProperties and engaging in some hacks to make specialization work. Rather than storing the bind group data in MaterialBindGroupAllocator, right now we're storing it in a closure on MaterialProperties. 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:
    Screenshot 2025-06-26 235426

  • @DGriffin91's Caldera
    cargo run --release --features=bevy/trace_tracy -- --random-materials
    image

  • @DGriffin91's Caldera with 20 unique material types (i.e. MaterialPlugin<M>) and random materials per mesh
    cargo run --release --features=bevy/trace_tracy -- --random-materials
    Screenshot 2025-06-27 000425

TODO

  • We almost certainly lost some parallelization from removing the type params that could be gained back from smarter iteration.
  • Test all the things that could have broken.
  • Fix meshlets

Showcase

See the example for a custom material implemented without the use of the Material trait and thus AsBindGroup.

image

@tychedelia tychedelia changed the title Erase material types from the render world Remove Material trait bound from all render world systems and resources Jun 16, 2025
@tychedelia tychedelia added A-Rendering Drawing game state to the screen M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide D-Complex Quite challenging from either a design or technical perspective. Ask for help! X-Controversial There is active debate or serious implications around merging this PR M-Needs-Release-Note Work that should be called out in the blog due to impact S-Needs-Review Needs reviewer attention (from anyone!) to move forward S-Needs-SME Decision or review from an SME is required labels Jun 16, 2025
Copy link
Contributor

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!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-19667

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.

Copy link
Contributor

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!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-19667

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.

@ecoskey ecoskey self-requested a review June 16, 2025 01:46
Copy link
Contributor

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!
You can review it at https://pixel-eagle.com/project/B04F67C0-C054-4A6F-92EC-F599FEC2FD1D?filter=PR-19667

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.

@tychedelia tychedelia changed the title Remove Material trait bound from all render world systems and resources Type erased materials Jun 16, 2025
@IceSentry IceSentry self-requested a review June 16, 2025 19:32
@@ -566,7 +566,7 @@ ron = "0.10"
flate2 = "1.0"
serde = { version = "1", features = ["derive"] }
serde_json = "1.0.140"
bytemuck = "1.7"
Copy link
Contributor

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?

Copy link
Member Author

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.

Copy link
Contributor

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 😅

Copy link
Member Author

@tychedelia tychedelia Jun 16, 2025

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.

@tychedelia tychedelia requested a review from IceSentry June 27, 2025 07:35
@tychedelia
Copy link
Member Author

@ecoskey

I'm not the biggest fan of all the new interned labels or how big MaterialProperties has gotten, but it makes sense while we figure out better workflows/materials-as-entities.

I'm not either at all, but having a bunch of fields was gross. Part of the goal here too is to be able to re-use this for 2d, and so it would be ideal to keep it somewhat general. I have a version of this PR where I convert everything to entities and components and it's nice and clean but results in a lot more changes. I think we can get there but I wanted to do this as an incremental step. I'd be happy to remove the labels since ideally we remove them before 0.17 but idk, having 27 shader fields wasn't great either.

@tychedelia tychedelia requested a review from ecoskey June 27, 2025 07:48
);

#[cfg(feature = "meshlet")]
render_app.add_systems(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that these don't depend on material generics, lets move them into the meshlet plugin.

@tychedelia tychedelia requested a review from pcwalton June 27, 2025 16:13
(
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
Copy link
Contributor

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?

Copy link
Contributor

@atlv24 atlv24 left a 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 {}
Copy link
Contributor

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

Copy link
Contributor

@IceSentry IceSentry left a 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

@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Blessed Has a large architectural impact or tradeoffs, but the design has been endorsed by decision makers and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward S-Needs-SME Decision or review from an SME is required X-Controversial There is active debate or serious implications around merging this PR labels Jun 27, 2025
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Jun 27, 2025
Merged via the queue into bevyengine:main with commit e6ba9a6 Jun 27, 2025
40 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen D-Complex Quite challenging from either a design or technical perspective. Ask for help! M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide M-Needs-Release-Note Work that should be called out in the blog due to impact S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Blessed Has a large architectural impact or tradeoffs, but the design has been endorsed by decision makers
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Type erased / dynamic runtime materials
6 participants