{"version":3,"file":"ShaderSystem.mjs","sources":["../../src/shader/ShaderSystem.ts"],"sourcesContent":["import { extensions, ExtensionType } from '@pixi/extensions';\nimport { generateUniformsSync, unsafeEvalSupported } from './utils';\nimport { generateProgram } from './utils/generateProgram';\nimport { generateUniformBufferSync } from './utils/generateUniformBufferSync';\n\nimport type { ExtensionMetadata } from '@pixi/extensions';\nimport type { Dict } from '@pixi/utils';\nimport type { IRenderingContext } from '../IRenderer';\nimport type { Renderer } from '../Renderer';\nimport type { ISystem } from '../system/ISystem';\nimport type { GLProgram } from './GLProgram';\nimport type { Program } from './Program';\nimport type { Shader } from './Shader';\nimport type { UniformGroup } from './UniformGroup';\nimport type { UniformsSyncCallback } from './utils';\n\nlet UID = 0;\n// default sync data so we don't create a new one each time!\nconst defaultSyncData = { textureCount: 0, uboCount: 0 };\n\n/**\n * System plugin to the renderer to manage shaders.\n * @memberof PIXI\n */\nexport class ShaderSystem implements ISystem\n{\n    /** @ignore */\n    static extension: ExtensionMetadata = {\n        type: ExtensionType.RendererSystem,\n        name: 'shader',\n    };\n\n    /**\n     * The current WebGL rendering context.\n     * @member {WebGLRenderingContext}\n     */\n    protected gl: IRenderingContext;\n\n    public shader: Shader;\n    public program: Program;\n    public id: number;\n    public destroyed = false;\n\n    /** Cache to holds the generated functions. Stored against UniformObjects unique signature. */\n    private cache: Dict<UniformsSyncCallback>;\n    private _uboCache: Dict<{size: number, syncFunc: UniformsSyncCallback}>;\n    private renderer: Renderer;\n\n    /** @param renderer - The renderer this System works for. */\n    constructor(renderer: Renderer)\n    {\n        this.renderer = renderer;\n\n        // Validation check that this environment support `new Function`\n        this.systemCheck();\n\n        this.gl = null;\n\n        this.shader = null;\n        this.program = null;\n\n        this.cache = {};\n        this._uboCache = {};\n\n        this.id = UID++;\n    }\n\n    /**\n     * Overrideable function by `@pixi/unsafe-eval` to silence\n     * throwing an error if platform doesn't support unsafe-evals.\n     * @private\n     */\n    private systemCheck(): void\n    {\n        if (!unsafeEvalSupported())\n        {\n            throw new Error('Current environment does not allow unsafe-eval, '\n                + 'please use @pixi/unsafe-eval module to enable support.');\n        }\n    }\n\n    protected contextChange(gl: IRenderingContext): void\n    {\n        this.gl = gl;\n        this.reset();\n    }\n\n    /**\n     * Changes the current shader to the one given in parameter.\n     * @param shader - the new shader\n     * @param dontSync - false if the shader should automatically sync its uniforms.\n     * @returns the glProgram that belongs to the shader.\n     */\n    bind(shader: Shader, dontSync?: boolean): GLProgram\n    {\n        shader.disposeRunner.add(this);\n\n        shader.uniforms.globals = this.renderer.globalUniforms;\n\n        const program = shader.program;\n        const glProgram = program.glPrograms[this.renderer.CONTEXT_UID] || this.generateProgram(shader);\n\n        this.shader = shader;\n\n        // TODO - some current Pixi plugins bypass this.. so it not safe to use yet..\n        if (this.program !== program)\n        {\n            this.program = program;\n            this.gl.useProgram(glProgram.program);\n        }\n\n        if (!dontSync)\n        {\n            defaultSyncData.textureCount = 0;\n            defaultSyncData.uboCount = 0;\n\n            this.syncUniformGroup(shader.uniformGroup, defaultSyncData);\n        }\n\n        return glProgram;\n    }\n\n    /**\n     * Uploads the uniforms values to the currently bound shader.\n     * @param uniforms - the uniforms values that be applied to the current shader\n     */\n    setUniforms(uniforms: Dict<any>): void\n    {\n        const shader = this.shader.program;\n        const glProgram = shader.glPrograms[this.renderer.CONTEXT_UID];\n\n        shader.syncUniforms(glProgram.uniformData, uniforms, this.renderer);\n    }\n\n    /* eslint-disable @typescript-eslint/explicit-module-boundary-types */\n    /**\n     * Syncs uniforms on the group\n     * @param group - the uniform group to sync\n     * @param syncData - this is data that is passed to the sync function and any nested sync functions\n     */\n    syncUniformGroup(group: UniformGroup, syncData?: any): void\n    {\n        const glProgram = this.getGlProgram();\n\n        if (!group.static || group.dirtyId !== glProgram.uniformDirtyGroups[group.id])\n        {\n            glProgram.uniformDirtyGroups[group.id] = group.dirtyId;\n\n            this.syncUniforms(group, glProgram, syncData);\n        }\n    }\n\n    /**\n     * Overrideable by the @pixi/unsafe-eval package to use static syncUniforms instead.\n     * @param group\n     * @param glProgram\n     * @param syncData\n     */\n    syncUniforms(group: UniformGroup, glProgram: GLProgram, syncData: any): void\n    {\n        const syncFunc = group.syncUniforms[this.shader.program.id] || this.createSyncGroups(group);\n\n        syncFunc(glProgram.uniformData, group.uniforms, this.renderer, syncData);\n    }\n\n    createSyncGroups(group: UniformGroup): UniformsSyncCallback\n    {\n        const id = this.getSignature(group, this.shader.program.uniformData, 'u');\n\n        if (!this.cache[id])\n        {\n            this.cache[id] = generateUniformsSync(group, this.shader.program.uniformData);\n        }\n\n        group.syncUniforms[this.shader.program.id] = this.cache[id];\n\n        return group.syncUniforms[this.shader.program.id];\n    }\n\n    /**\n     * Syncs uniform buffers\n     * @param group - the uniform buffer group to sync\n     * @param name - the name of the uniform buffer\n     */\n    syncUniformBufferGroup(group: UniformGroup, name?: string)\n    {\n        const glProgram = this.getGlProgram();\n\n        if (!group.static || group.dirtyId !== 0 || !glProgram.uniformGroups[group.id])\n        {\n            group.dirtyId = 0;\n\n            const syncFunc = glProgram.uniformGroups[group.id]\n                || this.createSyncBufferGroup(group, glProgram, name);\n\n            // TODO wrap update in a cache??\n            group.buffer.update();\n\n            syncFunc(glProgram.uniformData,\n                group.uniforms,\n                this.renderer,\n                defaultSyncData,\n                group.buffer\n            );\n        }\n\n        this.renderer.buffer.bindBufferBase(group.buffer, glProgram.uniformBufferBindings[name]);\n    }\n\n    /**\n     * Will create a function that uploads a uniform buffer using the STD140 standard.\n     * The upload function will then be cached for future calls\n     * If a group is manually managed, then a simple upload function is generated\n     * @param group - the uniform buffer group to sync\n     * @param glProgram - the gl program to attach the uniform bindings to\n     * @param name - the name of the uniform buffer (must exist on the shader)\n     */\n    protected createSyncBufferGroup(group: UniformGroup, glProgram: GLProgram, name: string): UniformsSyncCallback\n    {\n        const { gl } = this.renderer;\n\n        this.renderer.buffer.bind(group.buffer);\n\n        // bind them...\n        const uniformBlockIndex = this.gl.getUniformBlockIndex(glProgram.program, name);\n\n        glProgram.uniformBufferBindings[name] = this.shader.uniformBindCount;\n\n        gl.uniformBlockBinding(glProgram.program, uniformBlockIndex, this.shader.uniformBindCount);\n\n        this.shader.uniformBindCount++;\n\n        const id = this.getSignature(group, this.shader.program.uniformData, 'ubo');\n\n        let uboData = this._uboCache[id];\n\n        if (!uboData)\n        {\n            uboData = this._uboCache[id] = generateUniformBufferSync(group, this.shader.program.uniformData);\n        }\n\n        if (group.autoManage)\n        {\n            const data = new Float32Array(uboData.size / 4);\n\n            group.buffer.update(data);\n        }\n\n        glProgram.uniformGroups[group.id] = uboData.syncFunc;\n\n        return glProgram.uniformGroups[group.id];\n    }\n\n    /**\n     * Takes a uniform group and data and generates a unique signature for them.\n     * @param group - The uniform group to get signature of\n     * @param group.uniforms\n     * @param uniformData - Uniform information generated by the shader\n     * @param preFix\n     * @returns Unique signature of the uniform group\n     */\n    private getSignature(group: {uniforms: Dict<any>}, uniformData: Dict<any>, preFix: string): string\n    {\n        const uniforms = group.uniforms;\n\n        const strings = [`${preFix}-`];\n\n        for (const i in uniforms)\n        {\n            strings.push(i);\n\n            if (uniformData[i])\n            {\n                strings.push(uniformData[i].type);\n            }\n        }\n\n        return strings.join('-');\n    }\n\n    /**\n     * Returns the underlying GLShade rof the currently bound shader.\n     *\n     * This can be handy for when you to have a little more control over the setting of your uniforms.\n     * @returns The glProgram for the currently bound Shader for this context\n     */\n    getGlProgram(): GLProgram\n    {\n        if (this.shader)\n        {\n            return this.shader.program.glPrograms[this.renderer.CONTEXT_UID];\n        }\n\n        return null;\n    }\n\n    /**\n     * Generates a glProgram version of the Shader provided.\n     * @param shader - The shader that the glProgram will be based on.\n     * @returns A shiny new glProgram!\n     */\n    generateProgram(shader: Shader): GLProgram\n    {\n        const gl = this.gl;\n        const program = shader.program;\n\n        const glProgram = generateProgram(gl, program);\n\n        program.glPrograms[this.renderer.CONTEXT_UID] = glProgram;\n\n        return glProgram;\n    }\n\n    /** Resets ShaderSystem state, does not affect WebGL state. */\n    reset(): void\n    {\n        this.program = null;\n        this.shader = null;\n    }\n\n    /**\n     * Disposes shader.\n     * If disposing one equals with current shader, set current as null.\n     * @param shader - Shader object\n     */\n    disposeShader(shader: Shader): void\n    {\n        if (this.shader === shader)\n        {\n            this.shader = null;\n        }\n    }\n\n    /** Destroys this System and removes all its textures. */\n    destroy(): void\n    {\n        this.renderer = null;\n        // TODO implement destroy method for ShaderSystem\n        this.destroyed = true;\n    }\n}\n\nextensions.add(ShaderSystem);\n"],"names":[],"mappings":";;;;;;AAgBA,IAAI,MAAM;AAEV,MAAM,kBAAkB,EAAE,cAAc,GAAG,UAAU,EAAE;AAMhD,MAAM,aACb;AAAA;AAAA,EAwBI,YAAY,UACZ;AATA,SAAO,YAAY,IAUV,KAAA,WAAW,UAGhB,KAAK,YAAA,GAEL,KAAK,KAAK,MAEV,KAAK,SAAS,MACd,KAAK,UAAU,MAEf,KAAK,QAAQ,CAAA,GACb,KAAK,YAAY,IAEjB,KAAK,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,cACR;AACI,QAAI,CAAC,oBAAoB;AAEf,YAAA,IAAI,MAAM,wGAC8C;AAAA,EAEtE;AAAA,EAEU,cAAc,IACxB;AACS,SAAA,KAAK,IACV,KAAK,MAAM;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,KAAK,QAAgB,UACrB;AACW,WAAA,cAAc,IAAI,IAAI,GAE7B,OAAO,SAAS,UAAU,KAAK,SAAS;AAExC,UAAM,UAAU,OAAO,SACjB,YAAY,QAAQ,WAAW,KAAK,SAAS,WAAW,KAAK,KAAK,gBAAgB,MAAM;AAEzF,WAAA,KAAA,SAAS,QAGV,KAAK,YAAY,YAEjB,KAAK,UAAU,SACf,KAAK,GAAG,WAAW,UAAU,OAAO,IAGnC,aAED,gBAAgB,eAAe,GAC/B,gBAAgB,WAAW,GAE3B,KAAK,iBAAiB,OAAO,cAAc,eAAe,IAGvD;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,YAAY,UACZ;AACU,UAAA,SAAS,KAAK,OAAO,SACrB,YAAY,OAAO,WAAW,KAAK,SAAS,WAAW;AAE7D,WAAO,aAAa,UAAU,aAAa,UAAU,KAAK,QAAQ;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,iBAAiB,OAAqB,UACtC;AACU,UAAA,YAAY,KAAK;AAEnB,KAAA,CAAC,MAAM,UAAU,MAAM,YAAY,UAAU,mBAAmB,MAAM,EAAE,OAExE,UAAU,mBAAmB,MAAM,EAAE,IAAI,MAAM,SAE/C,KAAK,aAAa,OAAO,WAAW,QAAQ;AAAA,EAEpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,aAAa,OAAqB,WAAsB,UACxD;AAGI,KAFiB,MAAM,aAAa,KAAK,OAAO,QAAQ,EAAE,KAAK,KAAK,iBAAiB,KAAK,GAEjF,UAAU,aAAa,MAAM,UAAU,KAAK,UAAU,QAAQ;AAAA,EAC3E;AAAA,EAEA,iBAAiB,OACjB;AACU,UAAA,KAAK,KAAK,aAAa,OAAO,KAAK,OAAO,QAAQ,aAAa,GAAG;AAExE,WAAK,KAAK,MAAM,EAAE,MAEd,KAAK,MAAM,EAAE,IAAI,qBAAqB,OAAO,KAAK,OAAO,QAAQ,WAAW,IAGhF,MAAM,aAAa,KAAK,OAAO,QAAQ,EAAE,IAAI,KAAK,MAAM,EAAE,GAEnD,MAAM,aAAa,KAAK,OAAO,QAAQ,EAAE;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,uBAAuB,OAAqB,MAC5C;AACU,UAAA,YAAY,KAAK;AAEnB,QAAA,CAAC,MAAM,UAAU,MAAM,YAAY,KAAK,CAAC,UAAU,cAAc,MAAM,EAAE,GAC7E;AACI,YAAM,UAAU;AAEV,YAAA,WAAW,UAAU,cAAc,MAAM,EAAE,KAC1C,KAAK,sBAAsB,OAAO,WAAW,IAAI;AAGlD,YAAA,OAAO,UAEb;AAAA,QAAS,UAAU;AAAA,QACf,MAAM;AAAA,QACN,KAAK;AAAA,QACL;AAAA,QACA,MAAM;AAAA,MAAA;AAAA,IAEd;AAEK,SAAA,SAAS,OAAO,eAAe,MAAM,QAAQ,UAAU,sBAAsB,IAAI,CAAC;AAAA,EAC3F;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUU,sBAAsB,OAAqB,WAAsB,MAC3E;AACU,UAAA,EAAE,GAAG,IAAI,KAAK;AAEpB,SAAK,SAAS,OAAO,KAAK,MAAM,MAAM;AAGtC,UAAM,oBAAoB,KAAK,GAAG,qBAAqB,UAAU,SAAS,IAAI;AAE9E,cAAU,sBAAsB,IAAI,IAAI,KAAK,OAAO,kBAEpD,GAAG,oBAAoB,UAAU,SAAS,mBAAmB,KAAK,OAAO,gBAAgB,GAEzF,KAAK,OAAO;AAEN,UAAA,KAAK,KAAK,aAAa,OAAO,KAAK,OAAO,QAAQ,aAAa,KAAK;AAEtE,QAAA,UAAU,KAAK,UAAU,EAAE;AAO/B,QALK,YAED,UAAU,KAAK,UAAU,EAAE,IAAI,0BAA0B,OAAO,KAAK,OAAO,QAAQ,WAAW,IAG/F,MAAM,YACV;AACI,YAAM,OAAO,IAAI,aAAa,QAAQ,OAAO,CAAC;AAExC,YAAA,OAAO,OAAO,IAAI;AAAA,IAC5B;AAEU,WAAA,UAAA,cAAc,MAAM,EAAE,IAAI,QAAQ,UAErC,UAAU,cAAc,MAAM,EAAE;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,aAAa,OAA8B,aAAwB,QAC3E;AACI,UAAM,WAAW,MAAM,UAEjB,UAAU,CAAC,GAAG,MAAM,GAAG;AAE7B,eAAW,KAAK;AAEJ,cAAA,KAAK,CAAC,GAEV,YAAY,CAAC,KAEb,QAAQ,KAAK,YAAY,CAAC,EAAE,IAAI;AAIjC,WAAA,QAAQ,KAAK,GAAG;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eACA;AACQ,WAAA,KAAK,SAEE,KAAK,OAAO,QAAQ,WAAW,KAAK,SAAS,WAAW,IAG5D;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAgB,QAChB;AACU,UAAA,KAAK,KAAK,IACV,UAAU,OAAO,SAEjB,YAAY,gBAAgB,IAAI,OAAO;AAE7C,WAAA,QAAQ,WAAW,KAAK,SAAS,WAAW,IAAI,WAEzC;AAAA,EACX;AAAA;AAAA,EAGA,QACA;AACS,SAAA,UAAU,MACf,KAAK,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAc,QACd;AACQ,SAAK,WAAW,WAEhB,KAAK,SAAS;AAAA,EAEtB;AAAA;AAAA,EAGA,UACA;AACS,SAAA,WAAW,MAEhB,KAAK,YAAY;AAAA,EACrB;AACJ;AA5Ta,aAGF,YAA+B;AAAA,EAClC,MAAM,cAAc;AAAA,EACpB,MAAM;AACV;AAwTJ,WAAW,IAAI,YAAY;"}