{"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 { type GlBuffer } from '../../gl/buffer/GlBuffer';\nimport { type GpuBufferData } from '../../gpu/buffer/GpuBufferSystem';\nimport { type GPUDataOwner } from '../../types';\nimport { type GCable, type GCData } from '../GCSystem';\nimport { BufferUsage } from './const';\n\nimport type { BindResource } from '../../gpu/shader/BindResource';\n\n/**\n * All the various typed arrays that exist in js\n * @category rendering\n * @advanced\n */\n// eslint-disable-next-line max-len\nexport type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array;\n\n/**\n * Options for creating a buffer\n *\n * This interface defines the options that can be passed to the Buffer constructor.\n * It includes the data to initialize the buffer with, the size of the buffer,\n * the usage of the buffer, a label for debugging, and whether the buffer should shrink to fit\n * when the data becomes smaller.\n * @category rendering\n * @advanced\n */\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 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\n/** @internal */\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 * @category rendering\n * @advanced\n */\nexport class Buffer extends EventEmitter<{\n    change: BindResource,\n    update: Buffer,\n    destroy: Buffer,\n    unload: Buffer,\n}> implements BindResource, GPUDataOwner, GCable\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    /** @internal */\n    public _gpuData: Record<number, GlBuffer | GpuBufferData> = Object.create(null);\n    /** @internal */\n    public _gcData?: GCData;\n    /** @internal */\n    public _gcLastUsed = -1;\n    /** If set to true, the buffer will be garbage collected automatically when it is not used. */\n    public autoGarbageCollect = true;\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     */\n    public readonly _resourceType = 'buffer';\n\n    /**\n     * the resource id used internally by the renderer to build bind group keys\n     * @internal\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     */\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     */\n    public readonly descriptor: BufferDescriptor;\n\n    /** @internal */\n    public _updateID = 1;\n\n    /** @internal */\n    public _updateSize: number;\n\n    private _data: TypedArray;\n\n    private _dataInt32: Int32Array = null;\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 ??= (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    get dataInt32()\n    {\n        if (!this._dataInt32)\n        {\n            this._dataInt32 = new Int32Array((this.data as any).buffer);\n        }\n\n        return this._dataInt32;\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        this._dataInt32 = null;\n\n        // Event handling\n        if (!oldData || oldData.length !== value.length)\n        {\n            if (!this.shrinkToFit && oldData && 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    /** Unloads the buffer from the GPU */\n    public unload()\n    {\n        /** Unloads the GPU data from the view container. */\n        this.emit('unload', this);\n        for (const key in this._gpuData)\n        {\n            this._gpuData[key]?.destroy();\n        }\n        this._gpuData = Object.create(null);\n    }\n\n    /** Destroys the buffer */\n    public destroy()\n    {\n        this.destroyed = true;\n\n        this.unload();\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":";;;;;AA6FO,MAAM,eAAe,YAAA,CAM5B;AAAA;AAAA;AAAA;AAAA;AAAA,EAoFI,YAAY,OAAA,EACZ;AACI,IAAA,IAAI,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,OAAA;AACrB,IAAA,MAAM,EAAE,KAAA,EAAO,KAAA,EAAO,WAAA,EAAY,GAAI,OAAA;AAEtC,IAAA,KAAA,EAAM;AAtEV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,IAAA,CAAO,QAAA,mBAAqD,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA;AAI9E;AAAA,IAAA,IAAA,CAAO,WAAA,GAAc,CAAA,CAAA;AAErB;AAAA,IAAA,IAAA,CAAO,kBAAA,GAAqB,IAAA;AAG5B;AAAA,IAAA,IAAA,CAAgB,GAAA,GAAc,IAAI,QAAQ,CAAA;AAM1C;AAAA;AAAA;AAAA;AAAA,IAAA,IAAA,CAAgB,aAAA,GAAgB,QAAA;AAMhC;AAAA;AAAA;AAAA;AAAA,IAAA,IAAA,CAAO,WAAA,GAAc,IAAI,UAAU,CAAA;AAMnC;AAAA;AAAA;AAAA;AAAA,IAAA,IAAA,CAAO,QAAA,GAAW,CAAA;AASlB;AAAA,IAAA,IAAA,CAAO,SAAA,GAAY,CAAA;AAOnB,IAAA,IAAA,CAAQ,UAAA,GAAyB,IAAA;AAUjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAA,IAAA,CAAO,WAAA,GAAc,IAAA;AAMrB;AAAA;AAAA;AAAA;AAAA,IAAA,IAAA,CAAO,SAAA,GAAY,KAAA;AAaf,IAAA,IAAI,gBAAgB,KAAA,EACpB;AACI,MAAA,IAAA,GAAO,IAAI,aAAa,IAAgB,CAAA;AAAA,IAC5C;AAEA,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AAEb,IAAA,IAAA,KAAA,IAAA,GAAU,IAAA,EAAqB,UAAA,CAAA;AAE/B,IAAA,MAAM,gBAAA,GAAmB,CAAC,CAAC,IAAA;AAE3B,IAAA,IAAA,CAAK,UAAA,GAAa;AAAA,MACd,IAAA;AAAA,MACA,KAAA;AAAA,MACA,gBAAA;AAAA,MACA;AAAA,KACJ;AAEA,IAAA,IAAA,CAAK,cAAc,WAAA,IAAe,IAAA;AAAA,EACtC;AAAA;AAAA,EAGA,IAAI,IAAA,GACJ;AACI,IAAA,OAAO,IAAA,CAAK,KAAA;AAAA,EAChB;AAAA,EAEA,IAAI,KAAK,KAAA,EACT;AACI,IAAA,IAAA,CAAK,eAAA,CAAgB,KAAA,EAAO,KAAA,CAAM,MAAA,EAAQ,IAAI,CAAA;AAAA,EAClD;AAAA,EAEA,IAAI,SAAA,GACJ;AACI,IAAA,IAAI,CAAC,KAAK,UAAA,EACV;AACI,MAAA,IAAA,CAAK,UAAA,GAAa,IAAI,UAAA,CAAY,IAAA,CAAK,KAAa,MAAM,CAAA;AAAA,IAC9D;AAEA,IAAA,OAAO,IAAA,CAAK,UAAA;AAAA,EAChB;AAAA;AAAA,EAGA,IAAI,MAAA,GACJ;AACI,IAAA,OAAO,CAAC,EAAE,IAAA,CAAK,UAAA,CAAW,QAAQ,WAAA,CAAY,MAAA,CAAA;AAAA,EAClD;AAAA,EAEA,IAAI,OAAO,KAAA,EACX;AACI,IAAA,IAAI,KAAA,EACJ;AACI,MAAA,IAAA,CAAK,UAAA,CAAW,SAAS,WAAA,CAAY,MAAA;AAAA,IACzC,CAAA,MAEA;AACI,MAAA,IAAA,CAAK,UAAA,CAAW,KAAA,IAAS,CAAC,WAAA,CAAY,MAAA;AAAA,IAC1C;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,eAAA,CAAgB,KAAA,EAAmB,IAAA,EAAc,OAAA,EACxD;AAEI,IAAA,IAAA,CAAK,SAAA,EAAA;AAEL,IAAA,IAAA,CAAK,WAAA,GAAe,OAAO,KAAA,CAAM,iBAAA;AAGjC,IAAA,IAAI,IAAA,CAAK,UAAU,KAAA,EACnB;AACI,MAAA,IAAI,OAAA,EAAS,IAAA,CAAK,IAAA,CAAK,QAAA,EAAU,IAAI,CAAA;AAErC,MAAA;AAAA,IACJ;AAGA,IAAA,MAAM,UAAU,IAAA,CAAK,KAAA;AAErB,IAAA,IAAA,CAAK,KAAA,GAAQ,KAAA;AACb,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAGlB,IAAA,IAAI,CAAC,OAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,MAAM,MAAA,EACzC;AACI,MAAA,IAAI,CAAC,IAAA,CAAK,WAAA,IAAe,WAAW,KAAA,CAAM,UAAA,GAAa,QAAQ,UAAA,EAC/D;AACI,QAAA,IAAI,OAAA,EAAS,IAAA,CAAK,IAAA,CAAK,QAAA,EAAU,IAAI,CAAA;AAAA,MACzC,CAAA,MAEA;AACI,QAAA,IAAA,CAAK,UAAA,CAAW,OAAO,KAAA,CAAM,UAAA;AAC7B,QAAA,IAAA,CAAK,WAAA,GAAc,IAAI,UAAU,CAAA;AACjC,QAAA,IAAA,CAAK,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,MAC5B;AAEA,MAAA;AAAA,IACJ;AAEA,IAAA,IAAI,OAAA,EAAS,IAAA,CAAK,IAAA,CAAK,QAAA,EAAU,IAAI,CAAA;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQO,OAAO,WAAA,EACd;AACI,IAAA,IAAA,CAAK,WAAA,GAAc,eAAe,IAAA,CAAK,WAAA;AAEvC,IAAA,IAAA,CAAK,SAAA,EAAA;AAEL,IAAA,IAAA,CAAK,IAAA,CAAK,UAAU,IAAI,CAAA;AAAA,EAC5B;AAAA;AAAA,EAGO,MAAA,GACP;AAEI,IAAA,IAAA,CAAK,IAAA,CAAK,UAAU,IAAI,CAAA;AACxB,IAAA,KAAA,MAAW,GAAA,IAAO,KAAK,QAAA,EACvB;AACI,MAAA,IAAA,CAAK,QAAA,CAAS,GAAG,CAAA,EAAG,OAAA,EAAQ;AAAA,IAChC;AACA,IAAA,IAAA,CAAK,QAAA,mBAAW,MAAA,CAAO,MAAA,CAAO,IAAI,CAAA;AAAA,EACtC;AAAA;AAAA,EAGO,OAAA,GACP;AACI,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AAEjB,IAAA,IAAA,CAAK,MAAA,EAAO;AACZ,IAAA,IAAA,CAAK,IAAA,CAAK,WAAW,IAAI,CAAA;AACzB,IAAA,IAAA,CAAK,IAAA,CAAK,UAAU,IAAI,CAAA;AAExB,IAAA,IAAA,CAAK,KAAA,GAAQ,IAAA;AACb,IAAC,KAAK,UAAA,GAAsB,IAAA;AAE5B,IAAA,IAAA,CAAK,kBAAA,EAAmB;AAAA,EAC5B;AACJ;;;;"}