/** * The per mesh instance data the vertex shaders read from a storage buffer instead of a per draw * uniform buffer: a slot per mesh instance, holding its model and normal matrix. A draw passes * the slot as its first instance, and the shader indexes the buffer by the instance index. The * data persists between frames, so only the slots of the mesh instances whose transform changed * are written, into a CPU copy of the buffer, and uploaded when the device submits its command * buffers - before those run. The buffer grows when it runs out of slots, and never shrinks. * * WebGPU only, see {@link GraphicsDevice#supportsMeshInstanceStorage}. * * @ignore */ export class MeshInstanceStorage { /** * @param {GraphicsDevice} device - The graphics device. * @param {number} [capacity] - The initial number of slots. Defaults to 1024. */ constructor(device: GraphicsDevice, capacity?: number); /** * The number of slots the buffer holds. * * @type {number} */ capacity: number; /** * The number of slots ever allocated, the freed ones included. * * @type {number} */ count: number; /** * Incremented when the buffer is replaced by a larger one, so that the bind groups holding it * are updated. * * @type {number} */ version: number; /** @type {StorageBuffer|null} */ buffer: StorageBuffer | null; /** * The CPU copy of the buffer. * * @type {Float32Array} */ data: Float32Array; /** * The slots which can be allocated. * * @type {number[]} * @private */ private _freeSlots; /** * The slots released since the last submit, which can be allocated once it is done. The * draws recorded before it may still use them, and the data of the slots is uploaded once * for all of these draws. * * @type {number[]} * @private */ private _releasedSlots; /** * A bit per slot, set when the slot was written since the last upload, which walks them in * slot order. * * @type {Uint32Array} * @private */ private _dirtyBits; /** * True when any slot was written since the last upload. * * @type {boolean} * @private */ private _dirty; device: GraphicsDevice; scopeId: import("./scope-id.js").ScopeId; destroy(): void; /** * Uploads all the slots again after the device was lost and restored, which recreates the * buffer empty. The slots and their CPU copy are kept, as the mesh instances hold on to them. */ restoreContext(): void; /** * Allocates a slot, growing the buffer when all are in use. * * @returns {number} The slot. */ allocate(): number; /** * Returns a slot for reuse. * * @param {number} slot - The slot. */ free(slot: number): void; /** * Writes the matrices of a slot, uploaded on the next submit. * * @param {number} slot - The slot. * @param {Float32Array} model - The 16 floats of the model matrix. * @param {Float32Array} normal - The 9 floats of the normal matrix. */ write(slot: number, model: Float32Array, normal: Float32Array): void; /** * Uploads the slots written since the last upload, merging slots close together into one * write, and makes the slots released since available for allocation. Called by the device * before it submits its command buffers, which then run after the upload. */ upload(): void; /** * Makes the released slots available for allocation, once no draws recorded before their * release are pending. * * @private */ private _recycleReleasedSlots; /** * @private */ private _uploadDirtySlots; /** * @param {number} first - The first slot. * @param {number} last - The last slot, included. * @private */ private _writeRange; /** * Replaces the buffer with one of a new capacity, keeping the data. The old buffer is still * used by the commands recorded this frame, so the writes pending for it are uploaded to it * first, and its destruction is deferred until the commands are submitted. * * @param {number} capacity - The number of slots. * @private */ private _resize; } import { StorageBuffer } from './storage-buffer.js'; import type { GraphicsDevice } from './graphics-device.js';