@openhps/core
Version:
Open Hybrid Positioning System - Core component
329 lines (314 loc) • 11.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _WebGPUConstants = require("./WebGPUConstants.js");
var _constants = require("../../../constants.js");
var _constants2 = require("../../../nodes/core/constants.js");
/**
* A WebGPU backend utility module for managing bindings.
*
* When reading the documentation it's helpful to keep in mind that
* all class definitions starting with 'GPU*' are modules from the
* WebGPU API. So for example `BindGroup` is a class from the engine
* whereas `GPUBindGroup` is a class from WebGPU.
*
* @private
*/
class WebGPUBindingUtils {
/**
* Constructs a new utility object.
*
* @param {WebGPUBackend} backend - The WebGPU backend.
*/
constructor(backend) {
/**
* A reference to the WebGPU backend.
*
* @type {WebGPUBackend}
*/
this.backend = backend;
/**
* A cache for managing bind group layouts.
*
* @type {WeakMap<Array<Binding>,GPUBindGroupLayout>}
*/
this.bindGroupLayoutCache = new WeakMap();
}
/**
* Creates a GPU bind group layout for the given bind group.
*
* @param {BindGroup} bindGroup - The bind group.
* @return {GPUBindGroupLayout} The GPU bind group layout.
*/
createBindingsLayout(bindGroup) {
const backend = this.backend;
const device = backend.device;
const entries = [];
let index = 0;
for (const binding of bindGroup.bindings) {
const bindingGPU = {
binding: index++,
visibility: binding.visibility
};
if (binding.isUniformBuffer || binding.isStorageBuffer) {
const buffer = {}; // GPUBufferBindingLayout
if (binding.isStorageBuffer) {
if (binding.visibility & 4) {
// compute
if (binding.access === _constants2.NodeAccess.READ_WRITE || binding.access === _constants2.NodeAccess.WRITE_ONLY) {
buffer.type = _WebGPUConstants.GPUBufferBindingType.Storage;
} else {
buffer.type = _WebGPUConstants.GPUBufferBindingType.ReadOnlyStorage;
}
} else {
buffer.type = _WebGPUConstants.GPUBufferBindingType.ReadOnlyStorage;
}
}
bindingGPU.buffer = buffer;
} else if (binding.isSampler) {
const sampler = {}; // GPUSamplerBindingLayout
if (binding.texture.isDepthTexture) {
if (binding.texture.compareFunction !== null) {
sampler.type = 'comparison';
}
}
bindingGPU.sampler = sampler;
} else if (binding.isSampledTexture && binding.texture.isVideoTexture) {
bindingGPU.externalTexture = {}; // GPUExternalTextureBindingLayout
} else if (binding.isSampledTexture && binding.store) {
const storageTexture = {}; // GPUStorageTextureBindingLayout
storageTexture.format = this.backend.get(binding.texture).texture.format;
const access = binding.access;
if (access === _constants2.NodeAccess.READ_WRITE) {
storageTexture.access = _WebGPUConstants.GPUStorageTextureAccess.ReadWrite;
} else if (access === _constants2.NodeAccess.WRITE_ONLY) {
storageTexture.access = _WebGPUConstants.GPUStorageTextureAccess.WriteOnly;
} else {
storageTexture.access = _WebGPUConstants.GPUStorageTextureAccess.ReadOnly;
}
bindingGPU.storageTexture = storageTexture;
} else if (binding.isSampledTexture) {
const texture = {}; // GPUTextureBindingLayout
const {
primarySamples
} = backend.utils.getTextureSampleData(binding.texture);
if (primarySamples > 1) {
texture.multisampled = true;
if (!binding.texture.isDepthTexture) {
texture.sampleType = _WebGPUConstants.GPUTextureSampleType.UnfilterableFloat;
}
}
if (binding.texture.isDepthTexture) {
texture.sampleType = _WebGPUConstants.GPUTextureSampleType.Depth;
} else if (binding.texture.isDataTexture || binding.texture.isDataArrayTexture || binding.texture.isData3DTexture) {
const type = binding.texture.type;
if (type === _constants.IntType) {
texture.sampleType = _WebGPUConstants.GPUTextureSampleType.SInt;
} else if (type === _constants.UnsignedIntType) {
texture.sampleType = _WebGPUConstants.GPUTextureSampleType.UInt;
} else if (type === _constants.FloatType) {
if (this.backend.hasFeature('float32-filterable')) {
texture.sampleType = _WebGPUConstants.GPUTextureSampleType.Float;
} else {
texture.sampleType = _WebGPUConstants.GPUTextureSampleType.UnfilterableFloat;
}
}
}
if (binding.isSampledCubeTexture) {
texture.viewDimension = _WebGPUConstants.GPUTextureViewDimension.Cube;
} else if (binding.texture.isDataArrayTexture || binding.texture.isCompressedArrayTexture) {
texture.viewDimension = _WebGPUConstants.GPUTextureViewDimension.TwoDArray;
} else if (binding.isSampledTexture3D) {
texture.viewDimension = _WebGPUConstants.GPUTextureViewDimension.ThreeD;
}
bindingGPU.texture = texture;
} else {
console.error(`WebGPUBindingUtils: Unsupported binding "${binding}".`);
}
entries.push(bindingGPU);
}
return device.createBindGroupLayout({
entries
});
}
/**
* Creates bindings from the given bind group definition.
*
* @param {BindGroup} bindGroup - The bind group.
* @param {Array<BindGroup>} bindings - Array of bind groups.
* @param {number} cacheIndex - The cache index.
* @param {number} version - The version.
*/
createBindings(bindGroup, bindings, cacheIndex, version = 0) {
const {
backend,
bindGroupLayoutCache
} = this;
const bindingsData = backend.get(bindGroup);
// setup (static) binding layout and (dynamic) binding group
let bindLayoutGPU = bindGroupLayoutCache.get(bindGroup.bindingsReference);
if (bindLayoutGPU === undefined) {
bindLayoutGPU = this.createBindingsLayout(bindGroup);
bindGroupLayoutCache.set(bindGroup.bindingsReference, bindLayoutGPU);
}
let bindGroupGPU;
if (cacheIndex > 0) {
if (bindingsData.groups === undefined) {
bindingsData.groups = [];
bindingsData.versions = [];
}
if (bindingsData.versions[cacheIndex] === version) {
bindGroupGPU = bindingsData.groups[cacheIndex];
}
}
if (bindGroupGPU === undefined) {
bindGroupGPU = this.createBindGroup(bindGroup, bindLayoutGPU);
if (cacheIndex > 0) {
bindingsData.groups[cacheIndex] = bindGroupGPU;
bindingsData.versions[cacheIndex] = version;
}
}
bindingsData.group = bindGroupGPU;
bindingsData.layout = bindLayoutGPU;
}
/**
* Updates a buffer binding.
*
* @param {Buffer} binding - The buffer binding to update.
*/
updateBinding(binding) {
const backend = this.backend;
const device = backend.device;
const buffer = binding.buffer;
const bufferGPU = backend.get(binding).buffer;
device.queue.writeBuffer(bufferGPU, 0, buffer, 0);
}
/**
* Creates a GPU bind group for the camera index.
*
* @param {Uint32Array} data - The index data.
* @param {GPUBindGroupLayout} layout - The GPU bind group layout.
* @return {GPUBindGroup} The GPU bind group.
*/
createBindGroupIndex(data, layout) {
const backend = this.backend;
const device = backend.device;
const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
const index = data[0];
const buffer = device.createBuffer({
label: 'bindingCameraIndex_' + index,
size: 16,
// uint(4) * 4
usage: usage
});
device.queue.writeBuffer(buffer, 0, data, 0);
const entries = [{
binding: 0,
resource: {
buffer
}
}];
return device.createBindGroup({
label: 'bindGroupCameraIndex_' + index,
layout,
entries
});
}
/**
* Creates a GPU bind group for the given bind group and GPU layout.
*
* @param {BindGroup} bindGroup - The bind group.
* @param {GPUBindGroupLayout} layoutGPU - The GPU bind group layout.
* @return {GPUBindGroup} The GPU bind group.
*/
createBindGroup(bindGroup, layoutGPU) {
const backend = this.backend;
const device = backend.device;
let bindingPoint = 0;
const entriesGPU = [];
for (const binding of bindGroup.bindings) {
if (binding.isUniformBuffer) {
const bindingData = backend.get(binding);
if (bindingData.buffer === undefined) {
const byteLength = binding.byteLength;
const usage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
const bufferGPU = device.createBuffer({
label: 'bindingBuffer_' + binding.name,
size: byteLength,
usage: usage
});
bindingData.buffer = bufferGPU;
}
entriesGPU.push({
binding: bindingPoint,
resource: {
buffer: bindingData.buffer
}
});
} else if (binding.isStorageBuffer) {
const bindingData = backend.get(binding);
if (bindingData.buffer === undefined) {
const attribute = binding.attribute;
//const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.VERTEX | /*GPUBufferUsage.COPY_SRC |*/ GPUBufferUsage.COPY_DST;
//backend.attributeUtils.createAttribute( attribute, usage ); // @TODO: Move it to universal renderer
bindingData.buffer = backend.get(attribute).buffer;
}
entriesGPU.push({
binding: bindingPoint,
resource: {
buffer: bindingData.buffer
}
});
} else if (binding.isSampler) {
const textureGPU = backend.get(binding.texture);
entriesGPU.push({
binding: bindingPoint,
resource: textureGPU.sampler
});
} else if (binding.isSampledTexture) {
const textureData = backend.get(binding.texture);
let resourceGPU;
if (textureData.externalTexture !== undefined) {
resourceGPU = device.importExternalTexture({
source: textureData.externalTexture
});
} else {
const mipLevelCount = binding.store ? 1 : textureData.texture.mipLevelCount;
const propertyName = `view-${textureData.texture.width}-${textureData.texture.height}-${mipLevelCount}`;
resourceGPU = textureData[propertyName];
if (resourceGPU === undefined) {
const aspectGPU = _WebGPUConstants.GPUTextureAspect.All;
let dimensionViewGPU;
if (binding.isSampledCubeTexture) {
dimensionViewGPU = _WebGPUConstants.GPUTextureViewDimension.Cube;
} else if (binding.isSampledTexture3D) {
dimensionViewGPU = _WebGPUConstants.GPUTextureViewDimension.ThreeD;
} else if (binding.texture.isDataArrayTexture || binding.texture.isCompressedArrayTexture) {
dimensionViewGPU = _WebGPUConstants.GPUTextureViewDimension.TwoDArray;
} else {
dimensionViewGPU = _WebGPUConstants.GPUTextureViewDimension.TwoD;
}
resourceGPU = textureData[propertyName] = textureData.texture.createView({
aspect: aspectGPU,
dimension: dimensionViewGPU,
mipLevelCount
});
}
}
entriesGPU.push({
binding: bindingPoint,
resource: resourceGPU
});
}
bindingPoint++;
}
return device.createBindGroup({
label: 'bindGroup_' + bindGroup.name,
layout: layoutGPU,
entries: entriesGPU
});
}
}
var _default = exports.default = WebGPUBindingUtils;