Skip to content
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

Generating a lot of garbage by using BufferAttribute.updateRange #18387

Closed
Usnul opened this issue Jan 13, 2020 · 5 comments
Closed

Generating a lot of garbage by using BufferAttribute.updateRange #18387

Usnul opened this issue Jan 13, 2020 · 5 comments

Comments

@Usnul
Copy link
Contributor

Usnul commented Jan 13, 2020

updateRange parameter of a BufferAttribute is intended to improve performance. I use it in my particle engine. I have been doing some performance testing and found following picture to be pretty standard across my game:
image

As you can see, about 26% of the garbage alone comes from here:

function updateBuffer( buffer, attribute, bufferType ) {
var array = attribute.array;
var updateRange = attribute.updateRange;
gl.bindBuffer( bufferType, buffer );
if ( updateRange.count === - 1 ) {
// Not using update ranges
gl.bufferSubData( bufferType, 0, array );
} else {
gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,
array.subarray( updateRange.offset, updateRange.offset + updateRange.count ) );
updateRange.count = - 1; // reset range
}
}

Why does this happen? Because WebGL1.0 does not allow you to specify offset and length of the source array that you you supply.

Here's a relevant piece from MDN:

// WebGL1: 
void gl.bufferSubData(target, offset, ArrayBuffer srcData); 
void gl.bufferSubData(target, offset, ArrayBufferView srcData); 

// WebGL2: 
void gl.bufferSubData(target, dstByteOffset, ArrayBufferView srcData, srcOffset, length);

Well, I'm in luck, I do use WebGL2. I'm not sure how to make three.js understand that though, so that we can avoid that needless .subarray call that generates all the garbage currently.

Any thoughts?

@Usnul Usnul changed the title Generating a lot of garbage by using updateRange parameter Generating a lot of garbage by using BufferAttribute.updateRange Jan 13, 2020
@aardgoose
Copy link
Contributor

Do you see the same results with Chrome, TypedArray.subarray() is documented as using the same backing storage as the source object, and should just create a small object wrapping it and not consume much additional memory.

@Usnul
Copy link
Contributor Author

Usnul commented Jan 14, 2020

Chrome memory profiling tools don't do nearly as good of a job, but I do see GC pauses, and relatively large ones, which leads me to believe that memory fragments are fairly large too. That's pure speculation on my part though.

@Mugen87
Copy link
Collaborator

Mugen87 commented Jan 15, 2020

Maybe better to move the discussion to https://bugs.chromium.org/p/chromium/issues/list and verify the performance of subarray() there 🤔

@aardgoose
Copy link
Contributor

Looking at the stats more closely it does look like an overhead of about 90 bytes per array buffer update, so this is probably just the overhead of creating a new ArrayBuffer via subarray() rather than a performance issue with subarray (the issue occurs in FF and Chrome anyway). Which was presumably one of the drivers for the change in the WebGL2 API. There doesn't appear to be any other way of avoiding the problem.

Would it be acceptable to query the gl context gl.VERSION at WebGLAttributes construction time and set a flag to select the WebGL API form of the call when using bufferSubData?

@Mugen87
Copy link
Collaborator

Mugen87 commented Jan 15, 2020

Would it be acceptable to query the gl context gl.VERSION at WebGLAttributes construction time and set a flag to select the WebGL API form of the call when using bufferSubData?

You may want to use the existing isWebGL2 flag of WebGLCapabilities.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants