259 lines
5.4 KiB
JavaScript
259 lines
5.4 KiB
JavaScript
import { IntType } from 'three';
|
|
|
|
let _id = 0;
|
|
|
|
class DualAttributeData {
|
|
|
|
constructor( attributeData, dualBuffer ) {
|
|
|
|
this.buffers = [ attributeData.bufferGPU, dualBuffer ];
|
|
this.type = attributeData.type;
|
|
this.bufferType = attributeData.bufferType;
|
|
this.pbo = attributeData.pbo;
|
|
this.byteLength = attributeData.byteLength;
|
|
this.bytesPerElement = attributeData.BYTES_PER_ELEMENT;
|
|
this.version = attributeData.version;
|
|
this.isInteger = attributeData.isInteger;
|
|
this.activeBufferIndex = 0;
|
|
this.baseId = attributeData.id;
|
|
|
|
}
|
|
|
|
|
|
get id() {
|
|
|
|
return `${ this.baseId }|${ this.activeBufferIndex }`;
|
|
|
|
}
|
|
|
|
get bufferGPU() {
|
|
|
|
return this.buffers[ this.activeBufferIndex ];
|
|
|
|
}
|
|
|
|
get transformBuffer() {
|
|
|
|
return this.buffers[ this.activeBufferIndex ^ 1 ];
|
|
|
|
}
|
|
|
|
switchBuffers() {
|
|
|
|
this.activeBufferIndex ^= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class WebGLAttributeUtils {
|
|
|
|
constructor( backend ) {
|
|
|
|
this.backend = backend;
|
|
|
|
}
|
|
|
|
createAttribute( attribute, bufferType ) {
|
|
|
|
const backend = this.backend;
|
|
const { gl } = backend;
|
|
|
|
const array = attribute.array;
|
|
const usage = attribute.usage || gl.STATIC_DRAW;
|
|
|
|
const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute;
|
|
const bufferData = backend.get( bufferAttribute );
|
|
|
|
let bufferGPU = bufferData.bufferGPU;
|
|
|
|
if ( bufferGPU === undefined ) {
|
|
|
|
bufferGPU = this._createBuffer( gl, bufferType, array, usage );
|
|
|
|
bufferData.bufferGPU = bufferGPU;
|
|
bufferData.bufferType = bufferType;
|
|
bufferData.version = bufferAttribute.version;
|
|
|
|
}
|
|
|
|
//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.WebGLBackend: Unsupported buffer data format: ' + array );
|
|
|
|
}
|
|
|
|
let attributeData = {
|
|
bufferGPU,
|
|
bufferType,
|
|
type,
|
|
byteLength: array.byteLength,
|
|
bytesPerElement: array.BYTES_PER_ELEMENT,
|
|
version: attribute.version,
|
|
pbo: attribute.pbo,
|
|
isInteger: type === gl.INT || type === gl.UNSIGNED_INT || type === gl.UNSIGNED_SHORT || attribute.gpuType === IntType,
|
|
id: _id ++
|
|
};
|
|
|
|
if ( attribute.isStorageBufferAttribute || attribute.isStorageInstancedBufferAttribute ) {
|
|
|
|
// create buffer for tranform feedback use
|
|
const bufferGPUDual = this._createBuffer( gl, bufferType, array, usage );
|
|
attributeData = new DualAttributeData( attributeData, bufferGPUDual );
|
|
|
|
}
|
|
|
|
backend.set( attribute, attributeData );
|
|
|
|
}
|
|
|
|
updateAttribute( attribute ) {
|
|
|
|
const backend = this.backend;
|
|
const { gl } = backend;
|
|
|
|
const array = attribute.array;
|
|
const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute;
|
|
const bufferData = backend.get( bufferAttribute );
|
|
const bufferType = bufferData.bufferType;
|
|
const updateRanges = attribute.isInterleavedBufferAttribute ? attribute.data.updateRanges : attribute.updateRanges;
|
|
|
|
gl.bindBuffer( bufferType, bufferData.bufferGPU );
|
|
|
|
if ( updateRanges.length === 0 ) {
|
|
|
|
// Not using update ranges
|
|
|
|
gl.bufferSubData( bufferType, 0, array );
|
|
|
|
} else {
|
|
|
|
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 );
|
|
|
|
}
|
|
|
|
bufferAttribute.clearUpdateRanges();
|
|
|
|
}
|
|
|
|
gl.bindBuffer( bufferType, null );
|
|
|
|
bufferData.version = bufferAttribute.version;
|
|
|
|
}
|
|
|
|
destroyAttribute( attribute ) {
|
|
|
|
const backend = this.backend;
|
|
const { gl } = backend;
|
|
|
|
if ( attribute.isInterleavedBufferAttribute ) {
|
|
|
|
backend.delete( attribute.data );
|
|
|
|
}
|
|
|
|
const attributeData = backend.get( attribute );
|
|
|
|
gl.deleteBuffer( attributeData.bufferGPU );
|
|
|
|
backend.delete( attribute );
|
|
|
|
}
|
|
|
|
async getArrayBufferAsync( attribute ) {
|
|
|
|
const backend = this.backend;
|
|
const { gl } = backend;
|
|
|
|
const bufferAttribute = attribute.isInterleavedBufferAttribute ? attribute.data : attribute;
|
|
const { bufferGPU } = backend.get( bufferAttribute );
|
|
|
|
const array = attribute.array;
|
|
const byteLength = array.byteLength;
|
|
|
|
gl.bindBuffer( gl.COPY_READ_BUFFER, bufferGPU );
|
|
|
|
const writeBuffer = gl.createBuffer();
|
|
|
|
gl.bindBuffer( gl.COPY_WRITE_BUFFER, writeBuffer );
|
|
gl.bufferData( gl.COPY_WRITE_BUFFER, byteLength, gl.STREAM_READ );
|
|
|
|
gl.copyBufferSubData( gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, 0, 0, byteLength );
|
|
|
|
await backend.utils._clientWaitAsync();
|
|
|
|
const dstBuffer = new attribute.array.constructor( array.length );
|
|
|
|
gl.getBufferSubData( gl.COPY_WRITE_BUFFER, 0, dstBuffer );
|
|
|
|
gl.deleteBuffer( writeBuffer );
|
|
|
|
return dstBuffer.buffer;
|
|
|
|
}
|
|
|
|
_createBuffer( gl, bufferType, array, usage ) {
|
|
|
|
const bufferGPU = gl.createBuffer();
|
|
|
|
gl.bindBuffer( bufferType, bufferGPU );
|
|
gl.bufferData( bufferType, array, usage );
|
|
gl.bindBuffer( bufferType, null );
|
|
|
|
return bufferGPU;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
export default WebGLAttributeUtils;
|