UNPKG

playcanvas

Version:

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

192 lines (191 loc) 8.49 kB
var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); import { Debug } from "../../core/debug.js"; import { TRACEID_BINDGROUP_ALLOC } from "../../core/constants.js"; import { UNIFORM_BUFFER_DEFAULT_SLOT_NAME } from "./constants.js"; import { DebugGraphics } from "./debug-graphics.js"; import { getBuiltInTexture } from "./built-in-textures.js"; import { TextureView } from "./texture-view.js"; let id = 0; class DynamicBindGroup { constructor() { __publicField(this, "bindGroup"); __publicField(this, "offsets", []); } } class BindGroup { /** * Create a new Bind Group. * * @param {GraphicsDevice} graphicsDevice - The graphics device used to manage this uniform buffer. * @param {BindGroupFormat} format - Format of the bind group. * @param {UniformBuffer} [defaultUniformBuffer] - The default uniform buffer. Typically a bind * group only has a single uniform buffer, and this allows easier access. */ constructor(graphicsDevice, format, defaultUniformBuffer) { /** * A render version the bind group was last updated on. * * @private */ __publicField(this, "renderVersionUpdated", -1); /** @type {UniformBuffer[]} */ __publicField(this, "uniformBuffers"); /** * An array of offsets for each uniform buffer in the bind group. This is the offset in the * buffer where the uniform buffer data starts. * * @type {number[]} */ __publicField(this, "uniformBufferOffsets", []); this.id = id++; this.device = graphicsDevice; this.format = format; this.dirty = true; this.impl = graphicsDevice.createBindGroupImpl(this); this.textures = []; this.storageTextures = []; this.storageBuffers = []; this.uniformBuffers = []; this.defaultUniformBuffer = defaultUniformBuffer; if (defaultUniformBuffer) { this.setUniformBuffer(UNIFORM_BUFFER_DEFAULT_SLOT_NAME, defaultUniformBuffer); } Debug.trace(TRACEID_BINDGROUP_ALLOC, `Alloc: Id ${this.id}`, this, format); } /** * Frees resources associated with this bind group. */ destroy() { this.impl.destroy(); this.impl = null; this.format = null; this.defaultUniformBuffer = null; } /** * Assign a uniform buffer to a slot. * * @param {string} name - The name of the uniform buffer slot * @param {UniformBuffer} uniformBuffer - The Uniform buffer to assign to the slot. */ setUniformBuffer(name, uniformBuffer) { const index = this.format.bufferFormatsMap.get(name); Debug.assert(index !== void 0, `Setting a uniform [${name}] on a bind group with id ${this.id} which does not contain it, while rendering [${DebugGraphics.toString()}]`, this); if (this.uniformBuffers[index] !== uniformBuffer) { this.uniformBuffers[index] = uniformBuffer; this.dirty = true; } } /** * Assign a storage buffer to a slot. * * @param {string} name - The name of the storage buffer slot. * @param {StorageBuffer} storageBuffer - The storage buffer to assign to the slot. */ setStorageBuffer(name, storageBuffer) { const index = this.format.storageBufferFormatsMap.get(name); Debug.assert(index !== void 0, `Setting a storage buffer [${name}] on a bind group with id: ${this.id} which does not contain it, while rendering [${DebugGraphics.toString()}]`, this); if (this.storageBuffers[index] !== storageBuffer) { this.storageBuffers[index] = storageBuffer; this.dirty = true; } } /** * Assign a texture to a named slot. * * @param {string} name - The name of the texture slot. * @param {Texture|TextureView} value - Texture or TextureView to assign to the slot. */ setTexture(name, value) { const index = this.format.textureFormatsMap.get(name); Debug.assert(index !== void 0, `Setting a texture [${name}] on a bind group with id: ${this.id} which does not contain it, while rendering [${DebugGraphics.toString()}]`, this); const texture = value instanceof TextureView ? value.texture : value; if (this.textures[index] !== value) { this.textures[index] = value; this.dirty = true; } else if (this.renderVersionUpdated < texture.renderVersionDirty) { this.dirty = true; } } /** * Assign a storage texture to a named slot. * * @param {string} name - The name of the texture slot. * @param {Texture|TextureView} value - Texture or TextureView to assign to the slot. */ setStorageTexture(name, value) { const index = this.format.storageTextureFormatsMap.get(name); Debug.assert(index !== void 0, `Setting a storage texture [${name}] on a bind group with id: ${this.id} which does not contain it, while rendering [${DebugGraphics.toString()}]`, this); const texture = value instanceof TextureView ? value.texture : value; if (this.storageTextures[index] !== value) { this.storageTextures[index] = value; this.dirty = true; } else if (this.renderVersionUpdated < texture.renderVersionDirty) { this.dirty = true; } } /** * Updates the uniform buffers in this bind group. */ updateUniformBuffers() { for (let i = 0; i < this.uniformBuffers.length; i++) { this.uniformBuffers[i].update(); } } /** * Applies any changes made to the bind group's properties. Note that the content of used * uniform buffers needs to be updated before calling this method. */ update() { const { textureFormats, storageTextureFormats, storageBufferFormats } = this.format; for (let i = 0; i < textureFormats.length; i++) { const textureFormat = textureFormats[i]; let value = textureFormat.scopeId.value; if (!value) { if (textureFormat.name === "uSceneDepthMap") { Debug.errorOnce(`A uSceneDepthMap texture is used by the shader but a scene depth texture is not available. Use CameraComponent.requestSceneDepthMap / enable Depth Grabpass on the Camera Component / CameraFrame.rendering.sceneDepthMap to enable it. Rendering [${DebugGraphics.toString()}]`); value = getBuiltInTexture(this.device, "white"); } if (textureFormat.name === "uSceneColorMap") { Debug.errorOnce(`A uSceneColorMap texture is used by the shader but a scene color texture is not available. Use CameraComponent.requestSceneColorMap / enable Color Grabpass on the Camera Component / CameraFrame.rendering.sceneColorMap to enable it. Rendering [${DebugGraphics.toString()}]`); value = getBuiltInTexture(this.device, "pink"); } if (!value) { Debug.errorOnce(`Texture ${textureFormat.name} is required for rendering but was not set. Rendering [${DebugGraphics.toString()}]`); value = getBuiltInTexture(this.device, "pink"); } } this.setTexture(textureFormat.name, value); } for (let i = 0; i < storageTextureFormats.length; i++) { const storageTextureFormat = storageTextureFormats[i]; const value = storageTextureFormat.scopeId.value; Debug.assert(value, `Value was not set when assigning storage texture slot [${storageTextureFormat.name}] to a bind group, while rendering [${DebugGraphics.toString()}]`, this); this.setStorageTexture(storageTextureFormat.name, value); } for (let i = 0; i < storageBufferFormats.length; i++) { const storageBufferFormat = storageBufferFormats[i]; const value = storageBufferFormat.scopeId.value; Debug.assert(value, `Value was not set when assigning storage buffer slot [${storageBufferFormat.name}] to a bind group, while rendering [${DebugGraphics.toString()}]`, this); this.setStorageBuffer(storageBufferFormat.name, value); } this.uniformBufferOffsets.length = this.uniformBuffers.length; for (let i = 0; i < this.uniformBuffers.length; i++) { const uniformBuffer = this.uniformBuffers[i]; this.uniformBufferOffsets[i] = uniformBuffer.offset; if (this.renderVersionUpdated < uniformBuffer.renderVersionDirty) { this.dirty = true; } } if (this.dirty) { this.dirty = false; this.renderVersionUpdated = this.device.renderVersion; this.impl.update(this); } } } export { BindGroup, DynamicBindGroup };