2
0

webgl-debug-helper.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. /*
  2. * Copyright 2012, Gregg Tavares.
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are
  7. * met:
  8. *
  9. * * Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * * Redistributions in binary form must reproduce the above
  12. * copyright notice, this list of conditions and the following disclaimer
  13. * in the documentation and/or other materials provided with the
  14. * distribution.
  15. * * Neither the name of Gregg Tavares. nor the names of his
  16. * contributors may be used to endorse or promote products derived from
  17. * this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. /* global define, globalThis */
  32. (function(root, factory) { // eslint-disable-line
  33. if ( typeof define === 'function' && define.amd ) {
  34. // AMD. Register as an anonymous module.
  35. define( [], function () {
  36. return factory.call( root );
  37. } );
  38. } else {
  39. // Browser globals
  40. root.webglDebugHelper = factory.call( root );
  41. }
  42. }( this || globalThis, function () {
  43. 'use strict'; // eslint-disable-line
  44. //------------ [ from https://github.com/KhronosGroup/WebGLDeveloperTools ]
  45. /*
  46. ** Copyright (c) 2012 The Khronos Group Inc.
  47. **
  48. ** Permission is hereby granted, free of charge, to any person obtaining a
  49. ** copy of this software and/or associated documentation files (the
  50. ** "Materials"), to deal in the Materials without restriction, including
  51. ** without limitation the rights to use, copy, modify, merge, publish,
  52. ** distribute, sublicense, and/or sell copies of the Materials, and to
  53. ** permit persons to whom the Materials are furnished to do so, subject to
  54. ** the following conditions:
  55. **
  56. ** The above copyright notice and this permission notice shall be included
  57. ** in all copies or substantial portions of the Materials.
  58. **
  59. ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  60. ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  61. ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  62. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  63. ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  64. ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  65. ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
  66. */
  67. /**
  68. * Types of contexts we have added to map
  69. */
  70. const mappedContextTypes = {};
  71. /**
  72. * Map of numbers to names.
  73. * @type {Object}
  74. */
  75. const glEnums = {};
  76. /**
  77. * Map of names to numbers.
  78. * @type {Object}
  79. */
  80. const enumStringToValue = {};
  81. /**
  82. * Initializes this module. Safe to call more than once.
  83. * @param {!WebGLRenderingContext} ctx A WebGL context. If
  84. * you have more than one context it doesn't matter which one
  85. * you pass in, it is only used to pull out constants.
  86. */
  87. function addEnumsForContext( ctx, type ) {
  88. if ( ! mappedContextTypes[ type ] ) {
  89. mappedContextTypes[ type ] = true;
  90. for ( const propertyName in ctx ) {
  91. if ( typeof ctx[ propertyName ] === 'number' ) {
  92. glEnums[ ctx[ propertyName ] ] = propertyName;
  93. enumStringToValue[ propertyName ] = ctx[ propertyName ];
  94. }
  95. }
  96. }
  97. }
  98. function enumArrayToString( enums ) {
  99. const enumStrings = [];
  100. if ( enums.length ) {
  101. for ( let i = 0; i < enums.length; ++ i ) {
  102. enums.push(glEnumToString(enums[i])); // eslint-disable-line
  103. }
  104. return '[' + enumStrings.join( ', ' ) + ']';
  105. }
  106. return enumStrings.toString();
  107. }
  108. function makeBitFieldToStringFunc( enums ) {
  109. return function ( value ) {
  110. let orResult = 0;
  111. const orEnums = [];
  112. for ( let i = 0; i < enums.length; ++ i ) {
  113. const enumValue = enumStringToValue[ enums[ i ] ];
  114. if ( ( value & enumValue ) !== 0 ) {
  115. orResult |= enumValue;
  116. orEnums.push(glEnumToString(enumValue)); // eslint-disable-line
  117. }
  118. }
  119. if ( orResult === value ) {
  120. return orEnums.join( ' | ' );
  121. } else {
  122. return glEnumToString(value); // eslint-disable-line
  123. }
  124. };
  125. }
  126. const destBufferBitFieldToString = makeBitFieldToStringFunc( [
  127. 'COLOR_BUFFER_BIT',
  128. 'DEPTH_BUFFER_BIT',
  129. 'STENCIL_BUFFER_BIT',
  130. ] );
  131. /**
  132. * Which arguments are enums based on the number of arguments to the function.
  133. * So
  134. * 'texImage2D': {
  135. * 9: { 0:true, 2:true, 6:true, 7:true },
  136. * 6: { 0:true, 2:true, 3:true, 4:true },
  137. * },
  138. *
  139. * means if there are 9 arguments then 6 and 7 are enums, if there are 6
  140. * arguments 3 and 4 are enums. Maybe a function as well in which case
  141. * value is passed to function and returns a string
  142. *
  143. * @type {!Object.<number, (!Object.<number, string>|function)}
  144. */
  145. const glValidEnumContexts = {
  146. // Generic setters and getters
  147. 'enable': { 1: { 0: true } },
  148. 'disable': { 1: { 0: true } },
  149. 'getParameter': { 1: { 0: true } },
  150. // Rendering
  151. 'drawArrays': { 3: { 0: true } },
  152. 'drawElements': { 4: { 0: true, 2: true } },
  153. 'drawArraysInstanced': { 4: { 0: true } },
  154. 'drawElementsInstanced': { 5: { 0: true, 2: true } },
  155. 'drawRangeElements': { 6: { 0: true, 4: true } },
  156. // Shaders
  157. 'createShader': { 1: { 0: true } },
  158. 'getShaderParameter': { 2: { 1: true } },
  159. 'getProgramParameter': { 2: { 1: true } },
  160. 'getShaderPrecisionFormat': { 2: { 0: true, 1: true } },
  161. // Vertex attributes
  162. 'getVertexAttrib': { 2: { 1: true } },
  163. 'vertexAttribPointer': { 6: { 2: true } },
  164. 'vertexAttribIPointer': { 5: { 2: true } }, // WebGL2
  165. // Textures
  166. 'bindTexture': { 2: { 0: true } },
  167. 'activeTexture': { 1: { 0: true } },
  168. 'getTexParameter': { 2: { 0: true, 1: true } },
  169. 'texParameterf': { 3: { 0: true, 1: true } },
  170. 'texParameteri': { 3: { 0: true, 1: true, 2: true } },
  171. 'texImage2D': {
  172. 9: { 0: true, 2: true, 6: true, 7: true },
  173. 6: { 0: true, 2: true, 3: true, 4: true },
  174. 10: { 0: true, 2: true, 6: true, 7: true }, // WebGL2
  175. },
  176. 'texImage3D': {
  177. 10: { 0: true, 2: true, 7: true, 8: true }, // WebGL2
  178. 11: { 0: true, 2: true, 7: true, 8: true }, // WebGL2
  179. },
  180. 'texSubImage2D': {
  181. 9: { 0: true, 6: true, 7: true },
  182. 7: { 0: true, 4: true, 5: true },
  183. 10: { 0: true, 6: true, 7: true }, // WebGL2
  184. },
  185. 'texSubImage3D': {
  186. 11: { 0: true, 8: true, 9: true }, // WebGL2
  187. 12: { 0: true, 8: true, 9: true }, // WebGL2
  188. },
  189. 'texStorage2D': { 5: { 0: true, 2: true } }, // WebGL2
  190. 'texStorage3D': { 6: { 0: true, 2: true } }, // WebGL2
  191. 'copyTexImage2D': { 8: { 0: true, 2: true } },
  192. 'copyTexSubImage2D': { 8: { 0: true } },
  193. 'copyTexSubImage3D': { 9: { 0: true } }, // WebGL2
  194. 'generateMipmap': { 1: { 0: true } },
  195. 'compressedTexImage2D': {
  196. 7: { 0: true, 2: true },
  197. 8: { 0: true, 2: true }, // WebGL2
  198. },
  199. 'compressedTexSubImage2D': {
  200. 8: { 0: true, 6: true },
  201. 9: { 0: true, 6: true }, // WebGL2
  202. },
  203. 'compressedTexImage3D': {
  204. 8: { 0: true, 2: true, }, // WebGL2
  205. 9: { 0: true, 2: true, }, // WebGL2
  206. },
  207. 'compressedTexSubImage3D': {
  208. 9: { 0: true, 8: true, }, // WebGL2
  209. 10: { 0: true, 8: true, }, // WebGL2
  210. },
  211. // Buffer objects
  212. 'bindBuffer': { 2: { 0: true } },
  213. 'bufferData': {
  214. 3: { 0: true, 2: true },
  215. 4: { 0: true, 2: true }, // WebGL2
  216. 5: { 0: true, 2: true }, // WebGL2
  217. },
  218. 'bufferSubData': {
  219. 3: { 0: true },
  220. 4: { 0: true }, // WebGL2
  221. 5: { 0: true }, // WebGL2
  222. },
  223. 'copyBufferSubData': {
  224. 5: { 0: true }, // WeBGL2
  225. },
  226. 'getBufferParameter': { 2: { 0: true, 1: true } },
  227. 'getBufferSubData': {
  228. 3: { 0: true, }, // WebGL2
  229. 4: { 0: true, }, // WebGL2
  230. 5: { 0: true, }, // WebGL2
  231. },
  232. // Renderbuffers and framebuffers
  233. 'pixelStorei': { 2: { 0: true, 1: true } },
  234. 'readPixels': {
  235. 7: { 4: true, 5: true },
  236. 8: { 4: true, 5: true }, // WebGL2
  237. },
  238. 'bindRenderbuffer': { 2: { 0: true } },
  239. 'bindFramebuffer': { 2: { 0: true } },
  240. 'blitFramebuffer': { 10: { 8: destBufferBitFieldToString, 9: true } }, // WebGL2
  241. 'checkFramebufferStatus': { 1: { 0: true } },
  242. 'framebufferRenderbuffer': { 4: { 0: true, 1: true, 2: true } },
  243. 'framebufferTexture2D': { 5: { 0: true, 1: true, 2: true } },
  244. 'framebufferTextureLayer': { 5: { 0: true, 1: true } }, // WebGL2
  245. 'getFramebufferAttachmentParameter': { 3: { 0: true, 1: true, 2: true } },
  246. 'getInternalformatParameter': { 3: { 0: true, 1: true, 2: true } }, // WebGL2
  247. 'getRenderbufferParameter': { 2: { 0: true, 1: true } },
  248. 'invalidateFramebuffer': { 2: { 0: true, 1: enumArrayToString, } }, // WebGL2
  249. 'invalidateSubFramebuffer': { 6: { 0: true, 1: enumArrayToString, } }, // WebGL2
  250. 'readBuffer': { 1: { 0: true } }, // WebGL2
  251. 'renderbufferStorage': { 4: { 0: true, 1: true } },
  252. 'renderbufferStorageMultisample': { 5: { 0: true, 2: true } }, // WebGL2
  253. // Frame buffer operations (clear, blend, depth test, stencil)
  254. 'clear': { 1: { 0: destBufferBitFieldToString } },
  255. 'depthFunc': { 1: { 0: true } },
  256. 'blendFunc': { 2: { 0: true, 1: true } },
  257. 'blendFuncSeparate': { 4: { 0: true, 1: true, 2: true, 3: true } },
  258. 'blendEquation': { 1: { 0: true } },
  259. 'blendEquationSeparate': { 2: { 0: true, 1: true } },
  260. 'stencilFunc': { 3: { 0: true } },
  261. 'stencilFuncSeparate': { 4: { 0: true, 1: true } },
  262. 'stencilMaskSeparate': { 2: { 0: true } },
  263. 'stencilOp': { 3: { 0: true, 1: true, 2: true } },
  264. 'stencilOpSeparate': { 4: { 0: true, 1: true, 2: true, 3: true } },
  265. // Culling
  266. 'cullFace': { 1: { 0: true } },
  267. 'frontFace': { 1: { 0: true } },
  268. // ANGLE_instanced_arrays extension
  269. 'drawArraysInstancedANGLE': { 4: { 0: true } },
  270. 'drawElementsInstancedANGLE': { 5: { 0: true, 2: true } },
  271. // EXT_blend_minmax extension
  272. 'blendEquationEXT': { 1: { 0: true } },
  273. // Multiple Render Targets
  274. 'drawBuffersWebGL': { 1: { 0: enumArrayToString, } }, // WEBGL_draw_bufers
  275. 'drawBuffers': { 1: { 0: enumArrayToString, } }, // WebGL2
  276. 'clearBufferfv': {
  277. 4: { 0: true }, // WebGL2
  278. 5: { 0: true }, // WebGL2
  279. },
  280. 'clearBufferiv': {
  281. 4: { 0: true }, // WebGL2
  282. 5: { 0: true }, // WebGL2
  283. },
  284. 'clearBufferuiv': {
  285. 4: { 0: true }, // WebGL2
  286. 5: { 0: true }, // WebGL2
  287. },
  288. 'clearBufferfi': { 4: { 0: true } }, // WebGL2
  289. // QueryObjects
  290. 'beginQuery': { 2: { 0: true } }, // WebGL2
  291. 'endQuery': { 1: { 0: true } }, // WebGL2
  292. 'getQuery': { 2: { 0: true, 1: true } }, // WebGL2
  293. 'getQueryParameter': { 2: { 1: true } }, // WebGL2
  294. // Sampler Objects
  295. 'samplerParameteri': { 3: { 1: true } }, // WebGL2
  296. 'samplerParameterf': { 3: { 1: true } }, // WebGL2
  297. 'getSamplerParameter': { 2: { 1: true } }, // WebGL2
  298. // Sync objects
  299. 'clientWaitSync': { 3: { 1: makeBitFieldToStringFunc( [ 'SYNC_FLUSH_COMMANDS_BIT' ] ) } }, // WebGL2
  300. 'fenceSync': { 2: { 0: true } }, // WebGL2
  301. 'getSyncParameter': { 2: { 1: true } }, // WebGL2
  302. // Transform Feedback
  303. 'bindTransformFeedback': { 2: { 0: true } }, // WebGL2
  304. 'beginTransformFeedback': { 1: { 0: true } }, // WebGL2
  305. // Uniform Buffer Objects and Transform Feedback Buffers
  306. 'bindBufferBase': { 3: { 0: true } }, // WebGL2
  307. 'bindBufferRange': { 5: { 0: true } }, // WebGL2
  308. 'getIndexedParameter': { 2: { 0: true } }, // WebGL2
  309. 'getActiveUniforms': { 3: { 2: true } }, // WebGL2
  310. 'getActiveUniformBlockParameter': { 3: { 2: true } }, // WebGL2
  311. };
  312. /**
  313. * Gets an string version of an WebGL enum.
  314. *
  315. * Example:
  316. * var str = WebGLDebugUtil.glEnumToString(ctx.getError());
  317. *
  318. * @param {number} value Value to return an enum for
  319. * @return {string} The string version of the enum.
  320. */
  321. function glEnumToString( value ) {
  322. const name = glEnums[ value ];
  323. return ( name !== undefined )
  324. ? `gl.${name}`
  325. : `/*UNKNOWN WebGL ENUM*/ 0x${value.toString( 16 )}`;
  326. }
  327. /**
  328. * Returns the string version of a WebGL argument.
  329. * Attempts to convert enum arguments to strings.
  330. * @param {string} functionName the name of the WebGL function.
  331. * @param {number} numArgs the number of arguments passed to the function.
  332. * @param {number} argumentIndx the index of the argument.
  333. * @param {*} value The value of the argument.
  334. * @return {string} The value as a string.
  335. */
  336. function glFunctionArgToString( functionName, numArgs, argumentIndex, value ) {
  337. const funcInfos = glValidEnumContexts[ functionName ];
  338. if ( funcInfos !== undefined ) {
  339. const funcInfo = funcInfos[ numArgs ];
  340. if ( funcInfo !== undefined ) {
  341. const argType = funcInfo[ argumentIndex ];
  342. if ( argType ) {
  343. if ( typeof argType === 'function' ) {
  344. return argType( value );
  345. } else {
  346. return glEnumToString( value );
  347. }
  348. }
  349. }
  350. }
  351. if ( value === null ) {
  352. return 'null';
  353. } else if ( value === undefined ) {
  354. return 'undefined';
  355. } else {
  356. return value.toString();
  357. }
  358. }
  359. /**
  360. * Converts the arguments of a WebGL function to a string.
  361. * Attempts to convert enum arguments to strings.
  362. *
  363. * @param {string} functionName the name of the WebGL function.
  364. * @param {number} args The arguments.
  365. * @return {string} The arguments as a string.
  366. */
  367. function glFunctionArgsToString( functionName, args ) {
  368. // apparently we can't do args.join(",");
  369. const argStrs = [];
  370. const numArgs = args.length;
  371. for ( let ii = 0; ii < numArgs; ++ ii ) {
  372. argStrs.push( glFunctionArgToString( functionName, numArgs, ii, args[ ii ] ) );
  373. }
  374. return argStrs.join( ', ' );
  375. }
  376. function makePropertyWrapper( wrapper, original, propertyName ) {
  377. wrapper.__defineGetter__(propertyName, function() { // eslint-disable-line
  378. return original[ propertyName ];
  379. } );
  380. // TODO(gmane): this needs to handle properties that take more than
  381. // one value?
  382. wrapper.__defineSetter__(propertyName, function(value) { // eslint-disable-line
  383. original[ propertyName ] = value;
  384. } );
  385. }
  386. /**
  387. * Given a WebGL context returns a wrapped context that calls
  388. * gl.getError after every command and calls a function if the
  389. * result is not gl.NO_ERROR.
  390. *
  391. * @param {!WebGLRenderingContext} ctx The webgl context to
  392. * wrap.
  393. * @param {!function(err, funcName, args): void} opt_onErrorFunc
  394. * The function to call when gl.getError returns an
  395. * error. If not specified the default function calls
  396. * console.log with a message.
  397. * @param {!function(funcName, args): void} opt_onFunc The
  398. * function to call when each webgl function is called.
  399. * You can use this to log all calls for example.
  400. * @param {!WebGLRenderingContext} opt_err_ctx The webgl context
  401. * to call getError on if different than ctx.
  402. */
  403. function makeDebugContext( ctx, options ) {
  404. options = options || {};
  405. const errCtx = options.errCtx || ctx;
  406. const onFunc = options.funcFunc;
  407. const sharedState = options.sharedState || {
  408. numDrawCallsRemaining: options.maxDrawCalls || - 1,
  409. wrappers: {},
  410. };
  411. options.sharedState = sharedState;
  412. const errorFunc = options.errorFunc || function ( err, functionName, args ) {
  413. console.error( `WebGL error ${glEnumToString( err )} in ${functionName}(${glFunctionArgsToString( functionName, args )})` ); /* eslint-disable-line no-console */
  414. };
  415. // Holds booleans for each GL error so after we get the error ourselves
  416. // we can still return it to the client app.
  417. const glErrorShadow = { };
  418. const wrapper = {};
  419. function removeChecks() {
  420. Object.keys( sharedState.wrappers ).forEach( function ( name ) {
  421. const pair = sharedState.wrappers[ name ];
  422. const wrapper = pair.wrapper;
  423. const orig = pair.orig;
  424. for ( const propertyName in wrapper ) {
  425. if ( typeof wrapper[ propertyName ] === 'function' ) {
  426. wrapper[ propertyName ] = orig[ propertyName ].bind( orig );
  427. }
  428. }
  429. } );
  430. }
  431. function checkMaxDrawCalls() {
  432. if ( sharedState.numDrawCallsRemaining === 0 ) {
  433. removeChecks();
  434. }
  435. -- sharedState.numDrawCallsRemaining;
  436. }
  437. function noop() {
  438. }
  439. // Makes a function that calls a WebGL function and then calls getError.
  440. function makeErrorWrapper( ctx, functionName ) {
  441. const check = functionName.substring( 0, 4 ) === 'draw' ? checkMaxDrawCalls : noop;
  442. return function () {
  443. if ( onFunc ) {
  444. onFunc( functionName, arguments );
  445. }
  446. const result = ctx[ functionName ].apply( ctx, arguments );
  447. const err = errCtx.getError();
  448. if ( err !== 0 ) {
  449. glErrorShadow[ err ] = true;
  450. errorFunc( err, functionName, arguments );
  451. }
  452. check();
  453. return result;
  454. };
  455. }
  456. function makeGetExtensionWrapper( ctx, wrapped ) {
  457. return function () {
  458. const extensionName = arguments[ 0 ];
  459. let ext = sharedState.wrappers[ extensionName ];
  460. if ( ! ext ) {
  461. ext = wrapped.apply( ctx, arguments );
  462. if ( ext ) {
  463. const origExt = ext;
  464. ext = makeDebugContext( ext, { ...options, errCtx: ctx } );
  465. sharedState.wrappers[ extensionName ] = { wrapper: ext, orig: origExt };
  466. addEnumsForContext( origExt, extensionName );
  467. }
  468. }
  469. return ext;
  470. };
  471. }
  472. // Make a an object that has a copy of every property of the WebGL context
  473. // but wraps all functions.
  474. for ( const propertyName in ctx ) {
  475. if ( typeof ctx[ propertyName ] === 'function' ) {
  476. if ( propertyName !== 'getExtension' ) {
  477. wrapper[ propertyName ] = makeErrorWrapper( ctx, propertyName );
  478. } else {
  479. const wrapped = makeErrorWrapper( ctx, propertyName );
  480. wrapper[ propertyName ] = makeGetExtensionWrapper( ctx, wrapped );
  481. }
  482. } else {
  483. makePropertyWrapper( wrapper, ctx, propertyName );
  484. }
  485. }
  486. // Override the getError function with one that returns our saved results.
  487. if ( wrapper.getError ) {
  488. wrapper.getError = function () {
  489. for ( const err of Object.keys( glErrorShadow ) ) {
  490. if ( glErrorShadow[ err ] ) {
  491. glErrorShadow[ err ] = false;
  492. return err;
  493. }
  494. }
  495. return ctx.NO_ERROR;
  496. };
  497. }
  498. if ( wrapper.bindBuffer ) {
  499. sharedState.wrappers[ 'webgl' ] = { wrapper: wrapper, orig: ctx };
  500. addEnumsForContext( ctx, ctx.bindBufferBase ? 'WebGL2' : 'WebGL' );
  501. }
  502. return wrapper;
  503. }
  504. return {
  505. makeDebugContext,
  506. glFunctionArgsToString,
  507. glFunctionArgToString,
  508. glEnumToString,
  509. };
  510. } ) );