playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
260 lines (259 loc) • 9.28 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 { TRACEID_BINDGROUPFORMAT_ALLOC } from "../../core/constants.js";
import { Debug, DebugHelper } from "../../core/debug.js";
import {
TEXTUREDIMENSION_2D,
SAMPLETYPE_FLOAT,
PIXELFORMAT_RGBA8,
SHADERSTAGE_COMPUTE,
SHADERSTAGE_VERTEX
} from "./constants.js";
import { DebugGraphics } from "./debug-graphics.js";
let id = 0;
class BindBaseFormat {
/**
* Create a new instance.
*
* @param {string} name - The name of the resource.
* @param {number} visibility - A bit-flag that specifies the shader stages in which the resource
* is visible. Can be:
*
* - {@link SHADERSTAGE_VERTEX}
* - {@link SHADERSTAGE_FRAGMENT}
* - {@link SHADERSTAGE_COMPUTE}
*/
constructor(name, visibility) {
/** @ignore */
__publicField(this, "slot", -1);
/**
* @type {ScopeId|null}
* @ignore
*/
__publicField(this, "scopeId", null);
this.name = name;
this.visibility = visibility;
}
}
class BindUniformBufferFormat extends BindBaseFormat {
}
class BindStorageBufferFormat extends BindBaseFormat {
/**
* Create a new instance.
*
* @param {string} name - The name of the storage buffer.
* @param {number} visibility - A bit-flag that specifies the shader stages in which the storage
* buffer is visible. Can be:
*
* - {@link SHADERSTAGE_VERTEX}
* - {@link SHADERSTAGE_FRAGMENT}
* - {@link SHADERSTAGE_COMPUTE}
*
* @param {boolean} [readOnly] - Whether the storage buffer is read-only, or read-write. Defaults
* to false. This has to be true for the storage buffer used in the vertex shader.
*/
constructor(name, visibility, readOnly = false) {
super(name, visibility);
/**
* Format, extracted from vertex and fragment shader.
*
* @ignore
*/
__publicField(this, "format", "");
this.readOnly = readOnly;
Debug.assert(readOnly || !(visibility & SHADERSTAGE_VERTEX), "Storage buffer can only be used in read-only mode in SHADERSTAGE_VERTEX.");
}
}
class BindTextureFormat extends BindBaseFormat {
/**
* Create a new instance.
*
* @param {string} name - The name of the storage buffer.
* @param {number} visibility - A bit-flag that specifies the shader stages in which the storage
* buffer is visible. Can be:
*
* - {@link SHADERSTAGE_VERTEX}
* - {@link SHADERSTAGE_FRAGMENT}
* - {@link SHADERSTAGE_COMPUTE}
*
* @param {string} [textureDimension] - The dimension of the texture. Defaults to
* {@link TEXTUREDIMENSION_2D}. Can be:
*
* - {@link TEXTUREDIMENSION_1D}
* - {@link TEXTUREDIMENSION_2D}
* - {@link TEXTUREDIMENSION_2D_ARRAY}
* - {@link TEXTUREDIMENSION_CUBE}
* - {@link TEXTUREDIMENSION_CUBE_ARRAY}
* - {@link TEXTUREDIMENSION_3D}
*
* @param {number} [sampleType] - The type of the texture samples. Defaults to
* {@link SAMPLETYPE_FLOAT}. Can be:
*
* - {@link SAMPLETYPE_FLOAT}
* - {@link SAMPLETYPE_UNFILTERABLE_FLOAT}
* - {@link SAMPLETYPE_DEPTH}
* - {@link SAMPLETYPE_INT}
* - {@link SAMPLETYPE_UINT}
*
* @param {boolean} [hasSampler] - True if the sampler for the texture is needed. Note that if the
* sampler is used, it will take up an additional slot, directly following the texture slot.
* Defaults to true.
* @param {string|null} [samplerName] - Optional name of the sampler. Defaults to null.
*/
constructor(name, visibility, textureDimension = TEXTUREDIMENSION_2D, sampleType = SAMPLETYPE_FLOAT, hasSampler = true, samplerName = null) {
super(name, visibility);
this.textureDimension = textureDimension;
this.sampleType = sampleType;
this.hasSampler = hasSampler;
this.samplerName = samplerName ?? `${name}_sampler`;
}
}
class BindStorageTextureFormat extends BindBaseFormat {
/**
* Create a new instance.
*
* @param {string} name - The name of the storage buffer.
* @param {number} [format] - The pixel format of the texture. Note that not all formats can be
* used. Defaults to {@link PIXELFORMAT_RGBA8}.
* @param {string} [textureDimension] - The dimension of the texture. Defaults to
* {@link TEXTUREDIMENSION_2D}. Can be:
*
* - {@link TEXTUREDIMENSION_1D}
* - {@link TEXTUREDIMENSION_2D}
* - {@link TEXTUREDIMENSION_2D_ARRAY}
* - {@link TEXTUREDIMENSION_3D}
*
* @param {boolean} [write] - Whether the storage texture is writeable. Defaults to true.
* @param {boolean} [read] - Whether the storage texture is readable. Defaults to false. Note
* that storage texture reads are only supported if
* {@link GraphicsDevice#supportsStorageTextureRead} is true. Also note that only a subset of
* pixel formats can be used for storage texture reads - as an example, PIXELFORMAT_RGBA8 is not
* compatible, but PIXELFORMAT_R32U is.
*/
constructor(name, format = PIXELFORMAT_RGBA8, textureDimension = TEXTUREDIMENSION_2D, write = true, read = false) {
super(name, SHADERSTAGE_COMPUTE);
this.format = format;
this.textureDimension = textureDimension;
this.write = write;
this.read = read;
}
}
class BindGroupFormat {
/**
* Create a new instance.
*
* @param {GraphicsDevice} graphicsDevice - The graphics device used to manage this vertex format.
* @param {(BindTextureFormat|BindStorageTextureFormat|BindUniformBufferFormat|BindStorageBufferFormat)[]} formats -
* An array of bind formats. Note that each entry in the array uses up one slot. The exception
* is a texture format that has a sampler, which uses up two slots. The slots are allocated
* sequentially, starting from 0.
*/
constructor(graphicsDevice, formats) {
/**
* @type {BindUniformBufferFormat[]}
* @private
*/
__publicField(this, "uniformBufferFormats", []);
/**
* @type {BindTextureFormat[]}
* @private
*/
__publicField(this, "textureFormats", []);
/**
* @type {BindStorageTextureFormat[]}
* @private
*/
__publicField(this, "storageTextureFormats", []);
/**
* @type {BindStorageBufferFormat[]}
* @private
*/
__publicField(this, "storageBufferFormats", []);
this.id = id++;
DebugHelper.setName(this, `BindGroupFormat_${this.id}`);
Debug.assert(formats);
let slot = 0;
formats.forEach((format) => {
format.slot = slot++;
if (format instanceof BindTextureFormat && format.hasSampler) {
slot++;
}
if (format instanceof BindUniformBufferFormat) {
this.uniformBufferFormats.push(format);
} else if (format instanceof BindTextureFormat) {
this.textureFormats.push(format);
} else if (format instanceof BindStorageTextureFormat) {
this.storageTextureFormats.push(format);
} else if (format instanceof BindStorageBufferFormat) {
this.storageBufferFormats.push(format);
} else {
Debug.assert("Invalid bind format", format);
}
});
this.device = graphicsDevice;
const scope = graphicsDevice.scope;
this.bufferFormatsMap = /* @__PURE__ */ new Map();
this.uniformBufferFormats.forEach((bf, i) => this.bufferFormatsMap.set(bf.name, i));
this.textureFormatsMap = /* @__PURE__ */ new Map();
this.textureFormats.forEach((tf, i) => {
this.textureFormatsMap.set(tf.name, i);
tf.scopeId = scope.resolve(tf.name);
});
this.storageTextureFormatsMap = /* @__PURE__ */ new Map();
this.storageTextureFormats.forEach((tf, i) => {
this.storageTextureFormatsMap.set(tf.name, i);
tf.scopeId = scope.resolve(tf.name);
});
this.storageBufferFormatsMap = /* @__PURE__ */ new Map();
this.storageBufferFormats.forEach((bf, i) => {
this.storageBufferFormatsMap.set(bf.name, i);
bf.scopeId = scope.resolve(bf.name);
});
this.impl = graphicsDevice.createBindGroupFormatImpl(this);
Debug.trace(TRACEID_BINDGROUPFORMAT_ALLOC, `Alloc: Id ${this.id}, while rendering [${DebugGraphics.toString()}]`, this);
}
/**
* Frees resources associated with this bind group.
*/
destroy() {
this.impl.destroy();
}
/**
* Returns format of texture with specified name.
*
* @param {string} name - The name of the texture slot.
* @returns {BindTextureFormat|null} - The format.
* @ignore
*/
getTexture(name) {
const index = this.textureFormatsMap.get(name);
if (index !== void 0) {
return this.textureFormats[index];
}
return null;
}
/**
* Returns format of storage texture with specified name.
*
* @param {string} name - The name of the texture slot.
* @returns {BindStorageTextureFormat|null} - The format.
* @ignore
*/
getStorageTexture(name) {
const index = this.storageTextureFormatsMap.get(name);
if (index !== void 0) {
return this.storageTextureFormats[index];
}
return null;
}
loseContext() {
}
}
export {
BindGroupFormat,
BindStorageBufferFormat,
BindStorageTextureFormat,
BindTextureFormat,
BindUniformBufferFormat
};