webgl-debug.js 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195
  1. /*
  2. ** Copyright (c) 2012 The Khronos Group Inc.
  3. **
  4. ** Permission is hereby granted, free of charge, to any person obtaining a
  5. ** copy of this software and/or associated documentation files (the
  6. ** "Materials"), to deal in the Materials without restriction, including
  7. ** without limitation the rights to use, copy, modify, merge, publish,
  8. ** distribute, sublicense, and/or sell copies of the Materials, and to
  9. ** permit persons to whom the Materials are furnished to do so, subject to
  10. ** the following conditions:
  11. **
  12. ** The above copyright notice and this permission notice shall be included
  13. ** in all copies or substantial portions of the Materials.
  14. **
  15. ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  18. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  19. ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  20. ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  21. ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
  22. */
  23. // Various functions for helping debug WebGL apps.
  24. WebGLDebugUtils = function() {
  25. /**
  26. * Wrapped logging function.
  27. * @param {string} msg Message to log.
  28. */
  29. var log = function(msg) {
  30. if (window.console && window.console.log) {
  31. window.console.log(msg);
  32. }
  33. };
  34. /**
  35. * Wrapped error logging function.
  36. * @param {string} msg Message to log.
  37. */
  38. var error = function(msg) {
  39. if (window.console && window.console.error) {
  40. window.console.error(msg);
  41. } else {
  42. log(msg);
  43. }
  44. };
  45. /**
  46. * Which arguments are enums based on the number of arguments to the function.
  47. * So
  48. * 'texImage2D': {
  49. * 9: { 0:true, 2:true, 6:true, 7:true },
  50. * 6: { 0:true, 2:true, 3:true, 4:true },
  51. * },
  52. *
  53. * means if there are 9 arguments then 6 and 7 are enums, if there are 6
  54. * arguments 3 and 4 are enums
  55. *
  56. * @type {!Object.<number, !Object.<number, string>}
  57. */
  58. var glValidEnumContexts = {
  59. // Generic setters and getters
  60. 'enable': {1: { 0:true }},
  61. 'disable': {1: { 0:true }},
  62. 'getParameter': {1: { 0:true }},
  63. // Rendering
  64. 'drawArrays': {3:{ 0:true }},
  65. 'drawElements': {4:{ 0:true, 2:true }},
  66. // Shaders
  67. 'createShader': {1: { 0:true }},
  68. 'getShaderParameter': {2: { 1:true }},
  69. 'getProgramParameter': {2: { 1:true }},
  70. 'getShaderPrecisionFormat': {2: { 0: true, 1:true }},
  71. // Vertex attributes
  72. 'getVertexAttrib': {2: { 1:true }},
  73. 'vertexAttribPointer': {6: { 2:true }},
  74. // Textures
  75. 'bindTexture': {2: { 0:true }},
  76. 'activeTexture': {1: { 0:true }},
  77. 'getTexParameter': {2: { 0:true, 1:true }},
  78. 'texParameterf': {3: { 0:true, 1:true }},
  79. 'texParameteri': {3: { 0:true, 1:true, 2:true }},
  80. // texImage2D and texSubImage2D are defined below with WebGL 2 entrypoints
  81. 'copyTexImage2D': {8: { 0:true, 2:true }},
  82. 'copyTexSubImage2D': {8: { 0:true }},
  83. 'generateMipmap': {1: { 0:true }},
  84. // compressedTexImage2D and compressedTexSubImage2D are defined below with WebGL 2 entrypoints
  85. // Buffer objects
  86. 'bindBuffer': {2: { 0:true }},
  87. // bufferData and bufferSubData are defined below with WebGL 2 entrypoints
  88. 'getBufferParameter': {2: { 0:true, 1:true }},
  89. // Renderbuffers and framebuffers
  90. 'pixelStorei': {2: { 0:true, 1:true }},
  91. // readPixels is defined below with WebGL 2 entrypoints
  92. 'bindRenderbuffer': {2: { 0:true }},
  93. 'bindFramebuffer': {2: { 0:true }},
  94. 'checkFramebufferStatus': {1: { 0:true }},
  95. 'framebufferRenderbuffer': {4: { 0:true, 1:true, 2:true }},
  96. 'framebufferTexture2D': {5: { 0:true, 1:true, 2:true }},
  97. 'getFramebufferAttachmentParameter': {3: { 0:true, 1:true, 2:true }},
  98. 'getRenderbufferParameter': {2: { 0:true, 1:true }},
  99. 'renderbufferStorage': {4: { 0:true, 1:true }},
  100. // Frame buffer operations (clear, blend, depth test, stencil)
  101. 'clear': {1: { 0: { 'enumBitwiseOr': ['COLOR_BUFFER_BIT', 'DEPTH_BUFFER_BIT', 'STENCIL_BUFFER_BIT'] }}},
  102. 'depthFunc': {1: { 0:true }},
  103. 'blendFunc': {2: { 0:true, 1:true }},
  104. 'blendFuncSeparate': {4: { 0:true, 1:true, 2:true, 3:true }},
  105. 'blendEquation': {1: { 0:true }},
  106. 'blendEquationSeparate': {2: { 0:true, 1:true }},
  107. 'stencilFunc': {3: { 0:true }},
  108. 'stencilFuncSeparate': {4: { 0:true, 1:true }},
  109. 'stencilMaskSeparate': {2: { 0:true }},
  110. 'stencilOp': {3: { 0:true, 1:true, 2:true }},
  111. 'stencilOpSeparate': {4: { 0:true, 1:true, 2:true, 3:true }},
  112. // Culling
  113. 'cullFace': {1: { 0:true }},
  114. 'frontFace': {1: { 0:true }},
  115. // ANGLE_instanced_arrays extension
  116. 'drawArraysInstancedANGLE': {4: { 0:true }},
  117. 'drawElementsInstancedANGLE': {5: { 0:true, 2:true }},
  118. // EXT_blend_minmax extension
  119. 'blendEquationEXT': {1: { 0:true }},
  120. // WebGL 2 Buffer objects
  121. 'bufferData': {
  122. 3: { 0:true, 2:true }, // WebGL 1
  123. 4: { 0:true, 2:true }, // WebGL 2
  124. 5: { 0:true, 2:true } // WebGL 2
  125. },
  126. 'bufferSubData': {
  127. 3: { 0:true }, // WebGL 1
  128. 4: { 0:true }, // WebGL 2
  129. 5: { 0:true } // WebGL 2
  130. },
  131. 'copyBufferSubData': {5: { 0:true, 1:true }},
  132. 'getBufferSubData': {3: { 0:true }, 4: { 0:true }, 5: { 0:true }},
  133. // WebGL 2 Framebuffer objects
  134. 'blitFramebuffer': {10: { 8: { 'enumBitwiseOr': ['COLOR_BUFFER_BIT', 'DEPTH_BUFFER_BIT', 'STENCIL_BUFFER_BIT'] }, 9:true }},
  135. 'framebufferTextureLayer': {5: { 0:true, 1:true }},
  136. 'invalidateFramebuffer': {2: { 0:true }},
  137. 'invalidateSubFramebuffer': {6: { 0:true }},
  138. 'readBuffer': {1: { 0:true }},
  139. // WebGL 2 Renderbuffer objects
  140. 'getInternalformatParameter': {3: { 0:true, 1:true, 2:true }},
  141. 'renderbufferStorageMultisample': {5: { 0:true, 2:true }},
  142. // WebGL 2 Texture objects
  143. 'texStorage2D': {5: { 0:true, 2:true }},
  144. 'texStorage3D': {6: { 0:true, 2:true }},
  145. 'texImage2D': {
  146. 9: { 0:true, 2:true, 6:true, 7:true }, // WebGL 1 & 2
  147. 6: { 0:true, 2:true, 3:true, 4:true }, // WebGL 1
  148. 10: { 0:true, 2:true, 6:true, 7:true } // WebGL 2
  149. },
  150. 'texImage3D': {
  151. 10: { 0:true, 2:true, 7:true, 8:true },
  152. 11: { 0:true, 2:true, 7:true, 8:true }
  153. },
  154. 'texSubImage2D': {
  155. 9: { 0:true, 6:true, 7:true }, // WebGL 1 & 2
  156. 7: { 0:true, 4:true, 5:true }, // WebGL 1
  157. 10: { 0:true, 6:true, 7:true } // WebGL 2
  158. },
  159. 'texSubImage3D': {
  160. 11: { 0:true, 8:true, 9:true },
  161. 12: { 0:true, 8:true, 9:true }
  162. },
  163. 'copyTexSubImage3D': {9: { 0:true }},
  164. 'compressedTexImage2D': {
  165. 7: { 0: true, 2:true }, // WebGL 1 & 2
  166. 8: { 0: true, 2:true }, // WebGL 2
  167. 9: { 0: true, 2:true } // WebGL 2
  168. },
  169. 'compressedTexImage3D': {
  170. 8: { 0: true, 2:true },
  171. 9: { 0: true, 2:true },
  172. 10: { 0: true, 2:true }
  173. },
  174. 'compressedTexSubImage2D': {
  175. 8: { 0: true, 6:true }, // WebGL 1 & 2
  176. 9: { 0: true, 6:true }, // WebGL 2
  177. 10: { 0: true, 6:true } // WebGL 2
  178. },
  179. 'compressedTexSubImage3D': {
  180. 10: { 0: true, 8:true },
  181. 11: { 0: true, 8:true },
  182. 12: { 0: true, 8:true }
  183. },
  184. // WebGL 2 Vertex attribs
  185. 'vertexAttribIPointer': {5: { 2:true }},
  186. // WebGL 2 Writing to the drawing buffer
  187. 'drawArraysInstanced': {4: { 0:true }},
  188. 'drawElementsInstanced': {5: { 0:true, 2:true }},
  189. 'drawRangeElements': {6: { 0:true, 4:true }},
  190. // WebGL 2 Reading back pixels
  191. 'readPixels': {
  192. 7: { 4:true, 5:true }, // WebGL 1 & 2
  193. 8: { 4:true, 5:true } // WebGL 2
  194. },
  195. // WebGL 2 Multiple Render Targets
  196. 'clearBufferfv': {3: { 0:true }, 4: { 0:true }},
  197. 'clearBufferiv': {3: { 0:true }, 4: { 0:true }},
  198. 'clearBufferuiv': {3: { 0:true }, 4: { 0:true }},
  199. 'clearBufferfi': {4: { 0:true }},
  200. // WebGL 2 Query objects
  201. 'beginQuery': {2: { 0:true }},
  202. 'endQuery': {1: { 0:true }},
  203. 'getQuery': {2: { 0:true, 1:true }},
  204. 'getQueryParameter': {2: { 1:true }},
  205. // WebGL 2 Sampler objects
  206. 'samplerParameteri': {3: { 1:true, 2:true }},
  207. 'samplerParameterf': {3: { 1:true }},
  208. 'getSamplerParameter': {2: { 1:true }},
  209. // WebGL 2 Sync objects
  210. 'fenceSync': {2: { 0:true, 1: { 'enumBitwiseOr': [] } }},
  211. 'clientWaitSync': {3: { 1: { 'enumBitwiseOr': ['SYNC_FLUSH_COMMANDS_BIT'] } }},
  212. 'waitSync': {3: { 1: { 'enumBitwiseOr': [] } }},
  213. 'getSyncParameter': {2: { 1:true }},
  214. // WebGL 2 Transform Feedback
  215. 'bindTransformFeedback': {2: { 0:true }},
  216. 'beginTransformFeedback': {1: { 0:true }},
  217. 'transformFeedbackVaryings': {3: { 2:true }},
  218. // WebGL2 Uniform Buffer Objects and Transform Feedback Buffers
  219. 'bindBufferBase': {3: { 0:true }},
  220. 'bindBufferRange': {5: { 0:true }},
  221. 'getIndexedParameter': {2: { 0:true }},
  222. 'getActiveUniforms': {3: { 2:true }},
  223. 'getActiveUniformBlockParameter': {3: { 2:true }}
  224. };
  225. /**
  226. * Map of numbers to names.
  227. * @type {Object}
  228. */
  229. var glEnums = null;
  230. /**
  231. * Map of names to numbers.
  232. * @type {Object}
  233. */
  234. var enumStringToValue = null;
  235. /**
  236. * Initializes this module. Safe to call more than once.
  237. * @param {!WebGLRenderingContext} ctx A WebGL context. If
  238. * you have more than one context it doesn't matter which one
  239. * you pass in, it is only used to pull out constants.
  240. */
  241. function init(ctx) {
  242. if (glEnums == null) {
  243. glEnums = { };
  244. enumStringToValue = { };
  245. for (var propertyName in ctx) {
  246. if (typeof ctx[propertyName] == 'number') {
  247. glEnums[ctx[propertyName]] = propertyName;
  248. enumStringToValue[propertyName] = ctx[propertyName];
  249. }
  250. }
  251. }
  252. }
  253. /**
  254. * Checks the utils have been initialized.
  255. */
  256. function checkInit() {
  257. if (glEnums == null) {
  258. throw 'WebGLDebugUtils.init(ctx) not called';
  259. }
  260. }
  261. /**
  262. * Returns true or false if value matches any WebGL enum
  263. * @param {*} value Value to check if it might be an enum.
  264. * @return {boolean} True if value matches one of the WebGL defined enums
  265. */
  266. function mightBeEnum(value) {
  267. checkInit();
  268. return (glEnums[value] !== undefined);
  269. }
  270. /**
  271. * Gets an string version of an WebGL enum.
  272. *
  273. * Example:
  274. * var str = WebGLDebugUtil.glEnumToString(ctx.getError());
  275. *
  276. * @param {number} value Value to return an enum for
  277. * @return {string} The string version of the enum.
  278. */
  279. function glEnumToString(value) {
  280. checkInit();
  281. var name = glEnums[value];
  282. return (name !== undefined) ? ("gl." + name) :
  283. ("/*UNKNOWN WebGL ENUM*/ 0x" + value.toString(16) + "");
  284. }
  285. /**
  286. * Returns the string version of a WebGL argument.
  287. * Attempts to convert enum arguments to strings.
  288. * @param {string} functionName the name of the WebGL function.
  289. * @param {number} numArgs the number of arguments passed to the function.
  290. * @param {number} argumentIndx the index of the argument.
  291. * @param {*} value The value of the argument.
  292. * @return {string} The value as a string.
  293. */
  294. function glFunctionArgToString(functionName, numArgs, argumentIndex, value) {
  295. var funcInfo = glValidEnumContexts[functionName];
  296. if (funcInfo !== undefined) {
  297. var funcInfo = funcInfo[numArgs];
  298. if (funcInfo !== undefined) {
  299. if (funcInfo[argumentIndex]) {
  300. if (typeof funcInfo[argumentIndex] === 'object' &&
  301. funcInfo[argumentIndex]['enumBitwiseOr'] !== undefined) {
  302. var enums = funcInfo[argumentIndex]['enumBitwiseOr'];
  303. var orResult = 0;
  304. var orEnums = [];
  305. for (var i = 0; i < enums.length; ++i) {
  306. var enumValue = enumStringToValue[enums[i]];
  307. if ((value & enumValue) !== 0) {
  308. orResult |= enumValue;
  309. orEnums.push(glEnumToString(enumValue));
  310. }
  311. }
  312. if (orResult === value) {
  313. return orEnums.join(' | ');
  314. } else {
  315. return glEnumToString(value);
  316. }
  317. } else {
  318. return glEnumToString(value);
  319. }
  320. }
  321. }
  322. }
  323. if (value === null) {
  324. return "null";
  325. } else if (value === undefined) {
  326. return "undefined";
  327. } else if (ArrayBuffer.isView(value)) {
  328. // Large typed array views are common in WebGL APIs and create
  329. // huge strings in logs.
  330. return "<" + value.constructor.name + ">";
  331. } else {
  332. return value.toString();
  333. }
  334. }
  335. /**
  336. * Converts the arguments of a WebGL function to a string.
  337. * Attempts to convert enum arguments to strings.
  338. *
  339. * @param {string} functionName the name of the WebGL function.
  340. * @param {number} args The arguments.
  341. * @return {string} The arguments as a string.
  342. */
  343. function glFunctionArgsToString(functionName, args) {
  344. // apparently we can't do args.join(",");
  345. var argStr = "";
  346. var numArgs = args.length;
  347. for (var ii = 0; ii < numArgs; ++ii) {
  348. argStr += ((ii == 0) ? '' : ', ') +
  349. glFunctionArgToString(functionName, numArgs, ii, args[ii]);
  350. }
  351. return argStr;
  352. };
  353. function makePropertyWrapper(wrapper, original, propertyName) {
  354. //log("wrap prop: " + propertyName);
  355. wrapper.__defineGetter__(propertyName, function() {
  356. return original[propertyName];
  357. });
  358. // TODO(gmane): this needs to handle properties that take more than
  359. // one value?
  360. wrapper.__defineSetter__(propertyName, function(value) {
  361. //log("set: " + propertyName);
  362. original[propertyName] = value;
  363. });
  364. }
  365. // Makes a function that calls a function on another object.
  366. function makeFunctionWrapper(original, functionName) {
  367. //log("wrap fn: " + functionName);
  368. var f = original[functionName];
  369. return function() {
  370. //log("call: " + functionName);
  371. var result = f.apply(original, arguments);
  372. return result;
  373. };
  374. }
  375. /**
  376. * Given a WebGL context returns a wrapped context that calls
  377. * gl.getError after every command and calls a function if the
  378. * result is not gl.NO_ERROR.
  379. *
  380. * @param {!WebGLRenderingContext} ctx The webgl context to
  381. * wrap.
  382. * @param {!function(err, funcName, args): void} opt_onErrorFunc
  383. * The function to call when gl.getError returns an
  384. * error. If not specified the default function calls
  385. * console.log with a message.
  386. * @param {!function(funcName, args): void} opt_onFunc The
  387. * function to call when each webgl function is called.
  388. * You can use this to log all calls for example.
  389. * @param {!WebGLRenderingContext} opt_err_ctx The webgl context
  390. * to call getError on if different than ctx.
  391. */
  392. function makeDebugContext(ctx, opt_onErrorFunc, opt_onFunc, opt_err_ctx) {
  393. opt_err_ctx = opt_err_ctx || ctx;
  394. init(ctx);
  395. opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) {
  396. // apparently we can't do args.join(",");
  397. var argStr = "";
  398. var numArgs = args.length;
  399. for (var ii = 0; ii < numArgs; ++ii) {
  400. argStr += ((ii == 0) ? '' : ', ') +
  401. glFunctionArgToString(functionName, numArgs, ii, args[ii]);
  402. }
  403. error("WebGL error "+ glEnumToString(err) + " in "+ functionName +
  404. "(" + argStr + ")");
  405. };
  406. // Holds booleans for each GL error so after we get the error ourselves
  407. // we can still return it to the client app.
  408. var glErrorShadow = { };
  409. // Makes a function that calls a WebGL function and then calls getError.
  410. function makeErrorWrapper(ctx, functionName) {
  411. return function() {
  412. if (opt_onFunc) {
  413. opt_onFunc(functionName, arguments);
  414. }
  415. var result = ctx[functionName].apply(ctx, arguments);
  416. var err = opt_err_ctx.getError();
  417. if (err != 0) {
  418. glErrorShadow[err] = true;
  419. opt_onErrorFunc(err, functionName, arguments);
  420. }
  421. return result;
  422. };
  423. }
  424. // Make a an object that has a copy of every property of the WebGL context
  425. // but wraps all functions.
  426. var wrapper = {};
  427. for (var propertyName in ctx) {
  428. if (typeof ctx[propertyName] == 'function') {
  429. if (propertyName != 'getExtension') {
  430. wrapper[propertyName] = makeErrorWrapper(ctx, propertyName);
  431. } else {
  432. var wrapped = makeErrorWrapper(ctx, propertyName);
  433. wrapper[propertyName] = function () {
  434. var result = wrapped.apply(ctx, arguments);
  435. if (!result) {
  436. return null;
  437. }
  438. return makeDebugContext(result, opt_onErrorFunc, opt_onFunc, opt_err_ctx);
  439. };
  440. }
  441. } else {
  442. makePropertyWrapper(wrapper, ctx, propertyName);
  443. }
  444. }
  445. // Override the getError function with one that returns our saved results.
  446. wrapper.getError = function() {
  447. for (var err in glErrorShadow) {
  448. if (glErrorShadow.hasOwnProperty(err)) {
  449. if (glErrorShadow[err]) {
  450. glErrorShadow[err] = false;
  451. return err;
  452. }
  453. }
  454. }
  455. return ctx.NO_ERROR;
  456. };
  457. return wrapper;
  458. }
  459. function resetToInitialState(ctx) {
  460. var isWebGL2RenderingContext = !!ctx.createTransformFeedback;
  461. if (isWebGL2RenderingContext) {
  462. ctx.bindVertexArray(null);
  463. }
  464. var numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS);
  465. var tmp = ctx.createBuffer();
  466. ctx.bindBuffer(ctx.ARRAY_BUFFER, tmp);
  467. for (var ii = 0; ii < numAttribs; ++ii) {
  468. ctx.disableVertexAttribArray(ii);
  469. ctx.vertexAttribPointer(ii, 4, ctx.FLOAT, false, 0, 0);
  470. ctx.vertexAttrib1f(ii, 0);
  471. if (isWebGL2RenderingContext) {
  472. ctx.vertexAttribDivisor(ii, 0);
  473. }
  474. }
  475. ctx.deleteBuffer(tmp);
  476. var numTextureUnits = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS);
  477. for (var ii = 0; ii < numTextureUnits; ++ii) {
  478. ctx.activeTexture(ctx.TEXTURE0 + ii);
  479. ctx.bindTexture(ctx.TEXTURE_CUBE_MAP, null);
  480. ctx.bindTexture(ctx.TEXTURE_2D, null);
  481. if (isWebGL2RenderingContext) {
  482. ctx.bindTexture(ctx.TEXTURE_2D_ARRAY, null);
  483. ctx.bindTexture(ctx.TEXTURE_3D, null);
  484. ctx.bindSampler(ii, null);
  485. }
  486. }
  487. ctx.activeTexture(ctx.TEXTURE0);
  488. ctx.useProgram(null);
  489. ctx.bindBuffer(ctx.ARRAY_BUFFER, null);
  490. ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null);
  491. ctx.bindFramebuffer(ctx.FRAMEBUFFER, null);
  492. ctx.bindRenderbuffer(ctx.RENDERBUFFER, null);
  493. ctx.disable(ctx.BLEND);
  494. ctx.disable(ctx.CULL_FACE);
  495. ctx.disable(ctx.DEPTH_TEST);
  496. ctx.disable(ctx.DITHER);
  497. ctx.disable(ctx.SCISSOR_TEST);
  498. ctx.blendColor(0, 0, 0, 0);
  499. ctx.blendEquation(ctx.FUNC_ADD);
  500. ctx.blendFunc(ctx.ONE, ctx.ZERO);
  501. ctx.clearColor(0, 0, 0, 0);
  502. ctx.clearDepth(1);
  503. ctx.clearStencil(-1);
  504. ctx.colorMask(true, true, true, true);
  505. ctx.cullFace(ctx.BACK);
  506. ctx.depthFunc(ctx.LESS);
  507. ctx.depthMask(true);
  508. ctx.depthRange(0, 1);
  509. ctx.frontFace(ctx.CCW);
  510. ctx.hint(ctx.GENERATE_MIPMAP_HINT, ctx.DONT_CARE);
  511. ctx.lineWidth(1);
  512. ctx.pixelStorei(ctx.PACK_ALIGNMENT, 4);
  513. ctx.pixelStorei(ctx.UNPACK_ALIGNMENT, 4);
  514. ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, false);
  515. ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
  516. // TODO: Delete this IF.
  517. if (ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL) {
  518. ctx.pixelStorei(ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL, ctx.BROWSER_DEFAULT_WEBGL);
  519. }
  520. ctx.polygonOffset(0, 0);
  521. ctx.sampleCoverage(1, false);
  522. ctx.scissor(0, 0, ctx.canvas.width, ctx.canvas.height);
  523. ctx.stencilFunc(ctx.ALWAYS, 0, 0xFFFFFFFF);
  524. ctx.stencilMask(0xFFFFFFFF);
  525. ctx.stencilOp(ctx.KEEP, ctx.KEEP, ctx.KEEP);
  526. ctx.viewport(0, 0, ctx.canvas.width, ctx.canvas.height);
  527. ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT);
  528. if (isWebGL2RenderingContext) {
  529. ctx.drawBuffers([ctx.BACK]);
  530. ctx.readBuffer(ctx.BACK);
  531. ctx.bindBuffer(ctx.COPY_READ_BUFFER, null);
  532. ctx.bindBuffer(ctx.COPY_WRITE_BUFFER, null);
  533. ctx.bindBuffer(ctx.PIXEL_PACK_BUFFER, null);
  534. ctx.bindBuffer(ctx.PIXEL_UNPACK_BUFFER, null);
  535. var numTransformFeedbacks = ctx.getParameter(ctx.MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
  536. for (var ii = 0; ii < numTransformFeedbacks; ++ii) {
  537. ctx.bindBufferBase(ctx.TRANSFORM_FEEDBACK_BUFFER, ii, null);
  538. }
  539. var numUBOs = ctx.getParameter(ctx.MAX_UNIFORM_BUFFER_BINDINGS);
  540. for (var ii = 0; ii < numUBOs; ++ii) {
  541. ctx.bindBufferBase(ctx.UNIFORM_BUFFER, ii, null);
  542. }
  543. ctx.disable(ctx.RASTERIZER_DISCARD);
  544. ctx.pixelStorei(ctx.UNPACK_IMAGE_HEIGHT, 0);
  545. ctx.pixelStorei(ctx.UNPACK_SKIP_IMAGES, 0);
  546. ctx.pixelStorei(ctx.UNPACK_ROW_LENGTH, 0);
  547. ctx.pixelStorei(ctx.UNPACK_SKIP_ROWS, 0);
  548. ctx.pixelStorei(ctx.UNPACK_SKIP_PIXELS, 0);
  549. ctx.pixelStorei(ctx.PACK_ROW_LENGTH, 0);
  550. ctx.pixelStorei(ctx.PACK_SKIP_ROWS, 0);
  551. ctx.pixelStorei(ctx.PACK_SKIP_PIXELS, 0);
  552. ctx.hint(ctx.FRAGMENT_SHADER_DERIVATIVE_HINT, ctx.DONT_CARE);
  553. }
  554. // TODO: This should NOT be needed but Firefox fails with 'hint'
  555. while(ctx.getError());
  556. }
  557. function makeLostContextSimulatingCanvas(canvas) {
  558. var unwrappedContext_;
  559. var wrappedContext_;
  560. var onLost_ = [];
  561. var onRestored_ = [];
  562. var wrappedContext_ = {};
  563. var contextId_ = 1;
  564. var contextLost_ = false;
  565. var resourceId_ = 0;
  566. var resourceDb_ = [];
  567. var numCallsToLoseContext_ = 0;
  568. var numCalls_ = 0;
  569. var canRestore_ = false;
  570. var restoreTimeout_ = 0;
  571. var isWebGL2RenderingContext;
  572. // Holds booleans for each GL error so can simulate errors.
  573. var glErrorShadow_ = { };
  574. canvas.getContext = function(f) {
  575. return function() {
  576. var ctx = f.apply(canvas, arguments);
  577. // Did we get a context and is it a WebGL context?
  578. if ((ctx instanceof WebGLRenderingContext) || (window.WebGL2RenderingContext && (ctx instanceof WebGL2RenderingContext))) {
  579. if (ctx != unwrappedContext_) {
  580. if (unwrappedContext_) {
  581. throw "got different context"
  582. }
  583. isWebGL2RenderingContext = window.WebGL2RenderingContext && (ctx instanceof WebGL2RenderingContext);
  584. unwrappedContext_ = ctx;
  585. wrappedContext_ = makeLostContextSimulatingContext(unwrappedContext_);
  586. }
  587. return wrappedContext_;
  588. }
  589. return ctx;
  590. }
  591. }(canvas.getContext);
  592. function wrapEvent(listener) {
  593. if (typeof(listener) == "function") {
  594. return listener;
  595. } else {
  596. return function(info) {
  597. listener.handleEvent(info);
  598. }
  599. }
  600. }
  601. var addOnContextLostListener = function(listener) {
  602. onLost_.push(wrapEvent(listener));
  603. };
  604. var addOnContextRestoredListener = function(listener) {
  605. onRestored_.push(wrapEvent(listener));
  606. };
  607. function wrapAddEventListener(canvas) {
  608. var f = canvas.addEventListener;
  609. canvas.addEventListener = function(type, listener, bubble) {
  610. switch (type) {
  611. case 'webglcontextlost':
  612. addOnContextLostListener(listener);
  613. break;
  614. case 'webglcontextrestored':
  615. addOnContextRestoredListener(listener);
  616. break;
  617. default:
  618. f.apply(canvas, arguments);
  619. }
  620. };
  621. }
  622. wrapAddEventListener(canvas);
  623. canvas.loseContext = function() {
  624. if (!contextLost_) {
  625. contextLost_ = true;
  626. numCallsToLoseContext_ = 0;
  627. ++contextId_;
  628. while (unwrappedContext_.getError());
  629. clearErrors();
  630. glErrorShadow_[unwrappedContext_.CONTEXT_LOST_WEBGL] = true;
  631. var event = makeWebGLContextEvent("context lost");
  632. var callbacks = onLost_.slice();
  633. setTimeout(function() {
  634. //log("numCallbacks:" + callbacks.length);
  635. for (var ii = 0; ii < callbacks.length; ++ii) {
  636. //log("calling callback:" + ii);
  637. callbacks[ii](event);
  638. }
  639. if (restoreTimeout_ >= 0) {
  640. setTimeout(function() {
  641. canvas.restoreContext();
  642. }, restoreTimeout_);
  643. }
  644. }, 0);
  645. }
  646. };
  647. canvas.restoreContext = function() {
  648. if (contextLost_) {
  649. if (onRestored_.length) {
  650. setTimeout(function() {
  651. if (!canRestore_) {
  652. throw "can not restore. webglcontestlost listener did not call event.preventDefault";
  653. }
  654. freeResources();
  655. resetToInitialState(unwrappedContext_);
  656. contextLost_ = false;
  657. numCalls_ = 0;
  658. canRestore_ = false;
  659. var callbacks = onRestored_.slice();
  660. var event = makeWebGLContextEvent("context restored");
  661. for (var ii = 0; ii < callbacks.length; ++ii) {
  662. callbacks[ii](event);
  663. }
  664. }, 0);
  665. }
  666. }
  667. };
  668. canvas.loseContextInNCalls = function(numCalls) {
  669. if (contextLost_) {
  670. throw "You can not ask a lost contet to be lost";
  671. }
  672. numCallsToLoseContext_ = numCalls_ + numCalls;
  673. };
  674. canvas.getNumCalls = function() {
  675. return numCalls_;
  676. };
  677. canvas.setRestoreTimeout = function(timeout) {
  678. restoreTimeout_ = timeout;
  679. };
  680. function isWebGLObject(obj) {
  681. //return false;
  682. return (obj instanceof WebGLBuffer ||
  683. obj instanceof WebGLFramebuffer ||
  684. obj instanceof WebGLProgram ||
  685. obj instanceof WebGLRenderbuffer ||
  686. obj instanceof WebGLShader ||
  687. obj instanceof WebGLTexture);
  688. }
  689. function checkResources(args) {
  690. for (var ii = 0; ii < args.length; ++ii) {
  691. var arg = args[ii];
  692. if (isWebGLObject(arg)) {
  693. return arg.__webglDebugContextLostId__ == contextId_;
  694. }
  695. }
  696. return true;
  697. }
  698. function clearErrors() {
  699. var k = Object.keys(glErrorShadow_);
  700. for (var ii = 0; ii < k.length; ++ii) {
  701. delete glErrorShadow_[k[ii]];
  702. }
  703. }
  704. function loseContextIfTime() {
  705. ++numCalls_;
  706. if (!contextLost_) {
  707. if (numCallsToLoseContext_ == numCalls_) {
  708. canvas.loseContext();
  709. }
  710. }
  711. }
  712. // Makes a function that simulates WebGL when out of context.
  713. function makeLostContextFunctionWrapper(ctx, functionName) {
  714. var f = ctx[functionName];
  715. return function() {
  716. // log("calling:" + functionName);
  717. // Only call the functions if the context is not lost.
  718. loseContextIfTime();
  719. if (!contextLost_) {
  720. //if (!checkResources(arguments)) {
  721. // glErrorShadow_[wrappedContext_.INVALID_OPERATION] = true;
  722. // return;
  723. //}
  724. var result = f.apply(ctx, arguments);
  725. return result;
  726. }
  727. };
  728. }
  729. function freeResources() {
  730. for (var ii = 0; ii < resourceDb_.length; ++ii) {
  731. var resource = resourceDb_[ii];
  732. if (resource instanceof WebGLBuffer) {
  733. unwrappedContext_.deleteBuffer(resource);
  734. } else if (resource instanceof WebGLFramebuffer) {
  735. unwrappedContext_.deleteFramebuffer(resource);
  736. } else if (resource instanceof WebGLProgram) {
  737. unwrappedContext_.deleteProgram(resource);
  738. } else if (resource instanceof WebGLRenderbuffer) {
  739. unwrappedContext_.deleteRenderbuffer(resource);
  740. } else if (resource instanceof WebGLShader) {
  741. unwrappedContext_.deleteShader(resource);
  742. } else if (resource instanceof WebGLTexture) {
  743. unwrappedContext_.deleteTexture(resource);
  744. }
  745. else if (isWebGL2RenderingContext) {
  746. if (resource instanceof WebGLQuery) {
  747. unwrappedContext_.deleteQuery(resource);
  748. } else if (resource instanceof WebGLSampler) {
  749. unwrappedContext_.deleteSampler(resource);
  750. } else if (resource instanceof WebGLSync) {
  751. unwrappedContext_.deleteSync(resource);
  752. } else if (resource instanceof WebGLTransformFeedback) {
  753. unwrappedContext_.deleteTransformFeedback(resource);
  754. } else if (resource instanceof WebGLVertexArrayObject) {
  755. unwrappedContext_.deleteVertexArray(resource);
  756. }
  757. }
  758. }
  759. }
  760. function makeWebGLContextEvent(statusMessage) {
  761. return {
  762. statusMessage: statusMessage,
  763. preventDefault: function() {
  764. canRestore_ = true;
  765. }
  766. };
  767. }
  768. return canvas;
  769. function makeLostContextSimulatingContext(ctx) {
  770. // copy all functions and properties to wrapper
  771. for (var propertyName in ctx) {
  772. if (typeof ctx[propertyName] == 'function') {
  773. wrappedContext_[propertyName] = makeLostContextFunctionWrapper(
  774. ctx, propertyName);
  775. } else {
  776. makePropertyWrapper(wrappedContext_, ctx, propertyName);
  777. }
  778. }
  779. // Wrap a few functions specially.
  780. wrappedContext_.getError = function() {
  781. loseContextIfTime();
  782. if (!contextLost_) {
  783. var err;
  784. while (err = unwrappedContext_.getError()) {
  785. glErrorShadow_[err] = true;
  786. }
  787. }
  788. for (var err in glErrorShadow_) {
  789. if (glErrorShadow_[err]) {
  790. delete glErrorShadow_[err];
  791. return err;
  792. }
  793. }
  794. return wrappedContext_.NO_ERROR;
  795. };
  796. var creationFunctions = [
  797. "createBuffer",
  798. "createFramebuffer",
  799. "createProgram",
  800. "createRenderbuffer",
  801. "createShader",
  802. "createTexture"
  803. ];
  804. if (isWebGL2RenderingContext) {
  805. creationFunctions.push(
  806. "createQuery",
  807. "createSampler",
  808. "fenceSync",
  809. "createTransformFeedback",
  810. "createVertexArray"
  811. );
  812. }
  813. for (var ii = 0; ii < creationFunctions.length; ++ii) {
  814. var functionName = creationFunctions[ii];
  815. wrappedContext_[functionName] = function(f) {
  816. return function() {
  817. loseContextIfTime();
  818. if (contextLost_) {
  819. return null;
  820. }
  821. var obj = f.apply(ctx, arguments);
  822. obj.__webglDebugContextLostId__ = contextId_;
  823. resourceDb_.push(obj);
  824. return obj;
  825. };
  826. }(ctx[functionName]);
  827. }
  828. var functionsThatShouldReturnNull = [
  829. "getActiveAttrib",
  830. "getActiveUniform",
  831. "getBufferParameter",
  832. "getContextAttributes",
  833. "getAttachedShaders",
  834. "getFramebufferAttachmentParameter",
  835. "getParameter",
  836. "getProgramParameter",
  837. "getProgramInfoLog",
  838. "getRenderbufferParameter",
  839. "getShaderParameter",
  840. "getShaderInfoLog",
  841. "getShaderSource",
  842. "getTexParameter",
  843. "getUniform",
  844. "getUniformLocation",
  845. "getVertexAttrib"
  846. ];
  847. if (isWebGL2RenderingContext) {
  848. functionsThatShouldReturnNull.push(
  849. "getInternalformatParameter",
  850. "getQuery",
  851. "getQueryParameter",
  852. "getSamplerParameter",
  853. "getSyncParameter",
  854. "getTransformFeedbackVarying",
  855. "getIndexedParameter",
  856. "getUniformIndices",
  857. "getActiveUniforms",
  858. "getActiveUniformBlockParameter",
  859. "getActiveUniformBlockName"
  860. );
  861. }
  862. for (var ii = 0; ii < functionsThatShouldReturnNull.length; ++ii) {
  863. var functionName = functionsThatShouldReturnNull[ii];
  864. wrappedContext_[functionName] = function(f) {
  865. return function() {
  866. loseContextIfTime();
  867. if (contextLost_) {
  868. return null;
  869. }
  870. return f.apply(ctx, arguments);
  871. }
  872. }(wrappedContext_[functionName]);
  873. }
  874. var isFunctions = [
  875. "isBuffer",
  876. "isEnabled",
  877. "isFramebuffer",
  878. "isProgram",
  879. "isRenderbuffer",
  880. "isShader",
  881. "isTexture"
  882. ];
  883. if (isWebGL2RenderingContext) {
  884. isFunctions.push(
  885. "isQuery",
  886. "isSampler",
  887. "isSync",
  888. "isTransformFeedback",
  889. "isVertexArray"
  890. );
  891. }
  892. for (var ii = 0; ii < isFunctions.length; ++ii) {
  893. var functionName = isFunctions[ii];
  894. wrappedContext_[functionName] = function(f) {
  895. return function() {
  896. loseContextIfTime();
  897. if (contextLost_) {
  898. return false;
  899. }
  900. return f.apply(ctx, arguments);
  901. }
  902. }(wrappedContext_[functionName]);
  903. }
  904. wrappedContext_.checkFramebufferStatus = function(f) {
  905. return function() {
  906. loseContextIfTime();
  907. if (contextLost_) {
  908. return wrappedContext_.FRAMEBUFFER_UNSUPPORTED;
  909. }
  910. return f.apply(ctx, arguments);
  911. };
  912. }(wrappedContext_.checkFramebufferStatus);
  913. wrappedContext_.getAttribLocation = function(f) {
  914. return function() {
  915. loseContextIfTime();
  916. if (contextLost_) {
  917. return -1;
  918. }
  919. return f.apply(ctx, arguments);
  920. };
  921. }(wrappedContext_.getAttribLocation);
  922. wrappedContext_.getVertexAttribOffset = function(f) {
  923. return function() {
  924. loseContextIfTime();
  925. if (contextLost_) {
  926. return 0;
  927. }
  928. return f.apply(ctx, arguments);
  929. };
  930. }(wrappedContext_.getVertexAttribOffset);
  931. wrappedContext_.isContextLost = function() {
  932. return contextLost_;
  933. };
  934. if (isWebGL2RenderingContext) {
  935. wrappedContext_.getFragDataLocation = function(f) {
  936. return function() {
  937. loseContextIfTime();
  938. if (contextLost_) {
  939. return -1;
  940. }
  941. return f.apply(ctx, arguments);
  942. };
  943. }(wrappedContext_.getFragDataLocation);
  944. wrappedContext_.clientWaitSync = function(f) {
  945. return function() {
  946. loseContextIfTime();
  947. if (contextLost_) {
  948. return wrappedContext_.WAIT_FAILED;
  949. }
  950. return f.apply(ctx, arguments);
  951. };
  952. }(wrappedContext_.clientWaitSync);
  953. wrappedContext_.getUniformBlockIndex = function(f) {
  954. return function() {
  955. loseContextIfTime();
  956. if (contextLost_) {
  957. return wrappedContext_.INVALID_INDEX;
  958. }
  959. return f.apply(ctx, arguments);
  960. };
  961. }(wrappedContext_.getUniformBlockIndex);
  962. }
  963. return wrappedContext_;
  964. }
  965. }
  966. return {
  967. /**
  968. * Initializes this module. Safe to call more than once.
  969. * @param {!WebGLRenderingContext} ctx A WebGL context. If
  970. * you have more than one context it doesn't matter which one
  971. * you pass in, it is only used to pull out constants.
  972. */
  973. 'init': init,
  974. /**
  975. * Returns true or false if value matches any WebGL enum
  976. * @param {*} value Value to check if it might be an enum.
  977. * @return {boolean} True if value matches one of the WebGL defined enums
  978. */
  979. 'mightBeEnum': mightBeEnum,
  980. /**
  981. * Gets an string version of an WebGL enum.
  982. *
  983. * Example:
  984. * WebGLDebugUtil.init(ctx);
  985. * var str = WebGLDebugUtil.glEnumToString(ctx.getError());
  986. *
  987. * @param {number} value Value to return an enum for
  988. * @return {string} The string version of the enum.
  989. */
  990. 'glEnumToString': glEnumToString,
  991. /**
  992. * Converts the argument of a WebGL function to a string.
  993. * Attempts to convert enum arguments to strings.
  994. *
  995. * Example:
  996. * WebGLDebugUtil.init(ctx);
  997. * var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 2, 0, gl.TEXTURE_2D);
  998. *
  999. * would return 'TEXTURE_2D'
  1000. *
  1001. * @param {string} functionName the name of the WebGL function.
  1002. * @param {number} numArgs The number of arguments
  1003. * @param {number} argumentIndx the index of the argument.
  1004. * @param {*} value The value of the argument.
  1005. * @return {string} The value as a string.
  1006. */
  1007. 'glFunctionArgToString': glFunctionArgToString,
  1008. /**
  1009. * Converts the arguments of a WebGL function to a string.
  1010. * Attempts to convert enum arguments to strings.
  1011. *
  1012. * @param {string} functionName the name of the WebGL function.
  1013. * @param {number} args The arguments.
  1014. * @return {string} The arguments as a string.
  1015. */
  1016. 'glFunctionArgsToString': glFunctionArgsToString,
  1017. /**
  1018. * Given a WebGL context returns a wrapped context that calls
  1019. * gl.getError after every command and calls a function if the
  1020. * result is not NO_ERROR.
  1021. *
  1022. * You can supply your own function if you want. For example, if you'd like
  1023. * an exception thrown on any GL error you could do this
  1024. *
  1025. * function throwOnGLError(err, funcName, args) {
  1026. * throw WebGLDebugUtils.glEnumToString(err) +
  1027. * " was caused by call to " + funcName;
  1028. * };
  1029. *
  1030. * ctx = WebGLDebugUtils.makeDebugContext(
  1031. * canvas.getContext("webgl"), throwOnGLError);
  1032. *
  1033. * @param {!WebGLRenderingContext} ctx The webgl context to wrap.
  1034. * @param {!function(err, funcName, args): void} opt_onErrorFunc The function
  1035. * to call when gl.getError returns an error. If not specified the default
  1036. * function calls console.log with a message.
  1037. * @param {!function(funcName, args): void} opt_onFunc The
  1038. * function to call when each webgl function is called. You
  1039. * can use this to log all calls for example.
  1040. */
  1041. 'makeDebugContext': makeDebugContext,
  1042. /**
  1043. * Given a canvas element returns a wrapped canvas element that will
  1044. * simulate lost context. The canvas returned adds the following functions.
  1045. *
  1046. * loseContext:
  1047. * simulates a lost context event.
  1048. *
  1049. * restoreContext:
  1050. * simulates the context being restored.
  1051. *
  1052. * lostContextInNCalls:
  1053. * loses the context after N gl calls.
  1054. *
  1055. * getNumCalls:
  1056. * tells you how many gl calls there have been so far.
  1057. *
  1058. * setRestoreTimeout:
  1059. * sets the number of milliseconds until the context is restored
  1060. * after it has been lost. Defaults to 0. Pass -1 to prevent
  1061. * automatic restoring.
  1062. *
  1063. * @param {!Canvas} canvas The canvas element to wrap.
  1064. */
  1065. 'makeLostContextSimulatingCanvas': makeLostContextSimulatingCanvas,
  1066. /**
  1067. * Resets a context to the initial state.
  1068. * @param {!WebGLRenderingContext} ctx The webgl context to
  1069. * reset.
  1070. */
  1071. 'resetToInitialState': resetToInitialState
  1072. };
  1073. }();