UNPKG

@pixi/core

Version:
163 lines (162 loc) 7.6 kB
"use strict"; var extensions = require("@pixi/extensions"); require("./utils/index.js"); var generateProgram = require("./utils/generateProgram.js"), generateUniformBufferSync = require("./utils/generateUniformBufferSync.js"), unsafeEvalSupported = require("./utils/unsafeEvalSupported.js"), generateUniformsSync = require("./utils/generateUniformsSync.js"); let UID = 0; const defaultSyncData = { textureCount: 0, uboCount: 0 }; class ShaderSystem { /** @param renderer - The renderer this System works for. */ constructor(renderer) { this.destroyed = !1, this.renderer = renderer, this.systemCheck(), this.gl = null, this.shader = null, this.program = null, this.cache = {}, this._uboCache = {}, this.id = UID++; } /** * Overrideable function by `@pixi/unsafe-eval` to silence * throwing an error if platform doesn't support unsafe-evals. * @private */ systemCheck() { if (!unsafeEvalSupported.unsafeEvalSupported()) throw new Error("Current environment does not allow unsafe-eval, please use @pixi/unsafe-eval module to enable support."); } contextChange(gl) { this.gl = gl, this.reset(); } /** * Changes the current shader to the one given in parameter. * @param shader - the new shader * @param dontSync - false if the shader should automatically sync its uniforms. * @returns the glProgram that belongs to the shader. */ bind(shader, dontSync) { shader.disposeRunner.add(this), shader.uniforms.globals = this.renderer.globalUniforms; const program = shader.program, glProgram = program.glPrograms[this.renderer.CONTEXT_UID] || this.generateProgram(shader); return this.shader = shader, this.program !== program && (this.program = program, this.gl.useProgram(glProgram.program)), dontSync || (defaultSyncData.textureCount = 0, defaultSyncData.uboCount = 0, this.syncUniformGroup(shader.uniformGroup, defaultSyncData)), glProgram; } /** * Uploads the uniforms values to the currently bound shader. * @param uniforms - the uniforms values that be applied to the current shader */ setUniforms(uniforms) { const shader = this.shader.program, glProgram = shader.glPrograms[this.renderer.CONTEXT_UID]; shader.syncUniforms(glProgram.uniformData, uniforms, this.renderer); } /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ /** * Syncs uniforms on the group * @param group - the uniform group to sync * @param syncData - this is data that is passed to the sync function and any nested sync functions */ syncUniformGroup(group, syncData) { const glProgram = this.getGlProgram(); (!group.static || group.dirtyId !== glProgram.uniformDirtyGroups[group.id]) && (glProgram.uniformDirtyGroups[group.id] = group.dirtyId, this.syncUniforms(group, glProgram, syncData)); } /** * Overrideable by the @pixi/unsafe-eval package to use static syncUniforms instead. * @param group * @param glProgram * @param syncData */ syncUniforms(group, glProgram, syncData) { (group.syncUniforms[this.shader.program.id] || this.createSyncGroups(group))(glProgram.uniformData, group.uniforms, this.renderer, syncData); } createSyncGroups(group) { const id = this.getSignature(group, this.shader.program.uniformData, "u"); return this.cache[id] || (this.cache[id] = generateUniformsSync.generateUniformsSync(group, this.shader.program.uniformData)), group.syncUniforms[this.shader.program.id] = this.cache[id], group.syncUniforms[this.shader.program.id]; } /** * Syncs uniform buffers * @param group - the uniform buffer group to sync * @param name - the name of the uniform buffer */ syncUniformBufferGroup(group, name) { const glProgram = this.getGlProgram(); if (!group.static || group.dirtyId !== 0 || !glProgram.uniformGroups[group.id]) { group.dirtyId = 0; const syncFunc = glProgram.uniformGroups[group.id] || this.createSyncBufferGroup(group, glProgram, name); group.buffer.update(), syncFunc( glProgram.uniformData, group.uniforms, this.renderer, defaultSyncData, group.buffer ); } this.renderer.buffer.bindBufferBase(group.buffer, glProgram.uniformBufferBindings[name]); } /** * Will create a function that uploads a uniform buffer using the STD140 standard. * The upload function will then be cached for future calls * If a group is manually managed, then a simple upload function is generated * @param group - the uniform buffer group to sync * @param glProgram - the gl program to attach the uniform bindings to * @param name - the name of the uniform buffer (must exist on the shader) */ createSyncBufferGroup(group, glProgram, name) { const { gl } = this.renderer; this.renderer.buffer.bind(group.buffer); const uniformBlockIndex = this.gl.getUniformBlockIndex(glProgram.program, name); glProgram.uniformBufferBindings[name] = this.shader.uniformBindCount, gl.uniformBlockBinding(glProgram.program, uniformBlockIndex, this.shader.uniformBindCount), this.shader.uniformBindCount++; const id = this.getSignature(group, this.shader.program.uniformData, "ubo"); let uboData = this._uboCache[id]; if (uboData || (uboData = this._uboCache[id] = generateUniformBufferSync.generateUniformBufferSync(group, this.shader.program.uniformData)), group.autoManage) { const data = new Float32Array(uboData.size / 4); group.buffer.update(data); } return glProgram.uniformGroups[group.id] = uboData.syncFunc, glProgram.uniformGroups[group.id]; } /** * Takes a uniform group and data and generates a unique signature for them. * @param group - The uniform group to get signature of * @param group.uniforms * @param uniformData - Uniform information generated by the shader * @param preFix * @returns Unique signature of the uniform group */ getSignature(group, uniformData, preFix) { const uniforms = group.uniforms, strings = [`${preFix}-`]; for (const i in uniforms) strings.push(i), uniformData[i] && strings.push(uniformData[i].type); return strings.join("-"); } /** * Returns the underlying GLShade rof the currently bound shader. * * This can be handy for when you to have a little more control over the setting of your uniforms. * @returns The glProgram for the currently bound Shader for this context */ getGlProgram() { return this.shader ? this.shader.program.glPrograms[this.renderer.CONTEXT_UID] : null; } /** * Generates a glProgram version of the Shader provided. * @param shader - The shader that the glProgram will be based on. * @returns A shiny new glProgram! */ generateProgram(shader) { const gl = this.gl, program = shader.program, glProgram = generateProgram.generateProgram(gl, program); return program.glPrograms[this.renderer.CONTEXT_UID] = glProgram, glProgram; } /** Resets ShaderSystem state, does not affect WebGL state. */ reset() { this.program = null, this.shader = null; } /** * Disposes shader. * If disposing one equals with current shader, set current as null. * @param shader - Shader object */ disposeShader(shader) { this.shader === shader && (this.shader = null); } /** Destroys this System and removes all its textures. */ destroy() { this.renderer = null, this.destroyed = !0; } } ShaderSystem.extension = { type: extensions.ExtensionType.RendererSystem, name: "shader" }; extensions.extensions.add(ShaderSystem); exports.ShaderSystem = ShaderSystem; //# sourceMappingURL=ShaderSystem.js.map