智慧水务管理系统 - 精河县供水工程综合管理平台

ShaderCache.js 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. import defined from "../Core/defined.js";
  2. import destroyObject from "../Core/destroyObject.js";
  3. import ShaderProgram from "./ShaderProgram.js";
  4. import ShaderSource from "./ShaderSource.js";
  5. /**
  6. * @private
  7. */
  8. function ShaderCache(context) {
  9. this._context = context;
  10. this._shaders = {};
  11. this._numberOfShaders = 0;
  12. this._shadersToRelease = {};
  13. }
  14. Object.defineProperties(ShaderCache.prototype, {
  15. numberOfShaders: {
  16. get: function () {
  17. return this._numberOfShaders;
  18. },
  19. },
  20. });
  21. /**
  22. * Returns a shader program from the cache, or creates and caches a new shader program,
  23. * given the GLSL vertex and fragment shader source and attribute locations.
  24. * <p>
  25. * The difference between this and {@link ShaderCache#getShaderProgram}, is this is used to
  26. * replace an existing reference to a shader program, which is passed as the first argument.
  27. * </p>
  28. *
  29. * @param {object} options Object with the following properties:
  30. * @param {ShaderProgram} [options.shaderProgram] The shader program that is being reassigned.
  31. * @param {string|ShaderSource} options.vertexShaderSource The GLSL source for the vertex shader.
  32. * @param {string|ShaderSource} options.fragmentShaderSource The GLSL source for the fragment shader.
  33. * @param {object} options.attributeLocations Indices for the attribute inputs to the vertex shader.
  34. * @returns {ShaderProgram} The cached or newly created shader program.
  35. *
  36. *
  37. * @example
  38. * this._shaderProgram = context.shaderCache.replaceShaderProgram({
  39. * shaderProgram : this._shaderProgram,
  40. * vertexShaderSource : vs,
  41. * fragmentShaderSource : fs,
  42. * attributeLocations : attributeLocations
  43. * });
  44. *
  45. * @see ShaderCache#getShaderProgram
  46. */
  47. ShaderCache.prototype.replaceShaderProgram = function (options) {
  48. if (defined(options.shaderProgram)) {
  49. options.shaderProgram.destroy();
  50. }
  51. return this.getShaderProgram(options);
  52. };
  53. function toSortedJson(dictionary) {
  54. const sortedKeys = Object.keys(dictionary).sort();
  55. return JSON.stringify(dictionary, sortedKeys);
  56. }
  57. /**
  58. * Returns a shader program from the cache, or creates and caches a new shader program,
  59. * given the GLSL vertex and fragment shader source and attribute locations.
  60. *
  61. * @param {object} options Object with the following properties:
  62. * @param {string|ShaderSource} options.vertexShaderSource The GLSL source for the vertex shader.
  63. * @param {string|ShaderSource} options.fragmentShaderSource The GLSL source for the fragment shader.
  64. * @param {object} options.attributeLocations Indices for the attribute inputs to the vertex shader.
  65. *
  66. * @returns {ShaderProgram} The cached or newly created shader program.
  67. */
  68. ShaderCache.prototype.getShaderProgram = function (options) {
  69. // convert shaders which are provided as strings into ShaderSource objects
  70. // because ShaderSource handles all the automatic including of built-in functions, etc.
  71. let vertexShaderSource = options.vertexShaderSource;
  72. let fragmentShaderSource = options.fragmentShaderSource;
  73. const attributeLocations = options.attributeLocations;
  74. if (typeof vertexShaderSource === "string") {
  75. vertexShaderSource = new ShaderSource({
  76. sources: [vertexShaderSource],
  77. });
  78. }
  79. if (typeof fragmentShaderSource === "string") {
  80. fragmentShaderSource = new ShaderSource({
  81. sources: [fragmentShaderSource],
  82. });
  83. }
  84. // Since ShaderSource.createCombinedXxxShader() can be expensive, use a
  85. // simpler key for caching. This way, the function does not have to be called
  86. // for each cache lookup.
  87. const vertexShaderKey = vertexShaderSource.getCacheKey();
  88. const fragmentShaderKey = fragmentShaderSource.getCacheKey();
  89. // Sort the keys in the JSON to ensure a consistent order
  90. const attributeLocationKey = defined(attributeLocations)
  91. ? toSortedJson(attributeLocations)
  92. : "";
  93. const keyword = `${vertexShaderKey}:${fragmentShaderKey}:${attributeLocationKey}`;
  94. let cachedShader;
  95. if (defined(this._shaders[keyword])) {
  96. cachedShader = this._shaders[keyword];
  97. // No longer want to release this if it was previously released.
  98. delete this._shadersToRelease[keyword];
  99. } else {
  100. const context = this._context;
  101. const vertexShaderText =
  102. vertexShaderSource.createCombinedVertexShader(context);
  103. const fragmentShaderText =
  104. fragmentShaderSource.createCombinedFragmentShader(context);
  105. const shaderProgram = new ShaderProgram({
  106. gl: context._gl,
  107. logShaderCompilation: context.logShaderCompilation,
  108. debugShaders: context.debugShaders,
  109. vertexShaderSource: vertexShaderSource,
  110. vertexShaderText: vertexShaderText,
  111. fragmentShaderSource: fragmentShaderSource,
  112. fragmentShaderText: fragmentShaderText,
  113. attributeLocations: attributeLocations,
  114. });
  115. cachedShader = {
  116. cache: this,
  117. shaderProgram: shaderProgram,
  118. keyword: keyword,
  119. derivedKeywords: [],
  120. count: 0,
  121. };
  122. // A shader can't be in more than one cache.
  123. shaderProgram._cachedShader = cachedShader;
  124. this._shaders[keyword] = cachedShader;
  125. ++this._numberOfShaders;
  126. }
  127. ++cachedShader.count;
  128. return cachedShader.shaderProgram;
  129. };
  130. ShaderCache.prototype.replaceDerivedShaderProgram = function (
  131. shaderProgram,
  132. keyword,
  133. options,
  134. ) {
  135. const cachedShader = shaderProgram._cachedShader;
  136. const derivedKeyword = keyword + cachedShader.keyword;
  137. const cachedDerivedShader = this._shaders[derivedKeyword];
  138. if (defined(cachedDerivedShader)) {
  139. destroyShader(this, cachedDerivedShader);
  140. const index = cachedShader.derivedKeywords.indexOf(keyword);
  141. if (index > -1) {
  142. cachedShader.derivedKeywords.splice(index, 1);
  143. }
  144. }
  145. return this.createDerivedShaderProgram(shaderProgram, keyword, options);
  146. };
  147. ShaderCache.prototype.getDerivedShaderProgram = function (
  148. shaderProgram,
  149. keyword,
  150. ) {
  151. const cachedShader = shaderProgram._cachedShader;
  152. const derivedKeyword = keyword + cachedShader.keyword;
  153. const cachedDerivedShader = this._shaders[derivedKeyword];
  154. if (!defined(cachedDerivedShader)) {
  155. return undefined;
  156. }
  157. return cachedDerivedShader.shaderProgram;
  158. };
  159. ShaderCache.prototype.createDerivedShaderProgram = function (
  160. shaderProgram,
  161. keyword,
  162. options,
  163. ) {
  164. const cachedShader = shaderProgram._cachedShader;
  165. const derivedKeyword = keyword + cachedShader.keyword;
  166. let vertexShaderSource = options.vertexShaderSource;
  167. let fragmentShaderSource = options.fragmentShaderSource;
  168. const attributeLocations = options.attributeLocations;
  169. if (typeof vertexShaderSource === "string") {
  170. vertexShaderSource = new ShaderSource({
  171. sources: [vertexShaderSource],
  172. });
  173. }
  174. if (typeof fragmentShaderSource === "string") {
  175. fragmentShaderSource = new ShaderSource({
  176. sources: [fragmentShaderSource],
  177. });
  178. }
  179. const context = this._context;
  180. const vertexShaderText =
  181. vertexShaderSource.createCombinedVertexShader(context);
  182. const fragmentShaderText =
  183. fragmentShaderSource.createCombinedFragmentShader(context);
  184. const derivedShaderProgram = new ShaderProgram({
  185. gl: context._gl,
  186. logShaderCompilation: context.logShaderCompilation,
  187. debugShaders: context.debugShaders,
  188. vertexShaderSource: vertexShaderSource,
  189. vertexShaderText: vertexShaderText,
  190. fragmentShaderSource: fragmentShaderSource,
  191. fragmentShaderText: fragmentShaderText,
  192. attributeLocations: attributeLocations,
  193. });
  194. const derivedCachedShader = {
  195. cache: this,
  196. shaderProgram: derivedShaderProgram,
  197. keyword: derivedKeyword,
  198. derivedKeywords: [],
  199. count: 0,
  200. };
  201. cachedShader.derivedKeywords.push(keyword);
  202. derivedShaderProgram._cachedShader = derivedCachedShader;
  203. this._shaders[derivedKeyword] = derivedCachedShader;
  204. return derivedShaderProgram;
  205. };
  206. function destroyShader(cache, cachedShader) {
  207. const derivedKeywords = cachedShader.derivedKeywords;
  208. const length = derivedKeywords.length;
  209. for (let i = 0; i < length; ++i) {
  210. const keyword = derivedKeywords[i] + cachedShader.keyword;
  211. const derivedCachedShader = cache._shaders[keyword];
  212. destroyShader(cache, derivedCachedShader);
  213. }
  214. delete cache._shaders[cachedShader.keyword];
  215. cachedShader.shaderProgram.finalDestroy();
  216. }
  217. ShaderCache.prototype.destroyReleasedShaderPrograms = function () {
  218. const shadersToRelease = this._shadersToRelease;
  219. for (const keyword in shadersToRelease) {
  220. if (shadersToRelease.hasOwnProperty(keyword)) {
  221. const cachedShader = shadersToRelease[keyword];
  222. destroyShader(this, cachedShader);
  223. --this._numberOfShaders;
  224. }
  225. }
  226. this._shadersToRelease = {};
  227. };
  228. ShaderCache.prototype.releaseShaderProgram = function (shaderProgram) {
  229. if (defined(shaderProgram)) {
  230. const cachedShader = shaderProgram._cachedShader;
  231. if (cachedShader && --cachedShader.count === 0) {
  232. this._shadersToRelease[cachedShader.keyword] = cachedShader;
  233. }
  234. }
  235. };
  236. ShaderCache.prototype.isDestroyed = function () {
  237. return false;
  238. };
  239. ShaderCache.prototype.destroy = function () {
  240. const shaders = this._shaders;
  241. for (const keyword in shaders) {
  242. if (shaders.hasOwnProperty(keyword)) {
  243. shaders[keyword].shaderProgram.finalDestroy();
  244. }
  245. }
  246. return destroyObject(this);
  247. };
  248. export default ShaderCache;