OLD | NEW |
| (Empty) |
1 //Copyright (c) 2009 The Chromium Authors. All rights reserved. | |
2 //Use of this source code is governed by a BSD-style license that can be | |
3 //found in the LICENSE file. | |
4 | |
5 // Various functions for helping debug WebGL apps. | |
6 | |
7 WebGLDebugUtils = function() { | |
8 | |
9 /** | |
10 * Wrapped logging function. | |
11 * @param {string} msg Message to log. | |
12 */ | |
13 var log = function(msg) { | |
14 if (window.console && window.console.log) { | |
15 window.console.log(msg); | |
16 } | |
17 }; | |
18 | |
19 /** | |
20 * Which arguements are enums. | |
21 * @type {!Object.<number, string>} | |
22 */ | |
23 var glValidEnumContexts = { | |
24 | |
25 // Generic setters and getters | |
26 | |
27 'enable': { 0:true }, | |
28 'disable': { 0:true }, | |
29 'getParameter': { 0:true }, | |
30 | |
31 // Rendering | |
32 | |
33 'drawArrays': { 0:true }, | |
34 'drawElements': { 0:true, 2:true }, | |
35 | |
36 // Shaders | |
37 | |
38 'createShader': { 0:true }, | |
39 'getShaderParameter': { 1:true }, | |
40 'getProgramParameter': { 1:true }, | |
41 | |
42 // Vertex attributes | |
43 | |
44 'getVertexAttrib': { 1:true }, | |
45 'vertexAttribPointer': { 2:true }, | |
46 | |
47 // Textures | |
48 | |
49 'bindTexture': { 0:true }, | |
50 'activeTexture': { 0:true }, | |
51 'getTexParameter': { 0:true, 1:true }, | |
52 'texParameterf': { 0:true, 1:true }, | |
53 'texParameteri': { 0:true, 1:true, 2:true }, | |
54 'texImage2D': { 0:true, 2:true, 6:true, 7:true }, | |
55 'texSubImage2D': { 0:true, 6:true, 7:true }, | |
56 'copyTexImage2D': { 0:true, 2:true }, | |
57 'copyTexSubImage2D': { 0:true }, | |
58 'generateMipmap': { 0:true }, | |
59 | |
60 // Buffer objects | |
61 | |
62 'bindBuffer': { 0:true }, | |
63 'bufferData': { 0:true, 2:true }, | |
64 'bufferSubData': { 0:true }, | |
65 'getBufferParameter': { 0:true, 1:true }, | |
66 | |
67 // Renderbuffers and framebuffers | |
68 | |
69 'pixelStorei': { 0:true, 1:true }, | |
70 'readPixels': { 4:true, 5:true }, | |
71 'bindRenderbuffer': { 0:true }, | |
72 'bindFramebuffer': { 0:true }, | |
73 'checkFramebufferStatus': { 0:true }, | |
74 'framebufferRenderbuffer': { 0:true, 1:true, 2:true }, | |
75 'framebufferTexture2D': { 0:true, 1:true, 2:true }, | |
76 'getFramebufferAttachmentParameter': { 0:true, 1:true, 2:true }, | |
77 'getRenderbufferParameter': { 0:true, 1:true }, | |
78 'renderbufferStorage': { 0:true, 1:true }, | |
79 | |
80 // Frame buffer operations (clear, blend, depth test, stencil) | |
81 | |
82 'clear': { 0:true }, | |
83 'depthFunc': { 0:true }, | |
84 'blendFunc': { 0:true, 1:true }, | |
85 'blendFuncSeparate': { 0:true, 1:true, 2:true, 3:true }, | |
86 'blendEquation': { 0:true }, | |
87 'blendEquationSeparate': { 0:true, 1:true }, | |
88 'stencilFunc': { 0:true }, | |
89 'stencilFuncSeparate': { 0:true, 1:true }, | |
90 'stencilMaskSeparate': { 0:true }, | |
91 'stencilOp': { 0:true, 1:true, 2:true }, | |
92 'stencilOpSeparate': { 0:true, 1:true, 2:true, 3:true }, | |
93 | |
94 // Culling | |
95 | |
96 'cullFace': { 0:true }, | |
97 'frontFace': { 0:true }, | |
98 }; | |
99 | |
100 /** | |
101 * Map of numbers to names. | |
102 * @type {Object} | |
103 */ | |
104 var glEnums = null; | |
105 | |
106 /** | |
107 * Initializes this module. Safe to call more than once. | |
108 * @param {!WebGLRenderingContext} ctx A WebGL context. If | |
109 * you have more than one context it doesn't matter which one | |
110 * you pass in, it is only used to pull out constants. | |
111 */ | |
112 function init(ctx) { | |
113 if (glEnums == null) { | |
114 glEnums = { }; | |
115 for (var propertyName in ctx) { | |
116 if (typeof ctx[propertyName] == 'number') { | |
117 glEnums[ctx[propertyName]] = propertyName; | |
118 } | |
119 } | |
120 } | |
121 } | |
122 | |
123 /** | |
124 * Checks the utils have been initialized. | |
125 */ | |
126 function checkInit() { | |
127 if (glEnums == null) { | |
128 throw 'WebGLDebugUtils.init(ctx) not called'; | |
129 } | |
130 } | |
131 | |
132 /** | |
133 * Returns true or false if value matches any WebGL enum | |
134 * @param {*} value Value to check if it might be an enum. | |
135 * @return {boolean} True if value matches one of the WebGL defined enums | |
136 */ | |
137 function mightBeEnum(value) { | |
138 checkInit(); | |
139 return (glEnums[value] !== undefined); | |
140 } | |
141 | |
142 /** | |
143 * Gets an string version of an WebGL enum. | |
144 * | |
145 * Example: | |
146 * var str = WebGLDebugUtil.glEnumToString(ctx.getError()); | |
147 * | |
148 * @param {number} value Value to return an enum for | |
149 * @return {string} The string version of the enum. | |
150 */ | |
151 function glEnumToString(value) { | |
152 checkInit(); | |
153 var name = glEnums[value]; | |
154 return (name !== undefined) ? name : | |
155 ("*UNKNOWN WebGL ENUM (0x" + value.toString(16) + ")"); | |
156 } | |
157 | |
158 /** | |
159 * Returns the string version of a WebGL argument. | |
160 * Attempts to convert enum arguments to strings. | |
161 * @param {string} functionName the name of the WebGL function. | |
162 * @param {number} argumentIndx the index of the argument. | |
163 * @param {*} value The value of the argument. | |
164 * @return {string} The value as a string. | |
165 */ | |
166 function glFunctionArgToString(functionName, argumentIndex, value) { | |
167 var funcInfo = glValidEnumContexts[functionName]; | |
168 if (funcInfo !== undefined) { | |
169 if (funcInfo[argumentIndex]) { | |
170 return glEnumToString(value); | |
171 } | |
172 } | |
173 return value.toString(); | |
174 } | |
175 | |
176 /** | |
177 * Given a WebGL context returns a wrapped context that calls | |
178 * gl.getError after every command and calls a function if the | |
179 * result is not gl.NO_ERROR. | |
180 * | |
181 * @param {!WebGLRenderingContext} ctx The webgl context to | |
182 * wrap. | |
183 * @param {!function(err, funcName, args): void} opt_onErrorFunc | |
184 * The function to call when gl.getError returns an | |
185 * error. If not specified the default function calls | |
186 * console.log with a message. | |
187 */ | |
188 function makeDebugContext(ctx, opt_onErrorFunc) { | |
189 init(ctx); | |
190 opt_onErrorFunc = opt_onErrorFunc || function(err, functionName, args) { | |
191 // apparently we can't do args.join(","); | |
192 var argStr = ""; | |
193 for (var ii = 0; ii < args.length; ++ii) { | |
194 argStr += ((ii == 0) ? '' : ', ') + | |
195 glFunctionArgToString(functionName, ii, args[ii]); | |
196 } | |
197 log("WebGL error "+ glEnumToString(err) + " in "+ functionName + | |
198 "(" + argStr + ")"); | |
199 }; | |
200 | |
201 // Holds booleans for each GL error so after we get the error ourselves | |
202 // we can still return it to the client app. | |
203 var glErrorShadow = { }; | |
204 | |
205 // Makes a function that calls a WebGL function and then calls getError. | |
206 function makeErrorWrapper(ctx, functionName) { | |
207 return function() { | |
208 var result = ctx[functionName].apply(ctx, arguments); | |
209 var err = ctx.getError(); | |
210 if (err != 0) { | |
211 glErrorShadow[err] = true; | |
212 opt_onErrorFunc(err, functionName, arguments); | |
213 } | |
214 return result; | |
215 }; | |
216 } | |
217 | |
218 // Make a an object that has a copy of every property of the WebGL context | |
219 // but wraps all functions. | |
220 var wrapper = {}; | |
221 for (var propertyName in ctx) { | |
222 if (typeof ctx[propertyName] == 'function') { | |
223 wrapper[propertyName] = makeErrorWrapper(ctx, propertyName); | |
224 } else { | |
225 wrapper[propertyName] = ctx[propertyName]; | |
226 } | |
227 } | |
228 | |
229 // Override the getError function with one that returns our saved results. | |
230 wrapper.getError = function() { | |
231 for (var err in glErrorShadow) { | |
232 if (glErrorShadow[err]) { | |
233 glErrorShadow[err] = false; | |
234 return err; | |
235 } | |
236 } | |
237 return ctx.NO_ERROR; | |
238 }; | |
239 | |
240 return wrapper; | |
241 } | |
242 | |
243 function resetToInitialState(ctx) { | |
244 var numAttribs = ctx.getParameter(ctx.MAX_VERTEX_ATTRIBS); | |
245 var tmp = ctx.createBuffer(); | |
246 ctx.bindBuffer(ctx.ARRAY_BUFFER, tmp); | |
247 for (var ii = 0; ii < numAttribs; ++ii) { | |
248 ctx.disableVertexAttribArray(ii); | |
249 ctx.vertexAttribPointer(ii, 4, ctx.FLOAT, false, 0, 0); | |
250 ctx.vertexAttrib1f(ii, 0); | |
251 } | |
252 ctx.deleteBuffer(tmp); | |
253 | |
254 var numTextureUnits = ctx.getParameter(ctx.MAX_TEXTURE_IMAGE_UNITS); | |
255 for (var ii = 0; ii < numTextureUnits; ++ii) { | |
256 ctx.activeTexture(ctx.TEXTURE0 + ii); | |
257 ctx.bindTexture(ctx.TEXTURE_CUBE_MAP, null); | |
258 ctx.bindTexture(ctx.TEXTURE_2D, null); | |
259 } | |
260 | |
261 ctx.activeTexture(ctx.TEXTURE0); | |
262 ctx.useProgram(null); | |
263 ctx.bindBuffer(ctx.ARRAY_BUFFER, null); | |
264 ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null); | |
265 ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); | |
266 ctx.bindRenderbuffer(ctx.RENDERBUFFER, null); | |
267 ctx.disable(ctx.BLEND); | |
268 ctx.disable(ctx.CULL_FACE); | |
269 ctx.disable(ctx.DEPTH_TEST); | |
270 ctx.disable(ctx.DITHER); | |
271 ctx.disable(ctx.SCISSOR_TEST); | |
272 ctx.blendColor(0, 0, 0, 0); | |
273 ctx.blendEquation(ctx.FUNC_ADD); | |
274 ctx.blendFunc(ctx.ONE, ctx.ZERO); | |
275 ctx.clearColor(0, 0, 0, 0); | |
276 ctx.clearDepth(1); | |
277 ctx.clearStencil(-1); | |
278 ctx.colorMask(true, true, true, true); | |
279 ctx.cullFace(ctx.BACK); | |
280 ctx.depthFunc(ctx.LESS); | |
281 ctx.depthMask(true); | |
282 ctx.depthRange(0, 1); | |
283 ctx.frontFace(ctx.CCW); | |
284 ctx.hint(ctx.GENERATE_MIPMAP_HINT, ctx.DONT_CARE); | |
285 ctx.lineWidth(1); | |
286 ctx.pixelStorei(ctx.PACK_ALIGNMENT, 4); | |
287 ctx.pixelStorei(ctx.UNPACK_ALIGNMENT, 4); | |
288 ctx.pixelStorei(ctx.UNPACK_FLIP_Y_WEBGL, false); | |
289 ctx.pixelStorei(ctx.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); | |
290 // TODO: Delete this IF. | |
291 if (ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL) { | |
292 ctx.pixelStorei(ctx.UNPACK_COLORSPACE_CONVERSION_WEBGL, ctx.BROWSER_DEFAULT_
WEBGL); | |
293 } | |
294 ctx.polygonOffset(0, 0); | |
295 ctx.sampleCoverage(1, false); | |
296 ctx.scissor(0, 0, ctx.canvas.width, ctx.canvas.height); | |
297 ctx.stencilFunc(ctx.ALWAYS, 0, 0xFFFFFFFF); | |
298 ctx.stencilMask(0xFFFFFFFF); | |
299 ctx.stencilOp(ctx.KEEP, ctx.KEEP, ctx.KEEP); | |
300 ctx.viewport(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight); | |
301 ctx.clear(ctx.COLOR_BUFFER_BIT | ctx.DEPTH_BUFFER_BIT | ctx.STENCIL_BUFFER_BIT
); | |
302 | |
303 // TODO: This should NOT be needed but Firefox fails with 'hint' | |
304 while(ctx.getError()); | |
305 } | |
306 | |
307 function makeLostContextSimulatingContext(ctx) { | |
308 var wrapper_ = {}; | |
309 var contextId_ = 1; | |
310 var contextLost_ = false; | |
311 var resourceId_ = 0; | |
312 var resourceDb_ = []; | |
313 var onLost_ = undefined; | |
314 var onRestored_ = undefined; | |
315 var nextOnRestored_ = undefined; | |
316 | |
317 // Holds booleans for each GL error so can simulate errors. | |
318 var glErrorShadow_ = { }; | |
319 | |
320 function isWebGLObject(obj) { | |
321 //return false; | |
322 return (obj instanceof WebGLBuffer || | |
323 obj instanceof WebGLFramebuffer || | |
324 obj instanceof WebGLProgram || | |
325 obj instanceof WebGLRenderbuffer || | |
326 obj instanceof WebGLShader || | |
327 obj instanceof WebGLTexture); | |
328 } | |
329 | |
330 function checkResources(args) { | |
331 for (var ii = 0; ii < args.length; ++ii) { | |
332 var arg = args[ii]; | |
333 if (isWebGLObject(arg)) { | |
334 return arg.__webglDebugContextLostId__ == contextId_; | |
335 } | |
336 } | |
337 return true; | |
338 } | |
339 | |
340 function clearErrors() { | |
341 var k = Object.keys(glErrorShadow_); | |
342 for (var ii = 0; ii < k.length; ++ii) { | |
343 delete glErrorShdow_[k]; | |
344 } | |
345 } | |
346 | |
347 // Makes a function that simulates WebGL when out of context. | |
348 function makeLostContextWrapper(ctx, functionName) { | |
349 var f = ctx[functionName]; | |
350 return function() { | |
351 // Only call the functions if the context is not lost. | |
352 if (!contextLost_) { | |
353 if (!checkResources(arguments)) { | |
354 glErrorShadow_[ctx.INVALID_OPERATION] = true; | |
355 return; | |
356 } | |
357 var result = f.apply(ctx, arguments); | |
358 return result; | |
359 } | |
360 }; | |
361 } | |
362 | |
363 for (var propertyName in ctx) { | |
364 if (typeof ctx[propertyName] == 'function') { | |
365 wrapper_[propertyName] = makeLostContextWrapper(ctx, propertyName); | |
366 } else { | |
367 wrapper_[propertyName] = ctx[propertyName]; | |
368 } | |
369 } | |
370 | |
371 function makeWebGLContextEvent(statusMessage) { | |
372 return {statusMessage: statusMessage}; | |
373 } | |
374 | |
375 function freeResources() { | |
376 for (var ii = 0; ii < resourceDb_.length; ++ii) { | |
377 var resource = resourceDb_[ii]; | |
378 if (resource instanceof WebGLBuffer) { | |
379 ctx.deleteBuffer(resource); | |
380 } else if (resource instanceof WebctxFramebuffer) { | |
381 ctx.deleteFramebuffer(resource); | |
382 } else if (resource instanceof WebctxProgram) { | |
383 ctx.deleteProgram(resource); | |
384 } else if (resource instanceof WebctxRenderbuffer) { | |
385 ctx.deleteRenderbuffer(resource); | |
386 } else if (resource instanceof WebctxShader) { | |
387 ctx.deleteShader(resource); | |
388 } else if (resource instanceof WebctxTexture) { | |
389 ctx.deleteTexture(resource); | |
390 } | |
391 } | |
392 } | |
393 | |
394 wrapper_.loseContext = function() { | |
395 if (!contextLost_) { | |
396 contextLost_ = true; | |
397 ++contextId_; | |
398 while (ctx.getError()); | |
399 clearErrors(); | |
400 glErrorShadow_[ctx.CONTEXT_LOST_WEBGL] = true; | |
401 setTimeout(function() { | |
402 if (onLost_) { | |
403 onLost_(makeWebGLContextEvent("context lost")); | |
404 } | |
405 }, 0); | |
406 } | |
407 }; | |
408 | |
409 wrapper_.restoreContext = function() { | |
410 if (contextLost_) { | |
411 if (onRestored_) { | |
412 setTimeout(function() { | |
413 freeResources(); | |
414 resetToInitialState(ctx); | |
415 contextLost_ = false; | |
416 if (onRestored_) { | |
417 var callback = onRestored_; | |
418 onRestored_ = nextOnRestored_; | |
419 nextOnRestored_ = undefined; | |
420 callback(makeWebGLContextEvent("context restored")); | |
421 } | |
422 }, 0); | |
423 } else { | |
424 throw "You can not restore the context without a listener" | |
425 } | |
426 } | |
427 }; | |
428 | |
429 // Wrap a few functions specially. | |
430 wrapper_.getError = function() { | |
431 if (!contextLost_) { | |
432 var err; | |
433 while (err = ctx.getError()) { | |
434 glErrorShadow_[err] = true; | |
435 } | |
436 } | |
437 for (var err in glErrorShadow_) { | |
438 if (glErrorShadow_[err]) { | |
439 delete glErrorShadow_[err]; | |
440 return err; | |
441 } | |
442 } | |
443 return ctx.NO_ERROR; | |
444 }; | |
445 | |
446 var creationFunctions = [ | |
447 "createBuffer", | |
448 "createFramebuffer", | |
449 "createProgram", | |
450 "createRenderbuffer", | |
451 "createShader", | |
452 "createTexture" | |
453 ]; | |
454 for (var ii = 0; ii < creationFunctions.length; ++ii) { | |
455 var functionName = creationFunctions[ii]; | |
456 wrapper_[functionName] = function(f) { | |
457 return function() { | |
458 if (contextLost_) { | |
459 return null; | |
460 } | |
461 var obj = f.apply(ctx, arguments); | |
462 obj.__webglDebugContextLostId__ = contextId_; | |
463 resourceDb_.push(obj); | |
464 return obj; | |
465 }; | |
466 }(ctx[functionName]); | |
467 } | |
468 | |
469 var functionsThatShouldReturnNull = [ | |
470 "getActiveAttrib", | |
471 "getActiveUniform", | |
472 "getBufferParameter", | |
473 "getContextAttributes", | |
474 "getAttachedShaders", | |
475 "getFramebufferAttachmentParameter", | |
476 "getParameter", | |
477 "getProgramParameter", | |
478 "getProgramInfoLog", | |
479 "getRenderbufferParameter", | |
480 "getShaderParameter", | |
481 "getShaderInfoLog", | |
482 "getShaderSource", | |
483 "getTexParameter", | |
484 "getUniform", | |
485 "getUniformLocation", | |
486 "getVertexAttrib" | |
487 ]; | |
488 for (var ii = 0; ii < functionsThatShouldReturnNull.length; ++ii) { | |
489 var functionName = functionsThatShouldReturnNull[ii]; | |
490 wrapper_[functionName] = function(f) { | |
491 return function() { | |
492 if (contextLost_) { | |
493 return null; | |
494 } | |
495 return f.apply(ctx, arguments); | |
496 } | |
497 }(wrapper_[functionName]); | |
498 } | |
499 | |
500 var isFunctions = [ | |
501 "isBuffer", | |
502 "isEnabled", | |
503 "isFramebuffer", | |
504 "isProgram", | |
505 "isRenderbuffer", | |
506 "isShader", | |
507 "isTexture" | |
508 ]; | |
509 for (var ii = 0; ii < isFunctions.length; ++ii) { | |
510 var functionName = isFunctions[ii]; | |
511 wrapper_[functionName] = function(f) { | |
512 return function() { | |
513 if (contextLost_) { | |
514 return false; | |
515 } | |
516 return f.apply(ctx, arguments); | |
517 } | |
518 }(wrapper_[functionName]); | |
519 } | |
520 | |
521 wrapper_.checkFramebufferStatus = function(f) { | |
522 return function() { | |
523 if (contextLost_) { | |
524 return ctx.FRAMEBUFFER_UNSUPPORTED; | |
525 } | |
526 return f.apply(ctx, arguments); | |
527 }; | |
528 }(wrapper_.checkFramebufferStatus); | |
529 | |
530 wrapper_.getAttribLocation = function(f) { | |
531 return function() { | |
532 if (contextLost_) { | |
533 return -1; | |
534 } | |
535 return f.apply(ctx, arguments); | |
536 }; | |
537 }(wrapper_.getAttribLocation); | |
538 | |
539 wrapper_.getVertexAttribOffset = function(f) { | |
540 return function() { | |
541 if (contextLost_) { | |
542 return 0; | |
543 } | |
544 return f.apply(ctx, arguments); | |
545 }; | |
546 }(wrapper_.getVertexAttribOffset); | |
547 | |
548 wrapper_.isContextLost = function() { | |
549 return contextLost_; | |
550 }; | |
551 | |
552 function wrapEvent(listener) { | |
553 if (typeof(listener) == "function") { | |
554 return listener; | |
555 } else { | |
556 return function(info) { | |
557 listener.handleEvent(info); | |
558 } | |
559 } | |
560 } | |
561 | |
562 wrapper_.registerOnContextLostListener = function(listener) { | |
563 onLost_ = wrapEvent(listener); | |
564 }; | |
565 | |
566 wrapper_.registerOnContextRestoredListener = function(listener) { | |
567 if (contextLost_) { | |
568 nextOnRestored_ = wrapEvent(listener); | |
569 } else { | |
570 onRestored_ = wrapEvent(listener); | |
571 } | |
572 } | |
573 | |
574 return wrapper_; | |
575 } | |
576 | |
577 return { | |
578 /** | |
579 * Initializes this module. Safe to call more than once. | |
580 * @param {!WebGLRenderingContext} ctx A WebGL context. If | |
581 * you have more than one context it doesn't matter which one | |
582 * you pass in, it is only used to pull out constants. | |
583 */ | |
584 'init': init, | |
585 | |
586 /** | |
587 * Returns true or false if value matches any WebGL enum | |
588 * @param {*} value Value to check if it might be an enum. | |
589 * @return {boolean} True if value matches one of the WebGL defined enums | |
590 */ | |
591 'mightBeEnum': mightBeEnum, | |
592 | |
593 /** | |
594 * Gets an string version of an WebGL enum. | |
595 * | |
596 * Example: | |
597 * WebGLDebugUtil.init(ctx); | |
598 * var str = WebGLDebugUtil.glEnumToString(ctx.getError()); | |
599 * | |
600 * @param {number} value Value to return an enum for | |
601 * @return {string} The string version of the enum. | |
602 */ | |
603 'glEnumToString': glEnumToString, | |
604 | |
605 /** | |
606 * Converts the argument of a WebGL function to a string. | |
607 * Attempts to convert enum arguments to strings. | |
608 * | |
609 * Example: | |
610 * WebGLDebugUtil.init(ctx); | |
611 * var str = WebGLDebugUtil.glFunctionArgToString('bindTexture', 0, gl.TEXTU
RE_2D); | |
612 * | |
613 * would return 'TEXTURE_2D' | |
614 * | |
615 * @param {string} functionName the name of the WebGL function. | |
616 * @param {number} argumentIndx the index of the argument. | |
617 * @param {*} value The value of the argument. | |
618 * @return {string} The value as a string. | |
619 */ | |
620 'glFunctionArgToString': glFunctionArgToString, | |
621 | |
622 /** | |
623 * Given a WebGL context returns a wrapped context that calls | |
624 * gl.getError after every command and calls a function if the | |
625 * result is not NO_ERROR. | |
626 * | |
627 * You can supply your own function if you want. For example, if you'd like | |
628 * an exception thrown on any GL error you could do this | |
629 * | |
630 * function throwOnGLError(err, funcName, args) { | |
631 * throw WebGLDebugUtils.glEnumToString(err) + " was caused by call to" + | |
632 * funcName; | |
633 * }; | |
634 * | |
635 * ctx = WebGLDebugUtils.makeDebugContext( | |
636 * canvas.getContext("webgl"), throwOnGLError); | |
637 * | |
638 * @param {!WebGLRenderingContext} ctx The webgl context to wrap. | |
639 * @param {!function(err, funcName, args): void} opt_onErrorFunc The function | |
640 * to call when gl.getError returns an error. If not specified the default | |
641 * function calls console.log with a message. | |
642 */ | |
643 'makeDebugContext': makeDebugContext, | |
644 | |
645 /** | |
646 * Given a WebGL context returns a wrapped context that adds 4 | |
647 * functions. | |
648 * | |
649 * ctx.loseContext: | |
650 * simulates a lost context event. | |
651 * | |
652 * ctx.restoreContext: | |
653 * simulates the context being restored. | |
654 * | |
655 * ctx.registerOnContextLostListener(listener): | |
656 * lets you register a listener for context lost. Use instead | |
657 * of addEventListener('webglcontextlostevent', listener); | |
658 * | |
659 * ctx.registerOnContextRestoredListener(listener): | |
660 * lets you register a listener for context restored. Use | |
661 * instead of addEventListener('webglcontextrestored', | |
662 * listener); | |
663 * | |
664 * @param {!WebGLRenderingContext} ctx The webgl context to wrap. | |
665 */ | |
666 'makeLostContextSimulatingContext': makeLostContextSimulatingContext, | |
667 | |
668 /** | |
669 * Resets a context to the initial state. | |
670 * @param {!WebGLRenderingContext} ctx The webgl context to | |
671 * reset. | |
672 */ | |
673 'resetToInitialState': resetToInitialState | |
674 }; | |
675 | |
676 }(); | |
677 | |
OLD | NEW |