UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

129 lines (128 loc) 4.74 kB
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 };