{"version":3,"file":"GlBufferSystem.mjs","sources":["../../../../../src/rendering/renderers/gl/buffer/GlBufferSystem.ts"],"sourcesContent":["import { ExtensionType } from '../../../../extensions/Extensions';\nimport { GCManagedHash } from '../../../../utils/data/GCManagedHash';\nimport { BufferUsage } from '../../shared/buffer/const';\nimport { BUFFER_TYPE } from './const';\nimport { GlBuffer } from './GlBuffer';\n\nimport type { Buffer } from '../../shared/buffer/Buffer';\nimport type { System } from '../../shared/system/System';\nimport type { GlRenderingContext } from '../context/GlRenderingContext';\nimport type { WebGLRenderer } from '../WebGLRenderer';\n\n/**\n * System plugin to the renderer to manage buffers.\n *\n * WebGL uses Buffers as a way to store objects to the GPU.\n * This system makes working with them a lot easier.\n *\n * Buffers are used in three main places in WebGL\n * - geometry information\n * - Uniform information (via uniform buffer objects - a WebGL 2 only feature)\n * - Transform feedback information. (WebGL 2 only feature)\n *\n * This system will handle the binding of buffers to the GPU as well as uploading\n * them. With this system, you never need to work directly with GPU buffers, but instead work with\n * the Buffer class.\n * @class\n * @category rendering\n * @advanced\n */\nexport class GlBufferSystem implements System\n{\n    /** @ignore */\n    public static extension = {\n        type: [\n            ExtensionType.WebGLSystem,\n        ],\n        name: 'buffer',\n    } as const;\n\n    /** @internal */\n    public _gl: GlRenderingContext;\n    protected _managedBuffers: GCManagedHash<Buffer>;\n\n    /** Cache keeping track of the base bound buffer bases */\n    private _boundBufferBases: {[key: number]: GlBuffer} = Object.create(null);\n\n    private _renderer: WebGLRenderer;\n\n    private _minBaseLocation = 0;\n    private _maxBindings: number;\n    private _nextBindBaseIndex = this._minBaseLocation;\n    private _bindCallId = 0;\n\n    /**\n     * @param {Renderer} renderer - The renderer this System works for.\n     */\n    constructor(renderer: WebGLRenderer)\n    {\n        this._renderer = renderer;\n        this._managedBuffers = new GCManagedHash({\n            renderer,\n            type: 'resource',\n            onUnload: this.onBufferUnload.bind(this),\n            name: 'glBuffer'\n        });\n    }\n\n    /** @ignore */\n    public destroy(): void\n    {\n        this._managedBuffers.destroy();\n        this._renderer = null;\n        this._gl = null;\n        this._boundBufferBases = {};\n    }\n\n    /** Sets up the renderer context and necessary buffers. */\n    protected contextChange(): void\n    {\n        this._gl = this._renderer.gl;\n\n        this.destroyAll(true);\n        this._maxBindings = this._renderer.limits.maxUniformBindings;\n    }\n\n    public getGlBuffer(buffer: Buffer): GlBuffer\n    {\n        buffer._gcLastUsed = this._renderer.gc.now;\n\n        return (buffer._gpuData[this._renderer.uid] as GlBuffer) || this.createGLBuffer(buffer);\n    }\n\n    /**\n     * This binds specified buffer. On first run, it will create the webGL buffers for the context too\n     * @param buffer - the buffer to bind to the renderer\n     */\n    public bind(buffer: Buffer): void\n    {\n        const { _gl: gl } = this;\n\n        const glBuffer = this.getGlBuffer(buffer);\n\n        gl.bindBuffer(glBuffer.type, glBuffer.buffer);\n    }\n\n    /**\n     * Binds an uniform buffer to at the given index.\n     *\n     * A cache is used so a buffer will not be bound again if already bound.\n     * @param glBuffer - the buffer to bind\n     * @param index - the base index to bind it to.\n     */\n    public bindBufferBase(glBuffer: GlBuffer, index: number): void\n    {\n        const { _gl: gl } = this;\n\n        if (this._boundBufferBases[index] !== glBuffer)\n        {\n            this._boundBufferBases[index] = glBuffer;\n            glBuffer._lastBindBaseLocation = index;\n\n            gl.bindBufferBase(gl.UNIFORM_BUFFER, index, glBuffer.buffer);\n        }\n    }\n\n    public nextBindBase(hasTransformFeedback: boolean)\n    {\n        this._bindCallId++;\n        this._minBaseLocation = 0;\n        if (hasTransformFeedback)\n        {\n            this._boundBufferBases[0] = null;\n            this._minBaseLocation = 1;\n            if (this._nextBindBaseIndex < 1)\n            {\n                this._nextBindBaseIndex = 1;\n            }\n        }\n    }\n\n    public freeLocationForBufferBase(glBuffer: GlBuffer): number\n    {\n        let freeIndex = this.getLastBindBaseLocation(glBuffer);\n\n        // check if it is already bound..\n        if (freeIndex >= this._minBaseLocation)\n        {\n            glBuffer._lastBindCallId = this._bindCallId;\n\n            return freeIndex;\n        }\n\n        let loop = 0;\n        let nextIndex = this._nextBindBaseIndex;\n\n        while (loop < 2)\n        {\n            if (nextIndex >= this._maxBindings)\n            {\n                nextIndex = this._minBaseLocation;\n                loop++;\n            }\n\n            const curBuf = this._boundBufferBases[nextIndex];\n\n            if (curBuf && curBuf._lastBindCallId === this._bindCallId)\n            {\n                nextIndex++;\n                continue;\n            }\n            break;\n        }\n\n        freeIndex = nextIndex;\n        this._nextBindBaseIndex = nextIndex + 1;\n\n        if (loop >= 2)\n        {\n            // TODO: error\n            return -1;\n        }\n\n        glBuffer._lastBindCallId = this._bindCallId;\n        this._boundBufferBases[freeIndex] = null;\n\n        return freeIndex;\n    }\n\n    public getLastBindBaseLocation(glBuffer: GlBuffer): number\n    {\n        const index = glBuffer._lastBindBaseLocation;\n\n        if (this._boundBufferBases[index] === glBuffer)\n        {\n            return index;\n        }\n\n        return -1;\n    }\n\n    /**\n     * Binds a buffer whilst also binding its range.\n     * This will make the buffer start from the offset supplied rather than 0 when it is read.\n     * @param glBuffer - the buffer to bind\n     * @param index - the base index to bind at, defaults to 0\n     * @param offset - the offset to bind at (this is blocks of 256). 0 = 0, 1 = 256, 2 = 512 etc\n     * @param size - the size to bind at (this is blocks of 256).\n     */\n    public bindBufferRange(glBuffer: GlBuffer, index?: number, offset?: number, size?: number): void\n    {\n        const { _gl: gl } = this;\n\n        offset ||= 0;\n        index ||= 0;\n\n        this._boundBufferBases[index] = null;\n\n        gl.bindBufferRange(gl.UNIFORM_BUFFER, index || 0, glBuffer.buffer, offset * 256, size || 256);\n    }\n\n    /**\n     * Will ensure the data in the buffer is uploaded to the GPU.\n     * @param {Buffer} buffer - the buffer to update\n     */\n    public updateBuffer(buffer: Buffer): GlBuffer\n    {\n        const { _gl: gl } = this;\n\n        const glBuffer = this.getGlBuffer(buffer);\n\n        if (buffer._updateID === glBuffer.updateID)\n        {\n            return glBuffer;\n        }\n\n        glBuffer.updateID = buffer._updateID;\n\n        gl.bindBuffer(glBuffer.type, glBuffer.buffer);\n\n        const data = buffer.data;\n\n        const drawType = (buffer.descriptor.usage & BufferUsage.STATIC) ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW;\n\n        if (data)\n        {\n            if (glBuffer.byteLength >= data.byteLength)\n            {\n                // assuming our buffers are aligned to 4 bits...\n                // offset is always zero for now!\n                gl.bufferSubData(glBuffer.type, 0, data, 0, buffer._updateSize / data.BYTES_PER_ELEMENT);\n            }\n            else\n            {\n                glBuffer.byteLength = data.byteLength;\n                // assuming our buffers are aligned to 4 bits...\n                gl.bufferData(glBuffer.type, data, drawType);\n            }\n        }\n        else\n        {\n            glBuffer.byteLength = buffer.descriptor.size;\n            gl.bufferData(glBuffer.type, glBuffer.byteLength, drawType);\n        }\n\n        return glBuffer;\n    }\n\n    /**\n     * dispose all WebGL resources of all managed buffers\n     * @param contextLost\n     */\n    public destroyAll(contextLost: boolean = false): void\n    {\n        this._managedBuffers.removeAll(contextLost);\n    }\n\n    protected onBufferUnload(buffer: Buffer, contextLost: boolean = false): void\n    {\n        const glBuffer = buffer._gpuData[this._renderer.uid] as GlBuffer;\n\n        if (!glBuffer) return;\n        if (!contextLost) this._gl.deleteBuffer(glBuffer.buffer);\n    }\n\n    /**\n     * creates and attaches a GLBuffer object tied to the current context.\n     * @param buffer\n     * @protected\n     */\n    protected createGLBuffer(buffer: Buffer): GlBuffer\n    {\n        const { _gl: gl } = this;\n\n        let type = BUFFER_TYPE.ARRAY_BUFFER;\n\n        if ((buffer.descriptor.usage & BufferUsage.INDEX))\n        {\n            type = BUFFER_TYPE.ELEMENT_ARRAY_BUFFER;\n        }\n        else if ((buffer.descriptor.usage & BufferUsage.UNIFORM))\n        {\n            type = BUFFER_TYPE.UNIFORM_BUFFER;\n        }\n\n        const glBuffer = new GlBuffer(gl.createBuffer(), type);\n\n        buffer._gpuData[this._renderer.uid] = glBuffer;\n        this._managedBuffers.add(buffer);\n\n        return glBuffer;\n    }\n\n    public resetState(): void\n    {\n        this._boundBufferBases = Object.create(null);\n    }\n}\n"],"names":[],"mappings":"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"}