playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
192 lines (191 loc) • 8.49 kB
JavaScript
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
};