docs: function _commitVertexBuffers(device, gl, cur, next) {
    let attrsDirty = false;
  
    // nothing changed for vertex buffer
    if (next.maxStream === -1) {
      console.warn('VertexBuffer not assigned, please call setVertexBuffer before every draw.');
      return;
    }
  
    if (cur.maxStream !== next.maxStream) {
      attrsDirty = true;
    } else if (cur.program !== next.program) {
      attrsDirty = true;
    } else {
      for (let i = 0; i < next.maxStream + 1; ++i) {
        if (
          cur.vertexBuffers[i] !== next.vertexBuffers[i] ||
          cur.vertexBufferOffsets[i] !== next.vertexBufferOffsets[i]
        ) {
          attrsDirty = true;
          break;
        }
      }
    }
  
    if (attrsDirty) {
      for (let i = 0; i < device._caps.maxVertexAttribs; ++i) {
        device._newAttributes[i] = 0;
      }
  
      for (let i = 0; i < next.maxStream + 1; ++i) {
        let vb = next.vertexBuffers[i];
        let vbOffset = next.vertexBufferOffsets[i];
        if (!vb) {
          continue;
        }
  
        gl.bindBuffer(gl.ARRAY_BUFFER, vb._glID);
  
        for (let j = 0; j < next.program._attributes.length; ++j) {
          let attr = next.program._attributes[j];
  
          let el = vb._format.element(attr.name);
          if (!el) {
            console.warn(`Can not find vertex attribute: ${attr.name}`);
            continue;
          }
  
          if (device._enabledAttributes[attr.location] === 0) {
            gl.enableVertexAttribArray(attr.location);
            device._enabledAttributes[attr.location] = 1;
          }
          device._newAttributes[attr.location] = 1;
  
          gl.vertexAttribPointer(
            attr.location,
            el.num,
            el.type,
            el.normalize,
            el.stride,
            el.offset + vbOffset * el.stride
          );
        }
      }
  
      // disable unused attributes
      for (let i = 0; i < device._caps.maxVertexAttribs; ++i) {
        if (device._enabledAttributes[i] !== device._newAttributes[i]) {
          gl.disableVertexAttribArray(i);
          device._enabledAttributes[i] = 0;
        }
      }
    }
  }