securityos/node_modules/regl/lib/buffer.js

417 lines
12 KiB
JavaScript
Raw Permalink Normal View History

2024-09-06 15:32:35 +00:00
var check = require('./util/check')
var isTypedArray = require('./util/is-typed-array')
var isNDArrayLike = require('./util/is-ndarray')
var values = require('./util/values')
var pool = require('./util/pool')
var flattenUtil = require('./util/flatten')
var arrayFlatten = flattenUtil.flatten
var arrayShape = flattenUtil.shape
var arrayTypes = require('./constants/arraytypes.json')
var bufferTypes = require('./constants/dtypes.json')
var usageTypes = require('./constants/usage.json')
var GL_STATIC_DRAW = 0x88E4
var GL_STREAM_DRAW = 0x88E0
var GL_UNSIGNED_BYTE = 5121
var GL_FLOAT = 5126
var DTYPES_SIZES = []
DTYPES_SIZES[5120] = 1 // int8
DTYPES_SIZES[5122] = 2 // int16
DTYPES_SIZES[5124] = 4 // int32
DTYPES_SIZES[5121] = 1 // uint8
DTYPES_SIZES[5123] = 2 // uint16
DTYPES_SIZES[5125] = 4 // uint32
DTYPES_SIZES[5126] = 4 // float32
function typedArrayCode (data) {
return arrayTypes[Object.prototype.toString.call(data)] | 0
}
function copyArray (out, inp) {
for (var i = 0; i < inp.length; ++i) {
out[i] = inp[i]
}
}
function transpose (
result, data, shapeX, shapeY, strideX, strideY, offset) {
var ptr = 0
for (var i = 0; i < shapeX; ++i) {
for (var j = 0; j < shapeY; ++j) {
result[ptr++] = data[strideX * i + strideY * j + offset]
}
}
}
module.exports = function wrapBufferState (gl, stats, config, destroyBuffer) {
var bufferCount = 0
var bufferSet = {}
function REGLBuffer (type) {
this.id = bufferCount++
this.buffer = gl.createBuffer()
this.type = type
this.usage = GL_STATIC_DRAW
this.byteLength = 0
this.dimension = 1
this.dtype = GL_UNSIGNED_BYTE
this.persistentData = null
if (config.profile) {
this.stats = { size: 0 }
}
}
REGLBuffer.prototype.bind = function () {
gl.bindBuffer(this.type, this.buffer)
}
REGLBuffer.prototype.destroy = function () {
destroy(this)
}
var streamPool = []
function createStream (type, data) {
var buffer = streamPool.pop()
if (!buffer) {
buffer = new REGLBuffer(type)
}
buffer.bind()
initBufferFromData(buffer, data, GL_STREAM_DRAW, 0, 1, false)
return buffer
}
function destroyStream (stream) {
streamPool.push(stream)
}
function initBufferFromTypedArray (buffer, data, usage) {
buffer.byteLength = data.byteLength
gl.bufferData(buffer.type, data, usage)
}
function initBufferFromData (buffer, data, usage, dtype, dimension, persist) {
var shape
buffer.usage = usage
if (Array.isArray(data)) {
buffer.dtype = dtype || GL_FLOAT
if (data.length > 0) {
var flatData
if (Array.isArray(data[0])) {
shape = arrayShape(data)
var dim = 1
for (var i = 1; i < shape.length; ++i) {
dim *= shape[i]
}
buffer.dimension = dim
flatData = arrayFlatten(data, shape, buffer.dtype)
initBufferFromTypedArray(buffer, flatData, usage)
if (persist) {
buffer.persistentData = flatData
} else {
pool.freeType(flatData)
}
} else if (typeof data[0] === 'number') {
buffer.dimension = dimension
var typedData = pool.allocType(buffer.dtype, data.length)
copyArray(typedData, data)
initBufferFromTypedArray(buffer, typedData, usage)
if (persist) {
buffer.persistentData = typedData
} else {
pool.freeType(typedData)
}
} else if (isTypedArray(data[0])) {
buffer.dimension = data[0].length
buffer.dtype = dtype || typedArrayCode(data[0]) || GL_FLOAT
flatData = arrayFlatten(
data,
[data.length, data[0].length],
buffer.dtype)
initBufferFromTypedArray(buffer, flatData, usage)
if (persist) {
buffer.persistentData = flatData
} else {
pool.freeType(flatData)
}
} else {
check.raise('invalid buffer data')
}
}
} else if (isTypedArray(data)) {
buffer.dtype = dtype || typedArrayCode(data)
buffer.dimension = dimension
initBufferFromTypedArray(buffer, data, usage)
if (persist) {
buffer.persistentData = new Uint8Array(new Uint8Array(data.buffer))
}
} else if (isNDArrayLike(data)) {
shape = data.shape
var stride = data.stride
var offset = data.offset
var shapeX = 0
var shapeY = 0
var strideX = 0
var strideY = 0
if (shape.length === 1) {
shapeX = shape[0]
shapeY = 1
strideX = stride[0]
strideY = 0
} else if (shape.length === 2) {
shapeX = shape[0]
shapeY = shape[1]
strideX = stride[0]
strideY = stride[1]
} else {
check.raise('invalid shape')
}
buffer.dtype = dtype || typedArrayCode(data.data) || GL_FLOAT
buffer.dimension = shapeY
var transposeData = pool.allocType(buffer.dtype, shapeX * shapeY)
transpose(transposeData,
data.data,
shapeX, shapeY,
strideX, strideY,
offset)
initBufferFromTypedArray(buffer, transposeData, usage)
if (persist) {
buffer.persistentData = transposeData
} else {
pool.freeType(transposeData)
}
} else if (data instanceof ArrayBuffer) {
buffer.dtype = GL_UNSIGNED_BYTE
buffer.dimension = dimension
initBufferFromTypedArray(buffer, data, usage)
if (persist) {
buffer.persistentData = new Uint8Array(new Uint8Array(data))
}
} else {
check.raise('invalid buffer data')
}
}
function destroy (buffer) {
stats.bufferCount--
// remove attribute link
destroyBuffer(buffer)
var handle = buffer.buffer
check(handle, 'buffer must not be deleted already')
gl.deleteBuffer(handle)
buffer.buffer = null
delete bufferSet[buffer.id]
}
function createBuffer (options, type, deferInit, persistent) {
stats.bufferCount++
var buffer = new REGLBuffer(type)
bufferSet[buffer.id] = buffer
function reglBuffer (options) {
var usage = GL_STATIC_DRAW
var data = null
var byteLength = 0
var dtype = 0
var dimension = 1
if (Array.isArray(options) ||
isTypedArray(options) ||
isNDArrayLike(options) ||
options instanceof ArrayBuffer) {
data = options
} else if (typeof options === 'number') {
byteLength = options | 0
} else if (options) {
check.type(
options, 'object',
'buffer arguments must be an object, a number or an array')
if ('data' in options) {
check(
data === null ||
Array.isArray(data) ||
isTypedArray(data) ||
isNDArrayLike(data),
'invalid data for buffer')
data = options.data
}
if ('usage' in options) {
check.parameter(options.usage, usageTypes, 'invalid buffer usage')
usage = usageTypes[options.usage]
}
if ('type' in options) {
check.parameter(options.type, bufferTypes, 'invalid buffer type')
dtype = bufferTypes[options.type]
}
if ('dimension' in options) {
check.type(options.dimension, 'number', 'invalid dimension')
dimension = options.dimension | 0
}
if ('length' in options) {
check.nni(byteLength, 'buffer length must be a nonnegative integer')
byteLength = options.length | 0
}
}
buffer.bind()
if (!data) {
// #475
if (byteLength) gl.bufferData(buffer.type, byteLength, usage)
buffer.dtype = dtype || GL_UNSIGNED_BYTE
buffer.usage = usage
buffer.dimension = dimension
buffer.byteLength = byteLength
} else {
initBufferFromData(buffer, data, usage, dtype, dimension, persistent)
}
if (config.profile) {
buffer.stats.size = buffer.byteLength * DTYPES_SIZES[buffer.dtype]
}
return reglBuffer
}
function setSubData (data, offset) {
check(offset + data.byteLength <= buffer.byteLength,
'invalid buffer subdata call, buffer is too small. ' + ' Can\'t write data of size ' + data.byteLength + ' starting from offset ' + offset + ' to a buffer of size ' + buffer.byteLength)
gl.bufferSubData(buffer.type, offset, data)
}
function subdata (data, offset_) {
var offset = (offset_ || 0) | 0
var shape
buffer.bind()
if (isTypedArray(data) || data instanceof ArrayBuffer) {
setSubData(data, offset)
} else if (Array.isArray(data)) {
if (data.length > 0) {
if (typeof data[0] === 'number') {
var converted = pool.allocType(buffer.dtype, data.length)
copyArray(converted, data)
setSubData(converted, offset)
pool.freeType(converted)
} else if (Array.isArray(data[0]) || isTypedArray(data[0])) {
shape = arrayShape(data)
var flatData = arrayFlatten(data, shape, buffer.dtype)
setSubData(flatData, offset)
pool.freeType(flatData)
} else {
check.raise('invalid buffer data')
}
}
} else if (isNDArrayLike(data)) {
shape = data.shape
var stride = data.stride
var shapeX = 0
var shapeY = 0
var strideX = 0
var strideY = 0
if (shape.length === 1) {
shapeX = shape[0]
shapeY = 1
strideX = stride[0]
strideY = 0
} else if (shape.length === 2) {
shapeX = shape[0]
shapeY = shape[1]
strideX = stride[0]
strideY = stride[1]
} else {
check.raise('invalid shape')
}
var dtype = Array.isArray(data.data)
? buffer.dtype
: typedArrayCode(data.data)
var transposeData = pool.allocType(dtype, shapeX * shapeY)
transpose(transposeData,
data.data,
shapeX, shapeY,
strideX, strideY,
data.offset)
setSubData(transposeData, offset)
pool.freeType(transposeData)
} else {
check.raise('invalid data for buffer subdata')
}
return reglBuffer
}
if (!deferInit) {
reglBuffer(options)
}
reglBuffer._reglType = 'buffer'
reglBuffer._buffer = buffer
reglBuffer.subdata = subdata
if (config.profile) {
reglBuffer.stats = buffer.stats
}
reglBuffer.destroy = function () { destroy(buffer) }
return reglBuffer
}
function restoreBuffers () {
values(bufferSet).forEach(function (buffer) {
buffer.buffer = gl.createBuffer()
gl.bindBuffer(buffer.type, buffer.buffer)
gl.bufferData(
buffer.type, buffer.persistentData || buffer.byteLength, buffer.usage)
})
}
if (config.profile) {
stats.getTotalBufferSize = function () {
var total = 0
// TODO: Right now, the streams are not part of the total count.
Object.keys(bufferSet).forEach(function (key) {
total += bufferSet[key].stats.size
})
return total
}
}
return {
create: createBuffer,
createStream: createStream,
destroyStream: destroyStream,
clear: function () {
values(bufferSet).forEach(destroy)
streamPool.forEach(destroy)
},
getBuffer: function (wrapper) {
if (wrapper && wrapper._buffer instanceof REGLBuffer) {
return wrapper._buffer
}
return null
},
restore: restoreBuffers,
_initBuffer: initBufferFromData
}
}