Skip to content

WebGLRenderer: Merge update ranges before issuing updates to the GPU. #29189

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 2 commits into from
Sep 2, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/renderers/webgl/WebGLAttributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,50 @@ function WebGLAttributes( gl ) {

if ( updateRanges.length !== 0 ) {

// Before applying update ranges, we merge any adjacent / overlapping
// ranges to reduce load on `gl.bufferSubData`. Empirically, this has led
// to performance improvements for applications which make heavy use of
// update ranges. Likely due to GPU command overhead.
//
// Note that to reduce garbage collection between frames, we merge the
// update ranges in-place. This is safe because this method will clear the
// update ranges once updated.

updateRanges.sort( ( a, b ) => a.start - b.start );

// To merge the update ranges in-place, we work from left to right in the
// existing updateRanges array, merging ranges. This may result in a final
// array which is smaller than the original. This index tracks the last
// index representing a merged range, any data after this index can be
// trimmed once the merge algorithm is completed.
let mergeIndex = 0;

for ( let i = 1; i < updateRanges.length; i ++ ) {

const previousRange = updateRanges[ mergeIndex ];
const range = updateRanges[ i ];

// We add one here to merge adjacent ranges. This is safe because ranges
// operate over positive integers.
if ( range.start <= previousRange.start + previousRange.count + 1 ) {

previousRange.count = Math.max(
previousRange.count,
range.start + range.count - previousRange.start
);

} else {

++ mergeIndex;
updateRanges[ mergeIndex ] = range;

}

}

// Trim the array to only contain the merged ranges.
updateRanges.length = mergeIndex + 1;

for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {

const range = updateRanges[ i ];
Expand Down