Don't recreate material bind groups if none of the GPU resources changed.#25058
Open
pcwalton wants to merge 3 commits into
Open
Don't recreate material bind groups if none of the GPU resources changed.#25058pcwalton wants to merge 3 commits into
pcwalton wants to merge 3 commits into
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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_groupfunction by introducing anBindGroupBuilderabstraction that allows reusing allocations between frames. TheBindGroupBuilder::binding_resourcesvector and theBindGroupBuilder::data_bufferare 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 toAtomicSparseBufferVecand 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
GpuComponentArrayBufferto 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 ofprepare_erased_assetsonStandardMaterialfrom 33.0 ms/frame to 21.7 ms/frame, a 1.51× speedup.