254 lines
9.1 KiB
JavaScript
254 lines
9.1 KiB
JavaScript
define([
|
|
'../Core/defined',
|
|
'../Core/defineProperties',
|
|
'../Core/destroyObject',
|
|
'./ShaderProgram',
|
|
'./ShaderSource'
|
|
], function(
|
|
defined,
|
|
defineProperties,
|
|
destroyObject,
|
|
ShaderProgram,
|
|
ShaderSource) {
|
|
'use strict';
|
|
|
|
/**
|
|
* @private
|
|
*/
|
|
function ShaderCache(context) {
|
|
this._context = context;
|
|
this._shaders = {};
|
|
this._numberOfShaders = 0;
|
|
this._shadersToRelease = {};
|
|
}
|
|
|
|
defineProperties(ShaderCache.prototype, {
|
|
numberOfShaders : {
|
|
get : function() {
|
|
return this._numberOfShaders;
|
|
}
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Returns a shader program from the cache, or creates and caches a new shader program,
|
|
* given the GLSL vertex and fragment shader source and attribute locations.
|
|
* <p>
|
|
* The difference between this and {@link ShaderCache#getShaderProgram}, is this is used to
|
|
* replace an existing reference to a shader program, which is passed as the first argument.
|
|
* </p>
|
|
*
|
|
* @param {Object} options Object with the following properties:
|
|
* @param {ShaderProgram} [options.shaderProgram] The shader program that is being reassigned.
|
|
* @param {String|ShaderSource} options.vertexShaderSource The GLSL source for the vertex shader.
|
|
* @param {String|ShaderSource} options.fragmentShaderSource The GLSL source for the fragment shader.
|
|
* @param {Object} options.attributeLocations Indices for the attribute inputs to the vertex shader.
|
|
|
|
* @returns {ShaderProgram} The cached or newly created shader program.
|
|
*
|
|
*
|
|
* @example
|
|
* this._shaderProgram = context.shaderCache.replaceShaderProgram({
|
|
* shaderProgram : this._shaderProgram,
|
|
* vertexShaderSource : vs,
|
|
* fragmentShaderSource : fs,
|
|
* attributeLocations : attributeLocations
|
|
* });
|
|
*
|
|
* @see ShaderCache#getShaderProgram
|
|
*/
|
|
ShaderCache.prototype.replaceShaderProgram = function(options) {
|
|
if (defined(options.shaderProgram)) {
|
|
options.shaderProgram.destroy();
|
|
}
|
|
|
|
return this.getShaderProgram(options);
|
|
};
|
|
|
|
/**
|
|
* Returns a shader program from the cache, or creates and caches a new shader program,
|
|
* given the GLSL vertex and fragment shader source and attribute locations.
|
|
*
|
|
* @param {Object} options Object with the following properties:
|
|
* @param {String|ShaderSource} options.vertexShaderSource The GLSL source for the vertex shader.
|
|
* @param {String|ShaderSource} options.fragmentShaderSource The GLSL source for the fragment shader.
|
|
* @param {Object} options.attributeLocations Indices for the attribute inputs to the vertex shader.
|
|
*
|
|
* @returns {ShaderProgram} The cached or newly created shader program.
|
|
*/
|
|
ShaderCache.prototype.getShaderProgram = function(options) {
|
|
// convert shaders which are provided as strings into ShaderSource objects
|
|
// because ShaderSource handles all the automatic including of built-in functions, etc.
|
|
|
|
var vertexShaderSource = options.vertexShaderSource;
|
|
var fragmentShaderSource = options.fragmentShaderSource;
|
|
var attributeLocations = options.attributeLocations;
|
|
|
|
if (typeof vertexShaderSource === 'string') {
|
|
vertexShaderSource = new ShaderSource({
|
|
sources : [vertexShaderSource]
|
|
});
|
|
}
|
|
|
|
if (typeof fragmentShaderSource === 'string') {
|
|
fragmentShaderSource = new ShaderSource({
|
|
sources : [fragmentShaderSource]
|
|
});
|
|
}
|
|
|
|
var vertexShaderText = vertexShaderSource.createCombinedVertexShader(this._context);
|
|
var fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader(this._context);
|
|
|
|
var keyword = vertexShaderText + fragmentShaderText + JSON.stringify(attributeLocations);
|
|
var cachedShader;
|
|
|
|
if (defined(this._shaders[keyword])) {
|
|
cachedShader = this._shaders[keyword];
|
|
|
|
// No longer want to release this if it was previously released.
|
|
delete this._shadersToRelease[keyword];
|
|
} else {
|
|
var context = this._context;
|
|
var shaderProgram = new ShaderProgram({
|
|
gl : context._gl,
|
|
logShaderCompilation : context.logShaderCompilation,
|
|
debugShaders : context.debugShaders,
|
|
vertexShaderSource : vertexShaderSource,
|
|
vertexShaderText : vertexShaderText,
|
|
fragmentShaderSource : fragmentShaderSource,
|
|
fragmentShaderText : fragmentShaderText,
|
|
attributeLocations : attributeLocations
|
|
});
|
|
|
|
cachedShader = {
|
|
cache : this,
|
|
shaderProgram : shaderProgram,
|
|
keyword : keyword,
|
|
derivedKeywords : [],
|
|
count : 0
|
|
};
|
|
|
|
// A shader can't be in more than one cache.
|
|
shaderProgram._cachedShader = cachedShader;
|
|
this._shaders[keyword] = cachedShader;
|
|
++this._numberOfShaders;
|
|
}
|
|
|
|
++cachedShader.count;
|
|
return cachedShader.shaderProgram;
|
|
};
|
|
|
|
ShaderCache.prototype.getDerivedShaderProgram = function(shaderProgram, keyword) {
|
|
var cachedShader = shaderProgram._cachedShader;
|
|
var derivedKeyword = keyword + cachedShader.keyword;
|
|
var cachedDerivedShader = this._shaders[derivedKeyword];
|
|
if (!defined(cachedDerivedShader)) {
|
|
return undefined;
|
|
}
|
|
|
|
return cachedDerivedShader.shaderProgram;
|
|
};
|
|
|
|
ShaderCache.prototype.createDerivedShaderProgram = function(shaderProgram, keyword, options) {
|
|
var cachedShader = shaderProgram._cachedShader;
|
|
var derivedKeyword = keyword + cachedShader.keyword;
|
|
|
|
var vertexShaderSource = options.vertexShaderSource;
|
|
var fragmentShaderSource = options.fragmentShaderSource;
|
|
var attributeLocations = options.attributeLocations;
|
|
|
|
if (typeof vertexShaderSource === 'string') {
|
|
vertexShaderSource = new ShaderSource({
|
|
sources : [vertexShaderSource]
|
|
});
|
|
}
|
|
|
|
if (typeof fragmentShaderSource === 'string') {
|
|
fragmentShaderSource = new ShaderSource({
|
|
sources : [fragmentShaderSource]
|
|
});
|
|
}
|
|
|
|
var context = this._context;
|
|
|
|
var vertexShaderText = vertexShaderSource.createCombinedVertexShader(context);
|
|
var fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader(context);
|
|
|
|
var derivedShaderProgram = new ShaderProgram({
|
|
gl : context._gl,
|
|
logShaderCompilation : context.logShaderCompilation,
|
|
debugShaders : context.debugShaders,
|
|
vertexShaderSource : vertexShaderSource,
|
|
vertexShaderText : vertexShaderText,
|
|
fragmentShaderSource : fragmentShaderSource,
|
|
fragmentShaderText : fragmentShaderText,
|
|
attributeLocations : attributeLocations
|
|
});
|
|
|
|
var derivedCachedShader = {
|
|
cache : this,
|
|
shaderProgram : derivedShaderProgram,
|
|
keyword : derivedKeyword,
|
|
derivedKeywords : [],
|
|
count : 0
|
|
};
|
|
|
|
cachedShader.derivedKeywords.push(keyword);
|
|
derivedShaderProgram._cachedShader = derivedCachedShader;
|
|
this._shaders[derivedKeyword] = derivedCachedShader;
|
|
return derivedShaderProgram;
|
|
};
|
|
|
|
function destroyShader(cache, cachedShader) {
|
|
var derivedKeywords = cachedShader.derivedKeywords;
|
|
var length = derivedKeywords.length;
|
|
for (var i = 0; i < length; ++i) {
|
|
var keyword = derivedKeywords[i] + cachedShader.keyword;
|
|
var derivedCachedShader = cache._shaders[keyword];
|
|
destroyShader(cache, derivedCachedShader);
|
|
}
|
|
|
|
delete cache._shaders[cachedShader.keyword];
|
|
cachedShader.shaderProgram.finalDestroy();
|
|
}
|
|
|
|
ShaderCache.prototype.destroyReleasedShaderPrograms = function() {
|
|
var shadersToRelease = this._shadersToRelease;
|
|
|
|
for ( var keyword in shadersToRelease) {
|
|
if (shadersToRelease.hasOwnProperty(keyword)) {
|
|
var cachedShader = shadersToRelease[keyword];
|
|
destroyShader(this, cachedShader);
|
|
--this._numberOfShaders;
|
|
}
|
|
}
|
|
|
|
this._shadersToRelease = {};
|
|
};
|
|
|
|
ShaderCache.prototype.releaseShaderProgram = function(shaderProgram) {
|
|
if (defined(shaderProgram)) {
|
|
var cachedShader = shaderProgram._cachedShader;
|
|
if (cachedShader && (--cachedShader.count === 0)) {
|
|
this._shadersToRelease[cachedShader.keyword] = cachedShader;
|
|
}
|
|
}
|
|
};
|
|
|
|
ShaderCache.prototype.isDestroyed = function() {
|
|
return false;
|
|
};
|
|
|
|
ShaderCache.prototype.destroy = function() {
|
|
var shaders = this._shaders;
|
|
for (var keyword in shaders) {
|
|
if (shaders.hasOwnProperty(keyword)) {
|
|
shaders[keyword].shaderProgram.finalDestroy();
|
|
}
|
|
}
|
|
return destroyObject(this);
|
|
};
|
|
|
|
return ShaderCache;
|
|
});
|