123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- import defined from "../Core/defined.js";
- import destroyObject from "../Core/destroyObject.js";
- import ShaderProgram from "./ShaderProgram.js";
- import ShaderSource from "./ShaderSource.js";
- /**
- * @private
- */
- function ShaderCache(context) {
- this._context = context;
- this._shaders = {};
- this._numberOfShaders = 0;
- this._shadersToRelease = {};
- }
- Object.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.
- let vertexShaderSource = options.vertexShaderSource;
- let fragmentShaderSource = options.fragmentShaderSource;
- const attributeLocations = options.attributeLocations;
- if (typeof vertexShaderSource === "string") {
- vertexShaderSource = new ShaderSource({
- sources: [vertexShaderSource],
- });
- }
- if (typeof fragmentShaderSource === "string") {
- fragmentShaderSource = new ShaderSource({
- sources: [fragmentShaderSource],
- });
- }
- const vertexShaderText = vertexShaderSource.createCombinedVertexShader(
- this._context
- );
- const fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader(
- this._context
- );
- const keyword =
- vertexShaderText + fragmentShaderText + JSON.stringify(attributeLocations);
- let 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 {
- const context = this._context;
- const 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.replaceDerivedShaderProgram = function (
- shaderProgram,
- keyword,
- options
- ) {
- const cachedShader = shaderProgram._cachedShader;
- const derivedKeyword = keyword + cachedShader.keyword;
- const cachedDerivedShader = this._shaders[derivedKeyword];
- if (defined(cachedDerivedShader)) {
- destroyShader(this, cachedDerivedShader);
- const index = cachedShader.derivedKeywords.indexOf(keyword);
- if (index > -1) {
- cachedShader.derivedKeywords.splice(index, 1);
- }
- }
- return this.createDerivedShaderProgram(shaderProgram, keyword, options);
- };
- ShaderCache.prototype.getDerivedShaderProgram = function (
- shaderProgram,
- keyword
- ) {
- const cachedShader = shaderProgram._cachedShader;
- const derivedKeyword = keyword + cachedShader.keyword;
- const cachedDerivedShader = this._shaders[derivedKeyword];
- if (!defined(cachedDerivedShader)) {
- return undefined;
- }
- return cachedDerivedShader.shaderProgram;
- };
- ShaderCache.prototype.createDerivedShaderProgram = function (
- shaderProgram,
- keyword,
- options
- ) {
- const cachedShader = shaderProgram._cachedShader;
- const derivedKeyword = keyword + cachedShader.keyword;
- let vertexShaderSource = options.vertexShaderSource;
- let fragmentShaderSource = options.fragmentShaderSource;
- const attributeLocations = options.attributeLocations;
- if (typeof vertexShaderSource === "string") {
- vertexShaderSource = new ShaderSource({
- sources: [vertexShaderSource],
- });
- }
- if (typeof fragmentShaderSource === "string") {
- fragmentShaderSource = new ShaderSource({
- sources: [fragmentShaderSource],
- });
- }
- const context = this._context;
- const vertexShaderText = vertexShaderSource.createCombinedVertexShader(
- context
- );
- const fragmentShaderText = fragmentShaderSource.createCombinedFragmentShader(
- context
- );
- const derivedShaderProgram = new ShaderProgram({
- gl: context._gl,
- logShaderCompilation: context.logShaderCompilation,
- debugShaders: context.debugShaders,
- vertexShaderSource: vertexShaderSource,
- vertexShaderText: vertexShaderText,
- fragmentShaderSource: fragmentShaderSource,
- fragmentShaderText: fragmentShaderText,
- attributeLocations: attributeLocations,
- });
- const 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) {
- const derivedKeywords = cachedShader.derivedKeywords;
- const length = derivedKeywords.length;
- for (let i = 0; i < length; ++i) {
- const keyword = derivedKeywords[i] + cachedShader.keyword;
- const derivedCachedShader = cache._shaders[keyword];
- destroyShader(cache, derivedCachedShader);
- }
- delete cache._shaders[cachedShader.keyword];
- cachedShader.shaderProgram.finalDestroy();
- }
- ShaderCache.prototype.destroyReleasedShaderPrograms = function () {
- const shadersToRelease = this._shadersToRelease;
- for (const keyword in shadersToRelease) {
- if (shadersToRelease.hasOwnProperty(keyword)) {
- const cachedShader = shadersToRelease[keyword];
- destroyShader(this, cachedShader);
- --this._numberOfShaders;
- }
- }
- this._shadersToRelease = {};
- };
- ShaderCache.prototype.releaseShaderProgram = function (shaderProgram) {
- if (defined(shaderProgram)) {
- const cachedShader = shaderProgram._cachedShader;
- if (cachedShader && --cachedShader.count === 0) {
- this._shadersToRelease[cachedShader.keyword] = cachedShader;
- }
- }
- };
- ShaderCache.prototype.isDestroyed = function () {
- return false;
- };
- ShaderCache.prototype.destroy = function () {
- const shaders = this._shaders;
- for (const keyword in shaders) {
- if (shaders.hasOwnProperty(keyword)) {
- shaders[keyword].shaderProgram.finalDestroy();
- }
- }
- return destroyObject(this);
- };
- export default ShaderCache;
|