@kitware/vtk.js
Version:
Visualization Toolkit for the Web
236 lines (218 loc) • 7.88 kB
JavaScript
import { m as macro } from '../../macros2.js';
import vtkWebGPUBufferManager from './BufferManager.js';
import vtkWebGPUTypes from './Types.js';
const {
BufferUsage
} = vtkWebGPUBufferManager;
const {
vtkErrorMacro
} = macro;
// ----------------------------------------------------------------------------
// vtkWebGPUStorageBuffer - similar to the UniformBuffer class
// but YOU are responsible for layout issues and alignment.
// The order you add entries is the order they will be layed out
// in memory. But you must follow layout rules.
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// vtkWebGPUStorageBuffer methods
// ----------------------------------------------------------------------------
function vtkWebGPUStorageBuffer(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkWebGPUStorageBuffer');
publicAPI.addEntry = (name, type) => {
if (model._bufferEntryNames.has(name)) {
vtkErrorMacro(`entry named ${name} already exists`);
return;
}
model._bufferEntryNames.set(name, model.bufferEntries.length);
const sizeInBytes = vtkWebGPUTypes.getByteStrideFromShaderFormat(type);
model.bufferEntries.push({
name,
type,
sizeInBytes,
offset: model.sizeInBytes,
nativeType: vtkWebGPUTypes.getNativeTypeFromShaderFormat(type)
});
model.sizeInBytes += sizeInBytes;
};
publicAPI.send = device => {
if (!model._buffer) {
const req = {
nativeArray: model.Float32Array,
usage: BufferUsage.Storage,
label: model.label
};
model._buffer = device.getBufferManager().getBuffer(req);
model.bindGroupTime.modified();
model._sendTime.modified();
return;
}
device.getHandle().queue.writeBuffer(model._buffer.getHandle(), 0, model.arrayBuffer, 0, model.sizeInBytes * model.numberOfInstances);
model._sendTime.modified();
};
publicAPI.createView = type => {
if (type in model === false) {
if (!model.arrayBuffer) {
model.arrayBuffer = new ArrayBuffer(model.sizeInBytes * model.numberOfInstances);
}
model[type] = macro.newTypedArray(type, model.arrayBuffer);
}
};
publicAPI.setValue = (name, instance, val) => {
const idx = model._bufferEntryNames.get(name);
if (idx === undefined) {
vtkErrorMacro(`entry named ${name} not found in UBO`);
return;
}
const entry = model.bufferEntries[idx];
publicAPI.createView(entry.nativeType);
const view = model[entry.nativeType];
view[(entry.offset + instance * model.sizeInBytes) / view.BYTES_PER_ELEMENT] = val;
};
publicAPI.setArray = (name, instance, arr) => {
const idx = model._bufferEntryNames.get(name);
if (idx === undefined) {
vtkErrorMacro(`entry named ${name} not found in UBO`);
return;
}
const entry = model.bufferEntries[idx];
publicAPI.createView(entry.nativeType);
const view = model[entry.nativeType];
const ioffset = (entry.offset + instance * model.sizeInBytes) / view.BYTES_PER_ELEMENT;
for (let i = 0; i < arr.length; i++) {
view[ioffset + i] = arr[i];
}
};
publicAPI.setAllInstancesFromArray = (name, arr) => {
const idx = model._bufferEntryNames.get(name);
if (idx === undefined) {
vtkErrorMacro(`entry named ${name} not found in UBO`);
return;
}
const entry = model.bufferEntries[idx];
publicAPI.createView(entry.nativeType);
const view = model[entry.nativeType];
const numComponents = arr.length / model.numberOfInstances;
for (let inst = 0; inst < model.numberOfInstances; inst++) {
const ioffset = (entry.offset + inst * model.sizeInBytes) / view.BYTES_PER_ELEMENT;
for (let i = 0; i < numComponents; i++) {
view[ioffset + i] = arr[inst * numComponents + i];
}
}
};
publicAPI.setAllInstancesFromArrayColorToFloat = (name, arr) => {
const idx = model._bufferEntryNames.get(name);
if (idx === undefined) {
vtkErrorMacro(`entry named ${name} not found in UBO`);
return;
}
const entry = model.bufferEntries[idx];
publicAPI.createView(entry.nativeType);
const view = model[entry.nativeType];
const numComponents = arr.length / model.numberOfInstances;
for (let inst = 0; inst < model.numberOfInstances; inst++) {
const ioffset = (entry.offset + inst * model.sizeInBytes) / view.BYTES_PER_ELEMENT;
for (let i = 0; i < numComponents; i++) {
view[ioffset + i] = arr[inst * numComponents + i] / 255.0;
}
}
};
publicAPI.setAllInstancesFromArray3x3To4x4 = (name, arr) => {
const idx = model._bufferEntryNames.get(name);
if (idx === undefined) {
vtkErrorMacro(`entry named ${name} not found in UBO`);
return;
}
const entry = model.bufferEntries[idx];
publicAPI.createView(entry.nativeType);
const view = model[entry.nativeType];
const numComponents = 9;
for (let inst = 0; inst < model.numberOfInstances; inst++) {
const ioffset = (entry.offset + inst * model.sizeInBytes) / view.BYTES_PER_ELEMENT;
for (let j = 0; j < 3; j++) {
for (let i = 0; i < 3; i++) {
view[ioffset + j * 4 + i] = arr[inst * numComponents + j * 3 + i];
}
}
}
};
publicAPI.getSendTime = () => model._sendTime.getMTime();
publicAPI.getShaderCode = (binding, group) => {
const lines = [`struct ${model.label}StructEntry\n{`];
for (let i = 0; i < model.bufferEntries.length; i++) {
const entry = model.bufferEntries[i];
lines.push(` ${entry.name}: ${entry.type},`);
}
lines.push(`
};
struct ${model.label}Struct
{
values: array<${model.label}StructEntry>,
};
@binding(${binding}) @group(${group}) var<storage, read> ${model.label}: ${model.label}Struct;
`);
return lines.join('\n');
};
publicAPI.getBindGroupEntry = () => {
const foo = {
resource: {
buffer: model._buffer.getHandle()
}
};
return foo;
};
publicAPI.clearData = () => {
model.numberOfInstances = 0;
model.sizeInBytes = 0;
model.bufferEntries = [];
model._bufferEntryNames = new Map();
model._buffer = null;
delete model.arrayBuffer;
delete model.Float32Array;
};
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
const DEFAULT_VALUES = {
bufferEntries: null,
bufferEntryNames: null,
sizeInBytes: 0,
label: null,
numberOfInstances: 1
};
// ----------------------------------------------------------------------------
function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);
// Build VTK API
macro.obj(publicAPI, model);
// Internal objects
model._bufferEntryNames = new Map();
model.bufferEntries = [];
model._sendTime = {};
macro.obj(model._sendTime, {
mtime: 0
});
model.bindGroupTime = {};
macro.obj(model.bindGroupTime, {
mtime: 0
});
// default SSBO desc
model.bindGroupLayoutEntry = model.bindGroupLayoutEntry || {
buffer: {
type: 'read-only-storage'
}
};
macro.get(publicAPI, model, ['bindGroupTime']);
macro.setGet(publicAPI, model, ['device', 'bindGroupLayoutEntry', 'label', 'numberOfInstances', 'sizeInBytes']);
// Object methods
vtkWebGPUStorageBuffer(publicAPI, model);
}
// ----------------------------------------------------------------------------
const newInstance = macro.newInstance(extend, 'vtkWebGPUStorageBuffer');
// ----------------------------------------------------------------------------
var vtkWebGPUStorageBuffer$1 = {
newInstance,
extend
};
export { vtkWebGPUStorageBuffer$1 as default, extend, newInstance };