UNPKG

@pixi/core

Version:
147 lines (144 loc) 5.17 kB
import { ExtensionType, extensions } from '@pixi/extensions'; import './utils/index.mjs'; import { generateProgram } from './utils/generateProgram.mjs'; import { generateUniformBufferSync } from './utils/generateUniformBufferSync.mjs'; import { unsafeEvalSupported } from './utils/unsafeEvalSupported.mjs'; import { generateUniformsSync } from './utils/generateUniformsSync.mjs'; let UID = 0; const defaultSyncData = { textureCount: 0, uboCount: 0 }; class ShaderSystem { constructor(renderer) { this.destroyed = false; this.renderer = renderer; this.systemCheck(); this.gl = null; this.shader = null; this.program = null; this.cache = {}; this._uboCache = {}; this.id = UID++; } systemCheck() { if (!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(); } bind(shader, dontSync) { shader.disposeRunner.add(this); shader.uniforms.globals = this.renderer.globalUniforms; const program = shader.program; const glProgram = program.glPrograms[this.renderer.CONTEXT_UID] || this.generateProgram(shader); this.shader = shader; if (this.program !== program) { this.program = program; this.gl.useProgram(glProgram.program); } if (!dontSync) { defaultSyncData.textureCount = 0; defaultSyncData.uboCount = 0; this.syncUniformGroup(shader.uniformGroup, defaultSyncData); } return glProgram; } setUniforms(uniforms) { const shader = this.shader.program; const glProgram = shader.glPrograms[this.renderer.CONTEXT_UID]; shader.syncUniforms(glProgram.uniformData, uniforms, this.renderer); } syncUniformGroup(group, syncData) { const glProgram = this.getGlProgram(); if (!group.static || group.dirtyId !== glProgram.uniformDirtyGroups[group.id]) { glProgram.uniformDirtyGroups[group.id] = group.dirtyId; this.syncUniforms(group, glProgram, syncData); } } syncUniforms(group, glProgram, syncData) { const syncFunc = group.syncUniforms[this.shader.program.id] || this.createSyncGroups(group); syncFunc(glProgram.uniformData, group.uniforms, this.renderer, syncData); } createSyncGroups(group) { const id = this.getSignature(group, this.shader.program.uniformData, "u"); if (!this.cache[id]) { this.cache[id] = generateUniformsSync(group, this.shader.program.uniformData); } group.syncUniforms[this.shader.program.id] = this.cache[id]; return group.syncUniforms[this.shader.program.id]; } 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]); } 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(group, this.shader.program.uniformData); } if (group.autoManage) { const data = new Float32Array(uboData.size / 4); group.buffer.update(data); } glProgram.uniformGroups[group.id] = uboData.syncFunc; return glProgram.uniformGroups[group.id]; } getSignature(group, uniformData, preFix) { const uniforms = group.uniforms; const strings = [`${preFix}-`]; for (const i in uniforms) { strings.push(i); if (uniformData[i]) { strings.push(uniformData[i].type); } } return strings.join("-"); } getGlProgram() { if (this.shader) { return this.shader.program.glPrograms[this.renderer.CONTEXT_UID]; } return null; } generateProgram(shader) { const gl = this.gl; const program = shader.program; const glProgram = generateProgram(gl, program); program.glPrograms[this.renderer.CONTEXT_UID] = glProgram; return glProgram; } reset() { this.program = null; this.shader = null; } disposeShader(shader) { if (this.shader === shader) { this.shader = null; } } destroy() { this.renderer = null; this.destroyed = true; } } ShaderSystem.extension = { type: ExtensionType.RendererSystem, name: "shader" }; extensions.add(ShaderSystem); export { ShaderSystem }; //# sourceMappingURL=ShaderSystem.mjs.map