{"version":3,"file":"Buffer.mjs","sources":["../../../../../src/rendering/renderers/shared/buffer/Buffer.ts"],"sourcesContent":["import EventEmitter from 'eventemitter3';\nimport { uid } from '../../../../utils/data/uid';\nimport { BufferUsage } from './const';\n\nimport type { BindResource } from '../../gpu/shader/BindResource';\n\n/** All the various typed arrays that exist in js */\n// eslint-disable-next-line max-len\nexport type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array;\n\n/** Options for creating a buffer */\nexport interface BufferOptions\n{\n    /**\n     * the data to initialize the buffer with, this can be a typed array,\n     * or a regular number array. If it is a number array, it will be converted to a Float32Array\n     */\n    data?: TypedArray | number[];\n    /** the size of the buffer in bytes, if not supplied, it will be inferred from the data */\n    size?: number;\n    /** the usage of the buffer, see {@link rendering.BufferUsage} */\n    usage: number;\n    /** a label for the buffer, this is useful for debugging */\n    label?: string;\n    /**\n     * should the GPU buffer be shrunk when the data becomes smaller?\n     * changing this will cause the buffer to be destroyed and a new one created on the GPU\n     * this can be expensive, especially if the buffer is already big enough!\n     * setting this to false will prevent the buffer from being shrunk. This will yield better performance\n     * if you are constantly setting data that is changing size often.\n     * @default true\n     */\n    shrinkToFit?: boolean;\n}\n\nexport interface BufferDescriptor\n{\n    label?: string;\n    size: GPUSize64;\n    usage: BufferUsage;\n    mappedAtCreation?: boolean;\n}\n\n/**\n * A wrapper for a WebGPU/WebGL Buffer.\n * In PixiJS, the Buffer class is used to manage the data that is sent to the GPU rendering pipeline.\n * It abstracts away the underlying GPU buffer and provides an interface for uploading typed arrays or other data to the GPU,\n * They are used in the following places:\n * <br><br>\n * .1. {@link Geometry} as attribute data or index data for geometry\n * <br>\n * .2. {@link UniformGroup} as an underlying buffer for uniform data\n * <br>\n * .3. {@link BufferResource} as an underlying part of a buffer used directly by the GPU program\n * <br>\n *\n * It is important to note that you must provide a usage type when creating a buffer. This is because\n * the underlying GPU buffer needs to know how it will be used. For example, if you are creating a buffer\n * to hold vertex data, you would use `BufferUsage.VERTEX`. This will tell the GPU that this buffer will be\n * used as a vertex buffer. This is important because it will affect how you can use the buffer.\n *\n * Buffers are updated by calling the {@link Buffer.update} method. This immediately updates the buffer on the GPU.\n * Be mindful of calling this more often than you need to. It is recommended to update buffers only when needed.\n *\n * In WebGPU, a GPU buffer cannot resized. This limitation is abstracted away, but know that resizing a buffer means\n * creating a brand new one and destroying the old, so it is best to limit this if possible.\n * @example\n *\n * const buffer = new Buffer({\n *     data: new Float32Array([1, 2, 3, 4]),\n *     usage: BufferUsage.VERTEX,\n * });\n * @memberof rendering\n */\nexport class Buffer extends EventEmitter<{\n    change: BindResource,\n    update: Buffer,\n    destroy: Buffer,\n}> implements BindResource\n{\n    /**\n     * emits when the underlying buffer has changed shape (i.e. resized)\n     * letting the renderer know that it needs to discard the old buffer on the GPU and create a new one\n     * @event change\n     */\n\n    /**\n     * emits when the underlying buffer data has been updated. letting the renderer know\n     * that it needs to update the buffer on the GPU\n     * @event update\n     */\n\n    /**\n     * emits when the buffer is destroyed. letting the renderer know that it needs to destroy the buffer on the GPU\n     * @event destroy\n     */\n\n    /** a unique id for this uniform group used through the renderer */\n    public readonly uid: number = uid('buffer');\n\n    /**\n     * a resource type, used to identify how to handle it when its in a bind group / shader resource\n     * @internal\n     * @ignore\n     */\n    public readonly _resourceType = 'buffer';\n\n    /**\n     * the resource id used internally by the renderer to build bind group keys\n     * @internal\n     * @ignore\n     */\n    public _resourceId = uid('resource');\n\n    /**\n     * used internally to know if a uniform group was used in the last render pass\n     * @internal\n     * @ignore\n     */\n    public _touched = 0;\n\n    /**\n     * a description of the buffer and how it should be set up on the GPU\n     * @internal\n     * @ignore\n     */\n    public readonly descriptor: BufferDescriptor;\n\n    /**\n     * @internal\n     * @ignore\n     */\n    public _updateID = 1;\n\n    /**\n     * @internal\n     * @ignore\n     */\n    public _updateSize: number;\n\n    private _data: TypedArray;\n\n    /**\n     * should the GPU buffer be shrunk when the data becomes smaller?\n     * changing this will cause the buffer to be destroyed and a new one created on the GPU\n     * this can be expensive, especially if the buffer is already big enough!\n     * setting this to false will prevent the buffer from being shrunk. This will yield better performance\n     * if you are constantly setting data that is changing size often.\n     * @default true\n     */\n    public shrinkToFit = true;\n\n    /**\n     * Has the buffer been destroyed?\n     * @readonly\n     */\n    public destroyed = false;\n\n    /**\n     * Creates a new Buffer with the given options\n     * @param options - the options for the buffer\n     */\n    constructor(options: BufferOptions)\n    {\n        let { data, size } = options;\n        const { usage, label, shrinkToFit } = options;\n\n        super();\n\n        if (data instanceof Array)\n        {\n            data = new Float32Array(data as number[]);\n        }\n\n        this._data = data as TypedArray;\n\n        size = size ?? (data as TypedArray)?.byteLength;\n\n        const mappedAtCreation = !!data;\n\n        this.descriptor = {\n            size,\n            usage,\n            mappedAtCreation,\n            label,\n        };\n\n        this.shrinkToFit = shrinkToFit ?? true;\n    }\n\n    /** the data in the buffer */\n    get data()\n    {\n        return this._data;\n    }\n\n    set data(value: TypedArray)\n    {\n        this.setDataWithSize(value, value.length, true);\n    }\n\n    /** whether the buffer is static or not */\n    get static()\n    {\n        return !!(this.descriptor.usage & BufferUsage.STATIC);\n    }\n\n    set static(value: boolean)\n    {\n        if (value)\n        {\n            this.descriptor.usage |= BufferUsage.STATIC;\n        }\n        else\n        {\n            this.descriptor.usage &= ~BufferUsage.STATIC;\n        }\n    }\n\n    /**\n     * Sets the data in the buffer to the given value. This will immediately update the buffer on the GPU.\n     * If you only want to update a subset of the buffer, you can pass in the size of the data.\n     * @param value - the data to set\n     * @param size - the size of the data in bytes\n     * @param syncGPU - should the buffer be updated on the GPU immediately?\n     */\n    public setDataWithSize(value: TypedArray, size: number, syncGPU: boolean)\n    {\n        // Increment update ID\n        this._updateID++;\n\n        this._updateSize = (size * value.BYTES_PER_ELEMENT);\n\n        // If the data hasn't changed, early return after emitting 'update'\n        if (this._data === value)\n        {\n            if (syncGPU) this.emit('update', this);\n\n            return;\n        }\n\n        // Cache old data and update to new value\n        const oldData = this._data;\n\n        this._data = value;\n\n        // Event handling\n        if (oldData.length !== value.length)\n        {\n            if (!this.shrinkToFit && value.byteLength < oldData.byteLength)\n            {\n                if (syncGPU) this.emit('update', this);\n            }\n            else\n            {\n                this.descriptor.size = value.byteLength;\n                this._resourceId = uid('resource');\n                this.emit('change', this);\n            }\n\n            return;\n        }\n\n        if (syncGPU) this.emit('update', this);\n    }\n\n    /**\n     * updates the buffer on the GPU to reflect the data in the buffer.\n     * By default it will update the entire buffer. If you only want to update a subset of the buffer,\n     * you can pass in the size of the buffer to update.\n     * @param sizeInBytes - the new size of the buffer in bytes\n     */\n    public update(sizeInBytes?: number): void\n    {\n        this._updateSize = sizeInBytes ?? this._updateSize;\n\n        this._updateID++;\n\n        this.emit('update', this);\n    }\n\n    /** Destroys the buffer */\n    public destroy()\n    {\n        this.destroyed = true;\n\n        this.emit('destroy', this);\n        this.emit('change', this);\n\n        this._data = null;\n        (this.descriptor as null) = null;\n\n        this.removeAllListeners();\n    }\n}\n\n"],"names":[],"mappings":"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"}