@openhps/core
Version:
Open Hybrid Positioning System - Core component
143 lines (136 loc) • 5.19 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WebGLAttributes = WebGLAttributes;
function WebGLAttributes(gl) {
const buffers = new WeakMap();
function createBuffer(attribute, bufferType) {
const array = attribute.array;
const usage = attribute.usage;
const size = array.byteLength;
const buffer = gl.createBuffer();
gl.bindBuffer(bufferType, buffer);
gl.bufferData(bufferType, array, usage);
attribute.onUploadCallback();
let type;
if (array instanceof Float32Array) {
type = gl.FLOAT;
} else if (array instanceof Uint16Array) {
if (attribute.isFloat16BufferAttribute) {
type = gl.HALF_FLOAT;
} else {
type = gl.UNSIGNED_SHORT;
}
} else if (array instanceof Int16Array) {
type = gl.SHORT;
} else if (array instanceof Uint32Array) {
type = gl.UNSIGNED_INT;
} else if (array instanceof Int32Array) {
type = gl.INT;
} else if (array instanceof Int8Array) {
type = gl.BYTE;
} else if (array instanceof Uint8Array) {
type = gl.UNSIGNED_BYTE;
} else if (array instanceof Uint8ClampedArray) {
type = gl.UNSIGNED_BYTE;
} else {
throw new Error('THREE.WebGLAttributes: Unsupported buffer data format: ' + array);
}
return {
buffer: buffer,
type: type,
bytesPerElement: array.BYTES_PER_ELEMENT,
version: attribute.version,
size: size
};
}
function updateBuffer(buffer, attribute, bufferType) {
const array = attribute.array;
const updateRanges = attribute.updateRanges;
gl.bindBuffer(bufferType, buffer);
if (updateRanges.length === 0) {
// Not using update ranges
gl.bufferSubData(bufferType, 0, array);
} else {
// 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];
gl.bufferSubData(bufferType, range.start * array.BYTES_PER_ELEMENT, array, range.start, range.count);
}
attribute.clearUpdateRanges();
}
attribute.onUploadCallback();
}
//
function get(attribute) {
if (attribute.isInterleavedBufferAttribute) attribute = attribute.data;
return buffers.get(attribute);
}
function remove(attribute) {
if (attribute.isInterleavedBufferAttribute) attribute = attribute.data;
const data = buffers.get(attribute);
if (data) {
gl.deleteBuffer(data.buffer);
buffers.delete(attribute);
}
}
function update(attribute, bufferType) {
if (attribute.isInterleavedBufferAttribute) attribute = attribute.data;
if (attribute.isGLBufferAttribute) {
const cached = buffers.get(attribute);
if (!cached || cached.version < attribute.version) {
buffers.set(attribute, {
buffer: attribute.buffer,
type: attribute.type,
bytesPerElement: attribute.elementSize,
version: attribute.version
});
}
return;
}
const data = buffers.get(attribute);
if (data === undefined) {
buffers.set(attribute, createBuffer(attribute, bufferType));
} else if (data.version < attribute.version) {
if (data.size !== attribute.array.byteLength) {
throw new Error('THREE.WebGLAttributes: The size of the buffer attribute\'s array buffer does not match the original size. Resizing buffer attributes is not supported.');
}
updateBuffer(data.buffer, attribute, bufferType);
data.version = attribute.version;
}
}
return {
get: get,
remove: remove,
update: update
};
}