Skip to content

Don't recreate material bind groups if none of the GPU resources changed.#25058

Open
pcwalton wants to merge 3 commits into
bevyengine:mainfrom
pcwalton:fast-material-update-prep-2
Open

Don't recreate material bind groups if none of the GPU resources changed.#25058
pcwalton wants to merge 3 commits into
bevyengine:mainfrom
pcwalton:fast-material-update-prep-2

Conversation

@pcwalton

Copy link
Copy Markdown
Contributor

At the moment, whenever a material changes, we free and recreate the bind group in the material bind group allocator. This is necessary in general when one or more GPU resources (buffers, textures, samplers) change, because it's possible for changing one of those to cause a material to overflow the slab. However, when only POD (plain old data) changes, for example a color, this constitutes needless overhead.

This patch improves the performance in this case by adding an early check and fast path to material asset preparation for bindless materials. With this PR, before we free and reallocate a material, we walk through the list of all GPU resources, checking to see if the new version of the material has the same bindings. If so, we keep the material as-is in the bind group allocator and only update the data buffers.

Additionally, this PR removes the allocations in the unprepared_bind_group function by introducing an BindGroupBuilder abstraction that allows reusing allocations between frames. The BindGroupBuilder::binding_resources vector and the BindGroupBuilder::data_buffer are now temporary staging buffers that can be reused from bind group to bind group.

Note that we currently still perform allocations for non-bindless materials. This can be improved, but because non-bindless materials upload their data later than bindless materials do, reusing the data buffers isn't as straightforward.

Importantly, this PR opens the door to parallel material preparation in the future. This is because neither the fast path nor the check to make sure we can take the fast path mutate the MaterialBindGroupAllocator, outside of the data buffer itself. Therefore, in the future, we can migrate the material data buffer to AtomicSparseBufferVec and update it in parallel just as we do for mesh instance uniforms. Note however that parallel material preparation needs some more work in the assets infrastructure, and I suspect that work will collide with assets-as-entities, so I opted to leave that for a follow-up (and also to prevent this patch from growing too large).

Future work could involve adding a special fast path for materials that are only POD to avoid most of the material bind group allocator machinery entirely. Note that, if updating shader-accessible instance data is performance-critical, applications may find GpuComponentArrayBuffer to be a better fit than the material system.

On many_cubes --vary-material-data-per-instance --animate-materials --instance-count 16000, this PR improves the performance of prepare_erased_assets on StandardMaterial from 33.0 ms/frame to 21.7 ms/frame, a 1.51× speedup.

Screenshot 2026-07-17 220544

changed.

At the moment, whenever a material changes, we free and recreate the
bind group in the material bind group allocator. This is necessary in
general when one or more GPU resources (buffers, textures, samplers)
change, because it's possible for changing one of those to cause a
material to overflow the slab. However, when only POD (plain old data)
changes, for example a color, this constitutes needless overhead.

This patch improves the performance in this case by adding an early
check and fast path to material asset preparation for bindless
materials. With this PR, before we free and reallocate a material, we
walk through the list of all GPU resources, checking to see if the new
version of the material has the same bindings. If so, we keep the
material as-is in the bind group allocator and only update the data
buffers.

Additionally, this PR removes the allocations in the
`unprepared_bind_group` function by introducing an `BindGroupBuilder`
abstraction that allows reusing allocations between frames. The
`BindGroupBuilder::binding_resources` vector and the
`BindGroupBuilder::data_buffer` are now temporary staging buffers that
can be reused from bind group to bind group.

Note that we currently still perform allocations for non-bindless
materials. This can be improved, but because non-bindless materials
upload their data later than bindless materials do, reusing the data
buffers isn't as straightforward.

Importantly, this PR opens the door to parallel material preparation in
the future. This is because neither the fast path nor the check to make
sure we can take the fast path mutate the `MaterialBindGroupAllocator`,
outside of the data buffer itself. Therefore, in the future, we can
migrate the material data buffer to `AtomicSparseBufferVec` and update
it in parallel just as we do for mesh instance uniforms. Note however
that parallel material preparation needs some more work in the assets
infrastructure, and I suspect that work will collide with
assets-as-entities, so I opted to leave that for a follow-up (and also
to prevent this patch from growing too large).

Future work could involve adding a special fast path for materials that
are *only* POD to avoid most of the material bind group allocator
machinery entirely. Note that, if updating shader-accessible instance
data is performance-critical, applications may find
[`GpuComponentArrayBuffer`] to be a better fit than the material system.

On `many_cubes --vary-material-data-per-instance --animate-materials
--instance-count 16000`, this PR improves the performance of
`prepare_erased_assets` on `StandardMaterial` from 33.0 ms/frame to
21.7 ms/frame, a 1.51× speedup.

[`GpuComponentArrayBuffer`]: bevyengine#24922
@pcwalton pcwalton added the A-Rendering Drawing game state to the screen label Jul 18, 2026
@github-project-automation github-project-automation Bot moved this to Needs SME Triage in Rendering Jul 18, 2026
@pcwalton pcwalton added C-Performance A change motivated by improving speed, memory usage or compile times S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Jul 18, 2026
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 C-Performance A change motivated by improving speed, memory usage or compile times S-Needs-Review Needs reviewer attention (from anyone!) to move forward

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

1 participant