Is it safe to use BufferGeometry.setAttribute?

Hi Everyone,

I’m using threejs to stream 3d objects data continuously with fair amount of geometry generation on the fly.

Below code illustrates this approach where I recreate buffer attributes only if needed, leaving Mesh+BufferGeometry constantly alive.

I haven’t noticed GPU memory pollution maybe because reallocations do not happen often.

I’m curious is my approach safe? I see BufferGeometries are disposed in WebGLGeometries.js as per ‘dispose’ event handling. If I don’t dispose a geometry and change its attributes instead, the old attribute buffers are not going to be disposed in the GPU.

export const updatePointsGeometry = (
  mesh: Points,
  positions: TypedArray | null,
) => {
  if (positions) {
    const pointCount = positions.length / 3
    const vb = mesh.geometry.getAttribute('position')

    const shouldRecreate =
      vb?.array?.buffer !== positions.buffer ||
      vb?.array.byteOffset !== positions.byteOffset ||
      vb?.array.length < positions.length

    if (shouldRecreate) {
      mesh.geometry.setAttribute('position', new BufferAttribute(positions, 3,      false))
    } else {
      updateAttributeRange(vb, 0, pointCount)
    }

    mesh.geometry.setDrawRange(0, pointCount)
  }
}

Edit: (see below)

  • The code above is called continuously.
  • ‘positions’ is the Float32Array (or its shorter view) that gets preallocated beforehand with some capacity.
  • It gets updated with new data frequently. When it’s within initial capacity, the BufferAttribute is updated by calling updateAttributeRange.
  • At some point its capacity may be less than needed, so it gets recreated with new capacity, which needs a new BufferAttribute.

I’m concerned what happens to old GPU buffer from previous BufferAttribute that I had in that BufferGeometry.

I can use GLBufferAttribute to manage vbo updating myself, but then I may want to align the CPU-GPU updates with Request Animation Frame callback, which sounds like what Threejs is already doing with BufferAttributes.

Edit: (see below)

Thanks for your opinion! Much appreciated. I will be watching what happens to the memory and keep finding more about the VBO workflow in Threejs source code.

So I tested it live, because this question is haunting me and I wanted to be sure.

And…I’m wrong. There is no guardrails at all after a frame is rendered.
The JS side is garbage collected, yes. But this is not the topic of the question, not what we want!

Once the buffer is passed to the GPU, the only “accessible” way in the whole three.js API is dispose(). Internal code would allow to delete specific bufferAttribute, but they are not exposed.
we don’t even have a choice to target a specific one.

Sorry to answer on memory and not testing it trough actual practice. Screw me :laughing:
It was discussed but never implemented.

TLDR: once one frame is rendererd dispose(), or leak. No other options