|
|
@@ -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 ];
|