playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
129 lines (128 loc) • 4.74 kB
JavaScript
import { StringIds } from "../../../core/string-ids.js";
import { SAMPLETYPE_FLOAT, SAMPLETYPE_UNFILTERABLE_FLOAT, SAMPLETYPE_DEPTH, SAMPLETYPE_INT, SAMPLETYPE_UINT } from "../constants.js";
import { WebgpuUtils } from "./webgpu-utils.js";
import { gpuTextureFormats } from "./constants.js";
const samplerTypes = [];
samplerTypes[SAMPLETYPE_FLOAT] = "filtering";
samplerTypes[SAMPLETYPE_UNFILTERABLE_FLOAT] = "non-filtering";
samplerTypes[SAMPLETYPE_DEPTH] = "comparison";
samplerTypes[SAMPLETYPE_INT] = "comparison";
samplerTypes[SAMPLETYPE_UINT] = "comparison";
const sampleTypes = [];
sampleTypes[SAMPLETYPE_FLOAT] = "float";
sampleTypes[SAMPLETYPE_UNFILTERABLE_FLOAT] = "unfilterable-float";
sampleTypes[SAMPLETYPE_DEPTH] = "depth";
sampleTypes[SAMPLETYPE_INT] = "sint";
sampleTypes[SAMPLETYPE_UINT] = "uint";
const stringIds = new StringIds();
class WebgpuBindGroupFormat {
constructor(bindGroupFormat) {
const device = bindGroupFormat.device;
const { key, desc } = this.createDescriptor(bindGroupFormat);
this.key = stringIds.get(key);
this.bindGroupLayout = device.wgpu.createBindGroupLayout(desc);
}
destroy() {
this.bindGroupLayout = null;
}
loseContext() {
}
createDescriptor(bindGroupFormat) {
const entries = [];
let key = "";
bindGroupFormat.uniformBufferFormats.forEach((bufferFormat) => {
const visibility = WebgpuUtils.shaderStage(bufferFormat.visibility);
key += `#${bufferFormat.slot}U:${visibility}`;
entries.push({
binding: bufferFormat.slot,
visibility,
buffer: {
type: "uniform",
// "uniform", "storage", "read-only-storage"
// whether this binding requires a dynamic offset
// currently all UBs are dynamic and need the offset
hasDynamicOffset: true
// defaults to 0 meaning no validation, can do early size validation using it
// minBindingSize
}
});
});
bindGroupFormat.textureFormats.forEach((textureFormat) => {
const visibility = WebgpuUtils.shaderStage(textureFormat.visibility);
const sampleType = textureFormat.sampleType;
const viewDimension = textureFormat.textureDimension;
const multisampled = false;
const gpuSampleType = sampleTypes[sampleType];
key += `#${textureFormat.slot}T:${visibility}-${gpuSampleType}-${viewDimension}-${multisampled}`;
entries.push({
binding: textureFormat.slot,
visibility,
texture: {
// Indicates the type required for texture views bound to this binding.
// "float", "unfilterable-float", "depth", "sint", "uint",
sampleType: gpuSampleType,
// Indicates the required dimension for texture views bound to this binding.
// "1d", "2d", "2d-array", "cube", "cube-array", "3d"
viewDimension,
// Indicates whether or not texture views bound to this binding must be multisampled
multisampled
}
});
if (textureFormat.hasSampler) {
const gpuSamplerType = samplerTypes[sampleType];
key += `#${textureFormat.slot + 1}S:${visibility}-${gpuSamplerType}`;
entries.push({
binding: textureFormat.slot + 1,
visibility,
sampler: {
// Indicates the required type of a sampler bound to this bindings
// 'filtering', 'non-filtering', 'comparison'
type: gpuSamplerType
}
});
}
});
bindGroupFormat.storageTextureFormats.forEach((textureFormat) => {
const { format, textureDimension } = textureFormat;
const { read, write } = textureFormat;
key += `#${textureFormat.slot}ST:${format}-${textureDimension}-${read ? "r1" : "r0"}-${write ? "w1" : "w0"}`;
entries.push({
binding: textureFormat.slot,
visibility: GPUShaderStage.COMPUTE,
storageTexture: {
// The access mode for this binding, indicating readability and writability.
// 'write-only' is always support, 'read-write' and 'read-only' optionally
access: read ? write ? "read-write" : "read-only" : "write-only",
// The required format of texture views bound to this binding.
format: gpuTextureFormats[format],
// Indicates the required dimension for texture views bound to this binding.
// "1d", "2d", "2d-array", "cube", "cube-array", "3d"
viewDimension: textureDimension
}
});
});
bindGroupFormat.storageBufferFormats.forEach((bufferFormat) => {
const readOnly = bufferFormat.readOnly;
const visibility = WebgpuUtils.shaderStage(bufferFormat.visibility);
key += `#${bufferFormat.slot}SB:${visibility}-${readOnly ? "ro" : "rw"}`;
entries.push({
binding: bufferFormat.slot,
visibility,
buffer: {
// "storage", "read-only-storage"
type: readOnly ? "read-only-storage" : "storage"
}
});
});
const desc = {
entries
};
return {
key,
desc
};
}
}
export {
WebgpuBindGroupFormat
};