149 lines
5.5 KiB
JavaScript
149 lines
5.5 KiB
JavaScript
'use strict';
|
|
|
|
var Extensions = require('../../../../extensions/Extensions.js');
|
|
var maxRecommendedTextures = require('../../../batcher/gl/utils/maxRecommendedTextures.js');
|
|
var GenerateShaderSyncCode = require('./GenerateShaderSyncCode.js');
|
|
var generateProgram = require('./program/generateProgram.js');
|
|
|
|
"use strict";
|
|
const defaultSyncData = {
|
|
textureCount: 0,
|
|
blockIndex: 0
|
|
};
|
|
class GlShaderSystem {
|
|
constructor(renderer) {
|
|
/**
|
|
* @internal
|
|
* @private
|
|
*/
|
|
this._activeProgram = null;
|
|
this._programDataHash = /* @__PURE__ */ Object.create(null);
|
|
this._nextIndex = 0;
|
|
this._boundUniformsIdsToIndexHash = /* @__PURE__ */ Object.create(null);
|
|
this._boundIndexToUniformsHash = /* @__PURE__ */ Object.create(null);
|
|
this._shaderSyncFunctions = /* @__PURE__ */ Object.create(null);
|
|
this._renderer = renderer;
|
|
}
|
|
contextChange(gl) {
|
|
this._gl = gl;
|
|
this._maxBindings = gl.MAX_UNIFORM_BUFFER_BINDINGS ? gl.getParameter(gl.MAX_UNIFORM_BUFFER_BINDINGS) : 0;
|
|
this._programDataHash = /* @__PURE__ */ Object.create(null);
|
|
this._boundUniformsIdsToIndexHash = /* @__PURE__ */ Object.create(null);
|
|
this._boundIndexToUniformsHash = /* @__PURE__ */ Object.create(null);
|
|
this._shaderSyncFunctions = /* @__PURE__ */ Object.create(null);
|
|
this._activeProgram = null;
|
|
this.maxTextures = maxRecommendedTextures.getMaxTexturesPerBatch();
|
|
}
|
|
/**
|
|
* Changes the current shader to the one given in parameter.
|
|
* @param shader - the new shader
|
|
* @param skipSync - false if the shader should automatically sync its uniforms.
|
|
* @returns the glProgram that belongs to the shader.
|
|
*/
|
|
bind(shader, skipSync) {
|
|
this._setProgram(shader.glProgram);
|
|
if (skipSync)
|
|
return;
|
|
defaultSyncData.textureCount = 0;
|
|
defaultSyncData.blockIndex = 0;
|
|
let syncFunction = this._shaderSyncFunctions[shader.glProgram._key];
|
|
if (!syncFunction) {
|
|
syncFunction = this._shaderSyncFunctions[shader.glProgram._key] = this._generateShaderSync(shader, this);
|
|
}
|
|
syncFunction(this._renderer, shader, defaultSyncData);
|
|
}
|
|
/**
|
|
* Updates the uniform group.
|
|
* @param uniformGroup - the uniform group to update
|
|
*/
|
|
updateUniformGroup(uniformGroup) {
|
|
this._renderer.uniformGroup.updateUniformGroup(uniformGroup, this._activeProgram, defaultSyncData);
|
|
}
|
|
/**
|
|
* Binds a uniform block to the shader.
|
|
* @param uniformGroup - the uniform group to bind
|
|
* @param name - the name of the uniform block
|
|
* @param index - the index of the uniform block
|
|
*/
|
|
bindUniformBlock(uniformGroup, name, index = 0) {
|
|
const bufferSystem = this._renderer.buffer;
|
|
const programData = this._getProgramData(this._activeProgram);
|
|
const isBufferResource = uniformGroup._bufferResource;
|
|
if (isBufferResource) {
|
|
this._renderer.ubo.updateUniformGroup(uniformGroup);
|
|
}
|
|
bufferSystem.updateBuffer(uniformGroup.buffer);
|
|
let boundIndex = this._boundUniformsIdsToIndexHash[uniformGroup.uid];
|
|
if (boundIndex === void 0) {
|
|
const nextIndex = this._nextIndex++ % this._maxBindings;
|
|
const currentBoundUniformGroup = this._boundIndexToUniformsHash[nextIndex];
|
|
if (currentBoundUniformGroup) {
|
|
this._boundUniformsIdsToIndexHash[currentBoundUniformGroup.uid] = void 0;
|
|
}
|
|
boundIndex = this._boundUniformsIdsToIndexHash[uniformGroup.uid] = nextIndex;
|
|
this._boundIndexToUniformsHash[nextIndex] = uniformGroup;
|
|
if (isBufferResource) {
|
|
bufferSystem.bindBufferRange(uniformGroup.buffer, nextIndex, uniformGroup.offset);
|
|
} else {
|
|
bufferSystem.bindBufferBase(uniformGroup.buffer, nextIndex);
|
|
}
|
|
}
|
|
const gl = this._gl;
|
|
const uniformBlockIndex = this._activeProgram._uniformBlockData[name].index;
|
|
if (programData.uniformBlockBindings[index] === boundIndex)
|
|
return;
|
|
programData.uniformBlockBindings[index] = boundIndex;
|
|
gl.uniformBlockBinding(programData.program, uniformBlockIndex, boundIndex);
|
|
}
|
|
_setProgram(program) {
|
|
if (this._activeProgram === program)
|
|
return;
|
|
this._activeProgram = program;
|
|
const programData = this._getProgramData(program);
|
|
this._gl.useProgram(programData.program);
|
|
}
|
|
/**
|
|
* @param program - the program to get the data for
|
|
* @internal
|
|
* @private
|
|
*/
|
|
_getProgramData(program) {
|
|
return this._programDataHash[program._key] || this._createProgramData(program);
|
|
}
|
|
_createProgramData(program) {
|
|
const key = program._key;
|
|
this._programDataHash[key] = generateProgram.generateProgram(this._gl, program);
|
|
return this._programDataHash[key];
|
|
}
|
|
destroy() {
|
|
for (const key of Object.keys(this._programDataHash)) {
|
|
const programData = this._programDataHash[key];
|
|
programData.destroy();
|
|
this._programDataHash[key] = null;
|
|
}
|
|
this._programDataHash = null;
|
|
this._boundUniformsIdsToIndexHash = null;
|
|
}
|
|
/**
|
|
* Creates a function that can be executed that will sync the shader as efficiently as possible.
|
|
* Overridden by the unsafe eval package if you don't want eval used in your project.
|
|
* @param shader - the shader to generate the sync function for
|
|
* @param shaderSystem - the shader system to use
|
|
* @returns - the generated sync function
|
|
* @ignore
|
|
*/
|
|
_generateShaderSync(shader, shaderSystem) {
|
|
return GenerateShaderSyncCode.generateShaderSyncCode(shader, shaderSystem);
|
|
}
|
|
}
|
|
/** @ignore */
|
|
GlShaderSystem.extension = {
|
|
type: [
|
|
Extensions.ExtensionType.WebGLSystem
|
|
],
|
|
name: "shader"
|
|
};
|
|
|
|
exports.GlShaderSystem = GlShaderSystem;
|
|
//# sourceMappingURL=GlShaderSystem.js.map
|